public KeyedHashAlgorithm GetValidationAlgorithm() { switch (_hashAlgorithm) { case ValidationAlgorithm.HmacSha256: return(CryptoAlgorithms.CreateHMACSHA256()); case ValidationAlgorithm.HmacSha384: return(CryptoAlgorithms.CreateHMACSHA384()); case ValidationAlgorithm.HmacSha512: return(CryptoAlgorithms.CreateHMACSHA512()); } throw new Exception("Unsupported hash type"); }
// Implements the KeyDerivationFunction delegate signature; public entry point to the API. public static CryptographicKey DeriveKey(CryptographicKey keyDerivationKey, Purpose purpose) { // After consultation with the crypto board, we have decided to use HMACSHA512 as the PRF // to our KDF. The reason for this is that our PRF is an HMAC, so the total entropy of the // PRF is given by MIN(key derivation key length, HMAC block size). It is conceivable that // a developer might specify a key greater than 256 bits in length, at which point using // a shorter PRF like HMACSHA256 starts discarding entropy. But from the crypto team's // perspective it is unreasonable for a developer to supply a key greater than 512 bits, // so there's no real harm in us limiting our PRF entropy to 512 bits (HMACSHA512). // // On 64-bit platforms, HMACSHA512 matches or outperforms HMACSHA256 in our perf testing. // On 32-bit platforms, HMACSHA512 is around 1/3 the speed of HMACSHA256. In both cases, we // try to cache the derived CryptographicKey wherever we can, so this shouldn't be a // bottleneck regardless. using (HMACSHA512 hmac = CryptoAlgorithms.CreateHMACSHA512(keyDerivationKey.GetKeyMaterial())) { byte[] label, context; purpose.GetKeyDerivationParameters(out label, out context); byte[] derivedKey = DeriveKeyImpl(hmac, label, context, keyDerivationKey.KeyLength); return(new CryptographicKey(derivedKey)); } }