private static byte[] PRF(EncryptionType type, byte[] protocolKey, byte[] truncated) { byte[] prf = Encoding.UTF8.GetBytes("prf"); switch (type) { case EncryptionType.AES256_CTS_HMAC_SHA1_96: { byte[] temp = AesKey.DK(protocolKey, prf, AesKeyType.Aes256BitsKey); byte[] initialVector = new byte[ConstValue.AES_BLOCK_SIZE]; CipherTextStealingMode aesCtsCrypto = CryptoUtility.CreateAesCtsCrypto(temp, initialVector); byte[] encryptedData = aesCtsCrypto.EncryptFinal(truncated, 0, truncated.Length); return(encryptedData); } case EncryptionType.AES128_CTS_HMAC_SHA1_96: { byte[] temp = AesKey.DK(protocolKey, prf, AesKeyType.Aes128BitsKey); break; } default: throw new NotSupportedException("Encryption type not support"); } throw new NotImplementedException(); }
/// <summary> /// Decrypt in aes128-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 /// </summary> /// <param name="key">key data</param> /// <param name="cipher">cipher data to be decrypted</param> /// <param name="usage">key usage number</param> /// <param name="aesKeyType">aes key type (128bit/256bit)</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use decrypted data directly if this parameter is null. /// </param> /// <returns>the decrypted data</returns> public static byte[] Decrypt( byte[] key, byte[] cipher, int usage, AesKeyType aesKeyType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == cipher) { throw new ArgumentNullException("cipher"); } // the cipher has two parts: encrypted(confounder + plain) + hmac byte[] encryptedData = ArrayUtility.SubArray <byte>( cipher, 0, cipher.Length - ConstValue.HMAC_HASH_OUTPUT_SIZE); byte[] hmacData = ArrayUtility.SubArray <byte>( cipher, cipher.Length - ConstValue.HMAC_HASH_OUTPUT_SIZE); // use ke key (the encryption key) to decrypt byte[] ke = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ke, aesKeyType); byte[] initialVector = new byte[ConstValue.AES_BLOCK_SIZE]; CipherTextStealingMode aesCtsCrypto = CryptoUtility.CreateAesCtsCrypto(ke, initialVector); byte[] decryptedData = aesCtsCrypto.DecryptFinal(encryptedData, 0, encryptedData.Length); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(decryptedData); } else { toBeSignedData = decryptedData; } // use ki key (the integrity key) to verify hmac data byte[] ki = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ki, aesKeyType); byte[] expectedHmacData = CryptoUtility.ComputeHmacSha1(ki, toBeSignedData); expectedHmacData = ArrayUtility.SubArray <byte>(expectedHmacData, 0, ConstValue.HMAC_HASH_OUTPUT_SIZE); if (!ArrayUtility.CompareArrays <byte>(hmacData, expectedHmacData)) { throw new FormatException( "Decryption: failed integrity check in hmac checksum."); } // remove confounder data decryptedData = ArrayUtility.SubArray <byte>(decryptedData, ConstValue.AES_BLOCK_SIZE, decryptedData.Length - ConstValue.AES_BLOCK_SIZE); return(decryptedData); }
/// <summary> /// Encrypt in aes128-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 /// </summary> /// <param name="key">key data</param> /// <param name="plain">plain data to be encrypted</param> /// <param name="usage">key usage number</param> /// <param name="aesKeyType">aes key type (128bit/256bit)</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use plain-text data directly if this parameter is null. /// </param> /// <returns>the encrypted data</returns> public static byte[] Encrypt( byte[] key, byte[] plain, int usage, AesKeyType aesKeyType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == plain) { throw new ArgumentNullException("plain"); } // add confounder data byte[] plainData = ArrayUtility.ConcatenateArrays( CryptoUtility.CreateConfounder(ConstValue.AES_BLOCK_SIZE), plain); // use ke key (the encryption key) to encrypt the plain data byte[] ke = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ke, aesKeyType); byte[] initialVector = new byte[ConstValue.AES_BLOCK_SIZE]; CipherTextStealingMode aesCtsCrypto = CryptoUtility.CreateAesCtsCrypto(ke, initialVector); byte[] encryptedData = aesCtsCrypto.EncryptFinal(plainData, 0, plainData.Length); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(plainData); } else { toBeSignedData = plainData; } // use ki key (the integrity key) to generate checksum byte[] ki = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ki, aesKeyType); byte[] hmacData = CryptoUtility.ComputeHmacSha1(ki, toBeSignedData); hmacData = ArrayUtility.SubArray <byte>(hmacData, 0, ConstValue.HMAC_HASH_OUTPUT_SIZE); // result: encryptedData + hmacData return(ArrayUtility.ConcatenateArrays(encryptedData, hmacData)); }
/// <summary> /// DR is the random-octet generation function described in RFC 3961 /// [RFC 3961 section 5.1 A Key Derivation Function] /// </summary> /// <param name="baseKey">the base key which is to be derived from</param> /// <param name="wellKnownConstant">the "well-known constant"</param> /// <param name="aesKeyType">AES key type which decides key size</param> /// <returns>the pseudorandom octets</returns> private static byte[] DR( byte[] baseKey, byte[] wellKnownConstant, AesKeyType aesKeyType) { // to be encrypted data byte[] toBeEncrypted = new byte[wellKnownConstant.Length]; wellKnownConstant.CopyTo(toBeEncrypted, 0); // n-fold the "well-known constant" if needed if (wellKnownConstant.Length != ConstValue.AES_BLOCK_SIZE) { toBeEncrypted = NFold(wellKnownConstant, ConstValue.AES_BLOCK_SIZE * ConstValue.BYTE_SIZE); } // AES key size uint aesKeySize = (uint)aesKeyType / ConstValue.BYTE_SIZE; // initialize key array byte[] rawkey = new byte[aesKeySize]; // count means the total number of bytes has been copy to the rawkey. // length means how length of bytes should be copy to the rawkey array. uint count = 0; uint length = 0; // The initialCipherVector should be all zeros. byte[] initialCipherVector = new byte[ConstValue.AES_BLOCK_SIZE]; // AES-CTS encryptor CipherTextStealingMode aesCtsCrypto = CryptoUtility.CreateAesCtsCrypto(baseKey, initialCipherVector); while (count < aesKeySize) { byte[] cipherBlock = aesCtsCrypto.EncryptFinal(toBeEncrypted, 0, toBeEncrypted.Length); length = (aesKeySize - count <= cipherBlock.Length ? (aesKeySize - count) : Convert.ToUInt32(cipherBlock.Length)); Array.Copy(cipherBlock, 0, rawkey, count, length); count += length; toBeEncrypted = cipherBlock; } return(rawkey); }