I have messages I need to be able to encrypt when being sent. They should only be able to be decrypted by the receiver.
Initially, I had a structure where the message is encrypted using the receiver's public key, and the receiver then uses their private key to decrypt their messages. However, since I was using RSA, the size of the message was quite limited.
I'm imagining two potential solutions, but am not quite sure how to implement the better one (option 2).
(Easy) just split up each message into many smaller parts, encrypt and store those. This would only change the query structure of my app but not the encryption structure.
I could encrypt the messages with symmetric keys, which is faster and works on any size. However, I would then need to encrypt that symmetric key with an asymmetric one. The problem then becomes that I can only decrypt the symmetric key when the asymmetric private one is provided, ie when the receiver wants to read their messages. So in that case, how would I actually encrypt the messages? Since I don't want the sender to be able to access a key used for decryption as well.
The problem then becomes that I can only decrypt the symmetric key when the asymmetric private one is provided, ie when the receiver wants to read their messages. So in that case, how would I actually encrypt the messages?
That's simple, you use an ephemeral, message specific, fully random symmetric key for data encryption before you encrypt it with the public key. Preferably you should explicitly destroy the symmetric key after that. You can prefix the wrapped (encrypted) symmetric key before the ciphertext of the message, as it will always have the same size in bytes as the modulus (i.e. the RSA key size in bytes).
The system you are thinking about, which is much better than splitting up messages for RSA, is called a hybrid cryptosystem. There are various other ways to accomplish the same thing such as RSA-KEM and - for elliptic curves - ECIES. Both are not often present in crypto-libraries though.
If you decide to use RSA/AES for sending cryptograms then I would advice you to use OAEP and e.g. AES-CTR rather than AES-CBC as RSA PKCS#1 v1.5 padding and CBC padding are both vulnerable to padding oracle attacks.
It is highly recommended to sign the messages, otherwise an adversary can encrypt fake messages. Encryption is only used to achieve message confidentiality, not message integrity & authenticity. An adversary may even try plaintext oracle attacks if any message can be send. If you are not allowing a set of private keys that you control then you should sign-then-encrypt, not encrypt-then-sign.
And as always, prefer TLS or other explicit secure transport protocols if that's an option for transport security.
I have a keystring which allows customer to have additional features.
Obviously I would like the software to check that this string is valid, and not modified.
Is the following idea feasible:
get the key string as encrypted value, and encode it in Base64
(my encrypted string is around 100 characters, for my purpose)
calculate the checksum (MD5) of course using a private salt.
weave the checksum into the encrypted data
In principle :
xxxxCxxxxxxCxxxxxxxxCxxxxxxxxxxCxxxxxxxxxxxxxCxxx
the places to weave into the encrypted data could be determined by first cher of the encrypted, creating up to 16 different patterns.
On checking the code validity I simply "unweave" the checksum, test if it's correct, and thereby know if the data has been modified.
Is my line of thoughts correct ?
The cryptographic feature you're thinking of is called "authentication," and there are many well-established approaches. You should strongly avoid inventing your own, particularly using a long-outdated hash like MD5. When an encryption system is authenticated, it can detect changes to the ciphertext.
Your best approach is to use an authenticated cipher mode, such as AES-GCM. Used correctly, that combines encryption an authentication in a single operation. While decrypting an authenticated scheme, the decryption will fail if the cipher text has been modified.
If you don't have access to AES-GCM, the next option is AES-CBC+HMAC, which uses the more ubiquitous AES-CBC with a random IV, and appends a type of encrypted hash (called an HMAC) to the end of the message to authenticate it. In order to authenticate, you need to remove the HMAC, use it to validate that the cipher text is unmodified, and then proceed to decrypt normally. This scheme is generally called "encrypt then MAC."
The implementation details will depend on your language and frameworks.
I want to do searching on encrypted data. Which means that there is the need to have the same ciphertext every time I encrypt the same plaintext. I.e. think of a list of encrypted names and I want to find all "Kevin"'s in it. I would now encrypt "Kevin" and search the database for the encrypted text. All hits will be "Kevin"'s — but still only the one who has the password knows.
Now my question: What about security if I use the same salt and IV (to get the effect described above) all the time? Is the encryption still secure? Or is there any other method to do searching on encrypted data?
If you want to do a deterministic encryption then you should use an encryption mode
that has been designed for deterministic encryption (and not modify an encryption mode designed for something else).
One possibility is the SIV encryption mode described in
RFC 5297.
(Of course, deterministic encryption has its drawbacks, but discussing this is not part of this question.)
I start with a weak password (8 lower case characters for ex) and a file. I need to encrypt that file using that password. Result has to be secure against known attacks.
Approach 1: I could hash the password using SHA-256 and then use the resulting hash and file as inputs to AES-256, giving me an encrypted file. I understand that both SHA-256 and AES-256 are very fast. Wouldn't this make the file vulnerable to a brute force attack?
For example, could one grab a rainbow table of pre-computed SHA-256 hashes and, assuming its a really small file and a really weak password, try to AES-256 decrypt using each hash from that table in a reasonable time (a few months with specialized hardware).
Approach 2: Use bcrypt. If I understand correctly, bcrypt is better suited for encrypting files than SHA-256 + AES-256, since it's key generation scheme has a work factor resulting in a stronger key. Or am I wrong?
The Ruby and Python implementations (wrappers?) that I've seen focus on using bcrypt as a hashing scheme for passwords, not a cipher per se. Can I even use bcrypt to hash a weak pass AND encrypt the file in "one step"?
Approach 3: Use bcrypt to hash the pass, use that hash and file as inputs into AES-256, giving me the encrypted file. This takes care of the "key is too fast to generate" problem. (Assuming its a problem.) However, bcrypt hashes are 448-bits long and AES-256 wants a 256-bit key. Naive solution is to simply drop the trailing bits of the hash and use that as the key for AES-256. I would NOT go this route because I don't know enough about cryptography to know what the consequences are.
EDIT: I can't salt the pass, since this is for an offline application. ie. there is no reasonable place to store the salt. I can salt the pass and store the salt unencrypted along with the encrypted file. Salts are almost inherently public/visible if say a database is compromised. Purpose of a salt is to prevent a rainbow table attack. Thanks to Nemo, bellow.
Approach 4: Use PKCS#5 (PBKDF2 for deriving a key from a pass + a cipher of your choice for encryption using that key), preferably somebody else's implementation.
And don't forget the salt. (You store it together with the encrypted data. It only needs to be 8 bytes or so.)
I tried to research this, but there were still some questions left unanswered. I was looking into figuring out how an 8 character password gets turned into a high-bit encryption key. During my research I found articles that would talk about the salt value.
Assume you could get all 256 characters to play with, then an 8-character password would be 64-bits long. So, the remaining 64 bits is simply a salt value. And, correct me if I'm wrong, but this is done so that if someone was going to try to try ALL the possible values (brute force) they'd have to try all 128-bits since even the salt is unknown.
My questions really relate to this 'salt' value:
When someone makes an application, is the salt value hard-coded into it? And if so, can't it be obtained through reverse engineering the executable?
If the salt is generated at random, then I assume it must have some way to duplicate it. So, isn't that function that returns a random salt able to be reverse engineered to force it to duplicate itself to get the salt value?
This might be out of the scope, but if a salt value is generated on a server side (of a client/server relation), then wouldn't it have to be shared with the client so they can decrypt data sent by the server? And, if it's being sent over to the client, can't it be intercepted which makes it useless?
Is there some other method that is used besides this 'salt' value that can turn an 8-character string into a strong encryption key?
As usual with security-related questions, this answer's going to be a long one.
First, the simple answer.
Q: How does one turn an 8-character string into a 128-bit key?
A: One doesn't.
This is a truthful answer. Now, one that's more appropriate to what you're asking:
A: Create a random 64-bit value, and store it with the password in the database. Now, the password is half the key, and the random value is the other half.
This one is a lie. Here's what you actually do:
A: Hash the password along with a random salt using a method producing 128-bit or longer output. Use 128 bits of that as the key. Store the salt.
Now to address your questions on salt. First off, the purpose of salt is not really to lengthen encryption keys. It is to prevent people building rainbow tables - mappings from hashed to unhashed forms. To see that your encryption is no stronger, just imagine the attacker knows your key-extending algorithm. Now, instead of guessing 128-bit keys, he just guesses your 64-bit password and then uses the same algorithm. Voila. If the salt is unknown to the attacker, yes, you've gained a bit, but they must already have your ciphertexts to attack them, and the salt must be stored in the plain along with the ciphertext. So this is an unlikely scenario.
Salt is random per encryption key.
Random means random. If you are insufficiently random when you use a cryptography algorithm which assumes unpredictable material, you are vulnerable. That's what /dev/random is for - the system entropy pool is very good. Get a better hardware RNG if you're worried.
Yes, if you salted the key, someone needs the salt to decrypt things you encrypted using the salted key's hashed value. No, sending the salt does not necessarily compromise your data; send the salt only to someone who has proved they already have the password, but it's stored in your database next to the ciphertext. As mentioned above, someone needs both the salt and the ciphertext to mount an attack. Again, the purpose of the salt is not to raise the strength of the encryption, it is only to prevent precomputation attacks against your hashes.
There are methods of key extension. But, fundamentally, your protection is only so strong as its weakest link, so to provide 100% unbreakable encryption you will need a one-time-pad (a truly random key as long as the data to be encrypted). In the real world, what is usually done is hashing the password along with a salt to produce unpredictable longer keying material.
The function that turns a password or passphrase into a cryptographic key is called a Key Derivation Function (this might help you searching for more information on the topic). Such functions take a password and a randomly generated salt, and produce a key through a process that is deliberately computationally intensive. To reproduce that key, you must have both the password and the salt - so you are correct, the salt must be stored or transmitted along with the encrypted data.
The reason that Key Derivation Functions use a salt is to increase the work factor for any attacker. If a salt was not used, then a given password will only ever produce one single key. This means that an attacker can easily create a dictionary of keys - one key for each word in his dictionary. If, on the other hand, a 64 bit salt is used then each password can produce ~2**64 different possible keys, which expands the size of the dictionary by the same factor. This essentially makes producing such a dictionary ahead-of-time impossible. Instead, the attacker has to wait until he's seen the salt value, and then start generating keys to test. Since the key derivation function is computationally expensive, this is slow, and he won't be able to get far through his dictionary in a reasonable timeframe.
1) Each password is salted differently, and the salt is stored with the hash.
2) It's stored.
3) No, the client never decrypts anything. It sends the password, which the server salts, hashes and compares.
4) Yes, I'll add a few links.
Salts are generally not hardcoded, but they are generated at random, usually server-side, and never communicated to the user.
The salt would be stored in a database, separate from the passwords. The idea is that even if the password hash database is stolen, it would be very difficult to get the actual passwords (you'd have to try a lot of combinations), without having the salts as well. The salts would be generated at random, and different for each user, so even if you found it out for one, you'd still need to find all the others.
The salt is never sent, because the client never decrypts anything. The client sends the password to the server, the server adds the salt (which is randomly generated and stored for each user, and the user never know it).
So basically on this is what happens.
On registration:
User sends password to server.
Server adds a random salt to the password and then hashes it.
The salt and final hash are stored in separate tables.
On login:
User sends password to server.
Server fetches stored hash, and adds it to the password.
Server hashes the password and salt.
If the final hash matches the one in database, the user is logged
in.
...Is there some other method that is used besides this 'salt' value that can turn an 8-character string into a strong encryption key?
YES but...
You can compute the hash of that 8-character string:
For example if you need a 256 bit key:
key-256bit = hash(8-character string) //use SHA-256 - very secure
key-128bit = hash(8-character string) //use MD5 no more considered secure
"into a strong encryption key?" about strong.... depend how strong you need it because if you use only a 8-character string it mean that you could only create 2^8=256 different hash values and that's an easy task to brute force!!
conclusion: a salt would be of great value!
cheers
Daniel