# HMAC key generation and encoding

I've this piece of .NET code that is based on a Microsoft sample on how to generate a key and sign using HMACSH256.

But I've altered the key generation a little bit and also decided to use Base64 to transport the key as a string:

Key generation:

byte[] secretkey = new Byte[64];

using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(secretkey);
using (SHA512 mySHA256 = SHA512.Create())
{
var hashedKey = mySHA256.ComputeHash(secretkey);
var encodedKey = Convert.ToBase64String(hashedKey);
return encodedKey;
}
}


So, besides generating the random bytes I also decided to hash the key with SHA512. And then Base64 encode to get the final string representation, which will be used only in transport, since before usage the receiver of the message will decode back to the SHA512 digest.

Any issues with the way I'm doing it? Unless I'm mistaken all the hashing will do is introduce more randomness, since the key will remain at the 64 byte length. Is it worth it?

Also, any issues with transporting the key as a Base64 string?

Thanks, and I hope someone can offer some feedback on this. Have a good one!

all the hashing will do is introduce more randomness

No. You cannot introduce randomness with a deterministic process. You can only introduce randomness with an actual source of random data.

You can use a hash as a component of a pseudorandom generator, and a (cryptographically secure!) pseudorandom generator is good enough for cryptography where randomness is needed, but another vital component of a pseudorandom generator is a secret. That secret is the random generator's state, which is derived from a random seed: a pseudorandom generator doesn't create randomness, it only “multiplies” it in the sense that it can turn a small amount of random data into a large amount of random data.

Hashing a random string only reduces its randomness: it's theoretically possible that two input strings have the same hash (you aren't going to actually find such strings, and we aren't sure they exist, but chances are that they do). The randomness is only reduced by a tiny amount, so this isn't an actual vulnerability in your code, but it is an unnecessary and counterproductive complication.

The way to maximize randomness is to get output from a random generator. Call rng.GetBytes(secretkey) and stop there.

Converting the key to Base64 for transport and then back to binary for use has no impact on the cryptography. It's just an encoding. Do decode it: using Base64 as a key could reduce security since each byte can only have 1/4 of the possible values. (The way HMAC uses its key, it wouldn't actually matter whether you use base64(random_bytes(64)) or random_bytes(64) as a key; but this would matter, for example, for an AES key, which wouldn't even have an acceptable length.)

• Thanks for the illuminating post. Yeah, now that you mention it it's obvious that since the digest is in a reduce space of values it will theoretically be reduced. Now that I think about it, I got the idea out of another system where I saw that they used randomly generated passwords (not to be used by actual people) and they hashed the values before storing them. But now that I think about it, I think that was more for purposes of not allowing reverse engineering their values. As you normally do with passwords. Sep 20, 2021 at 14:23
• About the encoding, yeah I thought as much that I have to decode it before using it. Luckily the API is smart enough to not even accept a string. It only accepts a byte[]. Sep 20, 2021 at 14:23
• Also, please ignore the repetition of "now that i think about it". Seems I didn't exactly think through the reply, and kept editing at it until it managed to lose almost all sense. :D And now I can't edit it for 5 mins :D Sep 20, 2021 at 14:34