public static void VerifyDefaults() { using (Aes aes = AesFactory.Create()) { Assert.Equal(128, aes.BlockSize); Assert.Equal(256, aes.KeySize); Assert.Equal(CipherMode.CBC, aes.Mode); Assert.Equal(PaddingMode.PKCS7, aes.Padding); } }
public static void TestDecryptorReusability() { byte[] expectedPlainText = new byte[] { 0x14, 0x30, 0x71, 0xad, 0xed, 0x8e, 0x58, 0x84, 0x81, 0x6f, 0x01, 0xa2, 0x0b, 0xea, 0x9e, 0x8b, 0x14, 0x0f, 0x0f, 0x10, 0x11, 0xb5, 0x22, 0x3d, 0x79, 0x58, 0x77, 0x17, 0xff, 0xd9, 0xec, 0x3a, }; byte[] cipher = new byte[expectedPlainText.Length]; byte[] output1 = new byte[expectedPlainText.Length]; byte[] output2 = new byte[expectedPlainText.Length]; using (Aes aes = AesFactory.Create()) { aes.Key = new byte[16]; aes.IV = new byte[] { 0x00, 0x3f, 0x7e, 0xbd, 0xfc, 0x3b, 0x7a, 0xb9, 0xf8, 0x37, 0x76, 0xb5, 0xf4, 0x33, 0x72, 0xb1 }; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.None; using (ICryptoTransform decryptor = aes.CreateDecryptor()) { if (!decryptor.CanReuseTransform) { return; } int len = decryptor.TransformBlock(cipher, 0, cipher.Length, output1, 0); byte[] remainder = decryptor.TransformFinalBlock(Array.Empty <byte>(), 0, 0); if (len != cipher.Length) { Assert.NotNull(remainder); Assert.Equal(cipher.Length - len, remainder.Length); Buffer.BlockCopy(remainder, 0, output1, len, remainder.Length); } Assert.Equal(expectedPlainText, output1); // Decryptor is now re-initialized, because TransformFinalBlock was called. len = decryptor.TransformBlock(cipher, 0, cipher.Length, output2, 0); remainder = decryptor.TransformFinalBlock(Array.Empty <byte>(), 0, 0); if (len != cipher.Length) { Assert.NotNull(remainder); Assert.Equal(cipher.Length - len, remainder.Length); Buffer.BlockCopy(remainder, 0, output2, len, remainder.Length); } Assert.Equal(expectedPlainText, output2); } } }
public static void CreateTransformExceptions() { byte[] key; byte[] iv; using (Aes aes = AesFactory.Create()) { aes.GenerateKey(); aes.GenerateIV(); key = aes.Key; iv = aes.IV; } using (Aes aes = AesFactory.Create()) { aes.Mode = CipherMode.CBC; Assert.Throws <ArgumentNullException>(() => aes.CreateEncryptor(null, iv)); Assert.Throws <ArgumentNullException>(() => aes.CreateEncryptor(null, null)); Assert.Throws <ArgumentNullException>(() => aes.CreateDecryptor(null, iv)); Assert.Throws <ArgumentNullException>(() => aes.CreateDecryptor(null, null)); // CBC requires an IV. Assert.Throws <CryptographicException>(() => aes.CreateEncryptor(key, null)); Assert.Throws <CryptographicException>(() => aes.CreateDecryptor(key, null)); } if (PlatformDetection.IsNotBrowser) { using (Aes aes = AesFactory.Create()) { aes.Mode = CipherMode.ECB; Assert.Throws <ArgumentNullException>(() => aes.CreateEncryptor(null, iv)); Assert.Throws <ArgumentNullException>(() => aes.CreateEncryptor(null, null)); Assert.Throws <ArgumentNullException>(() => aes.CreateDecryptor(null, iv)); Assert.Throws <ArgumentNullException>(() => aes.CreateDecryptor(null, null)); // ECB will accept an IV (but ignore it), and doesn't require it. using (ICryptoTransform didNotThrow = aes.CreateEncryptor(key, null)) { Assert.NotNull(didNotThrow); } using (ICryptoTransform didNotThrow = aes.CreateDecryptor(key, null)) { Assert.NotNull(didNotThrow); } } } }
public static void ValidateOffsetAndCount() { using (Aes aes = AesFactory.Create()) { aes.GenerateKey(); aes.GenerateIV(); // aes.BlockSize is in bits, new byte[] is in bytes, so we have 8 blocks. byte[] full = new byte[aes.BlockSize]; int blockByteCount = aes.BlockSize / 8; for (int i = 0; i < full.Length; i++) { full[i] = unchecked ((byte)i); } byte[] firstBlock = new byte[blockByteCount]; byte[] middleHalf = new byte[4 * blockByteCount]; // Copy the first blockBytes of full into firstBlock. Buffer.BlockCopy(full, 0, firstBlock, 0, blockByteCount); // [Skip][Skip][Take][Take][Take][Take][Skip][Skip] => "middle half" Buffer.BlockCopy(full, 2 * blockByteCount, middleHalf, 0, middleHalf.Length); byte[] firstBlockEncrypted; byte[] firstBlockEncryptedFromCount; byte[] middleHalfEncrypted; byte[] middleHalfEncryptedFromOffsetAndCount; using (ICryptoTransform encryptor = aes.CreateEncryptor()) { firstBlockEncrypted = encryptor.TransformFinalBlock(firstBlock, 0, firstBlock.Length); } using (ICryptoTransform encryptor = aes.CreateEncryptor()) { firstBlockEncryptedFromCount = encryptor.TransformFinalBlock(full, 0, firstBlock.Length); } using (ICryptoTransform encryptor = aes.CreateEncryptor()) { middleHalfEncrypted = encryptor.TransformFinalBlock(middleHalf, 0, middleHalf.Length); } using (ICryptoTransform encryptor = aes.CreateEncryptor()) { middleHalfEncryptedFromOffsetAndCount = encryptor.TransformFinalBlock(full, 2 * blockByteCount, middleHalf.Length); } Assert.Equal(firstBlockEncrypted, firstBlockEncryptedFromCount); Assert.Equal(middleHalfEncrypted, middleHalfEncryptedFromOffsetAndCount); } }
private static void SupportsMode(CipherMode mode) { using (Aes aes = AesFactory.Create()) { aes.Mode = mode; Assert.Equal(mode, aes.Mode); using (ICryptoTransform transform = aes.CreateEncryptor()) { transform.TransformFinalBlock(Array.Empty <byte>(), 0, 0); } } }
public static void ValidCFBFeedbackSizes(int feedbackSize) { using (Aes aes = AesFactory.Create()) { aes.GenerateKey(); aes.Mode = CipherMode.CFB; aes.FeedbackSize = feedbackSize; using var decryptor = aes.CreateDecryptor(); using var encryptor = aes.CreateEncryptor(); Assert.NotNull(decryptor); Assert.NotNull(encryptor); } }
public static void LegalBlockSizes() { using (Aes aes = AesFactory.Create()) { KeySizes[] blockSizes = aes.LegalBlockSizes; Assert.NotNull(blockSizes); Assert.Equal(1, blockSizes.Length); KeySizes blockSizeLimits = blockSizes[0]; Assert.Equal(128, blockSizeLimits.MinSize); Assert.Equal(128, blockSizeLimits.MaxSize); Assert.Equal(0, blockSizeLimits.SkipSize); } }
public static void LegalKeySizes() { using (Aes aes = AesFactory.Create()) { KeySizes[] keySizes = aes.LegalKeySizes; Assert.NotNull(keySizes); Assert.Equal(1, keySizes.Length); KeySizes keySizeLimits = keySizes[0]; Assert.Equal(128, keySizeLimits.MinSize); Assert.Equal(256, keySizeLimits.MaxSize); Assert.Equal(64, keySizeLimits.SkipSize); } }
public static void WrongKeyFailDecrypt_2() { // The test: // Using the encrypted bytes from the AES-192-ECB test, try decrypting // with the first 192 bits from the AES-256-CBC test. That would only work if // the implementation of AES was "return s_multiBlockBytes". // For this specific key/data combination, we actually expect a padding exception. byte[] encryptedBytes = new byte[] { 0xC9, 0x7F, 0xA5, 0x5B, 0xC3, 0x92, 0xDC, 0xA6, 0xE4, 0x9F, 0x2D, 0x1A, 0xEF, 0x7A, 0x27, 0x03, 0x04, 0x9C, 0xFB, 0x56, 0x63, 0x38, 0xAE, 0x4F, 0xDC, 0xF6, 0x36, 0x98, 0x28, 0x05, 0x32, 0xE9, 0xF2, 0x6E, 0xEC, 0x0C, 0x04, 0x9D, 0x12, 0x17, 0x18, 0x35, 0xD4, 0x29, 0xFC, 0x01, 0xB1, 0x20, 0xFA, 0x30, 0xAE, 0x00, 0x53, 0xD4, 0x26, 0x25, 0xA4, 0xFD, 0xD5, 0xE6, 0xED, 0x79, 0x35, 0x2A, 0xE2, 0xBB, 0x95, 0x0D, 0xEF, 0x09, 0xBB, 0x6D, 0xC5, 0xC4, 0xDB, 0x28, 0xC6, 0xF4, 0x31, 0x33, 0x9A, 0x90, 0x12, 0x36, 0x50, 0xA0, 0xB7, 0xD1, 0x35, 0xC4, 0xCE, 0x81, 0xE5, 0x2B, 0x85, 0x6B, }; byte[] decryptedBytes; // Load key as the first 192 bits of s_aes256Key. // It has the correct cipher block size, but the wrong value. byte[] key = new byte[s_aes192Key.Length]; Buffer.BlockCopy(s_aes256Key, 0, key, 0, key.Length); using (Aes aes = AesFactory.Create()) { aes.Mode = CipherMode.ECB; aes.Key = key; Assert.Throws <CryptographicException>(() => { using (MemoryStream input = new MemoryStream(encryptedBytes)) using (CryptoStream cryptoStream = new CryptoStream(input, aes.CreateDecryptor(), CryptoStreamMode.Read)) using (MemoryStream output = new MemoryStream()) { cryptoStream.CopyTo(output); decryptedBytes = output.ToArray(); } }); } }
public static void Cfb8ModeCanDepadCfb128Padding() { using (Aes aes = AesFactory.Create()) { // 1, 2, 3, 4, 5 encrypted with CFB8 but padded with block-size padding. byte[] ciphertext = "68C272ACF16BE005A361DB1C147CA3AD".HexToByteArray(); aes.Key = "3279CE2E9669A54E038AA62818672150D0B5A13F6757C27F378115501F83B119".HexToByteArray(); aes.IV = new byte[16]; aes.Padding = PaddingMode.PKCS7; aes.Mode = CipherMode.CFB; aes.FeedbackSize = 8; using ICryptoTransform transform = aes.CreateDecryptor(); byte[] decrypted = transform.TransformFinalBlock(ciphertext, 0, ciphertext.Length); Assert.Equal(new byte[] { 1, 2, 3, 4, 5 }, decrypted); } }
private static void SupportsMode(CipherMode mode, int?feedbackSize = null) { using (Aes aes = AesFactory.Create()) { aes.Mode = mode; Assert.Equal(mode, aes.Mode); if (feedbackSize.HasValue) { aes.FeedbackSize = feedbackSize.Value; } using (ICryptoTransform transform = aes.CreateEncryptor()) { transform.TransformFinalBlock(Array.Empty <byte>(), 0, 0); } } }
public static void EcbRoundtrip(byte[] plaintext, byte[] ciphertext, PaddingMode padding) { using (Aes aes = AesFactory.Create()) { aes.Key = s_aes128OneShotKey; // Even though we have set the instance to use CFB, the Ecb one shots should // always be done in ECB. aes.FeedbackSize = 8; aes.Mode = CipherMode.CFB; aes.Padding = padding == PaddingMode.None ? PaddingMode.PKCS7 : PaddingMode.None; byte[] encrypted = aes.EncryptEcb(plaintext, padding); byte[] decrypted = aes.DecryptEcb(encrypted, padding); if (padding == PaddingMode.Zeros) { Assert.Equal(plaintext, decrypted[..plaintext.Length]);
public static void VerifyIVGeneration() { using (Aes aes = AesFactory.Create()) { int blockSize = aes.BlockSize; aes.GenerateIV(); byte[] iv = aes.IV; Assert.NotNull(iv); Assert.Equal(blockSize, aes.BlockSize); Assert.Equal(blockSize, iv.Length * 8); // Standard randomness caveat: There's a very low chance that the generated IV -is- // all zeroes. This works out to 1/2^128, which is more unlikely than 1/10^38. Assert.NotEqual(new byte[iv.Length], iv); } }
public static void LegalKeySizes() { using (Aes aes = AesFactory.Create()) { KeySizes[] keySizes = aes.LegalKeySizes; Assert.NotNull(keySizes); Assert.Equal(1, keySizes.Length); KeySizes keySizeLimits = keySizes[0]; Assert.Equal(128, keySizeLimits.MinSize); Assert.Equal(256, keySizeLimits.MaxSize); // Browser's SubtleCrypto doesn't support AES-192 int expectedKeySkipSize = PlatformDetection.IsBrowser ? 128 : 64; Assert.Equal(expectedKeySkipSize, keySizeLimits.SkipSize); } }
public static void TransformWithTooShortOutputBuffer(bool encrypt, bool blockAlignedOutput) { // The CreateDecryptor call reads the Key/IV property to initialize them, bypassing an // uninitialized state protection. using (Aes alg = AesFactory.Create()) using (ICryptoTransform xform = encrypt ? alg.CreateEncryptor() : alg.CreateDecryptor(alg.Key, alg.IV)) { // 1 block, plus maybe three bytes int outputPadding = blockAlignedOutput ? 0 : 3; byte[] output = new byte[alg.BlockSize / 8 + outputPadding]; // 3 blocks of 0x00 byte[] input = new byte[3 * (alg.BlockSize / 8)]; Assert.Throws <ArgumentOutOfRangeException>( () => xform.TransformBlock(input, 0, input.Length, output, 0)); Assert.Equal(new byte[output.Length], output); } }
[InlineData(536870928)] // number of bits overflows and wraps around to default BlockSize public static void InvalidIVSizes(int invalidIvSize) { using (Aes aes = AesFactory.Create()) { aes.GenerateKey(); byte[] key = aes.Key; byte[] iv; try { iv = new byte[invalidIvSize]; } catch (OutOfMemoryException) // in case there isn't enough memory at test-time to allocate the large array { return; } Assert.Throws <ArgumentException>("rgbIV", () => aes.CreateEncryptor(key, iv)); Assert.Throws <ArgumentException>("rgbIV", () => aes.CreateDecryptor(key, iv)); } }
public static void VerifyInPlaceDecryption() { byte[] key = "1ed2f625c187b993256a8b3ccf9dcbfa5b44b4795c731012f70e4e64732efd5d".HexToByteArray(); byte[] iv = "47d1e060ba3c8643f9f8b65feeda4b30".HexToByteArray(); byte[] plainText = "f238882f6530ae9191c294868feed0b0df4058b322377dec14690c3b6bbf6ad1dd5b7c063a28e2cca2a6dce8cc2e668ea6ce80cee4c1a1a955ff46c530f3801b".HexToByteArray(); byte[] cipher = "7c6e1bcd3c30d2fb2d92e3346048307dc6719a6b96a945b4d987af09469ec68f5ca535fab7f596fffa80f7cfaeb26eefaf8d4ca8be190393b2569249d673f042".HexToByteArray(); using (Aes a = AesFactory.Create()) using (MemoryStream cipherStream = new MemoryStream(cipher)) { a.Key = key; a.IV = iv; a.Mode = CipherMode.CBC; a.Padding = PaddingMode.None; int blockSizeBytes = a.BlockSize / 8; List <byte> decrypted = new List <byte>(plainText.Length); using (ICryptoTransform decryptor = a.CreateDecryptor()) { while (true) { byte[] buffer = new byte[blockSizeBytes]; int numRead = cipherStream.Read(buffer, 0, blockSizeBytes); if (numRead == 0) { break; } Assert.Equal(blockSizeBytes, numRead); int numBytesWritten = decryptor.TransformBlock(buffer, 0, blockSizeBytes, buffer, 0); Array.Resize(ref buffer, numBytesWritten); decrypted.AddRange(buffer); } decrypted.AddRange(decryptor.TransformFinalBlock(Array.Empty <byte>(), 0, 0)); Assert.Equal(plainText, decrypted.ToArray()); } } }
public static void ValidCFBFeedbackSizes(int feedbackSize) { // Windows 7 only supports CFB8. if (feedbackSize != 8 && PlatformDetection.IsWindows7) { return; } using (Aes aes = AesFactory.Create()) { aes.GenerateKey(); aes.Mode = CipherMode.CFB; aes.FeedbackSize = feedbackSize; using var decryptor = aes.CreateDecryptor(); using var encryptor = aes.CreateEncryptor(); Assert.NotNull(decryptor); Assert.NotNull(encryptor); } }
public static void AesZeroPad() { byte[] decryptedBytes; byte[] expectedAnswer; using (Aes aes = AesFactory.Create()) { aes.Padding = PaddingMode.Zeros; int blockBytes = aes.BlockSize / 8; int missingBytes = blockBytes - (s_multiBlockBytes.Length % blockBytes); // Zero-padding doesn't have enough information to remove the trailing zeroes. // Therefore we expect the answer of ZeroPad(s_multiBlockBytes). // So, make a long enough array, and copy s_multiBlockBytes to the beginning of it. expectedAnswer = new byte[s_multiBlockBytes.Length + missingBytes]; Buffer.BlockCopy(s_multiBlockBytes, 0, expectedAnswer, 0, s_multiBlockBytes.Length); byte[] encryptedBytes; using (MemoryStream input = new MemoryStream(s_multiBlockBytes)) using (CryptoStream cryptoStream = new CryptoStream(input, aes.CreateEncryptor(), CryptoStreamMode.Read)) using (MemoryStream output = new MemoryStream()) { cryptoStream.CopyTo(output); encryptedBytes = output.ToArray(); } using (MemoryStream input = new MemoryStream(encryptedBytes)) using (CryptoStream cryptoStream = new CryptoStream(input, aes.CreateDecryptor(), CryptoStreamMode.Read)) using (MemoryStream output = new MemoryStream()) { cryptoStream.CopyTo(output); decryptedBytes = output.ToArray(); } } Assert.Equal(expectedAnswer, decryptedBytes); }
public static void StableEncryptDecrypt() { byte[] encrypted; byte[] encrypted2; byte[] decrypted; byte[] decrypted2; using (Aes aes = AesFactory.Create()) { aes.Mode = CipherMode.CBC; aes.Key = s_aes256Key; aes.IV = s_aes256CbcIv; using (ICryptoTransform encryptor = aes.CreateEncryptor()) { encrypted = encryptor.TransformFinalBlock(s_helloBytes, 0, s_helloBytes.Length); } // Use a new encryptor for encrypted2 so that this test doesn't depend on CanReuseTransform using (ICryptoTransform encryptor = aes.CreateEncryptor()) { encrypted2 = encryptor.TransformFinalBlock(s_helloBytes, 0, s_helloBytes.Length); } using (ICryptoTransform decryptor = aes.CreateDecryptor()) { decrypted = decryptor.TransformFinalBlock(encrypted, 0, encrypted.Length); } using (ICryptoTransform decryptor = aes.CreateDecryptor()) { decrypted2 = decryptor.TransformFinalBlock(encrypted2, 0, encrypted2.Length); } } Assert.Equal(encrypted, encrypted2); Assert.Equal(decrypted, decrypted2); Assert.Equal(s_helloBytes, decrypted); }
[InlineData(536870928)] // number of bits overflows and wraps around to default BlockSize public static void InvalidIVSizes(int invalidIvSize) { using (Aes aes = AesFactory.Create()) { aes.GenerateKey(); byte[] key = aes.Key; byte[] iv; try { iv = new byte[invalidIvSize]; } catch (OutOfMemoryException) // in case there isn't enough memory at test-time to allocate the large array { return; } Exception e = Record.Exception(() => aes.CreateEncryptor(key, iv)); Assert.True(e is ArgumentException || e is OutOfMemoryException, $"Got {e}"); e = Record.Exception(() => aes.CreateDecryptor(key, iv)); Assert.True(e is ArgumentException || e is OutOfMemoryException, $"Got {e}"); } }
[InlineData(536870928)] // number of bits overflows and wraps around to a valid size public static void InvalidKeySizes(int invalidKeySize) { using (Aes aes = AesFactory.Create()) { // Test KeySize property Assert.Throws <CryptographicException>(() => aes.KeySize = invalidKeySize); // Test passing a key to CreateEncryptor and CreateDecryptor aes.GenerateIV(); byte[] iv = aes.IV; byte[] key; try { key = new byte[invalidKeySize]; } catch (OutOfMemoryException) // in case there isn't enough memory at test-time to allocate the large array { return; } Assert.Throws <ArgumentException>("rgbKey", () => aes.CreateEncryptor(key, iv)); Assert.Throws <ArgumentException>("rgbKey", () => aes.CreateDecryptor(key, iv)); } }
public static void EncryptWithLargeOutputBuffer(bool blockAlignedOutput) { using (Aes alg = AesFactory.Create()) using (ICryptoTransform xform = alg.CreateEncryptor()) { // 8 blocks, plus maybe three bytes int outputPadding = blockAlignedOutput ? 0 : 3; byte[] output = new byte[alg.BlockSize + outputPadding]; // 2 blocks of 0x00 byte[] input = new byte[alg.BlockSize / 4]; int outputOffset = 0; outputOffset += xform.TransformBlock(input, 0, input.Length, output, outputOffset); byte[] overflow = xform.TransformFinalBlock(Array.Empty <byte>(), 0, 0); Buffer.BlockCopy(overflow, 0, output, outputOffset, overflow.Length); outputOffset += overflow.Length; Assert.Equal(3 * (alg.BlockSize / 8), outputOffset); string outputAsHex = output.ByteArrayToHex(); Assert.NotEqual(new string('0', outputOffset * 2), outputAsHex.Substring(0, outputOffset * 2)); Assert.Equal(new string('0', (output.Length - outputOffset) * 2), outputAsHex.Substring(outputOffset * 2)); } }
private static void TestAesTransformDirectKey( CipherMode cipherMode, PaddingMode paddingMode, byte[] key, byte[] iv, byte[] plainBytes, byte[] cipherBytes) { byte[] liveEncryptBytes; byte[] liveDecryptBytes; using (Aes aes = AesFactory.Create()) { aes.Mode = cipherMode; aes.Padding = paddingMode; liveEncryptBytes = AesEncryptDirectKey(aes, key, iv, plainBytes); liveDecryptBytes = AesDecryptDirectKey(aes, key, iv, cipherBytes); } Assert.Equal(plainBytes, liveDecryptBytes); Assert.Equal(cipherBytes, liveEncryptBytes); }
private static void DoesNotSupportMode(CipherMode mode) { using (Aes aes = AesFactory.Create()) { // One of the following should throw: // aes.Mode = invalidMode // aes.CreateEncryptor() (with an invalid Mode value) // transform.Transform[Final]Block() (with an invalid Mode value) Assert.ThrowsAny <CryptographicException>( () => { aes.Mode = mode; // If assigning the Mode property did not fail, then it should reflect what we asked for. Assert.Equal(mode, aes.Mode); using (ICryptoTransform transform = aes.CreateEncryptor()) { transform.TransformFinalBlock(Array.Empty <byte>(), 0, 0); } }); } }
protected override SymmetricAlgorithm CreateAlgorithm() => AesFactory.Create();