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)
{
|