// // TestSuite.System.Security.Cryptography.RijndaelManaged.cs // // Authors: // Andrew Birkett (andy@nobugs.org) // Sebastien Pouliot // // Copyright (C) 2005 Novell, Inc (http://www.novell.com) // using System; using System.Security.Cryptography; using NUnit.Framework; namespace MonoTests.System.Security.Cryptography { [TestFixture] public class RijndaelManagedTest { private RijndaelManaged aes; [SetUp] public void SetUp () { aes = new RijndaelManaged (); } public void CheckCBC(ICryptoTransform encryptor, ICryptoTransform decryptor, byte[] plaintext, byte[] expected) { if ((plaintext.Length % encryptor.InputBlockSize) != 0) { throw new ArgumentException("Must have complete blocks"); } byte[] ciphertext = new byte[plaintext.Length]; for (int i=0; i < plaintext.Length; i += encryptor.InputBlockSize) { encryptor.TransformBlock(plaintext, i, encryptor.InputBlockSize, ciphertext, i); } Assert.AreEqual (expected, ciphertext, "CBC"); byte[] roundtrip = new byte[plaintext.Length]; for (int i=0; i < ciphertext.Length; i += decryptor.InputBlockSize) { decryptor.TransformBlock(ciphertext, i, decryptor.InputBlockSize, roundtrip, i); } Assert.AreEqual (plaintext, roundtrip, "CBC-rt"); } [Test] public void CBC_0() { byte[] plaintext = new byte[32]; for (int i=0; i < plaintext.Length; i++) plaintext[i] = 0; byte[] iv = new byte[16]; for (byte i=0; i < iv.Length; i++) { iv[i] = 0; } RijndaelManaged r = new RijndaelManaged(); byte[] key = new byte[16]; for (int i=0; i < 16; i++) r.Key[i] = 0; r.BlockSize = 128; r.Mode = CipherMode.CBC; r.Padding = PaddingMode.Zeros; r.Key = key; byte[] expected = { 0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b, 0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e, 0xf7, 0x95, 0xbd, 0x4a, 0x52, 0xe2, 0x9e, 0xd7, 0x13, 0xd3, 0x13, 0xfa, 0x20, 0xe9, 0x8d, 0xbc }; CheckCBC(r.CreateEncryptor(key, iv), r.CreateDecryptor(key, iv), plaintext, expected); } [Test] public void CBC_1 () { byte[] plaintext = new byte[32]; for (int i=0; i < plaintext.Length; i++) plaintext[i] = 0; byte[] iv = new byte[16]; for (byte i=0; i < iv.Length; i++) { iv[i] = i; } RijndaelManaged r = new RijndaelManaged(); byte[] key = new byte[16]; for (byte i=0; i < 16; i++) key[i] = 0; r.Key = key; r.BlockSize = 128; r.Mode = CipherMode.CBC; r.Padding = PaddingMode.Zeros; byte[] expected = { 0x7a, 0xca, 0x0f, 0xd9, 0xbc, 0xd6, 0xec, 0x7c, 0x9f, 0x97, 0x46, 0x66, 0x16, 0xe6, 0xa2, 0x82, 0x66, 0xc5, 0x84, 0x17, 0x1d, 0x3c, 0x20, 0x53, 0x6f, 0x0a, 0x09, 0xdc, 0x4d, 0x1e, 0x45, 0x3b }; CheckCBC(r.CreateEncryptor(key, iv), r.CreateDecryptor(key, iv), plaintext, expected); } public void CheckECBRoundtrip(ICryptoTransform encryptor, ICryptoTransform decryptor, byte[] plaintext, byte[] expected) { byte[] ciphertext = new byte[plaintext.Length]; int n = encryptor.TransformBlock(plaintext, 0, plaintext.Length, ciphertext, 0); Assert.AreEqual (expected, ciphertext, "ECB"); byte[] roundtrip = new byte[plaintext.Length]; n = decryptor.TransformBlock(ciphertext, 0, ciphertext.Length, roundtrip, 0); Assert.AreEqual (plaintext, roundtrip, "ECB-rt-len"); } [Test] public void ECB () { byte[] plaintext = new byte[16]; byte[] iv = new byte[16]; for (int i=0; i < 16; i++) { plaintext[i] = (byte) (i*16 + i); } RijndaelManaged r = new RijndaelManaged(); r.Mode = CipherMode.ECB; r.Padding = PaddingMode.Zeros; byte[] key16 = new byte[16]; byte[] key24 = new byte[24]; byte[] key32 = new byte[32]; for (int i=0; i < 32; i++) { if (i < 16) key16[i] = (byte) i; if (i < 24) key24[i] = (byte) i; key32[i] = (byte) i; } byte[] exp16 = { 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }; byte[] exp24 = { 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 }; byte[] exp32 = { 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 }; r.Key = key16; r.KeySize = 128; CheckECBRoundtrip( r.CreateEncryptor(key16, iv), r.CreateDecryptor(key16, iv), plaintext, exp16 ); r.Key = key24; r.KeySize = 192; CheckECBRoundtrip( r.CreateEncryptor(key24, iv), r.CreateDecryptor(key24, iv), plaintext, exp24 ); r.Key = key32; r.KeySize = 256; CheckECBRoundtrip( r.CreateEncryptor(key32, iv), r.CreateDecryptor(key32, iv), plaintext, exp32 ); } [Test] [ExpectedException (typeof (CryptographicException))] public void CreateEncryptor_KeyNull () { ICryptoTransform encryptor = aes.CreateEncryptor (null, aes.IV); byte[] data = new byte[encryptor.InputBlockSize]; byte[] encdata = encryptor.TransformFinalBlock (data, 0, data.Length); ICryptoTransform decryptor = aes.CreateDecryptor (aes.Key, aes.IV); byte[] decdata = decryptor.TransformFinalBlock (encdata, 0, encdata.Length); // null key != SymmetricAlgorithm.Key } [Test] public void CreateEncryptor_IvNull () { ICryptoTransform encryptor = aes.CreateEncryptor (aes.Key, null); byte[] data = new byte[encryptor.InputBlockSize]; byte[] encdata = encryptor.TransformFinalBlock (data, 0, data.Length); ICryptoTransform decryptor = aes.CreateDecryptor (aes.Key, aes.IV); byte[] decdata = decryptor.TransformFinalBlock (encdata, 0, encdata.Length); Assert.IsFalse (BitConverter.ToString (data) == BitConverter.ToString (decdata), "Compare"); // null iv != SymmetricAlgorithm.IV } [Test] public void CreateEncryptor_KeyIv () { byte[] originalKey = aes.Key; byte[] originalIV = aes.IV; byte[] key = (byte[]) aes.Key.Clone (); Array.Reverse (key); byte[] iv = (byte[]) aes.IV.Clone (); Array.Reverse (iv); Assert.IsNotNull (aes.CreateEncryptor (key, iv), "CreateEncryptor"); Assert.AreEqual (originalKey, aes.Key, "Key"); Assert.AreEqual (originalIV, aes.IV, "IV"); // SymmetricAlgorithm Key and IV not changed by CreateEncryptor } [Test] [ExpectedException (typeof (CryptographicException))] [Category ("NotWorking")] // data is bad but no exception is thrown public void CreateDecryptor_KeyNull () { ICryptoTransform encryptor = aes.CreateEncryptor (aes.Key, aes.IV); byte[] data = new byte[encryptor.InputBlockSize]; byte[] encdata = encryptor.TransformFinalBlock (data, 0, data.Length); ICryptoTransform decryptor = aes.CreateDecryptor (null, aes.IV); byte[] decdata = decryptor.TransformFinalBlock (encdata, 0, encdata.Length); // null key != SymmetricAlgorithm.Key } [Test] public void CreateDecryptor_IvNull () { ICryptoTransform encryptor = aes.CreateEncryptor (aes.Key, aes.IV); byte[] data = new byte[encryptor.InputBlockSize]; byte[] encdata = encryptor.TransformFinalBlock (data, 0, data.Length); ICryptoTransform decryptor = aes.CreateDecryptor (aes.Key, null); byte[] decdata = decryptor.TransformFinalBlock (encdata, 0, encdata.Length); Assert.IsFalse (BitConverter.ToString (data) == BitConverter.ToString (decdata), "Compare"); // null iv != SymmetricAlgorithm.IV } [Test] public void CreateDecryptor_KeyIv () { byte[] originalKey = aes.Key; byte[] originalIV = aes.IV; byte[] key = (byte[]) aes.Key.Clone (); Array.Reverse (key); byte[] iv = (byte[]) aes.IV.Clone (); Array.Reverse (iv); Assert.IsNotNull (aes.CreateEncryptor (key, iv), "CreateDecryptor"); Assert.AreEqual (originalKey, aes.Key, "Key"); Assert.AreEqual (originalIV, aes.IV, "IV"); // SymmetricAlgorithm Key and IV not changed by CreateDecryptor } // Setting the IV is more restrictive than supplying an IV to // CreateEncryptor and CreateDecryptor. See bug #76483 private ICryptoTransform CreateEncryptor_IV (int size) { byte[] iv = (size == -1) ? null : new byte[size]; return aes.CreateEncryptor (aes.Key, iv); } [Test] public void CreateEncryptor_IV_Null () { int size = (aes.BlockSize >> 3) - 1; CreateEncryptor_IV (-1); } [Test] [ExpectedException (typeof (CryptographicException))] public void CreateEncryptor_IV_Zero () { int size = (aes.BlockSize >> 3) - 1; CreateEncryptor_IV (0); } [Test] [ExpectedException (typeof (CryptographicException))] public void CreateEncryptor_IV_TooSmall () { int size = (aes.BlockSize >> 3) - 1; CreateEncryptor_IV (size); } [Test] public void CreateEncryptor_IV_BlockSize () { int size = (aes.BlockSize >> 3); CreateEncryptor_IV (size); } [Test] [ExpectedException (typeof (CryptographicException))] // Rijndael is the only implementation that has // this behaviour for IV that are too large [Category ("NotWorking")] public void CreateEncryptor_IV_TooBig () { int size = aes.BlockSize; // 8 times too big CreateEncryptor_IV (size); } private ICryptoTransform CreateDecryptor_IV (int size) { byte[] iv = (size == -1) ? null : new byte[size]; return aes.CreateDecryptor (aes.Key, iv); } [Test] public void CreateDecryptor_IV_Null () { int size = (aes.BlockSize >> 3) - 1; CreateDecryptor_IV (-1); } [Test] [ExpectedException (typeof (CryptographicException))] public void CreateDecryptor_IV_Zero () { int size = (aes.BlockSize >> 3) - 1; CreateDecryptor_IV (0); } [Test] [ExpectedException (typeof (CryptographicException))] public void CreateDecryptor_IV_TooSmall () { int size = (aes.BlockSize >> 3) - 1; CreateDecryptor_IV (size); } [Test] public void CreateDecryptor_IV_BlockSize () { int size = (aes.BlockSize >> 3); CreateDecryptor_IV (size); } [Test] [ExpectedException (typeof (CryptographicException))] // Rijndael is the only implementation that has // this behaviour for IV that are too large [Category ("NotWorking")] public void CreateDecryptor_IV_TooBig () { int size = aes.BlockSize; // 8 times too big CreateDecryptor_IV (size); } } }