diff --git a/crypto/src/crypto/modes/OCBBlockCipher.cs b/crypto/src/crypto/modes/OCBBlockCipher.cs
index 3ee06b805..9f0e0f6bb 100644
--- a/crypto/src/crypto/modes/OCBBlockCipher.cs
+++ b/crypto/src/crypto/modes/OCBBlockCipher.cs
@@ -8,7 +8,7 @@ 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-03">The OCB Authenticated-Encryption
+ * href="http://tools.ietf.org/html/draft-irtf-cfrg-ocb-05">The OCB Authenticated-Encryption
* Algorithm</a>, licensed per:
*
* <blockquote><p><a href="http://www.cs.ucdavis.edu/~rogaway/ocb/license1.pdf">License for
@@ -45,7 +45,9 @@ namespace Org.BouncyCastle.Crypto.Modes
/*
* NONCE-DEPENDENT
*/
- private byte[] OffsetMAIN_0;
+ private byte[] KtopInput = null;
+ private byte[] Stretch = new byte[24];
+ private byte[] OffsetMAIN_0 = new byte[16];
/*
* PER-ENCRYPTION/DECRYPTION
@@ -55,7 +57,7 @@ namespace Org.BouncyCastle.Crypto.Modes
private long hashBlockCount, mainBlockCount;
private byte[] OffsetHASH;
private byte[] Sum;
- private byte[] OffsetMAIN;
+ private byte[] OffsetMAIN = new byte[16];
private byte[] Checksum;
// NOTE: The MAC value is preserved after doFinal
@@ -165,25 +167,8 @@ namespace Org.BouncyCastle.Crypto.Modes
* NONCE-DEPENDENT AND PER-ENCRYPTION/DECRYPTION INITIALISATION
*/
- byte[] nonce = new byte[16];
- Array.Copy(N, 0, nonce, nonce.Length - N.Length, N.Length);
- nonce[0] = (byte)(macSize << 4);
- nonce[15 - N.Length] |= 1;
-
- int bottom = nonce[15] & 0x3F;
-
- byte[] Ktop = new byte[16];
- nonce[15] &= 0xC0;
- hashCipher.ProcessBlock(nonce, 0, Ktop, 0);
+ int bottom = ProcessNonce(N);
- byte[] Stretch = new byte[24];
- Array.Copy(Ktop, 0, Stretch, 0, 16);
- for (int i = 0; i < 8; ++i)
- {
- Stretch[16 + i] = (byte) (Ktop[i] ^ Ktop[i + 1]);
- }
-
- this.OffsetMAIN_0 = new byte[16];
int bits = bottom % 8, bytes = bottom / 8;
if (bits == 0)
{
@@ -207,7 +192,7 @@ namespace Org.BouncyCastle.Crypto.Modes
this.OffsetHASH = new byte[16];
this.Sum = new byte[16];
- this.OffsetMAIN = Arrays.Clone(this.OffsetMAIN_0);
+ Array.Copy(OffsetMAIN_0, 0, OffsetMAIN, 0, 16);
this.Checksum = new byte[16];
if (initialAssociatedText != null)
@@ -216,6 +201,34 @@ namespace Org.BouncyCastle.Crypto.Modes
}
}
+ protected virtual int ProcessNonce(byte[] N)
+ {
+ byte[] nonce = new byte[16];
+ Array.Copy(N, 0, nonce, nonce.Length - N.Length, N.Length);
+ nonce[0] = (byte)(macSize << 4);
+ nonce[15 - N.Length] |= 1;
+
+ int bottom = nonce[15] & 0x3F;
+ nonce[15] &= 0xC0;
+
+ /*
+ * When used with incrementing nonces, the cipher is only applied once every 64 inits.
+ */
+ if (KtopInput == null || !Arrays.AreEqual(nonce, KtopInput))
+ {
+ byte[] Ktop = new byte[16];
+ KtopInput = nonce;
+ hashCipher.ProcessBlock(KtopInput, 0, Ktop, 0);
+ Array.Copy(Ktop, 0, Stretch, 0, 16);
+ for (int i = 0; i < 8; ++i)
+ {
+ Stretch[16 + i] = (byte)(Ktop[i] ^ Ktop[i + 1]);
+ }
+ }
+
+ return bottom;
+ }
+
public virtual int GetBlockSize()
{
return BLOCK_SIZE;
diff --git a/crypto/test/src/crypto/test/OCBTest.cs b/crypto/test/src/crypto/test/OCBTest.cs
index 051aa665a..284ae7fb3 100644
--- a/crypto/test/src/crypto/test/OCBTest.cs
+++ b/crypto/test/src/crypto/test/OCBTest.cs
@@ -14,7 +14,7 @@ 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-03">The OCB Authenticated-Encryption
+ * href="http://tools.ietf.org/html/draft-irtf-cfrg-ocb-05">The OCB Authenticated-Encryption
* Algorithm</a>
*/
public class OcbTest
@@ -90,6 +90,37 @@ namespace Org.BouncyCastle.Crypto.Tests
RunLongerTestCase(128, 64, Hex.Decode("B7ECE9D381FE437F"));
RunLongerTestCase(192, 64, Hex.Decode("DE0574C87FF06DF9"));
RunLongerTestCase(256, 64, Hex.Decode("833E45FF7D332F7E"));
+
+ DoTestExceptions();
+ }
+
+ private void DoTestExceptions()
+ {
+ OcbBlockCipher ocb = new OcbBlockCipher(new AesFastEngine(), new AesFastEngine());
+
+ try
+ {
+ ocb = new OcbBlockCipher(new DesEngine(), new DesEngine());
+ Fail("incorrect block size not picked up");
+ }
+ catch (ArgumentException e)
+ {
+ // expected
+ }
+
+ try
+ {
+ ocb.Init(false, new KeyParameter(new byte[16]));
+ Fail("illegal argument not picked up");
+ }
+ catch (ArgumentException e)
+ {
+ // expected
+ }
+
+ // TODO
+ //AEADTestUtil.testReset(this, new OCBBlockCipher(new AESEngine(), new AESEngine()), new OCBBlockCipher(new AESEngine(), new AESEngine()), new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[15]));
+ //AEADTestUtil.testTampering(this, ocb, new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[15]));
}
private void RunTestCase(string testName, string[] testVector)
|