I am building an authentication service for one of our internal tools, and after looking at various articles, I can summarize them as
I understand that anything which might lead to plaintext password is bad, but I was just wondering why nobody uses passwords to encrypt passwords, in say, AES256
? I mean, since it's a symmetric encryption it does not have any private key. Therefore, even in case of a breach, the actual passwords cannot be obtained back. What's wrong with salting the password and encrypting it with the password itself?
What's wrong with salting the password and encrypting it with the password itself?
This is a very fast operation, allowing passwords to be tested (i.e. "cracked") very quickly. The same is true of simply hashing with an algorithm like SHA-2. The correct way to handle passwords is to salt and stretch them (rather than simply hash them). "Stretching" means running them through a time-intensive algorithm called a KDF (Key Derivation Function) such as PBKDF2 or scrypt.
Just as importantly, a human-generated password cannot be used directly to encrypt with AES anyway. AES requires a key of precise size (16, 24, or 32 bytes), and to be secure that key should be completely random over the entire keyspace. Human generated passwords are rarely the correct length and are never random over the entire keyspace (both because humans are poor random value generators, and because 32 typeable characters is a trivial fraction of all the possible 32 byte keys; to type such a key correctly, the "password" would need to be nearly 40 characters long and typed completely at random using all upper/lowercase, numbers, and symbols on a common keyboard).
The correct way to turn a human-generated password into a key is to run it through a KDF (which is why it's called a "key derivation function"). If all you care about is authentication (validating the user knows the correct password), then there's no value in adding an additional encryption step. You can just work with the stretched key.
The stretched password (the output of the KDF) is the only thing that should be sent to the server. The server should then hash that value one more time using SHA-2 and store it. That way, the key that is presented to the server is not the same as the key stored in the database, and even if the database is stolen, it cannot be used to authenticate to the server.