aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/core/src/test/java/org/spongycastle/crypto/test/OCBTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/spongycastle/core/src/test/java/org/spongycastle/crypto/test/OCBTest.java')
-rw-r--r--libraries/spongycastle/core/src/test/java/org/spongycastle/crypto/test/OCBTest.java296
1 files changed, 296 insertions, 0 deletions
diff --git a/libraries/spongycastle/core/src/test/java/org/spongycastle/crypto/test/OCBTest.java b/libraries/spongycastle/core/src/test/java/org/spongycastle/crypto/test/OCBTest.java
new file mode 100644
index 000000000..d3bd2b784
--- /dev/null
+++ b/libraries/spongycastle/core/src/test/java/org/spongycastle/crypto/test/OCBTest.java
@@ -0,0 +1,296 @@
+package org.spongycastle.crypto.test;
+
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.engines.AESEngine;
+import org.spongycastle.crypto.engines.AESFastEngine;
+import org.spongycastle.crypto.engines.DESEngine;
+import org.spongycastle.crypto.modes.AEADBlockCipher;
+import org.spongycastle.crypto.modes.OCBBlockCipher;
+import org.spongycastle.crypto.params.AEADParameters;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.util.test.SimpleTest;
+
+/**
+ * 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
+ * Algorithm</a>
+ */
+public class OCBTest
+ extends SimpleTest
+{
+
+ private static final String K = "000102030405060708090A0B0C0D0E0F";
+ private static final String N = "000102030405060708090A0B";
+
+ // Each test vector contains the strings A, P, C in order
+ private static final String[][] TEST_VECTORS = new String[][]{
+ {"", "", "197B9C3C441D3C83EAFB2BEF633B9182"},
+ {"0001020304050607", "0001020304050607",
+ "92B657130A74B85A16DC76A46D47E1EAD537209E8A96D14E"},
+ {"0001020304050607", "", "98B91552C8C009185044E30A6EB2FE21"},
+ {"", "0001020304050607", "92B657130A74B85A971EFFCAE19AD4716F88E87B871FBEED"},
+ {"000102030405060708090A0B0C0D0E0F", "000102030405060708090A0B0C0D0E0F",
+ "BEA5E8798DBE7110031C144DA0B26122776C9924D6723A1F" + "C4524532AC3E5BEB"},
+ {"000102030405060708090A0B0C0D0E0F", "", "7DDB8E6CEA6814866212509619B19CC6"},
+ {"", "000102030405060708090A0B0C0D0E0F",
+ "BEA5E8798DBE7110031C144DA0B2612213CC8B747807121A" + "4CBB3E4BD6B456AF"},
+ {"000102030405060708090A0B0C0D0E0F1011121314151617",
+ "000102030405060708090A0B0C0D0E0F1011121314151617",
+ "BEA5E8798DBE7110031C144DA0B26122FCFCEE7A2A8D4D48" + "5FA94FC3F38820F1DC3F3D1FD4E55E1C"},
+ {"000102030405060708090A0B0C0D0E0F1011121314151617", "",
+ "282026DA3068BC9FA118681D559F10F6"},
+ {"", "000102030405060708090A0B0C0D0E0F1011121314151617",
+ "BEA5E8798DBE7110031C144DA0B26122FCFCEE7A2A8D4D48" + "6EF2F52587FDA0ED97DC7EEDE241DF68"},
+ {
+ "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F",
+ "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F",
+ "BEA5E8798DBE7110031C144DA0B26122CEAAB9B05DF771A6"
+ + "57149D53773463CBB2A040DD3BD5164372D76D7BB6824240"},
+ {"000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F", "",
+ "E1E072633BADE51A60E85951D9C42A1B"},
+ {
+ "",
+ "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F",
+ "BEA5E8798DBE7110031C144DA0B26122CEAAB9B05DF771A6"
+ + "57149D53773463CB4A3BAE824465CFDAF8C41FC50C7DF9D9"},
+ {
+ "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627",
+ "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627",
+ "BEA5E8798DBE7110031C144DA0B26122CEAAB9B05DF771A6"
+ + "57149D53773463CB68C65778B058A635659C623211DEEA0D" + "E30D2C381879F4C8"},
+ {"000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627",
+ "", "7AEB7A69A1687DD082CA27B0D9A37096"},
+ {
+ "",
+ "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627",
+ "BEA5E8798DBE7110031C144DA0B26122CEAAB9B05DF771A6"
+ + "57149D53773463CB68C65778B058A635060C8467F4ABAB5E" + "8B3C2067A2E115DC"},
+
+ };
+
+ public String getName()
+ {
+ return "OCB";
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ for (int i = 0; i < TEST_VECTORS.length; ++i)
+ {
+ runTestCase("Test Case " + i, TEST_VECTORS[i]);
+ }
+
+ runLongerTestCase(128, 128, Hex.decode("B2B41CBF9B05037DA7F16C24A35C1C94"));
+ runLongerTestCase(192, 128, Hex.decode("1529F894659D2B51B776740211E7D083"));
+ runLongerTestCase(256, 128, Hex.decode("42B83106E473C0EEE086C8D631FD4C7B"));
+ runLongerTestCase(128, 96, Hex.decode("1A4F0654277709A5BDA0D380"));
+ runLongerTestCase(192, 96, Hex.decode("AD819483E01DD648978F4522"));
+ runLongerTestCase(256, 96, Hex.decode("CD2E41379C7E7C4458CCFB4A"));
+ runLongerTestCase(128, 64, Hex.decode("B7ECE9D381FE437F"));
+ runLongerTestCase(192, 64, Hex.decode("DE0574C87FF06DF9"));
+ runLongerTestCase(256, 64, Hex.decode("833E45FF7D332F7E"));
+
+ testExceptions();
+ }
+
+ private void testExceptions() throws InvalidCipherTextException
+ {
+ OCBBlockCipher ocb = new OCBBlockCipher(new AESFastEngine(), new AESFastEngine());
+
+ try
+ {
+ ocb = new OCBBlockCipher(new DESEngine(), new DESEngine());
+
+ fail("incorrect block size not picked up");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // expected
+ }
+
+ try
+ {
+ ocb.init(false, new KeyParameter(new byte[16]));
+
+ fail("illegal argument not picked up");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // expected
+ }
+
+ 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)
+ throws InvalidCipherTextException
+ {
+
+ runTestCase(testName, testVector, 128);
+ }
+
+ private void runTestCase(String testName, String[] testVector, int macLengthBits)
+ throws InvalidCipherTextException
+ {
+
+ byte[] key = Hex.decode(K);
+ byte[] nonce = Hex.decode(N);
+
+ int pos = 0;
+ byte[] A = Hex.decode(testVector[pos++]);
+ byte[] P = Hex.decode(testVector[pos++]);
+ byte[] C = Hex.decode(testVector[pos++]);
+
+ int macLengthBytes = macLengthBits / 8;
+
+ // TODO Variations processing AAD and cipher bytes incrementally
+
+ KeyParameter keyParameter = new KeyParameter(key);
+ AEADParameters aeadParameters = new AEADParameters(keyParameter, macLengthBits, nonce, A);
+
+ OCBBlockCipher encCipher = initCipher(true, aeadParameters);
+ OCBBlockCipher decCipher = initCipher(false, aeadParameters);
+
+ checkTestCase(encCipher, decCipher, testName, macLengthBytes, P, C);
+ checkTestCase(encCipher, decCipher, testName + " (reused)", macLengthBytes, P, C);
+
+ // TODO Key reuse
+ }
+
+ private OCBBlockCipher initCipher(boolean forEncryption, AEADParameters parameters)
+ {
+ OCBBlockCipher c = new OCBBlockCipher(new AESFastEngine(), new AESFastEngine());
+ c.init(forEncryption, parameters);
+ return c;
+ }
+
+ private void checkTestCase(OCBBlockCipher encCipher, OCBBlockCipher decCipher, String testName,
+ int macLengthBytes, byte[] P, byte[] C)
+ throws InvalidCipherTextException
+ {
+
+ byte[] tag = Arrays.copyOfRange(C, C.length - macLengthBytes, C.length);
+
+ {
+ byte[] enc = new byte[encCipher.getOutputSize(P.length)];
+ int len = encCipher.processBytes(P, 0, P.length, enc, 0);
+ len += encCipher.doFinal(enc, len);
+
+ if (enc.length != len)
+ {
+ fail("encryption reported incorrect length: " + testName);
+ }
+
+ if (!areEqual(C, enc))
+ {
+ fail("incorrect encrypt in: " + testName);
+ }
+
+ if (!areEqual(tag, encCipher.getMac()))
+ {
+ fail("getMac() not the same as the appended tag: " + testName);
+ }
+ }
+
+ {
+ byte[] dec = new byte[decCipher.getOutputSize(C.length)];
+ int len = decCipher.processBytes(C, 0, C.length, dec, 0);
+ len += decCipher.doFinal(dec, len);
+
+ if (dec.length != len)
+ {
+ fail("decryption reported incorrect length: " + testName);
+ }
+
+ if (!areEqual(P, dec))
+ {
+ fail("incorrect decrypt in: " + testName);
+ }
+
+ if (!areEqual(tag, decCipher.getMac()))
+ {
+ fail("getMac() not the same as the appended tag: " + testName);
+ }
+ }
+ }
+
+ private void runLongerTestCase(int aesKeySize, int tagLen, byte[] expectedOutput)
+ throws InvalidCipherTextException
+ {
+ KeyParameter key = new KeyParameter(new byte[aesKeySize / 8]);
+ byte[] N = new byte[12];
+
+ AEADBlockCipher c1 = new OCBBlockCipher(new AESFastEngine(), new AESFastEngine());
+ c1.init(true, new AEADParameters(key, tagLen, N));
+
+ AEADBlockCipher c2 = new OCBBlockCipher(new AESFastEngine(), new AESFastEngine());
+
+ long total = 0;
+
+ byte[] S = new byte[128];
+
+ for (int i = 0; i < 128; ++i)
+ {
+ N[11] = (byte)i;
+
+ c2.init(true, new AEADParameters(key, tagLen, N));
+
+ total += updateCiphers(c1, c2, S, i, true, true);
+ total += updateCiphers(c1, c2, S, i, false, true);
+ total += updateCiphers(c1, c2, S, i, true, false);
+ }
+
+ long expectedTotal = 16256 + (48 * tagLen);
+
+ if (total != expectedTotal)
+ {
+ fail("test generated the wrong amount of input: " + total);
+ }
+
+ byte[] output = new byte[c1.getOutputSize(0)];
+ c1.doFinal(output, 0);
+
+ if (!areEqual(expectedOutput, output))
+ {
+ fail("incorrect encrypt in long-form test");
+ }
+ }
+
+ private int updateCiphers(AEADBlockCipher c1, AEADBlockCipher c2, byte[] S, int i,
+ boolean includeAAD, boolean includePlaintext)
+ throws InvalidCipherTextException
+ {
+
+ int inputLen = includePlaintext ? i : 0;
+ int outputLen = c2.getOutputSize(inputLen);
+
+ byte[] output = new byte[outputLen];
+
+ int len = 0;
+
+ if (includeAAD)
+ {
+ c2.processAADBytes(S, 0, i);
+ }
+
+ if (includePlaintext)
+ {
+ len += c2.processBytes(S, 0, i, output, len);
+ }
+
+ len += c2.doFinal(output, len);
+
+ c1.processAADBytes(output, 0, len);
+
+ return len;
+ }
+
+ public static void main(String[] args)
+ {
+ runTest(new OCBTest());
+ }
+}