Encrypting credentials and reusing them securely - python

I'm currently building a website where the users would enter their credentials for another web service that I'm going to scrape to get their data.
I want to make sure that when I save their credentials in my database, I'm using the best encryption possible and the best architecture to ensure the highest level of security.
The first idea that I had in mind was to encrypt the data using an RSA pub key (PBKDF2, PKCS1_OAEP, AES 256bit... ???) and then allowing my scrapping script to use the private key to decrypt the credentials and use them.
But if my server is hacked, the hacker would have access to both the database and the private key, since it will be kept on my server that runs the scrapping script and hosts the DB. Is there an architecture pattern that solves this ?
I've read that that there should be a mix of hashing and encryption to enable maximum security but hashing is uni directional and it doesn't fit my use case since I will have to reuse the credentials. If you can advise me with the best encryption cypher/pattern you know it could be awesome.
I'm coding in python and I believe PyCrypto is the go-to library for encryption. (Sorry I have very little knowledge about cryptography so I might be confusing technologies)

Do the encryption and decryption on the second server (encryption server).
Pass the password to the encryption server along with an id for encryption and it returns the encrypted password to store in the DB.
When the password is needed pass the encrypted password to the encryption server for decryption.
Have the encryption server monitor request activity, if an unusual number of requests are received sound an alarm and in extreme cases stop processing requests.
Make the second server very secure. No Internet access, minimal access accounts, 2-factor authentication.
The encryption server becomes a poor-man's HSM (Hardware Encryption Module).

from cryptography.fernet import Fernet
class Crypt():
def __init__(self, key):
self.cipher = Fernet(key)
def encrypt(self, my_message):
return self.cipher.encrypt(my_message)
def decrypt(self, my_message):
return self.cipher.decrypt(my_message)
#staticmethod
def key_maker():
return Fernet.generate_key()
if __name__ == '__main__':
KEY = Crypt.key_maker()
crypt = Crypt(KEY)
msg = crypt.encrypt(b'hi')
msg = crypt,decrypt(msg)

Related

Decrypting From OpenSSL PHP Library Using Python

I'm implementing an RSA encryption scheme where the MySQL database data is encrypted using a public key, and only the private key can be used to decrypt it.
I've managed to do encryption and decryption using the PHP openssl library, and even added a passphrase to protect the private key.
// $sRawText is the text string to encrypt.
// $sPublicKey is the public key stored on the server.
openssl_public_encrypt($sRawText, $sResult, $sPublicKey, OPENSSL_PKCS1_OAEP_PADDING);
// $sResult is the encrypted result which can then be stored in the database.
It works great for all the purposes I need to be publicly available, which is to add new entries if a user signs up or, in the future, verify details if they log in. This is sensitive data like contact information, which I only ever use very occasionally. Data that's verify only like passwords can be hashed still, and anything that needs to be read doesn't get encrypted.
Here's how I'm presently decrypting with PHP:
// $sPrivateKey is the matching private key.
// $sPassPhrase is the pass phrase (required to decrypt the result).
// $sRawBytes is the encrypted data from the database to decrypt.
$kRsaKey = openssl_pkey_get_private($sPrivateKey, $sPassPhrase);
openssl_private_decrypt($sRawBytes, $sResult, $kRsaKey, OPENSSL_PKCS1_OAEP_PADDING);
// $sResult will be the decrypted data.
The problem with this decryption approach is that it's all taking place live on the server. Obviously, storing the private key on that server would defeat most of the security benefits, as anyone with enough access to the server could pretty easily take it. The best I can come up with using PHP on the server is to pass the private key and/or pass phrase at each time of decryption. However, that still has the key being live there, and also opens up a new attack avenue for the key and pass phrase to be intercepted in those requests.
What I'm trying to do is perform all the decryption offline. So an offline software will be provided the encrypted data in a text file, which it translates into a list of instructions based on the data and intended operation. The private key never leaves that isolated environment and the pass phrase is never stored between sessions.
I'm running into all kinds of hurdles setting up an offline PHP environment, so I thought it might be easier to try to do the decryption in Python. Everything should be standard, or so I thought.
I'm currently trying to use the Python RSA library here:
https://stuvel.eu/python-rsa-doc/reference.html#exceptions
The thing I can't figure out is how to decrypt using the passphrase-protected private key. Would anyone be able to post a really simple example, or is it fundamentally not compatible without major modifications to the Python RSA library? What's the easiest approach to be able to do this decryption offline?
Okay I'll post the answer now that I figured out.
(1) We need to get the cryptography library in Python.
On Windows, enter into the command prompt (not Python interpreter):
py -m pip install cryptography
If the above doesn't work, try replacing 'py' with 'python'.
(2) The private key needs to be in a text file "privatekey.txt".
(3) Use this code for decryption:
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
#privatekey.txt must contain the private key.
#passphrase_bytes must be the passphrase, and it needs to be in bytes (ie b'My Pass Phrase')
with open("privatekey.txt", "rb") as key_file:
private_key = serialization.load_pem_private_key(
key_file.read(),
password=passphrase_bytes,
)
#rawtext_bytes must have the bytes of the ciphertext to decrypt
plaintext = private_key.decrypt(
rawtext_bytes,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None
)
)
#plaintext will now contain the result

