# AES - which cipher is the safest one out there and what are the best practices for creating and storing the key

I just started to learn cryptography. I've read a ton of articles but couldn't find a book or a course that is based on this subject (and also is not outdated).

Therefore I have a few questions (some of them were asked before but there's no specific answer).

Also i must specify that all my questions are related to aes in PHP:

First question is what is the best way to create a completely random and unique key? So far I've made this little code that is (in my opinion) an overkill (and I guess it ads no extra security and randomness to the key since it is only 32 bytes in the end anyways) but still here it is:

$length = 32;$hash = hash('sha512', microtime(true) . random_bytes(2) . chr(rand(0, 255)) . openssl_random_pseudo_bytes($length)); if((strlen($hash) / 2) > $length){$x = rand($length / rand(1,$length), strlen($hash) -$length);
$key = substr($hash, $x,$length);
} else{
$key = substr($hash, 0, $length); }  The cipher that I'm using is: aes-256-gcm. Is there a better cipher that I could use (a more secure one that has a longer key maybe)? Also why does aes-256-gcm accept a longer than 32 bytes key but on decryption it just ignores anything above the first 32 bytes of that key? Finally what is the best way to store the key for later usage (keeping in mind that I'm using php/mysql - I am aware of the fact that storing the key in the same database where you store the ciphertext/iv/tag is purely insane). PS: I do NOT use any of these lines in any project, those are just me trying to learn. ## 2 Answers First question is what is the best way to create a completely random and unique key? Simply generate an appropriately sized array of cryptographically random bytes from something like /dev/urandom, CryptGenRandom, or apparently openssl_random_pseudo_bytes. The rest of your derivation process appears to serve no function; Even if it did, the entropy content of time and three random bytes is very low, so low that it can be guessed in practice. So $length = 32;
$hash = hash('sha512', microtime(true) . random_bytes(2) . chr(rand(0, 255)) . openssl_random_pseudo_bytes($length));
if((strlen($hash) / 2) >$length){
$x = rand($length / rand(1, $length), strlen($hash) - $length);$key = substr($hash,$x, $length); } else{$key = substr($hash, 0,$length);


Would become:

$length = 32;$key = openssl_random_pseudo_bytes($length);  And that really is all that you need, assuming that openssl_random_pseudo_bytes provides cryptographically secure random bytes. The cipher that I'm using is: aes-256-gcm. Is there a better cipher that I could use (a more secure one that has a longer key maybe)? There is no benefit to using a key that is larger than 256 bits. One of the only reasonable alternatives to AES-256-gcm would be a Salsa/ChaCha-poly1305 based construction. If you're concerned about side channel attacks, then it might be wise to switch. However, if the library you're using doesn't happen to support Salsa/ChaCha-poly1305 out of the box, then don't worry about it. Also why does aes-256-gcm accept a longer than 32 bytes key but on decryption it just ignores anything above the first 32 bytes of that key? The algorithm is only defined to use key sizes of 128, 192, and 256 bits; You cannot simply supply more and expect them to be used. It is possible that the key length not being checked might lead to a bug somehow. Finally what is the best way to store the key for later usage Here are some options: • Derive the key from a password on application startup • Split the key into$n$secret shares and distribute them to a bunch of distinct servers • Retrieve the shares and recover the key on application startup • Store the key on a hardware device such as a flash drive • Make use of some kind of HSM (hardware security module) device. The last option should easily be the most secure, but it will cost money. If you go with any option other than the HSM, do your best to ensure the key only stays in memory in one location and isn't copied all over the place. With an HSM this isn't a concern, as the key never leaves the HSM. • In particular PHP uses OpenSSL's EVP_* API which silently ignores excess key input; other libraries sometimes give an error. Sep 8 '18 at 1:29 • Hey @EllaRose, thank you for taking time to answer to all my questions! Since i just started learning cryptography(which is a 'wow' field for me) i have one more question: is it a good thing to encrypt that key(32bytes) in sha512(128bytes), store it into a database and send that key(32bytes) to a user for example? I don't have a practical example of "what for" usage but i'm just thinking :-??. And also can you recommend me a book/course that i could buy/download that could help me wrap my head around cryptography? Thank you again and again and again! :D – emma Sep 8 '18 at 9:06 • Hey @dave_thompson_085, reading trough the php manual i couldn't find a more detailed documentation of openssl, could you guide me through the complicated business of finding a detailed documentation for openssl?(i'm not asking out of laziness, i just can't find a well documented article/book/course about cryptography - much less about openssl). Thank you, and sorry for bothering you X_X – emma Sep 8 '18 at 9:09 • @emma  is it a good thing to encrypt that key(32bytes) in sha512(128bytes) You want to establish what your goals are first, rather than the steps you want to perform. Then you can check if those steps fulfill the goal. Additionally: sha512 is a hash function and not an encryption algorithm. One major difference being that sha512(data) is not an encryption of data; you cannot "decrypt" a hash function. So given only a sha512 hash of your key, you cannot recover the key. The "Handbook of Applied Cryptography" is often recommended (not to be confused with "Applied Cryptography"). Sep 8 '18 at 15:40 • @EllaRose - first of all, thank for that book recommendation! As for my 'goal', for now i don't have one besides learning, but let's say that i have a website and i want some data(a phone number and maybe an address) to be protected. What would be a good practice in this case for storing the key since i need it around all the time? I'm sorry for asking this many questions! X_X – emma Sep 8 '18 at 16:07 I have to agree with Ella Rose with the change in the key generation method $$length = 32;$$key = openssl_random_pseudo_bytes($length);


but for a slightly different reason. The OP had the following code

$$length = 32;$$hash = hash('sha512', microtime(true) . random_bytes(2) . chr(rand(0, 255)) . openssl_random_pseudo_bytes($$length)); ...$$key = substr($$hash, 0,$$length);


That means that in this implementation, this is actually creating only a 128 bit key, even though the OP is spending a lot of effort trying to create something more complex. hash in PHP defaults to returning a simple HEX string so only the first 32 HEX digits are used for the key even though the intent was to create something much longer. This is such a common problem that I have seen too, I have written a blog covering this and other common mistakes here