/// <summary> /// Encode the data. The data is encrypted using the default encryption algorithm (AES-256), /// then the AES key is encrypted using RSA and the RSA public key is appended. /// </summary> /// <param name="value">The data to encode</param> /// <exception cref="ArgumentNullException">The argument 'value' is null.</exception> /// <exception cref="ArgumentException">The argument 'value' contains zero bytes.</exception> /// <exception cref="InvalidOperationException">The EncryptionKey is null.</exception> /// <returns>Encoded data</returns> public override byte[] Encode(byte[] value) { if (null == value) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); } if (0 == value.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", SR.GetString(SR.ID6044)); } RSA encryptionKey = EncryptionKey; if (null == encryptionKey) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6043)); } byte[] rsaHash; byte[] encryptedKeyAndIV; byte[] encryptedData; using (HashAlgorithm hash = CryptoHelper.CreateHashAlgorithm(_hashName)) { rsaHash = hash.ComputeHash(Encoding.UTF8.GetBytes(encryptionKey.ToXmlString(false))); } using (SymmetricAlgorithm encryptionAlgorithm = CryptoHelper.NewDefaultEncryption()) { encryptionAlgorithm.GenerateIV(); encryptionAlgorithm.GenerateKey(); using (ICryptoTransform encryptor = encryptionAlgorithm.CreateEncryptor()) { encryptedData = encryptor.TransformFinalBlock(value, 0, value.Length); } RSACryptoServiceProvider provider = encryptionKey as RSACryptoServiceProvider; if (provider == null) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6041)); } // // Concatenate the Key and IV in an attempt to avoid two minimum block lengths in the cookie // byte[] keyAndIV = new byte[encryptionAlgorithm.Key.Length + encryptionAlgorithm.IV.Length]; Array.Copy(encryptionAlgorithm.Key, keyAndIV, encryptionAlgorithm.Key.Length); Array.Copy(encryptionAlgorithm.IV, 0, keyAndIV, encryptionAlgorithm.Key.Length, encryptionAlgorithm.IV.Length); encryptedKeyAndIV = provider.Encrypt(keyAndIV, true); } using (MemoryStream ms = new MemoryStream()) { using (BinaryWriter bw = new BinaryWriter(ms)) { bw.Write(rsaHash); bw.Write(encryptedKeyAndIV.Length); bw.Write(encryptedKeyAndIV); bw.Write(encryptedData.Length); bw.Write(encryptedData); bw.Flush(); } return(ms.ToArray()); } }
internal static KeyedHashAlgorithm NewHmacSha1KeyedHashAlgorithm(byte[] key) { return(CryptoHelper.CreateKeyedHashAlgorithm(key, SecurityAlgorithms.HmacSha1Signature)); }
/// <summary> /// Decrypts data using the provided RSA key(s) to decrypt an AES key, which decrypts the cookie. /// </summary> /// <param name="encoded">The encoded data</param> /// <returns>The decoded data</returns> /// <exception cref="ArgumentNullException">The argument 'encoded' is null.</exception> /// <exception cref="ArgumentException">The argument 'encoded' contains zero bytes.</exception> /// <exception cref="NotSupportedException">The platform does not support the requested algorithm.</exception> /// <exception cref="InvalidOperationException">There are no decryption keys or none of the keys match.</exception> public override byte[] Decode(byte[] encoded) { if (null == encoded) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("encoded"); } if (0 == encoded.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("encoded", SR.GetString(SR.ID6045)); } ReadOnlyCollection <RSA> decryptionKeys = DecryptionKeys; if (0 == decryptionKeys.Count) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6039)); } byte[] encryptedKeyAndIV; byte[] encryptedData; byte[] rsaHash; RSA rsaDecryptionKey = null; using (HashAlgorithm hash = CryptoHelper.CreateHashAlgorithm(_hashName)) { int hashSizeInBytes = hash.HashSize / 8; using (BinaryReader br = new BinaryReader(new MemoryStream(encoded))) { rsaHash = br.ReadBytes(hashSizeInBytes); int encryptedKeyAndIVSize = br.ReadInt32(); if (encryptedKeyAndIVSize < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ID1006, encryptedKeyAndIVSize))); } // // Enforce upper limit on key size to prevent large buffer allocation in br.ReadBytes() // if (encryptedKeyAndIVSize > encoded.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ID1007))); } encryptedKeyAndIV = br.ReadBytes(encryptedKeyAndIVSize); int encryptedDataSize = br.ReadInt32(); if (encryptedDataSize < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ID1008, encryptedDataSize))); } // // Enforce upper limit on data size to prevent large buffer allocation in br.ReadBytes() // if (encryptedDataSize > encoded.Length) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ID1009))); } encryptedData = br.ReadBytes(encryptedDataSize); } // // Find the decryption key matching the one in XML // foreach (RSA key in decryptionKeys) { byte[] hashedKey = hash.ComputeHash(Encoding.UTF8.GetBytes(key.ToXmlString(false))); if (CryptoHelper.IsEqual(hashedKey, rsaHash)) { rsaDecryptionKey = key; break; } } } if (rsaDecryptionKey == null) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6040)); } RSACryptoServiceProvider rsaProvider = rsaDecryptionKey as RSACryptoServiceProvider; if (rsaProvider == null) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6041)); } byte[] decryptedKeyAndIV = rsaProvider.Decrypt(encryptedKeyAndIV, true); using (SymmetricAlgorithm symmetricAlgorithm = CryptoHelper.NewDefaultEncryption()) { byte[] decryptionKey = new byte[symmetricAlgorithm.KeySize / 8]; // // Ensure there is sufficient length in the descrypted key and IV buffer for an IV. // if (decryptedKeyAndIV.Length < decryptionKey.Length) { throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID6047, decryptedKeyAndIV.Length, decryptionKey.Length)); } byte[] decryptionIV = new byte[decryptedKeyAndIV.Length - decryptionKey.Length]; // // Copy key into its own buffer. // The remaining bytes are the IV copy those into a buffer as well. // Array.Copy(decryptedKeyAndIV, decryptionKey, decryptionKey.Length); Array.Copy(decryptedKeyAndIV, decryptionKey.Length, decryptionIV, 0, decryptionIV.Length); using (ICryptoTransform decryptor = symmetricAlgorithm.CreateDecryptor(decryptionKey, decryptionIV)) { return(decryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length)); } } }