// Password-Based Key Derivation Function 2. Used to generate "pseudorandom" keys from a given password and salt using a certain PRF applied a certain amount of times (iterations). // dklen specified the "derived key length" in bytes. It is recommended to use a high number for the iterations variable (somewhere around 4096 is the standard for SHA1 currently) public static byte[] PBKDF2(PRF function, byte[] password, byte[] salt, int iterations, int dklen) { byte[] dk = new byte[0]; // Create a placeholder for the derived key uint iter = 1; // Track the iterations while (dk.Length < dklen) { // F-function // The F-function (PRF) takes the amount of iterations performed in the opposite endianness format from what C# uses, so we have to swap the endianness byte[] u = function(password, Support.Concatenate(salt, Support.WriteToArray(new byte[4], Support.SwapEndian(iter), 0))); byte[] ures = new byte[u.Length]; Array.Copy(u, ures, u.Length); for (int i = 1; i < iterations; ++i) { // Iteratively apply the PRF u = function(password, u); for (int j = 0; j < u.Length; ++j) { ures[j] ^= u[j]; } } // Concatenate the result to the dk dk = Support.Concatenate(dk, ures); ++iter; } // Clip aby bytes past what we needed (yes, that's really what the standard is) return(dk.ToLength(dklen)); }
// Hash-based Message Authentication Codes: generates a code for verifying the sender of a message and the like public static byte[] HMAC(byte[] key, byte[] message, HashFunction func, int blockSizeBytes) { if (key.Length > blockSizeBytes) { key = func(key); } else if (key.Length < blockSizeBytes) { byte[] b = new byte[blockSizeBytes]; Array.Copy(key, b, key.Length); key = b; } byte[] o_key_pad = new byte[blockSizeBytes]; // Outer padding byte[] i_key_pad = new byte[blockSizeBytes]; // Inner padding for (int i = 0; i < blockSizeBytes; ++i) { // Combine padding with key o_key_pad[i] = (byte)(key[i] ^ 0x5c); i_key_pad[i] = (byte)(key[i] ^ 0x36); } return(func(Support.Concatenate(o_key_pad, func(Support.Concatenate(message, i_key_pad))))); }