diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-01-26 20:26:44 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-01-26 20:26:44 +0700 |
commit | 6f3de272501bd9153fdbc7b6c28a6de7c7dfbfae (patch) | |
tree | 40bc1f0d3b347511de311c08fe87179b52e4c3b3 | |
parent | Make class internal (diff) | |
download | BouncyCastle.NET-ed25519-6f3de272501bd9153fdbc7b6c28a6de7c7dfbfae.tar.xz |
When OCB is used with incrementing nonces, the cipher processing during initialization is only needed once every 64 inits.
-rw-r--r-- | crypto/src/crypto/modes/OCBBlockCipher.cs | 57 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/OCBTest.cs | 33 |
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) |