Related
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.
Recently I have been looking to add some security to a project. I have been doing lots of research into the situation and discovered that clearly password hashing is a must. Further I have concluded that the best options are to use bcrypt, PBKDF2 or scrypt.
Also I have seen much discussion over hashing vs encryption and discovered that it is clear that hashing is more important. That said, after many searches into the depths of Google I have yet to find any information on whether encrypting an already properly hashed password is of any benefit, serves to harm or is relatively neutral.
Is the CPU cost of doing both worth it? Are there any pitfalls?
Encrypting something leads to the need of decrypting, which in turn leads to the problem you already have: secure storage of a secret.
Assuming that you want to store passwords as hashes instead of plain text you are basically doing this:
hashpw := hash(salt + password)
You then store salt and hashpw in a file and use this data instead of the plain text passwords. (Note that the order of the concatenation of salt and password is crucial in many cases and that this is only a visualization of the process, nothing more; Use a tool to generate salted hashes).
A possible attacker then needs to guess the salt and the plain text password to check for a match with
the stored hashpw, which is as secure as the hash algorithm you're using (rate of collisions).
Encrypting something using some cipher has the benefit of being able to restore the plain text, which
the hashing way does not offer. It also requires the system which decrypt the cipher text to have the
key available. Say you encrypt a string foo with some key bar. To decrypt the resulting cipher text
brn you need the key bar again. This key needs secure storage on your system and if the key is exposed
to the attacker, all security is gone.
As a general rule of thumb I would say that hashing provides a good way of storing texts which are
checked against (e.g., passwords) as the security of that is determined by the collision rate of the
hashing algorithm. Encryption on the other hand, is the technique you're using to store the rest of
the data securely.
You're on the right track. Use a key derivation/password hashing function like the ones you've mentioned.
Do not use just a hash or salted hash. The main issue is that traditional hashing algorithms (MD5, SHA-*, etc.) are intended to be fast. That's not advantageous for password storage, and many implementations are breakable, even if you add a salt.
Encryption always introduces key management-related issues. It should be avoided for password storage.
The advantage of a KDF is the work factor. It's designed to be slow and computationally expensive, which is why they're idea for this situation. Scrypt is the most resilient of the options you're looking at since it requires a set amount of memory to execute. This kills the GPU attack vector. There are tradeoffs whichever way you go, but all of your choices are fine as long as you use appropriate work factors where they're configurable.
I would simply encrypt the password. Hashing is fast, but a little unsafe for passwords. When I use hashing for security purposes, it's usually for things like message signing e.g. message + hash(message+password) so that the message can be verified, but I'm no expert in the field. I don't see the point of doing both.
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
A few years ago, when first being introduced to ASP.net and the .NET Framework, I built a very simple online file storage system.
This system used Rijndael encryption for storing the files encrypted on the server's hard drive, and an HttpHandler to decrypt and send those files to the client.
Being one of my first project with ASP.net and databases, not understanding much about how the whole thing works (as well as falling to the same trap described by Jeff Atwood on this subject), I decided to store freshly generated keys and IVs together with each file entry in the database.
To make things a bit clearer, encryption was only to protect files from direct access to the server, and keys were not generated by user-entered passwords.
My question is, assuming I don't want to keep one key for all files, how should I store encryption keys for best security? What is considered best practice? (i.e: On a different server, on a plain-text file, encrypted).
Also, what is the initialization vector used for in this type of encryption algorithm? Should it be constant in a system?
Keys should be protected and kept secret, simple as that. The implementation is not. Key Management Systems get sold for large amounts of money by trusted vendors because solving the problem is hard.
You certainly don't want to use the same key for each user, the more a key is used the "easier" it comes to break it, or at least have some information leaks. AES is a block cipher, it splits the data into blocks and feeds the results of the last block encryption into the next block. An initialization vector is the initial feed into the algorithm, because at the starting point there is nothing to start with. Using random IVs with the same key lowers the risk of information leaks - it should be different for every single piece of data encrypted.
How you store the keys depends on how your system is architected. I've just finished a KMS where the keys are kept away from the main system and functions to encrypt and decrypt are exposed via WCF. You send in plain text and get a reference to a key and the ciphered text back - that way the KMS is responsible for all cryptography in the system. This may be overkill in your case. If the user enters a password into your system then you could use that to generate a key pair. This keypair could then be used to encrypt a key store for that user - XML, SQL, whatever, and used to decrypt each key which is used to protect data.
Without knowing more about how your system is configured, or it's purpose it's hard to recommend anything other than "Keys must be protected, keys and IVs must not be reused."
There's a very good article on this one at http://web.archive.org/web/20121017062956/http://www.di-mgt.com.au/cryptoCreditcard.html which covers the both the IV and salting issues and the problems with ECB referred to above.
It still doesn't quite cover "where do I store the key", admittedly, but after reading and digesting it, it won't be a huge leap to a solution hopefully....
As a pretty good soltution, you could store your Key/IV pair in a table:
ID Key IV
skjsh-38798-1298-hjj FHDJK398720== HFkjdf87923==
When you save an encrypted value, save the ID and a random Salt value along with it.
Then, when you need to decrypt the value, lookup the key/iv pair using the id and the salt stored with the data.
You'd want to make sure you have a good security model around the key storage. If you went with SQL server, don't grant SELECT rights to the user that accesses the database from the application. You wouldn't want to give someone access to the whole table.
What if, you simply just generated a key for each user, then encrypted it with a "master key"? Then, make sure to have random ivs and as long as you keep the master key secret, no one should be able to make much use of any amount of keys. Of course, the encryption and decryption functions would have to be server-side, as well as the master key not being exposed at all, not even to the rest of the server. This would be a decent way to go about it, but obviously, there are some issues, namely, if you have stored your master key unsafely, well there goes your security. Of course, you could encrypt the master key, but then your just kicking the can down the road. Maybe, you could have an AES key, encrypted with a RSA key, and the RSA key is then secured by a secret passprase. This would mitigate the problem, as if you have a decent sized RSA key, you should be good, and then you could expose the encryption functions to the client (though still probably shouldn't) and since the key encryption uses a public key, you can have that taken. For added security, you could cycle the RSA key every few months or even weeks if need be. These are just a few ideas, and I know that it isn't bulletproof, but is more secure than just stuffing it in a sql database.
I'm writing a little desktop app that should be able to encrypt a data file and protect it with a password (i.e. one must enter the correct password to decrypt). I want the encrypted data file to be self-contained and portable, so the authentication has to be embedded in the file (or so I assume).
I have a strategy that appears workable and seems logical based on what I know (which is probably just enough to be dangerous), but I have no idea if it's actually a good design or not. So tell me: is this crazy? Is there a better/best way to do it?
Step 1: User enters plain-text password, e.g. "MyDifficultPassword"
Step 2: App hashes the user-password and uses that value as the symmetric key to encrypt/decrypt the data file. e.g. "MyDifficultPassword" --> "HashedUserPwdAndKey".
Step 3: App hashes the hashed value from step 2 and saves the new value in the data file header (i.e. the unencrypted part of the data file) and uses that value to validate the user's password. e.g. "HashedUserPwdAndKey" --> "HashedValueForAuthentication"
Basically I'm extrapolating from the common way to implement web-site passwords (when you're not using OpenID, that is), which is to store the (salted) hash of the user's password in your DB and never save the actual password. But since I use the hashed user password for the symmetric encryption key, I can't use the same value for authentication. So I hash it again, basically treating it just like another password, and save the doubly-hashed value in the data file. That way, I can take the file to another PC and decrypt it by simply entering my password.
So is this design reasonably secure, or hopelessly naive, or somewhere in between? Thanks!
EDIT: clarification and follow-up question re: Salt.
I thought the salt had to be kept secret to be useful, but your answers and links imply this is not the case. For example, this spec linked by erickson (below) says:
Thus, password-based key derivation as defined here is a function of a password, a salt, and an iteration count, where the latter two quantities need not be kept secret.
Does this mean that I could store the salt value in the same place/file as the hashed key and still be more secure than if I used no salt at all when hashing? How does that work?
A little more context: the encrypted file isn't meant to be shared with or decrypted by others, it's really single-user data. But I'd like to deploy it in a shared environment on computers I don't fully control (e.g. at work) and be able to migrate/move the data by simply copying the file (so I can use it at home, on different workstations, etc.).
Key Generation
I would recommend using a recognized algorithm such as PBKDF2 defined in PKCS #5 version 2.0 to generate a key from your password. It's similar to the algorithm you outline, but is capable of generating longer symmetric keys for use with AES. You should be able to find an open-source library that implements PBE key generators for different algorithms.
File Format
You might also consider using the Cryptographic Message Syntax as a format for your file. This will require some study on your part, but again there are existing libraries to use, and it opens up the possibility of inter-operating more smoothly with other software, like S/MIME-enabled mail clients.
Password Validation
Regarding your desire to store a hash of the password, if you use PBKDF2 to generate the key, you could use a standard password hashing algorithm (big salt, a thousand rounds of hashing) for that, and get different values.
Alternatively, you could compute a MAC on the content. A hash collision on a password is more likely to be useful to an attacker; a hash collision on the content is likely to be worthless. But it would serve to let a legitimate recipient know that the wrong password was used for decryption.
Cryptographic Salt
Salt helps to thwart pre-computed dictionary attacks.
Suppose an attacker has a list of likely passwords. He can hash each and compare it to the hash of his victim's password, and see if it matches. If the list is large, this could take a long time. He doesn't want spend that much time on his next target, so he records the result in a "dictionary" where a hash points to its corresponding input. If the list of passwords is very, very long, he can use techniques like a Rainbow Table to save some space.
However, suppose his next target salted their password. Even if the attacker knows what the salt is, his precomputed table is worthless—the salt changes the hash resulting from each password. He has to re-hash all of the passwords in his list, affixing the target's salt to the input. Every different salt requires a different dictionary, and if enough salts are used, the attacker won't have room to store dictionaries for them all. Trading space to save time is no longer an option; the attacker must fall back to hashing each password in his list for each target he wants to attack.
So, it's not necessary to keep the salt secret. Ensuring that the attacker doesn't have a pre-computed dictionary corresponding to that particular salt is sufficient.
As Niyaz said, the approach sounds reasonable if you use a quality implementation of strong algorithms, like SHA-265 and AES for hashing and encryption. Additionally I would recommend using a Salt to reduce the possibility to create a dictionary of all password hashes.
Of course, reading Bruce Schneier's Applied Cryptography is never wrong either.
If you are using a strong hash algorithm (SHA-2) and a strong Encryption algorithm (AES), you will do fine with this approach.
Why not use a compression library that supports password-protected files? I've used a password-protected zip file containing XML content in the past :}
Is there really need to save the hashed password into the file. Can't you just use the password (or hashed password) with some salt and then encrypt the file with it. When decrypting just try to decrypt the file with the password + salt. If user gives wrong password the decrypted file isn't correct.
Only drawbacks I can think is if the user accidentally enters wrong password and the decryption is slow, he has to wait to try again. And of course if password is forgotten there's no way to decrypt the file.