Adding a user authentication system to my Python script or executable

I'm working on a program in Python that is highly valuable to certain people. I've been trying to add a user authentication system to keep people from copying and sharing the files easily. To explain further this is the flow:
1: User opens the EXE (cx_freezed python file)
2: Program asks user for their login (from a MySQL database)
3: Program checks if someone is already logged in using that info
4: If someone is logged in, don't let them log in. If someone isn't, log them in.
There are two ways I've thought about doing this but I have absolutely no idea where to start because this isn't in my typical range. I could either intigrate this into Python, or use a tool to take my exe file and add an auth (is that a thing?).
Any advice about where to remotely start would be awesome. This is out of my typical range so I'm a bit daunted by it.
iv'e done something like this in my latest project, however i'm not an expert whatsoever so take what i say with a grain of salt, there might be other, better ways to do this but its just how i implemented it.
these are the models i've worked with:
socket, json, sqlite3 , wxpython (for gui) + pycrypto (if you want to encrypt and decrypt the messages using RSA and AES keys for added security, like i did)
basically what i did was the following:
a socket connection is created between the client and the server.
if you're not going to use pycrypto skip the second and third parts - the server generates a pair of RSA private and public keys for himself and so does the client for himself. the client then sends its RSA public key to the server using the socket connection. the pair of RSA keys(the public key and private key) are essentialy two keys that can only decrypt the messages encrypted by the other key in the pair (public key encrypts-private key decrypts || private key encrypts-public key decrypts) (i would suggest this computerphile video for a little more in depth explanation, once you get how the keys suppose to theoretically work, the module itself is pretty straight forward, so don't worry about that).
the server now creates an AES key (a symmetrical key, that can decrypt the messages it encrypted), and then encrypts the AES key (which is basically a pretty long string) with the RSA public key he got from the client, and sends its to the client, so now only the client can decrypt this message with his private key and get the AES key that will be used for the communication between them.
the client enters a new username and password in order signup. the client script puts the data in a list like so: ["signup", newUserNameVar,NewPassWordVar], uses the json encoding on it using json.dumps() function (basically turns the entire list into a string that can be sent through a socket) then encrypts it using the AES key we got from the server earlier, and then sends it to the server through the socket connection.
so now the server receives an encrypted message only he can decrypt with his AES key (which is the same one the client holds, if you've followed my explanation earlier). so he decrypts the message using the AES key and gets the json message the client sent him. to turn the json back into the list the server uses the json.dumps() function (which turns the json object back into a list).
in my design, the first index of the list is the command so basically either "login" or "setup", so now the server deploys a switch case (or a bunch of ifs) on the first index of the list to see which command he needs to fulfill. if its signup then he takes the 2nd and 3rd index off of the list and creates the table in the database with rows corresponding to the users data, and if its login it takes the data from the database and if it matches the data that was sent by the client in the other indexes of the list then its sends a "correct" response back, and then you can tell your script to run that other program only when it gets a "correct" message from the server, which sends the message exactly as i mentioned in steps 4-5.
so to recap it goes something like this:
server: generate - RSA public key, RSA private key, AES key
client: generate - (other)RSA public key, (other)RSA private key
client ----> server, send clients RSA public key
server ----> client, encrypt the AES key using the clients RSA key and send it to him.
client: decrypt the AES key using the clients private RSA key.
continue to talk with each other in the following way: LIST -> JSON (json.dumps(LIST))-> AES encryption on the JSON object -> send through a socket.
AES decryption on the message you got -> UNJSON (json.loads(WHAT YOU GOT FROM THE DECRYPTION)) -> LIST ->deploy switch-case.

AES - Encryption with Crypto (node-js) / decryption with Pycrypto (python)

I'm writing this question + answer because I struggled a lot (maybe because of a lack of experience), got lost in many different ways of encrypting/decrypting things with node or python.
I thought maybe my case could help people in the future.
What I needed to do:
Get data from a form, encrypt them using Crypto (node-js)
Pass the encrypted data in Python and decrypt it using PyCrypto.
I chose to use the AES encryption.
Here is how I started (I'm not gonna go through everything I tried):
I followed the example at the end of this page
Which gave in my case:
(this might be a very bad mix between javascript and coffeescript)
crypto = require "crypto"
[...]
key = "mykeywhatever"
cipher = crypto.createCipher('aes192', key)
cipher.update('string i want to encode', 'binary', 'hex')
encoded_string = cipher.final('hex')
[...]
This worked pretty fine to encode my string.
Then I wrote my python script to decrypt this string, using the readme on PyCrypto's github's page:
from Crypto.Cipher import AES
[...]
my_string = data_coming_from_rabbitmq
obj = AES.new('mykeywhatever', AES.MODE_CBC)
obj.decrypt(ciphertext)
[...]
This obviously didn't work: in the readme there is an IV but since I didn't gave one in the node script, why would I give one in the python one?
After more googling, I learnt that node's Crypto uses OpenSSL, while PyCrypto apparently doesn't. So I looked into that and found those pages:
How can I decrypt something with PyCrypto that was encrypted using OpenSSL?
Is AES the same in libraries PyCrypto & Node.JS Crypto
and a lot more...
So things got complicated, no one is doing the same thing to decrypt data, I got lost, and asked for help.
The answer is what my coworker and I came up with (well, mostly my corworker).
So we started from the "How can i decrypt... OpenSSL" 's answer.
We needed to modify the encryption script which gave:
crypto = require "crypto"
[...]
var iv = new Buffer('asdfasdfasdfasdf')
var key = new Buffer('asdfasdfasdfasdfasdfasdfasdfasdf')
var cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
cipher.update(new Buffer("mystring"));
var enc = cipher.final('base64');
[...]
iv needs to be 16bytes long, key is 32bytes. And we changed createCipher to createCipheriv.
Back to the python decryption script:
Process was simply reading PyCrypto's documentation, and compare with the code we started from.
Then we decided to just stick to the API, and start from scratch. And it gave:
from base64 import b64decode
from Crypto.Cipher import AES
[...]
iv = 'asdfasdfasdfasdf'
key = 'asdfasdfasdfasdfasdfasdfasdfasdf'
encoded = b64decode('my_encrypted_string')
dec = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
value = dec.decrypt(encoded)
And it was as simple as that...
Hope it'll help some of you!
Update:
As Perseids wrote in the comments of his answer, the IV has to be random and different for every message
The system you are building is probably insecure
Except for storage you basically never want to just encrypt your data, but also authenticate it. Authentication in this context means that a valid message can only be generated by someone who knows the key. A widely used authentication scheme is HMAC.
If you do not authenticate your messages anyone can feed data into your service. An attacker might not be able to fully control the outcome after decryption but he/she might still be very dangerous. For example, if you use CBC (which you do) and the most common paddings schemes (AES is a block cipher and can only encrypt 128bit Blocks of data) and an attacker can differentiate between a padding error and any other error then all your messages can be decrypted by an attacker. This is called a padding oracle attack and is far too common.
To protect from this class of attacks you can use an authenticated encryption scheme, for example the GCM blockcipher mode.
Also you have to protect against replay attacks. Consider a banking application and the data you are transmitting is a bank transfer order. Barring any TAN an attacker might record a previous transaction and replay this transaction to your service again and again thus transferring a multiple of the money the customer originally wanted to.
Is the form you are getting the data from transmitted over HTTPS? If not: Can the key be eavesdropped by an attacker? How does a user know he got the form from you and not anybody else (SSL/TLS is as much about authentication as it is about confidentiality).
Probably I have forgotten some other attack vectors simple CBC-encryption offers.
Alternatives
Probably the easiest way to protect against these attacks is to transmit the form data over HTTPS. SSL/TLS was designed to prevent all of the above attacks and the client and server side implementations had a long time to mature.

How to encrypt password sent to server

I'm trying to send username and password data from a web form to my server.
The password is sent as plain text over a https connection, then properly encrypted on the server (using python hashlib.sha224) before being stored, however I'm not sure how to transmit the password text to the server in an encrypted format.
My web client is written in javascript, and the server is written in python.
You'd have to encrypt it in the JavaScript. Unfortunately JavaScript does not offer any cryptographic tools out of the box, so you'd have to either use a third-party library or write something on your own.
As others have said, HTTPS is meant to encrypt the whole traffic, so perhaps you don't need anything extra? If you do however, you may want to look at this Article, which might shed some light on the problem. Good luck ! :)
Actually you transmit the password encrypted, because you use SSL.
Furthermore you do not encrypt the password, you hash the password on the server.
Anyway, you can use something like jCryption for it. crypt-js could also fit your purpose.
For python there is a Crypto Library called PyCrypto. But I have a Problem with the communication between Javascript and Python. I try to do something similar, but have a problem with it. I think my question will help you with yours.
Include nonce and block count in PyCrypto AES MODE_CTR
But in general, you have already solved the problem on your own, by using https.
https is an encrypted format. You're good.
If you want to do it clientside anyway I recommend hashing it with sha1. This guy seems to have some libs for that: http://pajhome.org.uk/crypt/md5/ - SHA1, sha256, md5, etc.
The HTTPS channel over which you send the password to the server provides encryption that is good enough.
However, you need a more secure storage mechanism for the password. Use an algorithm like "bcrypt" with many thousands of hash iterations (bcrypt calls this the cost factor, and it should be at least 16, meaning 216 iterations), and a random "salt". This works by deriving an encryption key from the password, which is a computationally expensive process, then using that key to encrypt some known cipher text, which is saved for comparison on future login attempts.
Also, using HTTPS on the login only is not sufficient. You should use it for any requests that require an authenticated user, or that carry an authentication cookie.
On the contrary to http, https is an encrypted protocol. You don't need additional encryption between the client and the server.
SHA224, SHA1 or MD5 are not a encryption, but a hashing function, which means they are irreversible.
Some answers suggest hashing passwords client-side.
However, irreversible doesn't mean uncrackable. Having plain password hashed, it is relatively easy to obtain the matching password from hash (see Rainbow tables for example).
Therefore you should not hash the password on the client side, but concatenate it with a some arbitrary string selected on the server side (usually called a salt) and hash the result.

Secure Options for storing Openssl password on a server (Linux, Python, CherryPy)

I've implemented a HTTP server (CherryPy and Python) that receives an encrypted file from a client (Android). I'm using OpenSSL to decrypt the uploaded file. Currently I'm using openssl -enc -pass file:password.txt -in encryptedfile -out decryptedfile to perform to decryption on the server side. As you can see the password used by openssl is stored in a plain text file (password.txt).
Is there a more secure way to store this OpenSSL password?
Thanks.
Pass it through a higher FD, and use that FD in the command line. Note that you'll need to use the preexec_fn argument to set up the FD before the process gets run.
subprocess.Popen(['openssl', ..., 'file:/dev/fd/12', ...], ...,
preexec_fn=passtofd12(password), ...)
For the sake of privacy for a user and other reasons passwords are generally not stored by servers. Typically users choose a password which is stored as a hash of some sort on the server.
Users then authenticate with the web application by checking the stored hash against a hash supplied based on user input. Once the client is authenticated a session identifier is provided allowing use of server resource(s). During this time a user can for instance upload the file. Encryption of the file on the server should be un-necessary assuming the hosting server is secured properly and and absent of other issues.
In this case, the authentication mechanism is not made clear, neither are the threats that pose a danger, or the life cycle of that uploaded file.
It seems that a server is receiving an encrypted file, plus some type of password. Is the protection of the password being considered during the transmission phase, or as storage on the server? The HTTPS protocol can help guard against threats concerning the transmission of the file/data. As I see from your description the concern seems to be storage on the server side.
Encrypting the passwords once they have been received by the server (either individually or by using a master password) adds another layer of security, but this approach is not without fault as the passphrase either (1) needs to be stored on the server in cleartext for accessing the files (2) or needs to be entered manually by an administrator when needed as part of any processing requiring the password - note that any resources encrypted with the password become un-useable to users.
While I am not completely aware of what is going on, the most secure thing to do would be to re-work the web application and carefully think through the design and its requirements.

Categories

Resources