diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-07-21 12:27:21 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-07-21 12:27:21 +0700 |
commit | 784a42b0e5e94dc7e1c1fe6975715d0c466be569 (patch) | |
tree | 5d8f4f57127ec1d05077fe46caf6a9000827d329 | |
parent | Registerize inner loops (diff) | |
download | BouncyCastle.NET-ed25519-784a42b0e5e94dc7e1c1fe6975715d0c466be569.tar.xz |
Port of latest GCM/OCB changes
-rw-r--r-- | crypto/crypto.csproj | 5 | ||||
-rw-r--r-- | crypto/src/crypto/modes/OCBBlockCipher.cs | 28 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/AeadTestUtilities.cs | 14 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/GCMTest.cs | 198 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/OCBTest.cs | 218 |
5 files changed, 389 insertions, 74 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index 6539d2f9f..126f5f1d4 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -10057,6 +10057,11 @@ BuildAction = "Compile" /> <File + RelPath = "test\src\crypto\test\AeadTestUtilities.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "test\src\crypto\test\AESFastTest.cs" SubType = "Code" BuildAction = "Compile" diff --git a/crypto/src/crypto/modes/OCBBlockCipher.cs b/crypto/src/crypto/modes/OCBBlockCipher.cs index 8fb6f213f..54359dfe8 100644 --- a/crypto/src/crypto/modes/OCBBlockCipher.cs +++ b/crypto/src/crypto/modes/OCBBlockCipher.cs @@ -7,9 +7,8 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Modes { /** - * An implementation of the "work in progress" Internet-Draft <a - * href="http://tools.ietf.org/html/draft-irtf-cfrg-ocb-07">The OCB Authenticated-Encryption - * Algorithm</a>, licensed per: + * An implementation of <a href="http://tools.ietf.org/html/rfc7253">RFC 7253 on The OCB + * Authenticated-Encryption Algorithm</a>, licensed per: * * <blockquote><p><a href="http://www.cs.ucdavis.edu/~rogaway/ocb/license1.pdf">License for * Open-Source Software Implementations of OCB</a> (Jan 9, 2013) - 'License 1'<br/> @@ -71,9 +70,8 @@ namespace Org.BouncyCastle.Crypto.Modes throw new ArgumentException("must have a block size of " + BLOCK_SIZE, "hashCipher"); if (mainCipher == null) throw new ArgumentNullException("mainCipher"); - if (mainCipher.GetBlockSize() != BLOCK_SIZE) { + if (mainCipher.GetBlockSize() != BLOCK_SIZE) throw new ArgumentException("must have a block size of " + BLOCK_SIZE, "mainCipher"); - } if (!hashCipher.AlgorithmName.Equals(mainCipher.AlgorithmName)) throw new ArgumentException("'hashCipher' and 'mainCipher' must be the same algorithm"); @@ -94,6 +92,7 @@ namespace Org.BouncyCastle.Crypto.Modes public virtual void Init(bool forEncryption, ICipherParameters parameters) { + bool oldForEncryption = this.forEncryption; this.forEncryption = forEncryption; this.macBlock = null; @@ -145,20 +144,18 @@ namespace Org.BouncyCastle.Crypto.Modes * KEY-DEPENDENT INITIALISATION */ - // if keyParam is null we're reusing the last key. if (keyParameter != null) { - // TODO + // hashCipher always used in forward mode + hashCipher.Init(true, keyParameter); + mainCipher.Init(forEncryption, keyParameter); + KtopInput = null; } - else + else if (oldForEncryption != forEncryption) { - KtopInput = null; + throw new ArgumentException("cannot change encrypting state without providing key."); } - // hashCipher always used in forward mode - hashCipher.Init(true, keyParameter); - mainCipher.Init(forEncryption, keyParameter); - this.L_Asterisk = new byte[16]; hashCipher.ProcessBlock(L_Asterisk, 0, L_Asterisk, 0); @@ -528,10 +525,11 @@ namespace Org.BouncyCastle.Crypto.Modes } int n = 0; - while ((x & 1L) == 0L) + ulong ux = (ulong)x; + while ((ux & 1UL) == 0UL) { ++n; - x >>= 1; + ux >>= 1; } return n; } diff --git a/crypto/test/src/crypto/test/AeadTestUtilities.cs b/crypto/test/src/crypto/test/AeadTestUtilities.cs new file mode 100644 index 000000000..40f334202 --- /dev/null +++ b/crypto/test/src/crypto/test/AeadTestUtilities.cs @@ -0,0 +1,14 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; + +namespace Org.BouncyCastle.Crypto.Tests +{ + public class AeadTestUtilities + { + internal static AeadParameters ReuseKey(AeadParameters p) + { + return new AeadParameters(null, p.MacSize, p.GetNonce(), p.GetAssociatedText()); + } + } +} diff --git a/crypto/test/src/crypto/test/GCMTest.cs b/crypto/test/src/crypto/test/GCMTest.cs index 4fe185be7..cea183454 100644 --- a/crypto/test/src/crypto/test/GCMTest.cs +++ b/crypto/test/src/crypto/test/GCMTest.cs @@ -9,6 +9,7 @@ using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Modes.Gcm; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Date; using Org.BouncyCastle.Utilities.Encoders; using Org.BouncyCastle.Utilities.Test; @@ -316,24 +317,63 @@ namespace Org.BouncyCastle.Crypto.Tests { for (int i = 0; i < TestVectors.Length; ++i) { - runTestCase(TestVectors[i]); + RunTestCase(TestVectors[i]); } - randomTests(); - } + RandomTests(); + OutputSizeTests(); + DoTestExceptions(); + } + + protected IBlockCipher CreateAesEngine() + { + return new AesFastEngine(); + } + + private void DoTestExceptions() + { + GcmBlockCipher gcm = new GcmBlockCipher(CreateAesEngine()); + + try + { + gcm = new GcmBlockCipher(new DesEngine()); + + Fail("incorrect block size not picked up"); + } + catch (ArgumentException e) + { + // expected + } + + try + { + gcm.Init(false, new KeyParameter(new byte[16])); + + Fail("illegal argument not picked up"); + } + catch (ArgumentException e) + { + // expected + } - private void runTestCase( - string[] testVector) + // TODO + //AEADTestUtil.testReset(this, new GCMBlockCipher(createAESEngine()), new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16])); + //AEADTestUtil.testTampering(this, gcm, new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16])); + //AEADTestUtil.testOutputSizes(this, new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter( + // new byte[16]), 128, new byte[16])); + //AEADTestUtil.testBufferSizeChecks(this, new GCMBlockCipher(createAESEngine()), new AEADParameters( + // new KeyParameter(new byte[16]), 128, new byte[16])); + } + + private void RunTestCase(string[] testVector) { for (int macLength = 12; macLength <= 16; ++macLength) { - runTestCase(testVector, macLength); + RunTestCase(testVector, macLength); } } - private void runTestCase( - string[] testVector, - int macLength) + private void RunTestCase(string[] testVector, int macLength) { int pos = 0; string testName = testVector[pos++]; @@ -349,14 +389,14 @@ namespace Org.BouncyCastle.Crypto.Tests Array.Copy(t, T, T.Length); // Default multiplier - runTestCase(null, null, testName, K, IV, A, P, C, T); + RunTestCase(null, null, testName, K, IV, A, P, C, T); - runTestCase(new BasicGcmMultiplier(), new BasicGcmMultiplier(), testName, K, IV, A, P, C, T); - runTestCase(new Tables8kGcmMultiplier(), new Tables8kGcmMultiplier(), testName, K, IV, A, P, C, T); - runTestCase(new Tables64kGcmMultiplier(), new Tables64kGcmMultiplier(), testName, K, IV, A, P, C, T); + RunTestCase(new BasicGcmMultiplier(), new BasicGcmMultiplier(), testName, K, IV, A, P, C, T); + RunTestCase(new Tables8kGcmMultiplier(), new Tables8kGcmMultiplier(), testName, K, IV, A, P, C, T); + RunTestCase(new Tables64kGcmMultiplier(), new Tables64kGcmMultiplier(), testName, K, IV, A, P, C, T); } - private void runTestCase( + private void RunTestCase( IGcmMultiplier encM, IGcmMultiplier decM, string testName, @@ -372,12 +412,12 @@ namespace Org.BouncyCastle.Crypto.Tests Array.Copy(A, 0, fa, 0, fa.Length); Array.Copy(A, fa.Length, la, 0, la.Length); - runTestCase(encM, decM, testName + " all initial associated data", K, IV, A, null, P, C, T); - runTestCase(encM, decM, testName + " all subsequent associated data", K, IV, null, A, P, C, T); - runTestCase(encM, decM, testName + " split associated data", K, IV, fa, la, P, C, T); + RunTestCase(encM, decM, testName + " all initial associated data", K, IV, A, null, P, C, T); + RunTestCase(encM, decM, testName + " all subsequent associated data", K, IV, null, A, P, C, T); + RunTestCase(encM, decM, testName + " split associated data", K, IV, fa, la, P, C, T); } - private void runTestCase( + private void RunTestCase( IGcmMultiplier encM, IGcmMultiplier decM, string testName, @@ -390,30 +430,29 @@ namespace Org.BouncyCastle.Crypto.Tests byte[] T) { AeadParameters parameters = new AeadParameters(new KeyParameter(K), T.Length * 8, IV, A); - GcmBlockCipher encCipher = initCipher(encM, true, parameters); - GcmBlockCipher decCipher = initCipher(decM, false, parameters); - checkTestCase(encCipher, decCipher, testName, SA, P, C, T); - checkTestCase(encCipher, decCipher, testName + " (reused)", SA, P, C, T); + GcmBlockCipher encCipher = InitCipher(encM, true, parameters); + GcmBlockCipher decCipher = InitCipher(decM, false, parameters); + CheckTestCase(encCipher, decCipher, testName, SA, P, C, T); + CheckTestCase(encCipher, decCipher, testName + " (reused)", SA, P, C, T); // Key reuse - AeadParameters keyReuseParams = new AeadParameters(null, parameters.MacSize, parameters.GetNonce(), parameters.GetAssociatedText()); + AeadParameters keyReuseParams = AeadTestUtilities.ReuseKey(parameters); encCipher.Init(true, keyReuseParams); decCipher.Init(false, keyReuseParams); - checkTestCase(encCipher, decCipher, testName + " (key reuse)", SA, P, C, T); - checkTestCase(encCipher, decCipher, testName + " (key reuse)", SA, P, C, T); + CheckTestCase(encCipher, decCipher, testName + " (key reuse)", SA, P, C, T); } - private GcmBlockCipher initCipher( + private GcmBlockCipher InitCipher( IGcmMultiplier m, bool forEncryption, AeadParameters parameters) { - GcmBlockCipher c = new GcmBlockCipher(new AesFastEngine(), m); + GcmBlockCipher c = new GcmBlockCipher(CreateAesEngine(), m); c.Init(forEncryption, parameters); return c; } - private void checkTestCase( + private void CheckTestCase( GcmBlockCipher encCipher, GcmBlockCipher decCipher, string testName, @@ -476,21 +515,25 @@ namespace Org.BouncyCastle.Crypto.Tests } } - private void randomTests() + private void RandomTests() { SecureRandom srng = new SecureRandom(); + srng.SetSeed(DateTimeUtilities.CurrentUnixMs()); + RandomTests(srng, null); + RandomTests(srng, new BasicGcmMultiplier()); + RandomTests(srng, new Tables8kGcmMultiplier()); + RandomTests(srng, new Tables64kGcmMultiplier()); + } + + private void RandomTests(SecureRandom srng, IGcmMultiplier m) + { for (int i = 0; i < 10; ++i) { - randomTest(srng, null); - randomTest(srng, new BasicGcmMultiplier()); - randomTest(srng, new Tables8kGcmMultiplier()); - randomTest(srng, new Tables64kGcmMultiplier()); + RandomTest(srng, m); } } - private void randomTest( - SecureRandom srng, - IGcmMultiplier m) + private void RandomTest(SecureRandom srng, IGcmMultiplier m) { int kLength = 16 + 8 * srng.Next(3); byte[] K = new byte[kLength]; @@ -512,9 +555,8 @@ namespace Org.BouncyCastle.Crypto.Tests byte[] IV = new byte[ivLength]; srng.NextBytes(IV); - GcmBlockCipher cipher = new GcmBlockCipher(new AesFastEngine(), m); AeadParameters parameters = new AeadParameters(new KeyParameter(K), 16 * 8, IV, A); - cipher.Init(true, parameters); + GcmBlockCipher cipher = InitCipher(m, true, parameters); byte[] C = new byte[cipher.GetOutputSize(P.Length)]; int predicted = cipher.GetUpdateOutputSize(P.Length); @@ -570,6 +612,86 @@ namespace Org.BouncyCastle.Crypto.Tests { Fail("decryption produced different mac from encryption"); } + + // + // key reuse test + // + cipher.Init(false, AeadTestUtilities.ReuseKey(parameters)); + decP = new byte[cipher.GetOutputSize(C.Length)]; + + split = NextInt(srng, SA.Length + 1); + cipher.ProcessAadBytes(SA, 0, split); + len = cipher.ProcessBytes(C, 0, C.Length, decP, 0); + cipher.ProcessAadBytes(SA, split, SA.Length - split); + + len += cipher.DoFinal(decP, len); + + if (!AreEqual(P, decP)) + { + Fail("incorrect decrypt in randomised test"); + } + + decT = cipher.GetMac(); + if (!AreEqual(encT, decT)) + { + Fail("decryption produced different mac from encryption"); + } + } + + private void OutputSizeTests() + { + byte[] K = new byte[16]; + byte[] A = null; + byte[] IV = new byte[16]; + + AeadParameters parameters = new AeadParameters(new KeyParameter(K), 16 * 8, IV, A); + GcmBlockCipher cipher = InitCipher(null, true, parameters); + + if (cipher.GetUpdateOutputSize(0) != 0) + { + Fail("incorrect getUpdateOutputSize for initial 0 bytes encryption"); + } + + if (cipher.GetOutputSize(0) != 16) + { + Fail("incorrect getOutputSize for initial 0 bytes encryption"); + } + + cipher.Init(false, parameters); + + if (cipher.GetUpdateOutputSize(0) != 0) + { + Fail("incorrect getUpdateOutputSize for initial 0 bytes decryption"); + } + + // NOTE: 0 bytes would be truncated data, but we want it to fail in the doFinal, not here + if (cipher.GetOutputSize(0) != 0) + { + Fail("fragile getOutputSize for initial 0 bytes decryption"); + } + + if (cipher.GetOutputSize(16) != 0) + { + Fail("incorrect getOutputSize for initial MAC-size bytes decryption"); + } + } + + private static int NextInt(SecureRandom rand, int n) + { + if ((n & -n) == n) // i.e., n is a power of 2 + { + return (int)(((uint)n * (ulong)((uint)rand.NextInt() >> 1)) >> 31); + } + + int bits, value; + do + { + bits = (int)((uint)rand.NextInt() >> 1); + value = bits % n; + } + while (bits - value + (n - 1) < 0); + + return value; } public static void Main( diff --git a/crypto/test/src/crypto/test/OCBTest.cs b/crypto/test/src/crypto/test/OCBTest.cs index 0829cb078..f2476f6d5 100644 --- a/crypto/test/src/crypto/test/OCBTest.cs +++ b/crypto/test/src/crypto/test/OCBTest.cs @@ -6,16 +6,17 @@ using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Date; using Org.BouncyCastle.Utilities.Encoders; using Org.BouncyCastle.Utilities.Test; namespace Org.BouncyCastle.Crypto.Tests { /** - * Test vectors from the "work in progress" Internet-Draft <a - * href="http://tools.ietf.org/html/draft-irtf-cfrg-ocb-07">The OCB Authenticated-Encryption - * Algorithm</a> + * Test vectors from <a href="http://tools.ietf.org/html/rfc7253">RFC 7253 on The OCB + * Authenticated-Encryption Algorithm</a> */ public class OcbTest : SimpleTest @@ -120,16 +121,18 @@ namespace Org.BouncyCastle.Crypto.Tests RunTestCase("Test Case " + i, TEST_VECTORS_96[i], 96, K96); } - RunLongerTestCase(128, 128, Hex.Decode("67E944D23256C5E0B6C61FA22FDF1EA2")); - RunLongerTestCase(192, 128, Hex.Decode("F673F2C3E7174AAE7BAE986CA9F29E17")); - RunLongerTestCase(256, 128, Hex.Decode("D90EB8E9C977C88B79DD793D7FFA161C")); - RunLongerTestCase(128, 96, Hex.Decode("77A3D8E73589158D25D01209")); - RunLongerTestCase(192, 96, Hex.Decode("05D56EAD2752C86BE6932C5E")); - RunLongerTestCase(256, 96, Hex.Decode("5458359AC23B0CBA9E6330DD")); - RunLongerTestCase(128, 64, Hex.Decode("192C9B7BD90BA06A")); - RunLongerTestCase(192, 64, Hex.Decode("0066BC6E0EF34E24")); - RunLongerTestCase(256, 64, Hex.Decode("7D4EA5D445501CBE")); - + RunLongerTestCase(128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2"); + RunLongerTestCase(192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17"); + RunLongerTestCase(256, 128, "D90EB8E9C977C88B79DD793D7FFA161C"); + RunLongerTestCase(128, 96, "77A3D8E73589158D25D01209"); + RunLongerTestCase(192, 96, "05D56EAD2752C86BE6932C5E"); + RunLongerTestCase(256, 96, "5458359AC23B0CBA9E6330DD"); + RunLongerTestCase(128, 64, "192C9B7BD90BA06A"); + RunLongerTestCase(192, 64, "0066BC6E0EF34E24"); + RunLongerTestCase(256, 64, "7D4EA5D445501CBE"); + + RandomTests(); + OutputSizeTests(); DoTestExceptions(); } @@ -172,18 +175,20 @@ namespace Org.BouncyCastle.Crypto.Tests int macLengthBytes = macLengthBits / 8; - // TODO Variations processing AAD and cipher bytes incrementally - KeyParameter keyParameter = new KeyParameter(K); - AeadParameters aeadParameters = new AeadParameters(keyParameter, macLengthBits, N, A); + AeadParameters parameters = new AeadParameters(keyParameter, macLengthBits, N, A); - IAeadBlockCipher encCipher = InitOcbCipher(true, aeadParameters); - IAeadBlockCipher decCipher = InitOcbCipher(false, aeadParameters); + IAeadBlockCipher encCipher = InitOcbCipher(true, parameters); + IAeadBlockCipher decCipher = InitOcbCipher(false, parameters); CheckTestCase(encCipher, decCipher, testName, macLengthBytes, P, C); CheckTestCase(encCipher, decCipher, testName + " (reused)", macLengthBytes, P, C); - // TODO Key reuse + // Key reuse + AeadParameters keyReuseParams = AeadTestUtilities.ReuseKey(parameters); + encCipher.Init(true, keyReuseParams); + decCipher.Init(false, keyReuseParams); + CheckTestCase(encCipher, decCipher, testName + " (key reuse)", macLengthBytes, P, C); } private IBlockCipher CreateUnderlyingCipher() @@ -251,14 +256,14 @@ namespace Org.BouncyCastle.Crypto.Tests } } - private void RunLongerTestCase(int keyLen, int tagLen, byte[] expectedOutput) + private void RunLongerTestCase(int keyLen, int tagLen, string expectedOutputHex) { + byte[] expectedOutput = Hex.Decode(expectedOutputHex); byte[] keyBytes = new byte[keyLen / 8]; keyBytes[keyBytes.Length - 1] = (byte)tagLen; KeyParameter key = new KeyParameter(keyBytes); IAeadBlockCipher c1 = InitOcbCipher(true, new AeadParameters(key, tagLen, CreateNonce(385))); - IAeadBlockCipher c2 = CreateOcbCipher(); long total = 0; @@ -322,6 +327,177 @@ namespace Org.BouncyCastle.Crypto.Tests return len; } + private void RandomTests() + { + SecureRandom srng = new SecureRandom(); + srng.SetSeed(DateTimeUtilities.CurrentUnixMs()); + for (int i = 0; i < 10; ++i) + { + RandomTest(srng); + } + } + + private void RandomTest(SecureRandom srng) + { + int kLength = 16 + 8 * (System.Math.Abs(srng.NextInt()) % 3); + byte[] K = new byte[kLength]; + srng.NextBytes(K); + + int pLength = (int)((uint)srng.NextInt() >> 16); + byte[] P = new byte[pLength]; + srng.NextBytes(P); + + int aLength = (int)((uint)srng.NextInt() >> 24); + byte[] A = new byte[aLength]; + srng.NextBytes(A); + + int saLength = (int)((uint)srng.NextInt() >> 24); + byte[] SA = new byte[saLength]; + srng.NextBytes(SA); + + int ivLength = 1 + NextInt(srng, 15); + byte[] IV = new byte[ivLength]; + srng.NextBytes(IV); + + AeadParameters parameters = new AeadParameters(new KeyParameter(K), 16 * 8, IV, A); + IAeadBlockCipher cipher = InitOcbCipher(true, parameters); + byte[] C = new byte[cipher.GetOutputSize(P.Length)]; + int predicted = cipher.GetUpdateOutputSize(P.Length); + + int split = NextInt(srng, SA.Length + 1); + cipher.ProcessAadBytes(SA, 0, split); + int len = cipher.ProcessBytes(P, 0, P.Length, C, 0); + cipher.ProcessAadBytes(SA, split, SA.Length - split); + + if (predicted != len) + { + Fail("encryption reported incorrect update length in randomised test"); + } + + len += cipher.DoFinal(C, len); + + if (C.Length != len) + { + Fail("encryption reported incorrect length in randomised test"); + } + + byte[] encT = cipher.GetMac(); + byte[] tail = new byte[C.Length - P.Length]; + Array.Copy(C, P.Length, tail, 0, tail.Length); + + if (!AreEqual(encT, tail)) + { + Fail("stream contained wrong mac in randomised test"); + } + + cipher.Init(false, parameters); + byte[] decP = new byte[cipher.GetOutputSize(C.Length)]; + predicted = cipher.GetUpdateOutputSize(C.Length); + + split = NextInt(srng, SA.Length + 1); + cipher.ProcessAadBytes(SA, 0, split); + len = cipher.ProcessBytes(C, 0, C.Length, decP, 0); + cipher.ProcessAadBytes(SA, split, SA.Length - split); + + if (predicted != len) + { + Fail("decryption reported incorrect update length in randomised test"); + } + + len += cipher.DoFinal(decP, len); + + if (!AreEqual(P, decP)) + { + Fail("incorrect decrypt in randomised test"); + } + + byte[] decT = cipher.GetMac(); + if (!AreEqual(encT, decT)) + { + Fail("decryption produced different mac from encryption"); + } + + // + // key reuse test + // + cipher.Init(false, AeadTestUtilities.ReuseKey(parameters)); + decP = new byte[cipher.GetOutputSize(C.Length)]; + + split = NextInt(srng, SA.Length + 1); + cipher.ProcessAadBytes(SA, 0, split); + len = cipher.ProcessBytes(C, 0, C.Length, decP, 0); + cipher.ProcessAadBytes(SA, split, SA.Length - split); + + len += cipher.DoFinal(decP, len); + + if (!AreEqual(P, decP)) + { + Fail("incorrect decrypt in randomised test"); + } + + decT = cipher.GetMac(); + if (!AreEqual(encT, decT)) + { + Fail("decryption produced different mac from encryption"); + } + } + + private void OutputSizeTests() + { + byte[] K = new byte[16]; + byte[] A = null; + byte[] IV = new byte[15]; + + AeadParameters parameters = new AeadParameters(new KeyParameter(K), 16 * 8, IV, A); + IAeadBlockCipher cipher = InitOcbCipher(true, parameters); + + if (cipher.GetUpdateOutputSize(0) != 0) + { + Fail("incorrect getUpdateOutputSize for initial 0 bytes encryption"); + } + + if (cipher.GetOutputSize(0) != 16) + { + Fail("incorrect getOutputSize for initial 0 bytes encryption"); + } + + cipher.Init(false, parameters); + + if (cipher.GetUpdateOutputSize(0) != 0) + { + Fail("incorrect getUpdateOutputSize for initial 0 bytes decryption"); + } + + // NOTE: 0 bytes would be truncated data, but we want it to fail in the doFinal, not here + if (cipher.GetOutputSize(0) != 0) + { + Fail("fragile getOutputSize for initial 0 bytes decryption"); + } + + if (cipher.GetOutputSize(16) != 0) + { + Fail("incorrect getOutputSize for initial MAC-size bytes decryption"); + } + } + + private static int NextInt(SecureRandom rand, int n) + { + if ((n & -n) == n) // i.e., n is a power of 2 + { + return (int)(((uint)n * (ulong)((uint)rand.NextInt() >> 1)) >> 31); + } + + int bits, value; + do + { + bits = (int)((uint)rand.NextInt() >> 1); + value = bits % n; + } + while (bits - value + (n - 1) < 0); + + return value; + } + public static void Main( string[] args) { |