summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'crypto')
-rw-r--r--crypto/src/crypto/modes/OCBBlockCipher.cs57
-rw-r--r--crypto/test/src/crypto/test/OCBTest.cs33
2 files changed, 67 insertions, 23 deletions
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)