/// <summary> /// Returns an IV that's based solely on the contents of a buffer; useful for generating /// predictable IVs for ciphertexts that need to be cached. The output value is only /// appropriate for use as an IV and must not be used for any other purpose. /// </summary> /// <remarks>This method uses an iterated unkeyed SHA256 to calculate the IV.</remarks> /// <param name="buffer">The input buffer over which to calculate the IV.</param> /// <param name="ivBitLength">The requested length (in bits) of the IV to generate.</param> /// <returns>The calculated IV.</returns> public static byte[] CreatePredictableIV(byte[] buffer, int ivBitLength) { // Algorithm: // T_0 = SHA256(buffer) // T_n = SHA256(T_{n-1}) // output = T_0 || T_1 || ... || T_n (as many blocks as necessary to reach ivBitLength) byte[] output = new byte[ivBitLength / 8]; int bytesCopied = 0; int bytesRemaining = output.Length; using (SHA256 sha256 = CryptoAlgorithms.CreateSHA256()) { while (bytesRemaining > 0) { byte[] hashed = sha256.ComputeHash(buffer); int bytesToCopy = Math.Min(bytesRemaining, hashed.Length); Buffer.BlockCopy(hashed, 0, output, bytesCopied, bytesToCopy); bytesCopied += bytesToCopy; bytesRemaining -= bytesToCopy; buffer = hashed; // next iteration (if it occurs) will operate over the block just hashed } } return output; }
public KeyedHashAlgorithm GetValidationAlgorithm() { switch (this.validation) { case "SHA1": return(CryptoAlgorithms.CreateHMACSHA1()); case "HMACSHA256": return(CryptoAlgorithms.CreateHMACSHA256()); case "HMACSHA384": return(CryptoAlgorithms.CreateHMACSHA384()); case "HMACSHA512": return(CryptoAlgorithms.CreateHMACSHA512()); default: return(null); // unknown } }
// 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)); } }
public SymmetricAlgorithm GetEncryptionAlgorithm() { // We suppress CS0618 since some of the algorithms we support are marked with [Obsolete]. // These deprecated algorithms are *not* enabled by default. Developers must opt-in to // them, so we're secure by default. #pragma warning disable 618 switch (this.encryption) { case "AES": case "Auto": // currently "Auto" defaults to AES return(CryptoAlgorithms.CreateAes()); case "DES": return(CryptoAlgorithms.CreateDES()); case "3DES": return(CryptoAlgorithms.CreateTripleDES()); default: return(null); // unknown #pragma warning restore 618 } }
/// <summary> /// Computes the SHA256 hash of a given segment in a buffer. /// </summary> /// <param name="buffer">The buffer over which to compute the hash.</param> /// <param name="offset">The offset at which to begin computing the hash.</param> /// <param name="count">The number of bytes in the buffer to include in the hash.</param> /// <returns>The binary hash (32 bytes) of the buffer segment.</returns> public static byte[] ComputeSHA256Hash(byte[] buffer, int offset, int count) { using (SHA256 sha256 = CryptoAlgorithms.CreateSHA256()) { return sha256.ComputeHash(buffer, offset, count); } }