diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2022-07-17 23:27:26 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2022-07-17 23:27:26 +0700 |
commit | 40695be9c25db0223881aadf28baa21097555f94 (patch) | |
tree | 4167ebc034d4f0e298edb90c7234502fe6449aac | |
parent | Add net6.0 to target frameworks (diff) | |
download | BouncyCastle.NET-ed25519-40695be9c25db0223881aadf28baa21097555f94.tar.xz |
Add AesX86Engine using Aes intrinsics
-rw-r--r-- | crypto/src/crypto/AesUtilities.cs | 5 | ||||
-rw-r--r-- | crypto/src/crypto/engines/AesX86Engine.cs | 354 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/AesX86Test.cs | 85 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/CipherTest.cs | 157 |
4 files changed, 515 insertions, 86 deletions
diff --git a/crypto/src/crypto/AesUtilities.cs b/crypto/src/crypto/AesUtilities.cs index 648f988bc..3b4fb520f 100644 --- a/crypto/src/crypto/AesUtilities.cs +++ b/crypto/src/crypto/AesUtilities.cs @@ -6,6 +6,11 @@ namespace Org.BouncyCastle.Crypto { public static IBlockCipher CreateEngine() { +#if NET5_0_OR_GREATER + if (AesX86Engine.IsSupported) + return new AesX86Engine(); +#endif + return new AesEngine(); } } diff --git a/crypto/src/crypto/engines/AesX86Engine.cs b/crypto/src/crypto/engines/AesX86Engine.cs new file mode 100644 index 000000000..038704a5f --- /dev/null +++ b/crypto/src/crypto/engines/AesX86Engine.cs @@ -0,0 +1,354 @@ +#if NET5_0_OR_GREATER +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Engines +{ + using Aes = System.Runtime.Intrinsics.X86.Aes; + using Sse2 = System.Runtime.Intrinsics.X86.Sse2; + + public class AesX86Engine + : IBlockCipher + { + public static bool IsSupported => Aes.IsSupported && Sse2.IsSupported; + + private static Vector128<byte>[] CreateRoundKeys(byte[] key, bool forEncryption) + { + Vector128<byte>[] K; + + switch (key.Length) + { + case 16: + { + ReadOnlySpan<byte> rcon = stackalloc byte[]{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + + K = new Vector128<byte>[11]; + + var s = Load128(key, 0); + K[0] = s; + + for (int round = 0; round < 10;) + { + var t = Aes.KeygenAssist(s, rcon[round++]); + t = Sse2.Shuffle(t.AsInt32(), 0xFF).AsByte(); + s = Sse2.Xor(s, Sse2.ShiftLeftLogical128BitLane(s, 8)); + s = Sse2.Xor(s, Sse2.ShiftLeftLogical128BitLane(s, 4)); + s = Sse2.Xor(s, t); + K[round] = s; + } + + break; + } + case 24: + { + K = new Vector128<byte>[13]; + + var s1 = Load128(key, 0); + var s2 = Load64(key, 16).ToVector128(); + K[0] = s1; + + byte rcon = 0x01; + for (int round = 0;;) + { + var t1 = Aes.KeygenAssist(s2, rcon); rcon <<= 1; + t1 = Sse2.Shuffle(t1.AsInt32(), 0x55).AsByte(); + + s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 8)); + s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 4)); + s1 = Sse2.Xor(s1, t1); + + K[++round] = Sse2.Xor(s2, Sse2.ShiftLeftLogical128BitLane(s1, 8)); + + var s3 = Sse2.Xor(s2, Sse2.ShiftRightLogical128BitLane(s1, 12)); + s3 = Sse2.Xor(s3, Sse2.ShiftLeftLogical128BitLane(s3, 4)); + + K[++round] = Sse2.Xor( + Sse2.ShiftRightLogical128BitLane(s1, 8), + Sse2.ShiftLeftLogical128BitLane(s3, 8)); + + var t2 = Aes.KeygenAssist(s3, rcon); rcon <<= 1; + t2 = Sse2.Shuffle(t2.AsInt32(), 0x55).AsByte(); + + s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 8)); + s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 4)); + s1 = Sse2.Xor(s1, t2); + + K[++round] = s1; + + if (round == 12) + break; + + s2 = Sse2.Xor(s3, Sse2.ShiftRightLogical128BitLane(s1, 12)); + s2 = Sse2.Xor(s2, Sse2.ShiftLeftLogical128BitLane(s2, 4)); + s2 = s2.WithUpper(Vector64<byte>.Zero); + } + + break; + } + case 32: + { + K = new Vector128<byte>[15]; + + var s1 = Load128(key, 0); + var s2 = Load128(key, 16); + K[0] = s1; + K[1] = s2; + + byte rcon = 0x01; + for (int round = 1;;) + { + var t1 = Aes.KeygenAssist(s2, rcon); rcon <<= 1; + t1 = Sse2.Shuffle(t1.AsInt32(), 0xFF).AsByte(); + s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 8)); + s1 = Sse2.Xor(s1, Sse2.ShiftLeftLogical128BitLane(s1, 4)); + s1 = Sse2.Xor(s1, t1); + K[++round] = s1; + + if (round == 14) + break; + + var t2 = Aes.KeygenAssist(s1, 0x00); + t2 = Sse2.Shuffle(t2.AsInt32(), 0xAA).AsByte(); + s2 = Sse2.Xor(s2, Sse2.ShiftLeftLogical128BitLane(s2, 8)); + s2 = Sse2.Xor(s2, Sse2.ShiftLeftLogical128BitLane(s2, 4)); + s2 = Sse2.Xor(s2, t2); + K[++round] = s2; + } + + break; + } + default: + throw new ArgumentException("Key length not 128/192/256 bits."); + } + + if (!forEncryption) + { + for (int i = 1, last = K.Length - 1; i < last; ++i) + { + K[i] = Aes.InverseMixColumns(K[i]); + } + + Array.Reverse(K); + } + + return K; + } + + private enum Mode { DEC_128, DEC_192, DEC_256, ENC_128, ENC_192, ENC_256, UNINITIALIZED }; + + private Vector128<byte>[] m_roundKeys; + private Mode m_mode = Mode.UNINITIALIZED; + + public AesX86Engine() + { + if (!IsSupported) + throw new PlatformNotSupportedException(nameof(AesX86Engine)); + } + + public virtual void Init(bool forEncryption, ICipherParameters parameters) + { + if (!(parameters is KeyParameter keyParameter)) + throw new ArgumentException( + "invalid parameter passed to AES Init - " + Platform.GetTypeName(parameters)); + + m_roundKeys = CreateRoundKeys(keyParameter.GetKey(), forEncryption); + + if (m_roundKeys.Length == 11) + { + m_mode = forEncryption ? Mode.ENC_128 : Mode.DEC_128; + } + else if (m_roundKeys.Length == 13) + { + m_mode = forEncryption ? Mode.ENC_192 : Mode.DEC_192; + } + else + { + m_mode = forEncryption ? Mode.ENC_256 : Mode.DEC_256; + } + } + + public virtual string AlgorithmName => "AES"; + + public virtual bool IsPartialBlockOkay => false; + + public virtual int GetBlockSize() => 16; + + public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff) + { + Check.DataLength(input, inOff, 16, "input buffer too short"); + Check.OutputLength(output, outOff, 16, "output buffer too short"); + + switch (m_mode) + { + case Mode.DEC_128: Decrypt128(input, inOff, output, outOff, m_roundKeys); break; + case Mode.DEC_192: Decrypt192(input, inOff, output, outOff, m_roundKeys); break; + case Mode.DEC_256: Decrypt256(input, inOff, output, outOff, m_roundKeys); break; + case Mode.ENC_128: Encrypt128(input, inOff, output, outOff, m_roundKeys); break; + case Mode.ENC_192: Encrypt192(input, inOff, output, outOff, m_roundKeys); break; + case Mode.ENC_256: Encrypt256(input, inOff, output, outOff, m_roundKeys); break; + default: throw new InvalidOperationException("AES engine not initialised"); + } + + return 16; + } + + public virtual void Reset() + { + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Decrypt128(byte[] input, int inOff, byte[] output, int outOff, Vector128<byte>[] roundKeys) + { + var state = Load128(input, inOff); + state = Sse2.Xor(state, roundKeys[0]); + state = Aes.Decrypt(state, roundKeys[1]); + state = Aes.Decrypt(state, roundKeys[2]); + state = Aes.Decrypt(state, roundKeys[3]); + state = Aes.Decrypt(state, roundKeys[4]); + state = Aes.Decrypt(state, roundKeys[5]); + state = Aes.Decrypt(state, roundKeys[6]); + state = Aes.Decrypt(state, roundKeys[7]); + state = Aes.Decrypt(state, roundKeys[8]); + state = Aes.Decrypt(state, roundKeys[9]); + state = Aes.DecryptLast(state, roundKeys[10]); + Store128(ref state, output, outOff); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Decrypt192(byte[] input, int inOff, byte[] output, int outOff, Vector128<byte>[] roundKeys) + { + var state = Load128(input, inOff); + state = Sse2.Xor(state, roundKeys[0]); + state = Aes.Decrypt(state, roundKeys[1]); + state = Aes.Decrypt(state, roundKeys[2]); + state = Aes.Decrypt(state, roundKeys[3]); + state = Aes.Decrypt(state, roundKeys[4]); + state = Aes.Decrypt(state, roundKeys[5]); + state = Aes.Decrypt(state, roundKeys[6]); + state = Aes.Decrypt(state, roundKeys[7]); + state = Aes.Decrypt(state, roundKeys[8]); + state = Aes.Decrypt(state, roundKeys[9]); + state = Aes.Decrypt(state, roundKeys[10]); + state = Aes.Decrypt(state, roundKeys[11]); + state = Aes.DecryptLast(state, roundKeys[12]); + Store128(ref state, output, outOff); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Decrypt256(byte[] input, int inOff, byte[] output, int outOff, Vector128<byte>[] roundKeys) + { + var state = Load128(input, inOff); + state = Sse2.Xor(state, roundKeys[0]); + state = Aes.Decrypt(state, roundKeys[1]); + state = Aes.Decrypt(state, roundKeys[2]); + state = Aes.Decrypt(state, roundKeys[3]); + state = Aes.Decrypt(state, roundKeys[4]); + state = Aes.Decrypt(state, roundKeys[5]); + state = Aes.Decrypt(state, roundKeys[6]); + state = Aes.Decrypt(state, roundKeys[7]); + state = Aes.Decrypt(state, roundKeys[8]); + state = Aes.Decrypt(state, roundKeys[9]); + state = Aes.Decrypt(state, roundKeys[10]); + state = Aes.Decrypt(state, roundKeys[11]); + state = Aes.Decrypt(state, roundKeys[12]); + state = Aes.Decrypt(state, roundKeys[13]); + state = Aes.DecryptLast(state, roundKeys[14]); + Store128(ref state, output, outOff); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Encrypt128(byte[] input, int inOff, byte[] output, int outOff, Vector128<byte>[] roundKeys) + { + var state = Load128(input, inOff); + state = Sse2.Xor(state, roundKeys[0]); + state = Aes.Encrypt(state, roundKeys[1]); + state = Aes.Encrypt(state, roundKeys[2]); + state = Aes.Encrypt(state, roundKeys[3]); + state = Aes.Encrypt(state, roundKeys[4]); + state = Aes.Encrypt(state, roundKeys[5]); + state = Aes.Encrypt(state, roundKeys[6]); + state = Aes.Encrypt(state, roundKeys[7]); + state = Aes.Encrypt(state, roundKeys[8]); + state = Aes.Encrypt(state, roundKeys[9]); + state = Aes.EncryptLast(state, roundKeys[10]); + Store128(ref state, output, outOff); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Encrypt192(byte[] input, int inOff, byte[] output, int outOff, Vector128<byte>[] roundKeys) + { + var state = Load128(input, inOff); + state = Sse2.Xor(state, roundKeys[0]); + state = Aes.Encrypt(state, roundKeys[1]); + state = Aes.Encrypt(state, roundKeys[2]); + state = Aes.Encrypt(state, roundKeys[3]); + state = Aes.Encrypt(state, roundKeys[4]); + state = Aes.Encrypt(state, roundKeys[5]); + state = Aes.Encrypt(state, roundKeys[6]); + state = Aes.Encrypt(state, roundKeys[7]); + state = Aes.Encrypt(state, roundKeys[8]); + state = Aes.Encrypt(state, roundKeys[9]); + state = Aes.Encrypt(state, roundKeys[10]); + state = Aes.Encrypt(state, roundKeys[11]); + state = Aes.EncryptLast(state, roundKeys[12]); + Store128(ref state, output, outOff); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Encrypt256(byte[] input, int inOff, byte[] output, int outOff, Vector128<byte>[] roundKeys) + { + var state = Load128(input, inOff); + state = Sse2.Xor(state, roundKeys[0]); + state = Aes.Encrypt(state, roundKeys[1]); + state = Aes.Encrypt(state, roundKeys[2]); + state = Aes.Encrypt(state, roundKeys[3]); + state = Aes.Encrypt(state, roundKeys[4]); + state = Aes.Encrypt(state, roundKeys[5]); + state = Aes.Encrypt(state, roundKeys[6]); + state = Aes.Encrypt(state, roundKeys[7]); + state = Aes.Encrypt(state, roundKeys[8]); + state = Aes.Encrypt(state, roundKeys[9]); + state = Aes.Encrypt(state, roundKeys[10]); + state = Aes.Encrypt(state, roundKeys[11]); + state = Aes.Encrypt(state, roundKeys[12]); + state = Aes.Encrypt(state, roundKeys[13]); + state = Aes.EncryptLast(state, roundKeys[14]); + Store128(ref state, output, outOff); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector128<byte> Load128(byte[] b, int n) + { +#if NET7_0_OR_GREATER + return Vector128.Create(b, n); +#else + return Unsafe.ReadUnaligned<Vector128<byte>>(ref b[n]); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector64<byte> Load64(byte[] b, int n) + { +#if NET7_0_OR_GREATER + return Vector64.Create(b, n); +#else + return Unsafe.ReadUnaligned<Vector64<byte>>(ref b[n]); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Store128(ref Vector128<byte> s, byte[] b, int n) + { +#if NET7_0_OR_GREATER + Vector128.CopyTo(s, b, n); +#else + Unsafe.WriteUnaligned(ref b[n], s); +#endif + } + } +} +#endif diff --git a/crypto/test/src/crypto/test/AesX86Test.cs b/crypto/test/src/crypto/test/AesX86Test.cs new file mode 100644 index 000000000..379a31a0e --- /dev/null +++ b/crypto/test/src/crypto/test/AesX86Test.cs @@ -0,0 +1,85 @@ +#if NET5_0_OR_GREATER +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture, TestOf(typeof(AesX86Engine))] + public class AesX86Test + : CipherTest + { + private static SimpleTest[] CreateTests() => new SimpleTest[]{ + new BlockCipherVectorTest(0, new AesX86Engine(), new KeyParameter(Hex.Decode("80000000000000000000000000000000")), "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(1, new AesX86Engine(), new KeyParameter(Hex.Decode("00000000000000000000000000000080")), "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(2, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("00000000000000000000000000000000")), "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(3, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")), "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(4, new AesX86Engine(), new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(5, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(6, new AesX86Engine(), new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(7, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(8, new AesX86Engine(), new KeyParameter(Hex.Decode("80000000000000000000000000000000")), "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(9, new AesX86Engine(), new KeyParameter(Hex.Decode("00000000000000000000000000000080")), "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(10, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("00000000000000000000000000000000")), "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(11, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")), "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(12, new AesX86Engine(), new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(13, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(14, new AesX86Engine(), new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(15, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(16, new AesX86Engine(), new KeyParameter(Hex.Decode("80000000000000000000000000000000")), "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(17, new AesX86Engine(), new KeyParameter(Hex.Decode("00000000000000000000000000000080")), "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(18, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("00000000000000000000000000000000")), "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(19, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")), "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(20, new AesX86Engine(), new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(21, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(22, new AesX86Engine(), new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(23, 10000, new AesX86Engine(), new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168") + }; + + [OneTimeSetUp] + public static void OneTimeSetup() + { + if (!AesX86Engine.IsSupported) + { + Assert.Ignore(); + } + } + + public override string Name => "AesX86"; + + public AesX86Test() + : base() + { + } + + public override ITestResult Perform() + { + if (AesX86Engine.IsSupported) + { + ITestResult result = base.Perform(); + if (!result.IsSuccessful()) + return result; + } + + return new SimpleTestResult(true, Name + ": Okay"); + } + + public override void PerformTest() + { + RunTests(CreateTests()); + RunEngineChecks(new AesX86Engine(), new KeyParameter(new byte[16])); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} +#endif diff --git a/crypto/test/src/crypto/test/CipherTest.cs b/crypto/test/src/crypto/test/CipherTest.cs index d9c085d44..3d380514c 100644 --- a/crypto/test/src/crypto/test/CipherTest.cs +++ b/crypto/test/src/crypto/test/CipherTest.cs @@ -10,108 +10,93 @@ namespace Org.BouncyCastle.Crypto.Tests public abstract class CipherTest : SimpleTest { - private SimpleTest[] _tests; - private IBlockCipher _engine; - private KeyParameter _validKey; - -// protected CipherTest( -// SimpleTest[] tests) -// { -// _tests = tests; -// } - - protected CipherTest( - SimpleTest[] tests, - IBlockCipher engine, - KeyParameter validKey) + private readonly SimpleTest[] m_tests; + private readonly IBlockCipher m_engine; + private readonly KeyParameter m_validKey; + + protected CipherTest() + { + m_tests = null; + m_engine = null; + m_validKey = null; + } + + protected CipherTest(SimpleTest[] tests, IBlockCipher engine, KeyParameter validKey) { - _tests = tests; - _engine = engine; - _validKey = validKey; + m_tests = tests; + m_engine = engine; + m_validKey = validKey; } public override void PerformTest() { - for (int i = 0; i != _tests.Length; i++) + if (m_tests != null) { - _tests[i].PerformTest(); - } + RunTests(m_tests); + } - if (_engine != null) + if (m_engine != null) { - // - // state tests - // - byte[] buf = new byte[_engine.GetBlockSize()]; - - try - { - _engine.ProcessBlock(buf, 0, buf, 0); - - Fail("failed initialisation check"); - } - catch (InvalidOperationException) - { - // expected - } - - bufferSizeCheck((_engine)); - } + RunEngineChecks(m_engine, m_validKey); + } } - private void bufferSizeCheck( - IBlockCipher engine) - { - byte[] correctBuf = new byte[engine.GetBlockSize()]; - byte[] shortBuf = new byte[correctBuf.Length / 2]; - - engine.Init(true, _validKey); - - try - { - engine.ProcessBlock(shortBuf, 0, correctBuf, 0); - - Fail("failed short input check"); - } - catch (DataLengthException) - { - // expected - } + protected void RunEngineChecks(IBlockCipher engine, KeyParameter validKey) + { + byte[] buf = new byte[engine.GetBlockSize()]; + ExpectInvalidOperationException(engine, buf, buf, "failed initialisation check"); - try - { - engine.ProcessBlock(correctBuf, 0, shortBuf, 0); + CheckDataLengthExceptions(engine, validKey); + } - Fail("failed short output check"); - } - catch (DataLengthException) - { - // expected - } + protected void RunTests(SimpleTest[] tests) + { + foreach (var test in tests) + { + test.PerformTest(); + } + } - engine.Init(false, _validKey); + private void CheckDataLengthExceptions(IBlockCipher engine, ICipherParameters parameters) + { + byte[] correctBuf = new byte[engine.GetBlockSize()]; + byte[] shortBuf = new byte[correctBuf.Length / 2]; - try - { - engine.ProcessBlock(shortBuf, 0, correctBuf, 0); + engine.Init(true, parameters); - Fail("failed short input check"); - } - catch (DataLengthException) - { - // expected - } + ExpectDataLengthException(engine, shortBuf, correctBuf, "failed short input check"); + ExpectDataLengthException(engine, correctBuf, shortBuf, "failed short output check"); - try - { - engine.ProcessBlock(correctBuf, 0, shortBuf, 0); + engine.Init(false, parameters); - Fail("failed short output check"); - } - catch (DataLengthException) - { - // expected - } + ExpectDataLengthException(engine, shortBuf, correctBuf, "failed short input check"); + ExpectDataLengthException(engine, correctBuf, shortBuf, "failed short output check"); } - } + + private void ExpectDataLengthException(IBlockCipher engine, byte[] input, byte[] output, string message) + { + try + { + engine.ProcessBlock(input, 0, output, 0); + Fail(message); + } + catch (DataLengthException) + { + // expected + } + } + + private void ExpectInvalidOperationException(IBlockCipher engine, byte[] input, byte[] output, string message) + { + try + { + engine.ProcessBlock(input, 0, output, 0); + Fail(message); + } + catch (InvalidOperationException) + { + // expected + } + } + } } |