diff options
Diffstat (limited to 'core/src/test/java/org/spongycastle/crypto/test')
151 files changed, 29230 insertions, 0 deletions
diff --git a/core/src/test/java/org/spongycastle/crypto/test/AEADTestUtil.java b/core/src/test/java/org/spongycastle/crypto/test/AEADTestUtil.java new file mode 100644 index 00000000..e2ff7e4c --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/AEADTestUtil.java @@ -0,0 +1,474 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.OutputLengthException; +import org.spongycastle.crypto.modes.AEADBlockCipher; +import org.spongycastle.crypto.params.AEADParameters; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestFailedException; + +public class AEADTestUtil +{ + public static void testTampering(Test test, AEADBlockCipher cipher, CipherParameters params) + throws InvalidCipherTextException + { + byte[] plaintext = new byte[1000]; + for (int i = 0; i < plaintext.length; i++) + { + plaintext[i] = (byte)i; + } + cipher.init(true, params); + + byte[] ciphertext = new byte[cipher.getOutputSize(plaintext.length)]; + int len = cipher.processBytes(plaintext, 0, plaintext.length, ciphertext, 0); + cipher.doFinal(ciphertext, len); + + int macLength = cipher.getMac().length; + + // Test tampering with a single byte + cipher.init(false, params); + byte[] tampered = new byte[ciphertext.length]; + byte[] output = new byte[plaintext.length]; + System.arraycopy(ciphertext, 0, tampered, 0, tampered.length); + tampered[0] += 1; + + cipher.processBytes(tampered, 0, tampered.length, output, 0); + try + { + cipher.doFinal(output, 0); + throw new TestFailedException( + new SimpleTestResult(false, test + " : tampering of ciphertext not detected.")); + } + catch (InvalidCipherTextException e) + { + // Expected + } + + // Test truncation of ciphertext to < tag length + cipher.init(false, params); + byte[] truncated = new byte[macLength - 1]; + System.arraycopy(ciphertext, 0, truncated, 0, truncated.length); + + cipher.processBytes(truncated, 0, truncated.length, output, 0); + try + { + cipher.doFinal(output, 0); + fail(test, "tampering of ciphertext not detected."); + } + catch (InvalidCipherTextException e) + { + // Expected + } + } + + private static void fail(Test test, String message) + { + throw new TestFailedException(SimpleTestResult.failed(test, message)); + } + + private static void fail(Test test, String message, String expected, String result) + { + throw new TestFailedException(SimpleTestResult.failed(test, message, expected, result)); + } + + public static void testReset(Test test, AEADBlockCipher cipher1, AEADBlockCipher cipher2, CipherParameters params) + throws InvalidCipherTextException + { + cipher1.init(true, params); + + byte[] plaintext = new byte[1000]; + byte[] ciphertext = new byte[cipher1.getOutputSize(plaintext.length)]; + + // Establish baseline answer + crypt(cipher1, plaintext, ciphertext); + + // Test encryption resets + checkReset(test, cipher1, params, true, plaintext, ciphertext); + + // Test decryption resets with fresh instance + cipher2.init(false, params); + checkReset(test, cipher2, params, false, ciphertext, plaintext); + } + + private static void checkReset(Test test, + AEADBlockCipher cipher, + CipherParameters params, + boolean encrypt, + byte[] pretext, + byte[] posttext) + throws InvalidCipherTextException + { + // Do initial run + byte[] output = new byte[posttext.length]; + crypt(cipher, pretext, output); + + // Check encrypt resets cipher + crypt(cipher, pretext, output); + if (!Arrays.areEqual(output, posttext)) + { + fail(test, (encrypt ? "Encrypt" : "Decrypt") + " did not reset cipher."); + } + + // Check init resets data + cipher.processBytes(pretext, 0, 100, output, 0); + cipher.init(encrypt, params); + + try + { + crypt(cipher, pretext, output); + } + catch (DataLengthException e) + { + fail(test, "Init did not reset data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test, "Init did not reset data.", new String(Hex.encode(posttext)), new String(Hex.encode(output))); + } + + // Check init resets AD + cipher.processAADBytes(pretext, 0, 100); + cipher.init(encrypt, params); + + try + { + crypt(cipher, pretext, output); + } + catch (DataLengthException e) + { + fail(test, "Init did not reset additional data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test, "Init did not reset additional data."); + } + + // Check reset resets data + cipher.processBytes(pretext, 0, 100, output, 0); + cipher.reset(); + + try + { + crypt(cipher, pretext, output); + } + catch (DataLengthException e) + { + fail(test, "Init did not reset data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test, "Reset did not reset data."); + } + + // Check reset resets AD + cipher.processAADBytes(pretext, 0, 100); + cipher.reset(); + + try + { + crypt(cipher, pretext, output); + } + catch (DataLengthException e) + { + fail(test, "Init did not reset data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test, "Reset did not reset additional data."); + } + } + + private static void crypt(AEADBlockCipher cipher, byte[] plaintext, byte[] output) + throws InvalidCipherTextException + { + int len = cipher.processBytes(plaintext, 0, plaintext.length, output, 0); + cipher.doFinal(output, len); + } + + public static void testOutputSizes(Test test, AEADBlockCipher cipher, AEADParameters params) + throws IllegalStateException, + InvalidCipherTextException + { + int maxPlaintext = cipher.getUnderlyingCipher().getBlockSize() * 10; + byte[] plaintext = new byte[maxPlaintext]; + byte[] ciphertext = new byte[maxPlaintext * 2]; + + // Check output size calculations for truncated ciphertext lengths + cipher.init(true, params); + cipher.doFinal(ciphertext, 0); + int macLength = cipher.getMac().length; + + cipher.init(false, params); + for (int i = 0; i < macLength; i++) + { + cipher.reset(); + if (cipher.getUpdateOutputSize(i) != 0) + { + fail(test, "AE cipher should not produce update output with ciphertext length <= macSize"); + } + if (cipher.getOutputSize(i) != 0) + { + fail(test, "AE cipher should not produce output with ciphertext length <= macSize"); + } + } + + for (int i = 0; i < plaintext.length; i++) + { + cipher.init(true, params); + int expectedCTUpdateSize = cipher.getUpdateOutputSize(i); + int expectedCTOutputSize = cipher.getOutputSize(i); + + if (expectedCTUpdateSize < 0) + { + fail(test, "Encryption update output size should not be < 0 for size " + i); + } + + if (expectedCTOutputSize < 0) + { + fail(test, "Encryption update output size should not be < 0 for size " + i); + } + + int actualCTSize = cipher.processBytes(plaintext, 0, i, ciphertext, 0); + + if (expectedCTUpdateSize != actualCTSize) + { + fail(test, "Encryption update output size did not match calculated for plaintext length " + i, + String.valueOf(expectedCTUpdateSize), String.valueOf(actualCTSize)); + } + + actualCTSize += cipher.doFinal(ciphertext, actualCTSize); + + if (expectedCTOutputSize != actualCTSize) + { + fail(test, "Encryption actual final output size did not match calculated for plaintext length " + i, + String.valueOf(expectedCTOutputSize), String.valueOf(actualCTSize)); + } + + cipher.init(false, params); + int expectedPTUpdateSize = cipher.getUpdateOutputSize(actualCTSize); + int expectedPTOutputSize = cipher.getOutputSize(actualCTSize); + + if (expectedPTOutputSize != i) + { + fail(test, "Decryption update output size did not original plaintext length " + i, + String.valueOf(expectedPTUpdateSize), String.valueOf(i)); + } + + int actualPTSize = cipher.processBytes(ciphertext, 0, actualCTSize, plaintext, 0); + + if (expectedPTUpdateSize != actualPTSize) + { + fail(test, "Decryption update output size did not match calculated for plaintext length " + i, + String.valueOf(expectedPTUpdateSize), String.valueOf(actualPTSize)); + } + + actualPTSize += cipher.doFinal(plaintext, actualPTSize); + + if (expectedPTOutputSize != actualPTSize) + { + fail(test, "Decryption update output size did not match calculated for plaintext length " + i, + String.valueOf(expectedPTOutputSize), String.valueOf(actualPTSize)); + } + + } + } + + public static void testBufferSizeChecks(Test test, AEADBlockCipher cipher, AEADParameters params) + throws IllegalStateException, + InvalidCipherTextException + { + int blockSize = cipher.getUnderlyingCipher().getBlockSize(); + int maxPlaintext = (blockSize * 10); + byte[] plaintext = new byte[maxPlaintext]; + + + cipher.init(true, params); + + int expectedUpdateOutputSize = cipher.getUpdateOutputSize(plaintext.length); + byte[] ciphertext = new byte[cipher.getOutputSize(plaintext.length)]; + + try + { + cipher.processBytes(new byte[maxPlaintext - 1], 0, maxPlaintext, new byte[expectedUpdateOutputSize], 0); + fail(test, "processBytes should validate input buffer length"); + } + catch (DataLengthException e) + { + // Expected + } + cipher.reset(); + + if (expectedUpdateOutputSize > 0) + { + int outputTrigger = 0; + // Process bytes until output would be produced + for(int i = 0; i < plaintext.length; i++) { + if (cipher.getUpdateOutputSize(1) != 0) + { + outputTrigger = i + 1; + break; + } + cipher.processByte(plaintext[i], ciphertext, 0); + } + if (outputTrigger == 0) + { + fail(test, "Failed to find output trigger size"); + } + try + { + cipher.processByte(plaintext[0], new byte[cipher.getUpdateOutputSize(1) - 1], 0); + fail(test, "Encrypt processByte should validate output buffer length"); + } + catch (OutputLengthException e) + { + // Expected + } + cipher.reset(); + + // Repeat checking with entire input at once + try + { + cipher.processBytes(plaintext, 0, outputTrigger, + new byte[cipher.getUpdateOutputSize(outputTrigger) - 1], 0); + fail(test, "Encrypt processBytes should validate output buffer length"); + } + catch (OutputLengthException e) + { + // Expected + } + cipher.reset(); + + } + + // Remember the actual ciphertext for later + int actualOutputSize = cipher.processBytes(plaintext, 0, plaintext.length, ciphertext, 0); + actualOutputSize += cipher.doFinal(ciphertext, actualOutputSize); + int macSize = cipher.getMac().length; + + cipher.reset(); + try + { + cipher.processBytes(plaintext, 0, plaintext.length, ciphertext, 0); + cipher.doFinal(new byte[cipher.getOutputSize(0) - 1], 0); + fail(test, "Encrypt doFinal should validate output buffer length"); + } + catch (OutputLengthException e) + { + // Expected + } + + // Decryption tests + + cipher.init(false, params); + expectedUpdateOutputSize = cipher.getUpdateOutputSize(actualOutputSize); + + if (expectedUpdateOutputSize > 0) + { + // Process bytes until output would be produced + int outputTrigger = 0; + for (int i = 0; i < plaintext.length; i++) + { + if (cipher.getUpdateOutputSize(1) != 0) + { + outputTrigger = i + 1; + break; + } + cipher.processByte(ciphertext[i], plaintext, 0); + } + if (outputTrigger == 0) + { + fail(test, "Failed to find output trigger size"); + } + + try + { + cipher.processByte(ciphertext[0], new byte[cipher.getUpdateOutputSize(1) - 1], 0); + fail(test, "Decrypt processByte should validate output buffer length"); + } + catch (OutputLengthException e) + { + // Expected + } + cipher.reset(); + + // Repeat test with processBytes + try + { + cipher.processBytes(ciphertext, 0, outputTrigger, + new byte[cipher.getUpdateOutputSize(outputTrigger) - 1], 0); + fail(test, "Decrypt processBytes should validate output buffer length"); + } + catch (OutputLengthException e) + { + // Expected + } + } + + cipher.reset(); + // Data less than mac length should fail before output length check + try + { + // Assumes AE cipher on decrypt can't return any data until macSize bytes are received + if (cipher.processBytes(ciphertext, 0, macSize - 1, plaintext, 0) != 0) + { + fail(test, "AE cipher unexpectedly produced output"); + } + cipher.doFinal(new byte[0], 0); + fail(test, "Decrypt doFinal should check ciphertext length"); + } + catch (InvalidCipherTextException e) + { + // Expected + } + + try + { + // Search through plaintext lengths until one is found that creates >= 1 buffered byte + // during decryption of ciphertext for doFinal to handle + for (int i = 2; i < plaintext.length; i++) + { + cipher.init(true, params); + int encrypted = cipher.processBytes(plaintext, 0, i, ciphertext, 0); + encrypted += cipher.doFinal(ciphertext, encrypted); + + cipher.init(false, params); + cipher.processBytes(ciphertext, 0, encrypted - 1, plaintext, 0); + if (cipher.processByte(ciphertext[encrypted - 1], plaintext, 0) == 0) + { + cipher.doFinal(new byte[cipher.getOutputSize(0) - 1], 0); + fail(test, "Decrypt doFinal should check output length"); + cipher.reset(); + + // Truncated Mac should be reported in preference to inability to output + // buffered plaintext byte + try + { + cipher.processBytes(ciphertext, 0, actualOutputSize - 1, plaintext, 0); + cipher.doFinal(new byte[cipher.getOutputSize(0) - 1], 0); + fail(test, "Decrypt doFinal should check ciphertext length"); + } + catch (InvalidCipherTextException e) + { + // Expected + } + cipher.reset(); + } + } + fail(test, "Decrypt doFinal test couldn't find a ciphertext length that buffered for doFinal"); + } + catch (OutputLengthException e) + { + // Expected + } + } + + static AEADParameters reuseKey(AEADParameters p) + { + return new AEADParameters(null, p.getMacSize(), p.getNonce(), p.getAssociatedText()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/AESFastTest.java b/core/src/test/java/org/spongycastle/crypto/test/AESFastTest.java new file mode 100644 index 00000000..6892ed77 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/AESFastTest.java @@ -0,0 +1,150 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Test vectors from the NIST standard tests and Brian Gladman's vector set + * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/"> + * http://fp.gladman.plus.com/cryptography_technology/rijndael/</a> + */ +public class AESFastTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new AESFastEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(1, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(2, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(3, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(4, new AESFastEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(5, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(6, new AESFastEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(7, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(8, new AESFastEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(9, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(10, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(11, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(12, new AESFastEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(13, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(14, new AESFastEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(15, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(16, new AESFastEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(17, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(18, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(19, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(20, new AESFastEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(21, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(22, new AESFastEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(23, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168") + }; + + private BlockCipher _engine = new AESFastEngine(); + + AESFastTest() + { + super(tests, new AESFastEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "AESFast"; + } + + public void performTest() + throws Exception + { + super.performTest(); + + byte[] keyBytes = new byte[16]; + + _engine.init(true, new KeyParameter(keyBytes)); + + // + // init tests + // + try + { + byte[] dudKey = new byte[6]; + + _engine.init(true, new KeyParameter(dudKey)); + + fail("failed key length check"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + byte[] iv = new byte[16]; + + _engine.init(true, new ParametersWithIV(null, iv)); + + fail("failed parameter check"); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + public static void main( + String[] args) + { + runTest(new AESFastTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/AESLightTest.java b/core/src/test/java/org/spongycastle/crypto/test/AESLightTest.java new file mode 100644 index 00000000..a3c4ca53 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/AESLightTest.java @@ -0,0 +1,150 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.engines.AESLightEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Test vectors from the NIST standard tests and Brian Gladman's vector set + * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/"> + * http://fp.gladman.plus.com/cryptography_technology/rijndael/</a> + */ +public class AESLightTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new AESLightEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(1, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(2, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(3, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(4, new AESLightEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(5, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(6, new AESLightEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(7, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(8, new AESLightEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(9, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(10, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(11, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(12, new AESLightEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(13, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(14, new AESLightEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(15, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(16, new AESLightEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(17, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(18, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(19, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(20, new AESLightEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(21, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(22, new AESLightEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(23, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168") + }; + + private BlockCipher _engine = new AESLightEngine(); + + AESLightTest() + { + super(tests, new AESLightEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "AESLight"; + } + + public void performTest() + throws Exception + { + super.performTest(); + + byte[] keyBytes = new byte[16]; + + _engine.init(true, new KeyParameter(keyBytes)); + + // + // init tests + // + try + { + byte[] dudKey = new byte[6]; + + _engine.init(true, new KeyParameter(dudKey)); + + fail("failed key length check"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + byte[] iv = new byte[16]; + + _engine.init(true, new ParametersWithIV(null, iv)); + + fail("failed parameter check"); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + public static void main( + String[] args) + { + runTest(new AESLightTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/AESTest.java b/core/src/test/java/org/spongycastle/crypto/test/AESTest.java new file mode 100644 index 00000000..243d9e8b --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/AESTest.java @@ -0,0 +1,442 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.AESEngine; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.modes.CFBBlockCipher; +import org.spongycastle.crypto.modes.OFBBlockCipher; +import org.spongycastle.crypto.modes.SICBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Test vectors from the NIST standard tests and Brian Gladman's vector set + * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/"> + * http://fp.gladman.plus.com/cryptography_technology/rijndael/</a> + */ +public class AESTest + extends CipherTest +{ + private static final byte[] tData = Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114F3F6752AE8D7831138F041560631B1145A01020304050607"); + private static final byte[] outCBC1 = Hex.decode("a444a9a4d46eb30cb7ed34d62873a89f8fdf2bf8a54e1aeadd06fd85c9cb46f021ee7cd4f418fa0bb72e9d07c70d5d20"); + private static final byte[] outCBC2 = Hex.decode("585681354f0e01a86b32f94ebb6a675045d923cf201263c2aaecca2b4de82da0edd74ca5efd654c688f8a58e61955b11"); + private static final byte[] outSIC1 = Hex.decode("82a1744e8ebbd053ca72362d5e570326e0b6fdaf824ab673fbf029042886b23c75129a015852913790f81f94447475a0"); + private static final byte[] outSIC2 = Hex.decode("146cbb581d9e12c3333dd9c736fbb93043c92019f78580da48f81f80b3f551d58ea836fed480fc6912fefa9c5c89cc24"); + private static final byte[] outCFB1 = Hex.decode("82a1744e8ebbd053ca72362d5e5703264b4182de3208c374b8ac4fa36af9c5e5f4f87d1e3b67963d06acf5eb13914c90"); + private static final byte[] outCFB2 = Hex.decode("146cbb581d9e12c3333dd9c736fbb9303c8a3eb5185e2809e9d3c28e25cc2d2b6f5c11ee28d6530f72c412b1438a816a"); + private static final byte[] outOFB1 = Hex.decode("82a1744e8ebbd053ca72362d5e5703261ebf1fdbec05e57b3465b583132f84b43bf95b2c89040ad1677b22d42db69a7a"); + private static final byte[] outOFB2 = Hex.decode("146cbb581d9e12c3333dd9c736fbb9309ea4c2a7696c84959a2dada49f2f1c5905db1f0cec3a31acbc4701e74ab05e1f"); + + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new AESEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(1, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(2, 10000, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(3, 10000, new AESEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(4, new AESEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(5, 10000, new AESEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(6, new AESEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(7, 10000, new AESEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(8, new AESEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(9, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(10, 10000, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(11, 10000, new AESEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(12, new AESEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(13, 10000, new AESEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(14, new AESEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(15, 10000, new AESEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(16, new AESEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(17, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(18, 10000, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(19, 10000, new AESEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(20, new AESEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(21, 10000, new AESEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(22, new AESEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(23, 10000, new AESEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168") + }; + + private BlockCipher _engine = new AESEngine(); + + public AESTest() + { + super(tests, new AESEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "AES"; + } + + private void testNullSIC() + throws InvalidCipherTextException + { + BufferedBlockCipher b = new BufferedBlockCipher(new SICBlockCipher(new AESEngine())); + KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")); + + b.init(true, new ParametersWithIV(kp, new byte[16])); + + byte[] out = new byte[b.getOutputSize(tData.length)]; + + int len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outSIC1, out)) + { + fail("no match on first nullSIC check"); + } + + b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f"))); + + len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outSIC2, out)) + { + fail("no match on second nullSIC check"); + } + } + + private void testNullCBC() + throws InvalidCipherTextException + { + BufferedBlockCipher b = new BufferedBlockCipher(new CBCBlockCipher(new AESEngine())); + KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")); + + b.init(true, new ParametersWithIV(kp, new byte[16])); + + byte[] out = new byte[b.getOutputSize(tData.length)]; + + int len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outCBC1, out)) + { + fail("no match on first nullCBC check"); + } + + b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f"))); + + len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outCBC2, out)) + { + fail("no match on second nullCBC check"); + } + } + + private void testNullOFB() + throws InvalidCipherTextException + { + BufferedBlockCipher b = new BufferedBlockCipher(new OFBBlockCipher(new AESEngine(), 128)); + KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")); + + b.init(true, new ParametersWithIV(kp, new byte[16])); + + byte[] out = new byte[b.getOutputSize(tData.length)]; + + int len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outOFB1, out)) + { + fail("no match on first nullOFB check"); + } + + b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f"))); + + len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outOFB2, out)) + { + fail("no match on second nullOFB check"); + } + } + + private void testNullCFB() + throws InvalidCipherTextException + { + BufferedBlockCipher b = new BufferedBlockCipher(new CFBBlockCipher(new AESEngine(), 128)); + KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")); + + b.init(true, new ParametersWithIV(kp, new byte[16])); + + byte[] out = new byte[b.getOutputSize(tData.length)]; + + int len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outCFB1, out)) + { + fail("no match on first nullCFB check"); + } + + b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f"))); + + len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outCFB2, out)) + { + fail("no match on second nullCFB check"); + } + } + + private boolean areEqual(byte[] a, int aOff, byte[] b, int bOff) + { + for (int i = bOff; i != b.length; i++) + { + if (a[aOff + i - bOff] != b[i]) + { + return false; + } + } + + return true; + } + + private void skipTest() + { + CipherParameters params = new ParametersWithIV(new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), Hex.decode("00000000000000000000000000000000")); + SICBlockCipher engine = new SICBlockCipher(new AESEngine()); + + engine.init(true, params); + + SecureRandom rand = new SecureRandom(); + byte[] plain = new byte[5000]; + byte[] cipher = new byte[5000]; + + rand.nextBytes(plain); + engine.processBytes(plain, 0, plain.length, cipher, 0); + + byte[] fragment = new byte[20]; + + engine.init(true, params); + + engine.skip(10); + + if (engine.getPosition() != 10) + { + fail("skip position incorrect - 10 got " + engine.getPosition()); + } + + engine.processBytes(plain, 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 10, fragment, 0)) + { + fail("skip forward 10 failed"); + } + + engine.skip(1000); + + if (engine.getPosition() != 1010 + fragment.length) + { + fail("skip position incorrect - " + (1010 + fragment.length) + " got " + engine.getPosition()); + } + + engine.processBytes(plain, 1010 + fragment.length, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + fragment.length, fragment, 0)) + { + fail("skip forward 1000 failed"); + } + + engine.skip(-10); + + if (engine.getPosition() != 1010 + 2 * fragment.length - 10) + { + fail("skip position incorrect - " + (1010 + 2 * fragment.length - 10) + " got " + engine.getPosition()); + } + + engine.processBytes(plain, 1010 + 2 * fragment.length - 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + 2 * fragment.length - 10, fragment, 0)) + { + fail("skip back 10 failed"); + } + + engine.skip(-1000); + + if (engine.getPosition() != 60) + { + fail("skip position incorrect - " + 60 + " got " + engine.getPosition()); + } + + engine.processBytes(plain, 60, fragment.length, fragment, 0); + + if (!areEqual(cipher, 60, fragment, 0)) + { + fail("skip back 1000 failed"); + } + + long pos = engine.seekTo(1010); + + if (pos != 1010) + { + fail("position incorrect - " + 1010 + " got " + pos); + } + + engine.processBytes(plain, 1010, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010, fragment, 0)) + { + fail("seek to 1010 failed"); + } + + engine.reset(); + + for (int i = 0; i != 1000; i++) + { + engine.skip(i); + + if (engine.getPosition() != i) + { + fail("skip forward at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip forward i failed: " + i); + } + + if (engine.getPosition() != i + fragment.length) + { + fail("cipher at wrong position: " + engine.getPosition() + " [" + i + "]"); + } + + engine.skip(-fragment.length); + + if (engine.getPosition() != i) + { + fail("skip back at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip back i failed: " + i); + } + + engine.reset(); + } + } + + public void performTest() + throws Exception + { + super.performTest(); + + byte[] keyBytes = new byte[16]; + + _engine.init(true, new KeyParameter(keyBytes)); + + // + // init tests + // + try + { + byte[] dudKey = new byte[6]; + + _engine.init(true, new KeyParameter(dudKey)); + + fail("failed key length check"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + byte[] iv = new byte[16]; + + _engine.init(true, new ParametersWithIV(null, iv)); + + fail("failed parameter check"); + } + catch (IllegalArgumentException e) + { + // expected + } + + testNullCBC(); + testNullSIC(); + testNullOFB(); + testNullCFB(); + + skipTest(); + } + + public static void main( + String[] args) + { + runTest(new AESTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/AESVectorFileTest.java b/core/src/test/java/org/spongycastle/crypto/test/AESVectorFileTest.java new file mode 100644 index 00000000..504b4bd4 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/AESVectorFileTest.java @@ -0,0 +1,258 @@ +package org.spongycastle.crypto.test; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.engines.AESEngine; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.engines.AESLightEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * Test vectors from the NIST standard tests and Brian Gladman's vector set + * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/"> + * http://fp.gladman.plus.com/cryptography_technology/rijndael/</a> + */ +public class AESVectorFileTest + implements Test +{ + + private int countOfTests = 0; + private int testNum = 0; + + protected BlockCipher createNewEngineForTest() + { + return new AESEngine(); + } + + private Test[] readTestVectors(InputStream inStream) + { + // initialize key, plaintext, ciphertext = null + // read until find BLOCKSIZE= + // return if not 128 + // read KEYSIZE= or ignore + // loop + // read a line + // if starts with BLOCKSIZE= + // parse the rest. return if not 128 + // if starts with KEY= + // parse the rest and set KEY + // if starts with PT= + // parse the rest and set plaintext + // if starts with CT= + // parse the rest and set ciphertext + // if starts with TEST= or end of file + // if key, plaintext, ciphertext are all not null + // save away their values as the next test + // until end of file + List tests = new ArrayList(); + String key = null; + String plaintext = null; + String ciphertext = null; + + BufferedReader in = new BufferedReader(new InputStreamReader(inStream)); + + try + { + String line = in.readLine(); + + while (line != null) + { + line = line.trim().toLowerCase(); + if (line.startsWith("blocksize=")) + { + int i = 0; + try + { + i = Integer.parseInt(line.substring(10).trim()); + } + catch (Exception e) + { + } + if (i != 128) + { + return null; + } + } + else if (line.startsWith("keysize=")) + { + int i = 0; + try + { + i = Integer.parseInt(line.substring(10).trim()); + } + catch (Exception e) + { + } + if ((i != 128) && (i != 192) && (i != 256)) + { + return null; + } + } + else if (line.startsWith("key=")) + { + key = line.substring(4).trim(); + } + else if (line.startsWith("pt=")) + { + plaintext = line.substring(3).trim(); + } + else if (line.startsWith("ct=")) + { + ciphertext = line.substring(3).trim(); + } + else if (line.startsWith("test=")) + { + if ((key != null) && (plaintext != null) + && (ciphertext != null)) + { + tests.add(new BlockCipherVectorTest(testNum++, + createNewEngineForTest(), new KeyParameter(Hex + .decode(key)), plaintext, ciphertext)); + } + } + + line = in.readLine(); + } + try + { + in.close(); + } + catch (IOException e) + { + } + } + catch (IOException e) + { + } + if ((key != null) && (plaintext != null) && (ciphertext != null)) + { + tests.add(new BlockCipherVectorTest(testNum++, + createNewEngineForTest(), + new KeyParameter(Hex.decode(key)), plaintext, ciphertext)); + } + return (Test[])(tests.toArray(new Test[tests.size()])); + } + + public String getName() + { + return "AES"; + } + + private TestResult performTestsFromZipFile(File zfile) + { + try + { + ZipFile inZip = new ZipFile(zfile); + for (Enumeration files = inZip.entries(); files.hasMoreElements();) + { + Test[] tests = null; + try + { + tests = readTestVectors(inZip + .getInputStream((ZipEntry)(files.nextElement()))); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": threw " + + e); + } + if (tests != null) + { + for (int i = 0; i != tests.length; i++) + { + TestResult res = tests[i].perform(); + countOfTests++; + + if (!res.isSuccessful()) + { + return res; + } + } + } + } + inZip.close(); + return new SimpleTestResult(true, getName() + ": Okay"); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": threw " + e); + } + } + + private static final String[] zipFileNames = { "rijn.tv.ecbnk.zip", + "rijn.tv.ecbnt.zip", "rijn.tv.ecbvk.zip", "rijn.tv.ecbvt.zip" }; + + public TestResult perform() + { + countOfTests = 0; + for (int i = 0; i < zipFileNames.length; i++) + { + File inf = new File(zipFileNames[i]); + TestResult res = performTestsFromZipFile(inf); + if (!res.isSuccessful()) + { + return res; + } + } + return new SimpleTestResult(true, getName() + ": " + countOfTests + + " performed Okay"); + } + + public static void main(String[] args) + { + AESVectorFileTest test = new AESVectorFileTest(); + TestResult result = test.perform(); + System.out.println(result); + + test = new AESLightVectorFileTest(); + result = test.perform(); + System.out.println(result); + + test = new AESFastVectorFileTest(); + result = test.perform(); + System.out.println(result); + + } + + private static class AESLightVectorFileTest extends AESVectorFileTest + { + protected BlockCipher createNewEngineForTest() + { + return new AESLightEngine(); + } + + public String getName() + { + return "AESLight"; + } + + } + + private static class AESFastVectorFileTest extends AESVectorFileTest + { + protected BlockCipher createNewEngineForTest() + { + return new AESFastEngine(); + } + + public String getName() + { + return "AESFast"; + } + + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/AESWrapPadTest.java b/core/src/test/java/org/spongycastle/crypto/test/AESWrapPadTest.java new file mode 100644 index 00000000..992c4468 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/AESWrapPadTest.java @@ -0,0 +1,146 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.Wrapper; +import org.spongycastle.crypto.engines.AESWrapPadEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * This is a test harness I use because I cannot modify the BC test harness without + * invalidating the signature on their signed provider library. The code here is not + * high quality but it does test the RFC vectors as well as randomly generated values. + * The RFC test vectors are tested by making sure both the ciphertext and decrypted + * values match the expected values whereas the random values are just checked to make + * sure that: + * <p>unwrap(wrap(random_value, random_kek), random_kek) == random_value.</p> + */ + +public class AESWrapPadTest + extends SimpleTest +{ + + private final int numOfRandomIterations = 100; + + public AESWrapPadTest() + { + + } + + private void wrapAndUnwrap(byte[] kek, byte[] key, byte[] expected) + throws Exception + { + Wrapper wrapper = new AESWrapPadEngine(); + + wrapper.init(true, new KeyParameter(kek)); + + byte[] cipherText = wrapper.wrap(key, 0, key.length); + if (!areEqual(cipherText, expected)) + { + fail("Wrapped value does not match expected."); + } + wrapper.init(false, new KeyParameter(kek)); + byte[] plainText = wrapper.unwrap(cipherText, 0, cipherText.length); + + if (!areEqual(key, plainText)) + { + fail("Unwrapped value does not match original."); + } + } + + private void wrapAndUnwrap(byte[] kek, byte[] key) + throws Exception + { + Wrapper wrapper = new AESWrapPadEngine(); + + wrapper.init(true, new KeyParameter(kek)); + + byte[] cipherText = wrapper.wrap(key, 0, key.length); + + wrapper.init(false, new KeyParameter(kek)); + byte[] plainText = wrapper.unwrap(cipherText, 0, cipherText.length); + + if (!areEqual(key, plainText)) + { + fail("Unwrapped value does not match original."); + } + } + + public String getName() + { + return "AESWrapPad"; + } + + public void performTest() + throws Exception + { + // test RFC 5649 test vectors + byte[] kek = Hex.decode("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"); + byte[] key = Hex.decode("c37b7e6492584340bed12207808941155068f738"); + byte[] wrap = Hex.decode("138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a"); + + wrapAndUnwrap(kek, key, wrap); + + wrap = Hex.decode("afbeb0f07dfbf5419200f2ccb50bb24f"); + key = Hex.decode("466f7250617369"); + wrapAndUnwrap(kek, key, wrap); + + + // + // offset test + // + Wrapper wrapper = new AESWrapPadEngine(); + + byte[] pText = new byte[5 + key.length]; + byte[] cText; + + System.arraycopy(key, 0, pText, 5, key.length); + + wrapper.init(true, new KeyParameter(kek)); + + cText = wrapper.wrap(pText, 5, key.length); + if (!Arrays.areEqual(cText, wrap)) + { + fail("failed offset wrap test expected " + new String(Hex.encode(wrap)) + " got " + new String(Hex.encode(cText))); + } + + wrapper.init(false, new KeyParameter(kek)); + + cText = new byte[6 + wrap.length]; + System.arraycopy(wrap, 0, cText, 6, wrap.length); + + pText = wrapper.unwrap(cText, 6, wrap.length); + if (!Arrays.areEqual(pText, key)) + { + fail("failed offset unwrap test expected " + new String(Hex.encode(key)) + " got " + new String(Hex.encode(pText))); + } + + // test random values + SecureRandom rnd = new SecureRandom(); + for (int i = 0; i < numOfRandomIterations; i++) + { + int kekLength = 128; + boolean shouldIncrease = (rnd.nextInt() & 0x01) != 0; + if (shouldIncrease) + { + kekLength = 256; + } + kek = new byte[kekLength / 8]; + rnd.nextBytes(kek); + int keyToWrapSize = rnd.nextInt(256 / 8 - 8) + 8; + byte[] keyToWrap = new byte[keyToWrapSize]; + rnd.nextBytes(keyToWrap); + wrapAndUnwrap(kek, keyToWrap); + } + } + + public static void main( + String[] args) + { + runTest(new AESWrapPadTest()); + } +} + diff --git a/core/src/test/java/org/spongycastle/crypto/test/AESWrapTest.java b/core/src/test/java/org/spongycastle/crypto/test/AESWrapTest.java new file mode 100644 index 00000000..38f4af70 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/AESWrapTest.java @@ -0,0 +1,238 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.Wrapper; +import org.spongycastle.crypto.engines.AESWrapEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * Wrap Test + */ +public class AESWrapTest + implements Test +{ + public String getName() + { + return "AESWrap"; + } + + private TestResult wrapTest( + int id, + byte[] kek, + byte[] in, + byte[] out) + { + Wrapper wrapper = new AESWrapEngine(); + + wrapper.init(true, new KeyParameter(kek)); + + try + { + byte[] cText = wrapper.wrap(in, 0, in.length); + if (!Arrays.areEqual(cText, out)) + { + return new SimpleTestResult(false, getName() + ": failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": failed wrap test exception " + e.toString()); + } + + wrapper.init(false, new KeyParameter(kek)); + + try + { + byte[] pText = wrapper.unwrap(out, 0, out.length); + if (!Arrays.areEqual(pText, in)) + { + return new SimpleTestResult(false, getName() + ": failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText))); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": failed unwrap test exception.", e); + } + + // + // offset test + // + byte[] pText = new byte[5 + in.length]; + byte[] cText; + + System.arraycopy(in, 0, pText, 5, in.length); + + wrapper.init(true, new KeyParameter(kek)); + + try + { + cText = wrapper.wrap(pText, 5, in.length); + if (!Arrays.areEqual(cText, out)) + { + return new SimpleTestResult(false, getName() + ": failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": failed wrap test exception " + e.toString()); + } + + wrapper.init(false, new KeyParameter(kek)); + + cText = new byte[6 + out.length]; + System.arraycopy(out, 0, cText, 6, out.length); + + try + { + pText = wrapper.unwrap(cText, 6, out.length); + if (!Arrays.areEqual(pText, in)) + { + return new SimpleTestResult(false, getName() + ": failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText))); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": failed unwrap test exception.", e); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public TestResult perform() + { + byte[] kek1 = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] in1 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out1 = Hex.decode("1fa68b0a8112b447aef34bd8fb5a7b829d3e862371d2cfe5"); + TestResult result = wrapTest(1, kek1, in1, out1); + + if (!result.isSuccessful()) + { + return result; + } + + byte[] kek2 = Hex.decode("000102030405060708090a0b0c0d0e0f1011121314151617"); + byte[] in2 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out2 = Hex.decode("96778b25ae6ca435f92b5b97c050aed2468ab8a17ad84e5d"); + result = wrapTest(2, kek2, in2, out2); + if (!result.isSuccessful()) + { + return result; + } + + byte[] kek3 = Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + byte[] in3 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out3 = Hex.decode("64e8c3f9ce0f5ba263e9777905818a2a93c8191e7d6e8ae7"); + result = wrapTest(3, kek3, in3, out3); + if (!result.isSuccessful()) + { + return result; + } + + byte[] kek4 = Hex.decode("000102030405060708090a0b0c0d0e0f1011121314151617"); + byte[] in4 = Hex.decode("00112233445566778899aabbccddeeff0001020304050607"); + byte[] out4 = Hex.decode("031d33264e15d33268f24ec260743edce1c6c7ddee725a936ba814915c6762d2"); + result = wrapTest(4, kek4, in4, out4); + if (!result.isSuccessful()) + { + return result; + } + + byte[] kek5 = Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + byte[] in5 = Hex.decode("00112233445566778899aabbccddeeff0001020304050607"); + byte[] out5 = Hex.decode("a8f9bc1612c68b3ff6e6f4fbe30e71e4769c8b80a32cb8958cd5d17d6b254da1"); + result = wrapTest(5, kek5, in5, out5); + if (!result.isSuccessful()) + { + return result; + } + + byte[] kek6 = Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + byte[] in6 = Hex.decode("00112233445566778899aabbccddeeff000102030405060708090a0b0c0d0e0f"); + byte[] out6 = Hex.decode("28c9f404c4b810f4cbccb35cfb87f8263f5786e2d80ed326cbc7f0e71a99f43bfb988b9b7a02dd21"); + result = wrapTest(6, kek6, in6, out6); + if (!result.isSuccessful()) + { + return result; + } + + Wrapper wrapper = new AESWrapEngine(); + KeyParameter key = new KeyParameter(new byte[16]); + byte[] buf = new byte[16]; + + try + { + wrapper.init(true, key); + + wrapper.unwrap(buf, 0, buf.length); + + return new SimpleTestResult(false, getName() + ": failed unwrap state test."); + } + catch (IllegalStateException e) + { + // expected + } + catch (InvalidCipherTextException e) + { + return new SimpleTestResult(false, getName() + ": unexpected exception: " + e, e); + } + + try + { + wrapper.init(false, key); + + wrapper.wrap(buf, 0, buf.length); + + return new SimpleTestResult(false, getName() + ": failed unwrap state test."); + } + catch (IllegalStateException e) + { + // expected + } + + // + // short test + // + try + { + wrapper.init(false, key); + + wrapper.unwrap(buf, 0, buf.length / 2); + + return new SimpleTestResult(false, getName() + ": failed unwrap short test."); + } + catch (InvalidCipherTextException e) + { + // expected + } + + try + { + wrapper.init(true, key); + + wrapper.wrap(buf, 0, 15); + + return new SimpleTestResult(false, getName() + ": failed wrap length test."); + } + catch (DataLengthException e) + { + // expected + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + AESWrapTest test = new AESWrapTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/AllTests.java b/core/src/test/java/org/spongycastle/crypto/test/AllTests.java new file mode 100644 index 00000000..edc7b1b2 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/AllTests.java @@ -0,0 +1,41 @@ +package org.spongycastle.crypto.test; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.spongycastle.util.test.SimpleTestResult; + +public class AllTests + extends TestCase +{ + public void testCrypto() + { + org.spongycastle.util.test.Test[] tests = RegressionTest.tests; + + for (int i = 0; i != tests.length; i++) + { + SimpleTestResult result = (SimpleTestResult)tests[i].perform(); + + if (!result.isSuccessful()) + { + fail(result.toString()); + } + } + } + + public static void main (String[] args) + { + junit.textui.TestRunner.run(suite()); + } + + public static Test suite() + { + TestSuite suite = new TestSuite("Lightweight Crypto Tests"); + + suite.addTestSuite(AllTests.class); + suite.addTestSuite(GCMReorderTest.class); + + return suite; + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/BlockCipherMonteCarloTest.java b/core/src/test/java/org/spongycastle/crypto/test/BlockCipherMonteCarloTest.java new file mode 100644 index 00000000..0b08d461 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/BlockCipherMonteCarloTest.java @@ -0,0 +1,82 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * a basic test that takes a cipher, key parameter, and an input + * and output string. This test wraps the engine in a buffered block + * cipher with padding disabled. + */ +public class BlockCipherMonteCarloTest + extends SimpleTest +{ + int id; + int iterations; + BlockCipher engine; + CipherParameters param; + byte[] input; + byte[] output; + + public BlockCipherMonteCarloTest( + int id, + int iterations, + BlockCipher engine, + CipherParameters param, + String input, + String output) + { + this.id = id; + this.iterations = iterations; + this.engine = engine; + this.param = param; + this.input = Hex.decode(input); + this.output = Hex.decode(output); + } + + public String getName() + { + return engine.getAlgorithmName() + " Monte Carlo Test " + id; + } + + public void performTest() + throws Exception + { + BufferedBlockCipher cipher = new BufferedBlockCipher(engine); + + cipher.init(true, param); + + byte[] out = new byte[input.length]; + + System.arraycopy(input, 0, out, 0, out.length); + + for (int i = 0; i != iterations; i++) + { + int len1 = cipher.processBytes(out, 0, out.length, out, 0); + + cipher.doFinal(out, len1); + } + + if (!areEqual(out, output)) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + cipher.init(false, param); + + for (int i = 0; i != iterations; i++) + { + int len1 = cipher.processBytes(out, 0, out.length, out, 0); + + cipher.doFinal(out, len1); + } + + if (!areEqual(input, out)) + { + fail("failed reversal"); + } + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/BlockCipherResetTest.java b/core/src/test/java/org/spongycastle/crypto/test/BlockCipherResetTest.java new file mode 100644 index 00000000..9e95cfd8 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/BlockCipherResetTest.java @@ -0,0 +1,206 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.AESEngine; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.engines.AESLightEngine; +import org.spongycastle.crypto.engines.BlowfishEngine; +import org.spongycastle.crypto.engines.CAST5Engine; +import org.spongycastle.crypto.engines.CAST6Engine; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.engines.DESedeEngine; +import org.spongycastle.crypto.engines.NoekeonEngine; +import org.spongycastle.crypto.engines.RC6Engine; +import org.spongycastle.crypto.engines.SEEDEngine; +import org.spongycastle.crypto.engines.SerpentEngine; +import org.spongycastle.crypto.engines.TEAEngine; +import org.spongycastle.crypto.engines.TwofishEngine; +import org.spongycastle.crypto.engines.XTEAEngine; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.modes.CFBBlockCipher; +import org.spongycastle.crypto.modes.GOFBBlockCipher; +import org.spongycastle.crypto.modes.OFBBlockCipher; +import org.spongycastle.crypto.modes.OpenPGPCFBBlockCipher; +import org.spongycastle.crypto.modes.PGPCFBBlockCipher; +import org.spongycastle.crypto.modes.SICBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Test whether block ciphers implement reset contract on init, encrypt/decrypt and reset. + */ +public class BlockCipherResetTest + extends SimpleTest +{ + + public String getName() + { + return "Block Cipher Reset"; + } + + public void performTest() + throws Exception + { + // 128 bit block ciphers + testReset("AESFastEngine", new AESFastEngine(), new AESFastEngine(), new KeyParameter(new byte[16])); + testReset("AESEngine", new AESEngine(), new AESEngine(), new KeyParameter(new byte[16])); + testReset("AESLightEngine", new AESLightEngine(), new AESLightEngine(), new KeyParameter(new byte[16])); + testReset("Twofish", new TwofishEngine(), new TwofishEngine(), new KeyParameter(new byte[16])); + testReset("NoekeonEngine", new NoekeonEngine(), new NoekeonEngine(), new KeyParameter(new byte[16])); + testReset("SerpentEngine", new SerpentEngine(), new SerpentEngine(), new KeyParameter(new byte[16])); + testReset("SEEDEngine", new SEEDEngine(), new SEEDEngine(), new KeyParameter(new byte[16])); + testReset("CAST6Engine", new CAST6Engine(), new CAST6Engine(), new KeyParameter(new byte[16])); + testReset("RC6Engine", new RC6Engine(), new RC6Engine(), new KeyParameter(new byte[16])); + + // 64 bit block ciphers + testReset("DESEngine", new DESEngine(), new DESEngine(), new KeyParameter(new byte[8])); + testReset("BlowfishEngine", new BlowfishEngine(), new BlowfishEngine(), new KeyParameter(new byte[8])); + testReset("CAST5Engine", new CAST5Engine(), new CAST5Engine(), new KeyParameter(new byte[8])); + testReset("DESedeEngine", new DESedeEngine(), new DESedeEngine(), new KeyParameter(new byte[24])); + testReset("TEAEngine", new TEAEngine(), new TEAEngine(), new KeyParameter(new byte[16])); + testReset("XTEAEngine", new XTEAEngine(), new XTEAEngine(), new KeyParameter(new byte[16])); + + // primitive block cipher modes (don't reset on processBlock) + testModeReset("AES/CBC", new CBCBlockCipher(new AESEngine()), new CBCBlockCipher(new AESEngine()), + new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + testModeReset("AES/SIC", new SICBlockCipher(new AESEngine()), new SICBlockCipher(new AESEngine()), + new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + testModeReset("AES/CFB", new CFBBlockCipher(new AESEngine(), 128), new CFBBlockCipher(new AESEngine(), 128), + new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + testModeReset("AES/OFB", new OFBBlockCipher(new AESEngine(), 128), new OFBBlockCipher(new AESEngine(), 128), + new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + testModeReset("AES/GCTR", new GOFBBlockCipher(new DESEngine()), new GOFBBlockCipher(new DESEngine()), + new ParametersWithIV(new KeyParameter(new byte[8]), new byte[8])); + testModeReset("AES/OpenPGPCFB", new OpenPGPCFBBlockCipher(new AESEngine()), new OpenPGPCFBBlockCipher( + new AESEngine()), new KeyParameter(new byte[16])); + testModeReset("AES/PGPCFB", new PGPCFBBlockCipher(new AESEngine(), false), new PGPCFBBlockCipher( + new AESEngine(), false), new KeyParameter(new byte[16])); + + // PGPCFB with IV is broken (it's also not a PRP, so probably shouldn't be a BlockCipher) + // testModeReset("AES/PGPCFBwithIV", new PGPCFBBlockCipher(new AESEngine(), true), new + // PGPCFBBlockCipher( + // new AESEngine(), true), new ParametersWithIV(new KeyParameter(new byte[16]), new + // byte[16])); + // testModeReset("AES/PGPCFBwithIV_NoIV", new PGPCFBBlockCipher(new AESEngine(), true), new + // PGPCFBBlockCipher( + // new AESEngine(), true), new KeyParameter(new byte[16])); + + } + + private void testModeReset(String test, BlockCipher cipher1, BlockCipher cipher2, CipherParameters params) + throws InvalidCipherTextException + { + testReset(test, false, cipher1, cipher2, params); + } + + private void testReset(String test, BlockCipher cipher1, BlockCipher cipher2, CipherParameters params) + throws InvalidCipherTextException + { + testReset(test, true, cipher1, cipher2, params); + } + + private void testReset(String test, + boolean testCryptReset, + BlockCipher cipher1, + BlockCipher cipher2, + CipherParameters params) + throws InvalidCipherTextException + { + cipher1.init(true, params); + + byte[] plaintext = new byte[cipher1.getBlockSize()]; + byte[] ciphertext = new byte[(cipher1.getAlgorithmName().indexOf("PGPCFBwithIV")) > -1 ? 2 * cipher1.getBlockSize() + 2 + : cipher1.getBlockSize()]; + + // Establish baseline answer + crypt(cipher1, true, plaintext, ciphertext); + + // Test encryption resets + checkReset(test, testCryptReset, cipher1, params, true, plaintext, ciphertext); + + // Test decryption resets with fresh instance + cipher2.init(false, params); + checkReset(test, testCryptReset, cipher2, params, false, ciphertext, plaintext); + } + + private void checkReset(String test, + boolean testCryptReset, + BlockCipher cipher, + CipherParameters params, + boolean encrypt, + byte[] pretext, + byte[] posttext) + throws InvalidCipherTextException + { + // Do initial run + byte[] output = new byte[posttext.length]; + crypt(cipher, encrypt, pretext, output); + + // Check encrypt resets cipher + if (testCryptReset) + { + crypt(cipher, encrypt, pretext, output); + if (!Arrays.areEqual(output, posttext)) + { + fail(test + (encrypt ? " encrypt" : " decrypt") + " did not reset cipher."); + } + } + + // Check init resets data + cipher.processBlock(pretext, 0, output, 0); + cipher.init(encrypt, params); + + try + { + crypt(cipher, encrypt, pretext, output); + } + catch (DataLengthException e) + { + fail(test + " init did not reset data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test + " init did not reset data.", new String(Hex.encode(posttext)), new String(Hex.encode(output))); + } + + // Check reset resets data + cipher.processBlock(pretext, 0, output, 0); + cipher.reset(); + + try + { + crypt(cipher, encrypt, pretext, output); + } + catch (DataLengthException e) + { + fail(test + " reset did not reset data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test + " reset did not reset data."); + } + } + + private static void crypt(BlockCipher cipher1, boolean encrypt, byte[] plaintext, byte[] output) + throws InvalidCipherTextException + { + cipher1.processBlock(plaintext, 0, output, 0); + if ((cipher1.getAlgorithmName().indexOf("PGPCFBwithIV") > -1) && !encrypt) + { + // Process past IV in first block + cipher1.processBlock(plaintext, cipher1.getBlockSize(), output, 0); + } + } + + public static void main(String[] args) + { + runTest(new BlockCipherResetTest()); + } + +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/BlockCipherVectorTest.java b/core/src/test/java/org/spongycastle/crypto/test/BlockCipherVectorTest.java new file mode 100644 index 00000000..322a580d --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/BlockCipherVectorTest.java @@ -0,0 +1,71 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * a basic test that takes a cipher, key parameter, and an input + * and output string. This test wraps the engine in a buffered block + * cipher with padding disabled. + */ +public class BlockCipherVectorTest + extends SimpleTest +{ + int id; + BlockCipher engine; + CipherParameters param; + byte[] input; + byte[] output; + + public BlockCipherVectorTest( + int id, + BlockCipher engine, + CipherParameters param, + String input, + String output) + { + this.id = id; + this.engine = engine; + this.param = param; + this.input = Hex.decode(input); + this.output = Hex.decode(output); + } + + public String getName() + { + return engine.getAlgorithmName() + " Vector Test " + id; + } + + public void performTest() + throws Exception + { + BufferedBlockCipher cipher = new BufferedBlockCipher(engine); + + cipher.init(true, param); + + byte[] out = new byte[input.length]; + + int len1 = cipher.processBytes(input, 0, input.length, out, 0); + + cipher.doFinal(out, len1); + + if (!areEqual(out, output)) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + cipher.init(false, param); + + int len2 = cipher.processBytes(output, 0, output.length, out, 0); + + cipher.doFinal(out, len2); + + if (!areEqual(input, out)) + { + fail("failed reversal got " + new String(Hex.encode(out))); + } + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/BlowfishTest.java b/core/src/test/java/org/spongycastle/crypto/test/BlowfishTest.java new file mode 100644 index 00000000..57e38a3e --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/BlowfishTest.java @@ -0,0 +1,57 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.BlowfishEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * blowfish tester - vectors from http://www.counterpane.com/vectors.txt + */ +public class BlowfishTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new BlowfishEngine(), + new KeyParameter(Hex.decode("0000000000000000")), + "0000000000000000", "4EF997456198DD78"), + new BlockCipherVectorTest(1, new BlowfishEngine(), + new KeyParameter(Hex.decode("FFFFFFFFFFFFFFFF")), + "FFFFFFFFFFFFFFFF", "51866FD5B85ECB8A"), + new BlockCipherVectorTest(2, new BlowfishEngine(), + new KeyParameter(Hex.decode("3000000000000000")), + "1000000000000001", "7D856F9A613063F2"), + new BlockCipherVectorTest(3, new BlowfishEngine(), + new KeyParameter(Hex.decode("1111111111111111")), + "1111111111111111", "2466DD878B963C9D"), + new BlockCipherVectorTest(4, new BlowfishEngine(), + new KeyParameter(Hex.decode("0123456789ABCDEF")), + "1111111111111111", "61F9C3802281B096"), + new BlockCipherVectorTest(5, new BlowfishEngine(), + new KeyParameter(Hex.decode("FEDCBA9876543210")), + "0123456789ABCDEF", "0ACEAB0FC6A0A28D"), + new BlockCipherVectorTest(6, new BlowfishEngine(), + new KeyParameter(Hex.decode("7CA110454A1A6E57")), + "01A1D6D039776742", "59C68245EB05282B"), + new BlockCipherVectorTest(7, new BlowfishEngine(), + new KeyParameter(Hex.decode("0131D9619DC1376E")), + "5CD54CA83DEF57DA", "B1B8CC0B250F09A0"), + }; + + BlowfishTest() + { + super(tests, new BlowfishEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "Blowfish"; + } + + public static void main( + String[] args) + { + runTest(new BlowfishTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/CAST5Test.java b/core/src/test/java/org/spongycastle/crypto/test/CAST5Test.java new file mode 100644 index 00000000..339edd48 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/CAST5Test.java @@ -0,0 +1,44 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.CAST5Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * cast tester - vectors from http://www.ietf.org/rfc/rfc2144.txt + */ +public class CAST5Test + extends CipherTest +{ + static SimpleTest[] tests = { + new BlockCipherVectorTest(0, new CAST5Engine(), + new KeyParameter(Hex.decode("0123456712345678234567893456789A")), + "0123456789ABCDEF", + "238B4FE5847E44B2"), + new BlockCipherVectorTest(0, new CAST5Engine(), + new KeyParameter(Hex.decode("01234567123456782345")), + "0123456789ABCDEF", + "EB6A711A2C02271B"), + new BlockCipherVectorTest(0, new CAST5Engine(), + new KeyParameter(Hex.decode("0123456712")), + "0123456789ABCDEF", + "7Ac816d16E9B302E"), + }; + + CAST5Test() + { + super(tests, new CAST5Engine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "CAST5"; + } + + public static void main( + String[] args) + { + runTest(new CAST5Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/CAST6Test.java b/core/src/test/java/org/spongycastle/crypto/test/CAST6Test.java new file mode 100644 index 00000000..bd62fd2b --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/CAST6Test.java @@ -0,0 +1,44 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.CAST6Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * cast6 tester - vectors from http://www.ietf.org/rfc/rfc2612.txt + */ +public class CAST6Test + extends CipherTest +{ + static SimpleTest[] tests = { + new BlockCipherVectorTest(0, new CAST6Engine(), + new KeyParameter(Hex.decode("2342bb9efa38542c0af75647f29f615d")), + "00000000000000000000000000000000", + "c842a08972b43d20836c91d1b7530f6b"), + new BlockCipherVectorTest(0, new CAST6Engine(), + new KeyParameter(Hex.decode("2342bb9efa38542cbed0ac83940ac298bac77a7717942863")), + "00000000000000000000000000000000", + "1b386c0210dcadcbdd0e41aa08a7a7e8"), + new BlockCipherVectorTest(0, new CAST6Engine(), + new KeyParameter(Hex.decode("2342bb9efa38542cbed0ac83940ac2988d7c47ce264908461cc1b5137ae6b604")), + "00000000000000000000000000000000", + "4f6a2038286897b9c9870136553317fa") + }; + + CAST6Test() + { + super(tests, new CAST6Engine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "CAST6"; + } + + public static void main( + String[] args) + { + runTest(new CAST6Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/CCMTest.java b/core/src/test/java/org/spongycastle/crypto/test/CCMTest.java new file mode 100644 index 00000000..92c22cd1 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/CCMTest.java @@ -0,0 +1,305 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.AESEngine; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.modes.CCMBlockCipher; +import org.spongycastle.crypto.params.AEADParameters; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Strings; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * First four test vectors from + * NIST Special Publication 800-38C. + */ +public class CCMTest + extends SimpleTest +{ + private byte[] K1 = Hex.decode("404142434445464748494a4b4c4d4e4f"); + private byte[] N1 = Hex.decode("10111213141516"); + private byte[] A1 = Hex.decode("0001020304050607"); + private byte[] P1 = Hex.decode("20212223"); + private byte[] C1 = Hex.decode("7162015b4dac255d"); + private byte[] T1 = Hex.decode("6084341b"); + + private byte[] K2 = Hex.decode("404142434445464748494a4b4c4d4e4f"); + private byte[] N2 = Hex.decode("1011121314151617"); + private byte[] A2 = Hex.decode("000102030405060708090a0b0c0d0e0f"); + private byte[] P2 = Hex.decode("202122232425262728292a2b2c2d2e2f"); + private byte[] C2 = Hex.decode("d2a1f0e051ea5f62081a7792073d593d1fc64fbfaccd"); + private byte[] T2 = Hex.decode("7f479ffca464"); + + private byte[] K3 = Hex.decode("404142434445464748494a4b4c4d4e4f"); + private byte[] N3 = Hex.decode("101112131415161718191a1b"); + private byte[] A3 = Hex.decode("000102030405060708090a0b0c0d0e0f10111213"); + private byte[] P3 = Hex.decode("202122232425262728292a2b2c2d2e2f3031323334353637"); + private byte[] C3 = Hex.decode("e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5484392fbc1b09951"); + private byte[] T3 = Hex.decode("67c99240c7d51048"); + + private byte[] K4 = Hex.decode("404142434445464748494a4b4c4d4e4f"); + private byte[] N4 = Hex.decode("101112131415161718191a1b1c"); + private byte[] A4 = Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); + private byte[] P4 = Hex.decode("202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"); + private byte[] C4 = Hex.decode("69915dad1e84c6376a68c2967e4dab615ae0fd1faec44cc484828529463ccf72b4ac6bec93e8598e7f0dadbcea5b"); + private byte[] T4 = Hex.decode("f4dd5d0ee404617225ffe34fce91"); + + // + // long data vector + // + private byte[] C5 = Hex.decode("49b17d8d3ea4e6174a48e2b65e6d8b417ac0dd3f8ee46ce4a4a2a509661cef52528c1cd9805333a5cfd482fa3f095a3c2fdd1cc47771c5e55fddd60b5c8d6d3fa5c8dd79d08b16242b6642106e7c0c28bd1064b31e6d7c9800c8397dbc3fa8071e6a38278b386c18d65d39c6ad1ef9501a5c8f68d38eb6474799f3cc898b4b9b97e87f9c95ce5c51bc9d758f17119586663a5684e0a0daf6520ec572b87473eb141d10471e4799ded9e607655402eca5176bbf792ef39dd135ac8d710da8e9e854fd3b95c681023f36b5ebe2fb213d0b62dd6e9e3cfe190b792ccb20c53423b2dca128f861a61d306910e1af418839467e466f0ec361d2539eedd99d4724f1b51c07beb40e875a87491ec8b27cd1"); + private byte[] T5 = Hex.decode("5c768856796b627b13ec8641581b"); + + public void performTest() + throws Exception + { + CCMBlockCipher ccm = new CCMBlockCipher(new AESEngine()); + + checkVectors(0, ccm, K1, 32, N1, A1, P1, T1, C1); + checkVectors(1, ccm, K2, 48, N2, A2, P2, T2, C2); + checkVectors(2, ccm, K3, 64, N3, A3, P3, T3, C3); + + ivParamTest(0, ccm, K1, N1); + + // + // 4 has a reduced associated text which needs to be replicated + // + byte[] a4 = new byte[65536]; // 524288 / 8 + + for (int i = 0; i < a4.length; i += A4.length) + { + System.arraycopy(A4, 0, a4, i, A4.length); + } + + checkVectors(3, ccm, K4, 112, N4, a4, P4, T4, C4); + + // + // long data test + // + checkVectors(4, ccm, K4, 112, N4, A4, A4, T5, C5); + + // decryption with output specified, non-zero offset. + ccm.init(false, new AEADParameters(new KeyParameter(K2), 48, N2, A2)); + + byte[] inBuf = new byte[C2.length + 10]; + byte[] outBuf = new byte[ccm.getOutputSize(C2.length) + 10]; + + System.arraycopy(C2, 0, inBuf, 10, C2.length); + + int len = ccm.processPacket(inBuf, 10, C2.length, outBuf, 10); + byte[] out = ccm.processPacket(C2, 0, C2.length); + + if (len != out.length || !isEqual(out, outBuf, 10)) + { + fail("decryption output incorrect"); + } + + // encryption with output specified, non-zero offset. + ccm.init(true, new AEADParameters(new KeyParameter(K2), 48, N2, A2)); + + int inLen = len; + inBuf = outBuf; + outBuf = new byte[ccm.getOutputSize(inLen) + 10]; + + len = ccm.processPacket(inBuf, 10, inLen, outBuf, 10); + out = ccm.processPacket(inBuf, 10, inLen); + + if (len != out.length || !isEqual(out, outBuf, 10)) + { + fail("encryption output incorrect"); + } + + // + // exception tests + // + + try + { + ccm.init(false, new AEADParameters(new KeyParameter(K1), 32, N2, A2)); + + ccm.processPacket(C2, 0, C2.length); + + fail("invalid cipher text not picked up"); + } + catch (InvalidCipherTextException e) + { + // expected + } + + try + { + ccm = new CCMBlockCipher(new DESEngine()); + + fail("incorrect block size not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + ccm.init(false, new KeyParameter(K1)); + + fail("illegal argument not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + AEADTestUtil.testReset(this, new CCMBlockCipher(new AESEngine()), new CCMBlockCipher(new AESEngine()), new AEADParameters(new KeyParameter(K1), 32, N2)); + AEADTestUtil.testTampering(this, ccm, new AEADParameters(new KeyParameter(K1), 32, N2)); + AEADTestUtil.testOutputSizes(this, new CCMBlockCipher(new AESEngine()), new AEADParameters( + new KeyParameter(K1), 32, N2)); + AEADTestUtil.testBufferSizeChecks(this, new CCMBlockCipher(new AESEngine()), new AEADParameters( + new KeyParameter(K1), 32, N2)); + } + + private boolean isEqual(byte[] exp, byte[] other, int off) + { + for (int i = 0; i != exp.length; i++) + { + if (exp[i] != other[off + i]) + { + return false; + } + } + + return true; + } + + private void checkVectors( + int count, + CCMBlockCipher ccm, + byte[] k, + int macSize, + byte[] n, + byte[] a, + byte[] p, + byte[] t, + byte[] c) + throws InvalidCipherTextException + { + byte[] fa = new byte[a.length / 2]; + byte[] la = new byte[a.length - (a.length / 2)]; + System.arraycopy(a, 0, fa, 0, fa.length); + System.arraycopy(a, fa.length, la, 0, la.length); + + checkVectors(count, ccm, "all initial associated data", k, macSize, n, a, null, p, t, c); + checkVectors(count, ccm, "subsequent associated data", k, macSize, n, null, a, p, t, c); + checkVectors(count, ccm, "split associated data", k, macSize, n, fa, la, p, t, c); + checkVectors(count, ccm, "reuse key", null, macSize, n, fa, la, p, t, c); + } + + private void checkVectors( + int count, + CCMBlockCipher ccm, + String additionalDataType, + byte[] k, + int macSize, + byte[] n, + byte[] a, + byte[] sa, + byte[] p, + byte[] t, + byte[] c) + throws InvalidCipherTextException + { + KeyParameter keyParam = (k == null) ? null : new KeyParameter(k); + + ccm.init(true, new AEADParameters(keyParam, macSize, n, a)); + + byte[] enc = new byte[c.length]; + + if (sa != null) + { + ccm.processAADBytes(sa, 0, sa.length); + } + + int len = ccm.processBytes(p, 0, p.length, enc, 0); + + len += ccm.doFinal(enc, len); + + if (!areEqual(c, enc)) + { + fail("encrypted stream fails to match in test " + count + " with " + additionalDataType); + } + + ccm.init(false, new AEADParameters(keyParam, macSize, n, a)); + + byte[] tmp = new byte[enc.length]; + + if (sa != null) + { + ccm.processAADBytes(sa, 0, sa.length); + } + + len = ccm.processBytes(enc, 0, enc.length, tmp, 0); + + len += ccm.doFinal(tmp, len); + + byte[] dec = new byte[len]; + + System.arraycopy(tmp, 0, dec, 0, len); + + if (!areEqual(p, dec)) + { + fail("decrypted stream fails to match in test " + count + " with " + additionalDataType, + new String(Hex.encode(p)), new String(Hex.encode(dec))); + } + + if (!areEqual(t, ccm.getMac())) + { + fail("MAC fails to match in test " + count + " with " + additionalDataType); + } + } + + private void ivParamTest( + int count, + CCMBlockCipher ccm, + byte[] k, + byte[] n) + throws InvalidCipherTextException + { + byte[] p = Strings.toByteArray("hello world!!"); + + ccm.init(true, new ParametersWithIV(new KeyParameter(k), n)); + + byte[] enc = new byte[p.length + 8]; + + int len = ccm.processBytes(p, 0, p.length, enc, 0); + + len += ccm.doFinal(enc, len); + + ccm.init(false, new ParametersWithIV(new KeyParameter(k), n)); + + byte[] tmp = new byte[enc.length]; + + len = ccm.processBytes(enc, 0, enc.length, tmp, 0); + + len += ccm.doFinal(tmp, len); + + byte[] dec = new byte[len]; + + System.arraycopy(tmp, 0, dec, 0, len); + + if (!areEqual(p, dec)) + { + fail("decrypted stream fails to match in test " + count); + } + } + + public String getName() + { + return "CCM"; + } + + public static void main( + String[] args) + { + runTest(new CCMTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/CMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/CMacTest.java new file mode 100644 index 00000000..a55ad1d2 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/CMacTest.java @@ -0,0 +1,321 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.engines.AESEngine; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.macs.CMac; +import org.spongycastle.crypto.macs.CMacWithIV; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * CMAC tester - <a href="http://www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/tv/omac1-tv.txt">Official Test Vectors</a>. + */ +public class CMacTest + extends SimpleTest +{ + private static final byte[] keyBytes128 = Hex.decode("2b7e151628aed2a6abf7158809cf4f3c"); + private static final byte[] keyBytes192 = Hex.decode( + "8e73b0f7da0e6452c810f32b809079e5" + + "62f8ead2522c6b7b"); + private static final byte[] keyBytes256 = Hex.decode( + "603deb1015ca71be2b73aef0857d7781" + + "1f352c073b6108d72d9810a30914dff4"); + + private static final byte[] input0 = Hex.decode(""); + private static final byte[] input16 = Hex.decode("6bc1bee22e409f96e93d7e117393172a"); + private static final byte[] input40 = Hex.decode( + "6bc1bee22e409f96e93d7e117393172a" + + "ae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411"); + private static final byte[] input64 = Hex.decode( + "6bc1bee22e409f96e93d7e117393172a" + + "ae2d8a571e03ac9c9eb76fac45af8e51" + + "30c81c46a35ce411e5fbc1191a0a52ef" + + "f69f2445df4f9b17ad2b417be66c3710"); + + private static final byte[] output_k128_m0 = Hex.decode("bb1d6929e95937287fa37d129b756746"); + private static final byte[] output_k128_m16 = Hex.decode("070a16b46b4d4144f79bdd9dd04a287c"); + private static final byte[] output_k128_m40 = Hex.decode("dfa66747de9ae63030ca32611497c827"); + private static final byte[] output_k128_m64 = Hex.decode("51f0bebf7e3b9d92fc49741779363cfe"); + + private static final byte[] output_k192_m0 = Hex.decode("d17ddf46adaacde531cac483de7a9367"); + private static final byte[] output_k192_m16 = Hex.decode("9e99a7bf31e710900662f65e617c5184"); + private static final byte[] output_k192_m40 = Hex.decode("8a1de5be2eb31aad089a82e6ee908b0e"); + private static final byte[] output_k192_m64 = Hex.decode("a1d5df0eed790f794d77589659f39a11"); + + private static final byte[] output_k256_m0 = Hex.decode("028962f61b7bf89efc6b551f4667d983"); + private static final byte[] output_k256_m16 = Hex.decode("28a7023f452e8f82bd4bf28d8c37c35c"); + private static final byte[] output_k256_m40 = Hex.decode("aaf3d8f1de5640c232f5b169b9c911e6"); + private static final byte[] output_k256_m64 = Hex.decode("e1992190549f6ed5696a2c056c315410"); + + public CMacTest() + { + } + + public void performTest() + { + BlockCipher cipher = new AESFastEngine(); + Mac mac = new CMac(cipher, 128); + + //128 bytes key + + KeyParameter key = new KeyParameter(keyBytes128); + + // 0 bytes message - 128 bytes key + mac.init(key); + + mac.update(input0, 0, input0.length); + + byte[] out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m0)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m0)) + + " got " + new String(Hex.encode(out))); + } + + // 16 bytes message - 128 bytes key + mac.init(key); + + mac.update(input16, 0, input16.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m16)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m16)) + + " got " + new String(Hex.encode(out))); + } + + // 40 bytes message - 128 bytes key + mac.init(key); + + mac.update(input40, 0, input40.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m40)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m40)) + + " got " + new String(Hex.encode(out))); + } + + // 64 bytes message - 128 bytes key + mac.init(key); + + mac.update(input64, 0, input64.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m64)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m64)) + + " got " + new String(Hex.encode(out))); + } + + //192 bytes key + + key = new KeyParameter(keyBytes192); + + // 0 bytes message - 192 bytes key + mac.init(key); + + mac.update(input0, 0, input0.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m0)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m0)) + + " got " + new String(Hex.encode(out))); + } + + // 16 bytes message - 192 bytes key + mac.init(key); + + mac.update(input16, 0, input16.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m16)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m16)) + + " got " + new String(Hex.encode(out))); + } + + // 40 bytes message - 192 bytes key + mac.init(key); + + mac.update(input40, 0, input40.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m40)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m40)) + + " got " + new String(Hex.encode(out))); + } + + // 64 bytes message - 192 bytes key + mac.init(key); + + mac.update(input64, 0, input64.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m64)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m64)) + + " got " + new String(Hex.encode(out))); + } + + //256 bytes key + + key = new KeyParameter(keyBytes256); + + // 0 bytes message - 256 bytes key + mac.init(key); + + mac.update(input0, 0, input0.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m0)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m0)) + + " got " + new String(Hex.encode(out))); + } + + // 16 bytes message - 256 bytes key + mac.init(key); + + mac.update(input16, 0, input16.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m16)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m16)) + + " got " + new String(Hex.encode(out))); + } + + // 40 bytes message - 256 bytes key + mac.init(key); + + mac.update(input40, 0, input40.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m40)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m40)) + + " got " + new String(Hex.encode(out))); + } + + // 64 bytes message - 256 bytes key + mac.init(key); + + mac.update(input64, 0, input64.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m64)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m64)) + + " got " + new String(Hex.encode(out))); + } + + // CMAC with IV + // 16 bytes message - 256 bytes key + mac = new CMacWithIV(new AESFastEngine()); + + mac.init(key); + + mac.update(input16, 0, input16.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m16)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m16)) + + " got " + new String(Hex.encode(out))); + } + + // CMAC with IV + // 16 bytes message - 256 bytes key + mac = new CMacWithIV(new AESFastEngine()); + + mac.init(new ParametersWithIV(key, Hex.decode("000102030405060708090a0b0c0d0e0f"))); + + mac.update(input16, 0, input16.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (areEqual(out, output_k256_m16)) + { + fail("Failed - got " + new String(Hex.encode(output_k256_m16))); + } + + if (!areEqual(out, Hex.decode("9347a60c64061b9ff2a92522ca8e08fc"))) + { + fail("Failed - expected " + "9347a60c64061b9ff2a92522ca8e08fc" + + " got " + new String(Hex.encode(out))); + } + + testExceptions(); + } + + private void testExceptions() + { + try + { + CMac mac = new CMac(new AESEngine()); + mac.init(new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + fail("CMac does not accept IV"); + } catch(IllegalArgumentException e) + { + // Expected + } + } + + public String getName() + { + return "CMac"; + } + + public static void main(String[] args) + { + runTest(new CMacTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/CTSTest.java b/core/src/test/java/org/spongycastle/crypto/test/CTSTest.java new file mode 100644 index 00000000..76846193 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/CTSTest.java @@ -0,0 +1,212 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.AESEngine; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.engines.SkipjackEngine; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.modes.CTSBlockCipher; +import org.spongycastle.crypto.modes.OldCTSBlockCipher; +import org.spongycastle.crypto.modes.SICBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * CTS tester + */ +public class CTSTest + extends SimpleTest +{ + static byte[] in1 = Hex.decode("4e6f7720697320746865207420"); + static byte[] in2 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f0aaa"); + static byte[] out1 = Hex.decode("9952f131588465033fa40e8a98"); + static byte[] out2 = Hex.decode("358f84d01eb42988dc34efb994"); + static byte[] out3 = Hex.decode("170171cfad3f04530c509b0c1f0be0aefbd45a8e3755a873bff5ea198504b71683c6"); + + private void testCTS( + int id, + BlockCipher cipher, + CipherParameters params, + byte[] input, + byte[] output) + throws Exception + { + byte[] out = new byte[input.length]; + BufferedBlockCipher engine = new CTSBlockCipher(cipher); + + engine.init(true, params); + + int len = engine.processBytes(input, 0, input.length, out, 0); + + engine.doFinal(out, len); + + if (!areEqual(output, out)) + { + fail("failed encryption expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + engine.init(false, params); + + len = engine.processBytes(output, 0, output.length, out, 0); + + engine.doFinal(out, len); + + if (!areEqual(input, out)) + { + fail("failed decryption expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + } + + private void testOldCTS( + int id, + BlockCipher cipher, + CipherParameters params, + byte[] input, + byte[] output) + throws Exception + { + byte[] out = new byte[input.length]; + BufferedBlockCipher engine = new OldCTSBlockCipher(cipher); + + engine.init(true, params); + + int len = engine.processBytes(input, 0, input.length, out, 0); + + engine.doFinal(out, len); + + if (!areEqual(output, out)) + { + fail("failed encryption expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + engine.init(false, params); + + len = engine.processBytes(output, 0, output.length, out, 0); + + engine.doFinal(out, len); + + if (!areEqual(input, out)) + { + fail("failed decryption expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + } + + private void testExceptions() throws InvalidCipherTextException + { + BufferedBlockCipher engine = new CTSBlockCipher(new DESEngine()); + CipherParameters params = new KeyParameter(new byte[engine.getBlockSize()]); + engine.init(true, params); + + byte[] out = new byte[engine.getOutputSize(engine.getBlockSize())]; + + engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0); + try + { + engine.doFinal(out, 0); + fail("Expected CTS encrypt error on < 1 block input"); + } catch(DataLengthException e) + { + // Expected + } + + engine.init(true, params); + engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0); + try + { + engine.doFinal(out, 0); + } catch(DataLengthException e) + { + fail("Unexpected CTS encrypt error on == 1 block input"); + } + + engine.init(false, params); + engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0); + try + { + engine.doFinal(out, 0); + fail("Expected CTS decrypt error on < 1 block input"); + } catch(DataLengthException e) + { + // Expected + } + + engine.init(false, params); + engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0); + try + { + engine.doFinal(out, 0); + } catch(DataLengthException e) + { + fail("Unexpected CTS decrypt error on == 1 block input"); + } + + try + { + new CTSBlockCipher(new SICBlockCipher(new AESEngine())); + fail("Expected CTS construction error - only ECB/CBC supported."); + } catch(IllegalArgumentException e) + { + // Expected + } + + } + + public String getName() + { + return "CTS"; + } + + public void performTest() + throws Exception + { + byte[] key1 = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF }; + byte[] key2 = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF, (byte)0xee, (byte)0xff }; + byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + testCTS(1, new DESEngine(), new KeyParameter(key1), in1, out1); + testCTS(2, new CBCBlockCipher(new DESEngine()), new ParametersWithIV(new KeyParameter(key1), iv), in1, out2); + testCTS(3, new CBCBlockCipher(new SkipjackEngine()), new ParametersWithIV(new KeyParameter(key2), iv), in2, out3); + + // + // test vectors from rfc3962 + // + byte[] aes128 = Hex.decode("636869636b656e207465726979616b69"); + byte[] aesIn1 = Hex.decode("4920776f756c64206c696b652074686520"); + byte[] aesOut1 = Hex.decode("c6353568f2bf8cb4d8a580362da7ff7f97"); + byte[] aesIn2 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c20476175277320"); + byte[] aesOut2 = Hex.decode("fc00783e0efdb2c1d445d4c8eff7ed2297687268d6ecccc0c07b25e25ecfe5"); + byte[] aesIn3 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c2047617527732043"); + byte[] aesOut3 = Hex.decode("39312523a78662d5be7fcbcc98ebf5a897687268d6ecccc0c07b25e25ecfe584"); + + testCTS(4, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn1, aesOut1); + testCTS(5, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn2, aesOut2); + testCTS(6, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn3, aesOut3); + + testOldCTS(4, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn1, aesOut1); + testOldCTS(5, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn2, aesOut2); + testOldCTS(6, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn3, aesOut3); + + byte[] aes1Block = Hex.decode("4920776f756c64206c696b6520746865"); + byte[] preErrata = Hex.decode("e7664c13ff28c965b0d2a0e7ec353706"); // CTS style one block + byte[] pstErrata = Hex.decode("97687268d6ecccc0c07b25e25ecfe584"); // CBC style one block + byte[] pstErrataNonZeroIV = Hex.decode("571f5108c53fe95ab52df783df933fa3"); + + testCTS(7, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aes1Block, pstErrata); + testCTS(8, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), aes1Block), aes1Block, pstErrataNonZeroIV); + testOldCTS(7, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aes1Block, preErrata); + + testExceptions(); + } + + public static void main( + String[] args) + { + runTest(new CTSTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/CamelliaLightTest.java b/core/src/test/java/org/spongycastle/crypto/test/CamelliaLightTest.java new file mode 100644 index 00000000..71a89fba --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/CamelliaLightTest.java @@ -0,0 +1,66 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.CamelliaLightEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Camellia tester - vectors from https://www.cosic.esat.kuleuven.be/nessie/testvectors/ and RFC 3713 + */ +public class CamelliaLightTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "80000000000000000000000000000000", "07923A39EB0A817D1C4D87BDB82D1F1C"), + new BlockCipherVectorTest(1, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "6C227F749319A3AA7DA235A9BBA05A2C"), + new BlockCipherVectorTest(2, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba9876543210")), + "0123456789abcdeffedcba9876543210", "67673138549669730857065648eabe43"), + // + // 192 bit + // + new BlockCipherVectorTest(3, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba98765432100011223344556677")), + "0123456789abcdeffedcba9876543210", "b4993401b3e996f84ee5cee7d79b09b9"), + new BlockCipherVectorTest(4, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "00040000000000000000000000000000", "9BCA6C88B928C1B0F57F99866583A9BC"), + new BlockCipherVectorTest(5, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("949494949494949494949494949494949494949494949494")), + "636EB22D84B006381235641BCF0308D2", "94949494949494949494949494949494"), + // + // 256 bit + // + new BlockCipherVectorTest(6, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff")), + "0123456789abcdeffedcba9876543210", "9acc237dff16d76c20ef7c919e3a7509"), + new BlockCipherVectorTest(7, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A")), + "057764FE3A500EDBD988C5C3B56CBA9A", "4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A"), + new BlockCipherVectorTest(8, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("0303030303030303030303030303030303030303030303030303030303030303")), + "7968B08ABA92193F2295121EF8D75C8A", "03030303030303030303030303030303"), + }; + + CamelliaLightTest() + { + super(tests, new CamelliaLightEngine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "CamelliaLight"; + } + + public static void main( + String[] args) + { + runTest(new CamelliaLightTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/CamelliaTest.java b/core/src/test/java/org/spongycastle/crypto/test/CamelliaTest.java new file mode 100644 index 00000000..a3d48193 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/CamelliaTest.java @@ -0,0 +1,70 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.CamelliaEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.test.TestResult; + +/** + * Camellia tester - vectors from https://www.cosic.esat.kuleuven.be/nessie/testvectors/ and RFC 3713 + */ +public class CamelliaTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new CamelliaEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "80000000000000000000000000000000", "07923A39EB0A817D1C4D87BDB82D1F1C"), + new BlockCipherVectorTest(1, new CamelliaEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "6C227F749319A3AA7DA235A9BBA05A2C"), + new BlockCipherVectorTest(2, new CamelliaEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba9876543210")), + "0123456789abcdeffedcba9876543210", "67673138549669730857065648eabe43"), + // + // 192 bit + // + new BlockCipherVectorTest(3, new CamelliaEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba98765432100011223344556677")), + "0123456789abcdeffedcba9876543210", "b4993401b3e996f84ee5cee7d79b09b9"), + new BlockCipherVectorTest(4, new CamelliaEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "00040000000000000000000000000000", "9BCA6C88B928C1B0F57F99866583A9BC"), + new BlockCipherVectorTest(5, new CamelliaEngine(), + new KeyParameter(Hex.decode("949494949494949494949494949494949494949494949494")), + "636EB22D84B006381235641BCF0308D2", "94949494949494949494949494949494"), + // + // 256 bit + // + new BlockCipherVectorTest(6, new CamelliaEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff")), + "0123456789abcdeffedcba9876543210", "9acc237dff16d76c20ef7c919e3a7509"), + new BlockCipherVectorTest(7, new CamelliaEngine(), + new KeyParameter(Hex.decode("4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A")), + "057764FE3A500EDBD988C5C3B56CBA9A", "4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A"), + new BlockCipherVectorTest(8, new CamelliaEngine(), + new KeyParameter(Hex.decode("0303030303030303030303030303030303030303030303030303030303030303")), + "7968B08ABA92193F2295121EF8D75C8A", "03030303030303030303030303030303"), + }; + + CamelliaTest() + { + super(tests, new CamelliaEngine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "Camellia"; + } + + public static void main( + String[] args) + { + CamelliaTest test = new CamelliaTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ChaChaTest.java b/core/src/test/java/org/spongycastle/crypto/test/ChaChaTest.java new file mode 100644 index 00000000..21f24bf9 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ChaChaTest.java @@ -0,0 +1,403 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.engines.ChaChaEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * ChaCha Test + * <p> + * Test cases generated using ref version of ChaCha20 in estreambench-20080905. + */ +public class ChaChaTest + extends SimpleTest +{ + byte[] zeroes = Hex.decode( + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"); + + String set1v0_0 = "FBB87FBB8395E05DAA3B1D683C422046" + + "F913985C2AD9B23CFC06C1D8D04FF213" + + "D44A7A7CDB84929F915420A8A3DC58BF" + + "0F7ECB4B1F167BB1A5E6153FDAF4493D"; + + String set1v0_192 = "D9485D55B8B82D792ED1EEA8E93E9BC1" + + "E2834AD0D9B11F3477F6E106A2F6A5F2" + + "EA8244D5B925B8050EAB038F58D4DF57" + + "7FAFD1B89359DAE508B2B10CBD6B488E"; + + String set1v0_256 = "08661A35D6F02D3D9ACA8087F421F7C8" + + "A42579047D6955D937925BA21396DDD4" + + "74B1FC4ACCDCAA33025B4BCE817A4FBF" + + "3E5D07D151D7E6FE04934ED466BA4779"; + + String set1v0_448 = "A7E16DD38BA48CCB130E5BE9740CE359" + + "D631E91600F85C8A5D0785A612D1D987" + + "90780ACDDC26B69AB106CCF6D866411D" + + "10637483DBF08CC5591FD8B3C87A3AE0"; + + String set1v9_0 = "A276339F99316A913885A0A4BE870F06" + + "91E72B00F1B3F2239F714FE81E88E00C" + + "BBE52B4EBBE1EA15894E29658C4CB145" + + "E6F89EE4ABB045A78514482CE75AFB7C"; + + String set1v9_192 = "0DFB9BD4F87F68DE54FBC1C6428FDEB0" + + "63E997BE8490C9B7A4694025D6EBA2B1" + + "5FE429DB82A7CAE6AAB22918E8D00449" + + "6FB6291467B5AE81D4E85E81D8795EBB"; + + String set1v9_256 = "546F5BB315E7F71A46E56D4580F90889" + + "639A2BA528F757CF3B048738BA141AF3" + + "B31607CB21561BAD94721048930364F4" + + "B1227CFEB7CDECBA881FB44903550E68"; + + String set1v9_448 = "6F813586E76691305A0CF048C0D8586D" + + "C89460207D8B230CD172398AA33D19E9" + + "2D24883C3A9B0BB7CD8C6B2668DB142E" + + "37A97948A7A01498A21110297984CD20"; + + String set6v0_0 = "57459975BC46799394788DE80B928387" + + "862985A269B9E8E77801DE9D874B3F51" + + "AC4610B9F9BEE8CF8CACD8B5AD0BF17D" + + "3DDF23FD7424887EB3F81405BD498CC3"; + + String set6v0_65472 = "EF9AEC58ACE7DB427DF012B2B91A0C1E" + + "8E4759DCE9CDB00A2BD59207357BA06C" + + "E02D327C7719E83D6348A6104B081DB0" + + "3908E5186986AE41E3AE95298BB7B713"; + + String set6v0_65536 = "17EF5FF454D85ABBBA280F3A94F1D26E" + + "950C7D5B05C4BB3A78326E0DC5731F83" + + "84205C32DB867D1B476CE121A0D7074B" + + "AA7EE90525D15300F48EC0A6624BD0AF"; + + String set6v1_0 = "92A2508E2C4084567195F2A1005E552B" + + "4874EC0504A9CD5E4DAF739AB553D2E7" + + "83D79C5BA11E0653BEBB5C116651302E" + + "8D381CB728CA627B0B246E83942A2B99"; + + String set6v1_65472 = "E1974EC3063F7BD0CBA58B1CE34BC874" + + "67AAF5759B05EA46682A5D4306E5A76B" + + "D99A448DB8DE73AF97A73F5FBAE2C776" + + "35040464524CF14D7F08D4CE1220FD84"; + + String set6v1_65536 = "BE3436141CFD62D12FF7D852F80C1344" + + "81F152AD0235ECF8CA172C55CA8C031B" + + "2E785D773A988CA8D4BDA6FAE0E493AA" + + "71DCCC4C894D1F106CAC62A9FC0A9607"; + + // ChaCha12 + String chacha12_set1v0_0 = "36CF0D56E9F7FBF287BC5460D95FBA94" + + "AA6CBF17D74E7C784DDCF7E0E882DDAE" + + "3B5A58243EF32B79A04575A8E2C2B73D" + + "C64A52AA15B9F88305A8F0CA0B5A1A25"; + + String chacha12_set1v0_192 = "83496792AB68FEC75ADB16D3044420A4" + + "A00A6E9ADC41C3A63DBBF317A8258C85" + + "A9BC08B4F76B413A4837324AEDF8BC2A" + + "67D53C9AB9E1C5BC5F379D48DF9AF730"; + + String chacha12_set1v0_256 = "BAA28ED593690FD760ADA07C95E3B888" + + "4B4B64E488CA7A2D9BDC262243AB9251" + + "394C5037E255F8BCCDCD31306C508FFB" + + "C9E0161380F7911FCB137D46D9269250"; + + String chacha12_set1v0_448 = "B7ECFB6AE0B51915762FE1FD03A14D0C" + + "9E54DA5DC76EB16EBA5313BC535DE63D" + + "C72D7F9F1874E301E99C8531819F4E37" + + "75793F6A5D19C717FA5C78A39EB804A6"; + + // ChaCha8 + String chacha8_set1v0_0 = "BEB1E81E0F747E43EE51922B3E87FB38" + + "D0163907B4ED49336032AB78B67C2457" + + "9FE28F751BD3703E51D876C017FAA435" + + "89E63593E03355A7D57B2366F30047C5"; + + String chacha8_set1v0_192 = "33B8B7CA8F8E89F0095ACE75A379C651" + + "FD6BDD55703C90672E44C6BAB6AACDD8" + + "7C976A87FD264B906E749429284134C2" + + "38E3B88CF74A68245B860D119A8BDF43"; + + String chacha8_set1v0_256 = "F7CA95BF08688BD3BE8A27724210F9DC" + + "16F32AF974FBFB09E9F757C577A245AB" + + "F35F824B70A4C02CB4A8D7191FA8A5AD" + + "6A84568743844703D353B7F00A8601F4"; + + String chacha8_set1v0_448 = "7B4117E8BFFD595CD8482270B08920FB" + + "C9B97794E1809E07BB271BF07C861003" + + "4C38DBA6ECA04E5474F399A284CBF6E2" + + "7F70142E604D0977797DE5B58B6B25E0"; + + + + public String getName() + { + return "ChaCha"; + } + + public void performTest() + { + chachaTest1(20, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + set1v0_0, set1v0_192, set1v0_256, set1v0_448); + chachaTest1(20, new ParametersWithIV(new KeyParameter(Hex.decode("00400000000000000000000000000000")), Hex.decode("0000000000000000")), + set1v9_0, set1v9_192, set1v9_256, set1v9_448); + chachaTest1(12, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + chacha12_set1v0_0, chacha12_set1v0_192, chacha12_set1v0_256, chacha12_set1v0_448); + chachaTest1(8, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + chacha8_set1v0_0, chacha8_set1v0_192, chacha8_set1v0_256, chacha8_set1v0_448); + chachaTest2(new ParametersWithIV(new KeyParameter(Hex.decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.decode("0D74DB42A91077DE")), + set6v0_0, set6v0_65472, set6v0_65536); + chachaTest2(new ParametersWithIV(new KeyParameter(Hex.decode("0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12")), Hex.decode("167DE44BB21980E7")), + set6v1_0, set6v1_65472, set6v1_65536); + reinitBug(); + skipTest(); + } + + private void chachaTest1(int rounds, CipherParameters params, String v0, String v192, String v256, String v448) + { + StreamCipher chaCha = new ChaChaEngine(rounds); + byte[] buf = new byte[64]; + + chaCha.init(true, params); + + for (int i = 0; i != 7; i++) + { + chaCha.processBytes(zeroes, 0, 64, buf, 0); + switch (i) + { + case 0: + if (!areEqual(buf, Hex.decode(v0))) + { + mismatch("v0/" + rounds, v0, buf); + } + break; + case 3: + if (!areEqual(buf, Hex.decode(v192))) + { + mismatch("v192/" + rounds, v192, buf); + } + break; + case 4: + if (!areEqual(buf, Hex.decode(v256))) + { + mismatch("v256/" + rounds, v256, buf); + } + break; + default: + // ignore + } + } + + for (int i = 0; i != 64; i++) + { + buf[i] = chaCha.returnByte(zeroes[i]); + } + + if (!areEqual(buf, Hex.decode(v448))) + { + mismatch("v448", v448, buf); + } + } + + private void chachaTest2(CipherParameters params, String v0, String v65472, String v65536) + { + StreamCipher chaCha = new ChaChaEngine(); + byte[] buf = new byte[64]; + + chaCha.init(true, params); + + for (int i = 0; i != 1025; i++) + { + chaCha.processBytes(zeroes, 0, 64, buf, 0); + switch (i) + { + case 0: + if (!areEqual(buf, Hex.decode(v0))) + { + mismatch("v0", v0, buf); + } + break; + case 1023: + if (!areEqual(buf, Hex.decode(v65472))) + { + mismatch("v65472", v65472, buf); + } + break; + case 1024: + if (!areEqual(buf, Hex.decode(v65536))) + { + mismatch("v65536", v65536, buf); + } + break; + default: + // ignore + } + } + } + + private void mismatch(String name, String expected, byte[] found) + { + fail("mismatch on " + name, expected, new String(Hex.encode(found))); + } + + + private void reinitBug() + { + KeyParameter key = new KeyParameter(Hex.decode("80000000000000000000000000000000")); + ParametersWithIV parameters = new ParametersWithIV(key, Hex.decode("0000000000000000")); + + StreamCipher salsa = new ChaChaEngine(); + + salsa.init(true, parameters); + + try + { + salsa.init(true, key); + fail("Salsa20 should throw exception if no IV in Init"); + } + catch (IllegalArgumentException e) + { + } + } + + private boolean areEqual(byte[] a, int aOff, byte[] b, int bOff) + { + for (int i = bOff; i != b.length; i++) + { + if (a[aOff + i - bOff] != b[i]) + { + return false; + } + } + + return true; + } + + private void skipTest() + { + SecureRandom rand = new SecureRandom(); + byte[] plain = new byte[5000]; + byte[] cipher = new byte[5000]; + + rand.nextBytes(plain); + + CipherParameters params = new ParametersWithIV(new KeyParameter(Hex.decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.decode("0D74DB42A91077DE")); + ChaChaEngine engine = new ChaChaEngine(); + + engine.init(true, params); + + engine.processBytes(plain, 0, plain.length, cipher, 0); + + byte[] fragment = new byte[20]; + + engine.init(true, params); + + engine.skip(10); + + engine.processBytes(plain, 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 10, fragment, 0)) + { + fail("skip forward 10 failed"); + } + + engine.skip(1000); + + engine.processBytes(plain, 1010 + fragment.length, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + fragment.length, fragment, 0)) + { + fail("skip forward 1000 failed"); + } + + engine.skip(-10); + + engine.processBytes(plain, 1010 + 2 * fragment.length - 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + 2 * fragment.length - 10, fragment, 0)) + { + fail("skip back 10 failed"); + } + + engine.skip(-1000); + + if (engine.getPosition() != 60) + { + fail("skip position incorrect - " + 60 + " got " + engine.getPosition()); + } + + engine.processBytes(plain, 60, fragment.length, fragment, 0); + + if (!areEqual(cipher, 60, fragment, 0)) + { + fail("skip back 1000 failed"); + } + + long pos = engine.seekTo(1010); + if (pos != 1010) + { + fail("position wrong"); + } + + engine.processBytes(plain, 1010, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010, fragment, 0)) + { + fail("seek to 1010 failed"); + } + + engine.reset(); + + for (int i = 0; i != 1000; i++) + { + engine.skip(i); + + if (engine.getPosition() != i) + { + fail("skip forward at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip forward i failed: " + i); + } + + if (engine.getPosition() != i + fragment.length) + { + fail("cipher at wrong position: " + engine.getPosition() + " [" + i + "]"); + } + + engine.skip(-fragment.length); + + if (engine.getPosition() != i) + { + fail("skip back at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip back i failed: " + i); + } + + engine.reset(); + } + } + + public static void main( + String[] args) + { + runTest(new ChaChaTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/CipherStreamTest.java b/core/src/test/java/org/spongycastle/crypto/test/CipherStreamTest.java new file mode 100644 index 00000000..bc049fa2 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/CipherStreamTest.java @@ -0,0 +1,699 @@ +package org.spongycastle.crypto.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.SecureRandom; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.engines.AESEngine; +import org.spongycastle.crypto.engines.BlowfishEngine; +import org.spongycastle.crypto.engines.CAST5Engine; +import org.spongycastle.crypto.engines.CAST6Engine; +import org.spongycastle.crypto.engines.CamelliaEngine; +import org.spongycastle.crypto.engines.ChaChaEngine; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.engines.DESedeEngine; +import org.spongycastle.crypto.engines.Grain128Engine; +import org.spongycastle.crypto.engines.Grainv1Engine; +import org.spongycastle.crypto.engines.HC128Engine; +import org.spongycastle.crypto.engines.HC256Engine; +import org.spongycastle.crypto.engines.NoekeonEngine; +import org.spongycastle.crypto.engines.RC2Engine; +import org.spongycastle.crypto.engines.RC4Engine; +import org.spongycastle.crypto.engines.RC6Engine; +import org.spongycastle.crypto.engines.SEEDEngine; +import org.spongycastle.crypto.engines.Salsa20Engine; +import org.spongycastle.crypto.engines.SerpentEngine; +import org.spongycastle.crypto.engines.TEAEngine; +import org.spongycastle.crypto.engines.ThreefishEngine; +import org.spongycastle.crypto.engines.TwofishEngine; +import org.spongycastle.crypto.engines.XSalsa20Engine; +import org.spongycastle.crypto.engines.XTEAEngine; +import org.spongycastle.crypto.io.CipherInputStream; +import org.spongycastle.crypto.io.CipherOutputStream; +import org.spongycastle.crypto.io.InvalidCipherTextIOException; +import org.spongycastle.crypto.modes.AEADBlockCipher; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.modes.CCMBlockCipher; +import org.spongycastle.crypto.modes.CFBBlockCipher; +import org.spongycastle.crypto.modes.CTSBlockCipher; +import org.spongycastle.crypto.modes.EAXBlockCipher; +import org.spongycastle.crypto.modes.GCMBlockCipher; +import org.spongycastle.crypto.modes.OCBBlockCipher; +import org.spongycastle.crypto.modes.OFBBlockCipher; +import org.spongycastle.crypto.modes.SICBlockCipher; +import org.spongycastle.crypto.paddings.PKCS7Padding; +import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.test.SimpleTest; + +public class CipherStreamTest + extends SimpleTest +{ + private int streamSize; + + public String getName() + { + return "CipherStreamTest"; + } + + private void testMode(Object cipher, CipherParameters params) + throws Exception + { + testWriteRead(cipher, params, false); + testWriteRead(cipher, params, true); + testReadWrite(cipher, params, false); + testReadWrite(cipher, params, true); + + if (!(cipher instanceof CTSBlockCipher)) + { + testWriteReadEmpty(cipher, params, false); + testWriteReadEmpty(cipher, params, true); + } + + if (cipher instanceof AEADBlockCipher) + { + testTamperedRead((AEADBlockCipher)cipher, params); + testTruncatedRead((AEADBlockCipher)cipher, params); + testTamperedWrite((AEADBlockCipher)cipher, params); + } + } + + private OutputStream createCipherOutputStream(OutputStream output, Object cipher) + { + if (cipher instanceof BufferedBlockCipher) + { + return new CipherOutputStream(output, (BufferedBlockCipher)cipher); + } + else if (cipher instanceof AEADBlockCipher) + { + return new CipherOutputStream(output, (AEADBlockCipher)cipher); + } + else + { + return new CipherOutputStream(output, (StreamCipher)cipher); + } + } + + private InputStream createCipherInputStream(byte[] data, Object cipher) + { + ByteArrayInputStream input = new ByteArrayInputStream(data); + if (cipher instanceof BufferedBlockCipher) + { + return new CipherInputStream(input, (BufferedBlockCipher)cipher); + } + else if (cipher instanceof AEADBlockCipher) + { + return new CipherInputStream(input, (AEADBlockCipher)cipher); + } + else + { + return new CipherInputStream(input, (StreamCipher)cipher); + } + } + + /** + * Test tampering of ciphertext followed by read from decrypting CipherInputStream + */ + private void testTamperedRead(AEADBlockCipher cipher, CipherParameters params) + throws Exception + { + cipher.init(true, params); + + byte[] ciphertext = new byte[cipher.getOutputSize(streamSize)]; + cipher.doFinal(ciphertext, cipher.processBytes(new byte[streamSize], 0, streamSize, ciphertext, 0)); + + // Tamper + ciphertext[0] += 1; + + cipher.init(false, params); + InputStream input = createCipherInputStream(ciphertext, cipher); + try + { + while (input.read() >= 0) + { + } + fail("Expected invalid ciphertext after tamper and read : " + cipher.getAlgorithmName()); + } + catch (InvalidCipherTextIOException e) + { + // Expected + } + try + { + input.close(); + } + catch (Exception e) + { + fail("Unexpected exception after tamper and read : " + cipher.getAlgorithmName()); + } + } + + /** + * Test truncation of ciphertext to make tag calculation impossible, followed by read from + * decrypting CipherInputStream + */ + private void testTruncatedRead(AEADBlockCipher cipher, CipherParameters params) + throws Exception + { + cipher.init(true, params); + + byte[] ciphertext = new byte[cipher.getOutputSize(streamSize)]; + cipher.doFinal(ciphertext, cipher.processBytes(new byte[streamSize], 0, streamSize, ciphertext, 0)); + + // Truncate to just smaller than complete tag + byte[] truncated = new byte[ciphertext.length - streamSize - 1]; + System.arraycopy(ciphertext, 0, truncated, 0, truncated.length); + + cipher.init(false, params); + InputStream input = createCipherInputStream(truncated, cipher); + while (true) + { + int read = 0; + try + { + read = input.read(); + } + catch (InvalidCipherTextIOException e) + { + // Expected + break; + } + catch (Exception e) + { + fail("Unexpected exception on truncated read : " + cipher.getAlgorithmName()); + break; + } + if (read < 0) + { + fail("Expected invalid ciphertext after truncate and read : " + cipher.getAlgorithmName()); + break; + } + } + try + { + input.close(); + } + catch (Exception e) + { + fail("Unexpected exception after truncate and read : " + cipher.getAlgorithmName()); + } + } + + /** + * Test tampering of ciphertext followed by write to decrypting CipherOutputStream + */ + private void testTamperedWrite(AEADBlockCipher cipher, CipherParameters params) + throws Exception + { + cipher.init(true, params); + + byte[] ciphertext = new byte[cipher.getOutputSize(streamSize)]; + cipher.doFinal(ciphertext, cipher.processBytes(new byte[streamSize], 0, streamSize, ciphertext, 0)); + + // Tamper + ciphertext[0] += 1; + + cipher.init(false, params); + ByteArrayOutputStream plaintext = new ByteArrayOutputStream(); + OutputStream output = createCipherOutputStream(plaintext, cipher); + + for (int i = 0; i < ciphertext.length; i++) + { + output.write(ciphertext[i]); + } + try + { + output.close(); + fail("Expected invalid ciphertext after tamper and write : " + cipher.getAlgorithmName()); + } + catch (InvalidCipherTextIOException e) + { + // Expected + } + } + + /** + * Test CipherOutputStream in ENCRYPT_MODE, CipherInputStream in DECRYPT_MODE + */ + private void testWriteRead(Object cipher, CipherParameters params, boolean blocks) + throws Exception + { + byte[] data = new byte[streamSize]; + for (int i = 0; i < data.length; i++) + { + data[i] = (byte)(i % 255); + } + + testWriteRead(cipher, params, blocks, data); + } + + /** + * Test CipherOutputStream in ENCRYPT_MODE, CipherInputStream in DECRYPT_MODE + */ + private void testWriteReadEmpty(Object cipher, CipherParameters params, boolean blocks) + throws Exception + { + byte[] data = new byte[0]; + + testWriteRead(cipher, params, blocks, data); + } + + private void testWriteRead(Object cipher, CipherParameters params, boolean blocks, byte[] data) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try + { + init(cipher, true, params); + + OutputStream cOut = createCipherOutputStream(bOut, cipher); + if (blocks) + { + int chunkSize = Math.max(1, data.length / 8); + for (int i = 0; i < data.length; i += chunkSize) + { + cOut.write(data, i, Math.min(chunkSize, data.length - i)); + } + } + else + { + for (int i = 0; i < data.length; i++) + { + cOut.write(data[i]); + } + } + cOut.close(); + + byte[] cipherText = bOut.toByteArray(); + bOut.reset(); + init(cipher, false, params); + InputStream cIn = createCipherInputStream(cipherText, cipher); + + if (blocks) + { + byte[] block = new byte[getBlockSize(cipher) + 1]; + int c; + while ((c = cIn.read(block)) >= 0) + { + bOut.write(block, 0, c); + } + } + else + { + int c; + while ((c = cIn.read()) >= 0) + { + bOut.write(c); + } + + } + cIn.close(); + + } + catch (Exception e) + { + fail("Unexpected exception " + getName(cipher), e); + } + + byte[] decrypted = bOut.toByteArray(); + if (!Arrays.areEqual(data, decrypted)) + { + fail("Failed - decrypted data doesn't match: " + getName(cipher)); + } + } + + private String getName(Object cipher) + { + if (cipher instanceof BufferedBlockCipher) + { + return ((BufferedBlockCipher)cipher).getUnderlyingCipher().getAlgorithmName(); + } + else if (cipher instanceof AEADBlockCipher) + { + return ((AEADBlockCipher)cipher).getUnderlyingCipher().getAlgorithmName(); + } + else if (cipher instanceof StreamCipher) + { + return ((StreamCipher)cipher).getAlgorithmName(); + } + return null; + } + + private int getBlockSize(Object cipher) + { + if (cipher instanceof BlockCipher) + { + return ((BlockCipher)cipher).getBlockSize(); + } + else if (cipher instanceof BufferedBlockCipher) + { + return ((BufferedBlockCipher)cipher).getBlockSize(); + } + else if (cipher instanceof AEADBlockCipher) + { + return ((AEADBlockCipher)cipher).getUnderlyingCipher().getBlockSize(); + } + else if (cipher instanceof StreamCipher) + { + return 1; + } + return 0; + } + + private void init(Object cipher, boolean forEncrypt, CipherParameters params) + { + if (cipher instanceof BufferedBlockCipher) + { + ((BufferedBlockCipher)cipher).init(forEncrypt, params); + } + else if (cipher instanceof AEADBlockCipher) + { + ((AEADBlockCipher)cipher).init(forEncrypt, params); + } + else if (cipher instanceof StreamCipher) + { + ((StreamCipher)cipher).init(forEncrypt, params); + } + } + + protected void fail(String message, boolean authenticated, boolean bc) + { + if (bc || !authenticated) + { + super.fail(message); + } + else + { + // javax.crypto.CipherInputStream/CipherOutputStream + // are broken wrt handling AEAD failures + System.err.println("Broken JCE Streams: " + message); + } + } + + /** + * Test CipherInputStream in ENCRYPT_MODE, CipherOutputStream in DECRYPT_MODE + */ + private void testReadWrite(Object cipher, CipherParameters params, boolean blocks) + throws Exception + { + String lCode = "ABCDEFGHIJKLMNOPQRSTU"; + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try + { + init(cipher, true, params); + + InputStream cIn = createCipherInputStream(lCode.getBytes(), cipher); + ByteArrayOutputStream ct = new ByteArrayOutputStream(); + + if (blocks) + { + byte[] block = new byte[getBlockSize(cipher) + 1]; + int c; + while ((c = cIn.read(block)) >= 0) + { + ct.write(block, 0, c); + } + } + else + { + int c; + while ((c = cIn.read()) >= 0) + { + ct.write(c); + } + } + cIn.close(); + + init(cipher, false, params); + ByteArrayInputStream dataIn = new ByteArrayInputStream(ct.toByteArray()); + OutputStream cOut = createCipherOutputStream(bOut, cipher); + + if (blocks) + { + byte[] block = new byte[getBlockSize(cipher) + 1]; + int c; + while ((c = dataIn.read(block)) >= 0) + { + cOut.write(block, 0, c); + } + } + else + { + int c; + while ((c = dataIn.read()) >= 0) + { + cOut.write(c); + } + } + cOut.flush(); + cOut.close(); + + } + catch (Exception e) + { + fail("Unexpected exception " + getName(cipher), e); + } + + String res = new String(bOut.toByteArray()); + if (!res.equals(lCode)) + { + fail("Failed read/write - decrypted data doesn't match: " + getName(cipher), lCode, res); + } + } + + public void performTest() + throws Exception + { + int[] testSizes = new int[]{0, 1, 7, 8, 9, 15, 16, 17, 1023, 1024, 1025, 2047, 2048, 2049, 4095, 4096, 4097}; + for (int i = 0; i < testSizes.length; i++) + { + this.streamSize = testSizes[i]; + performTests(); + } + } + + private void performTests() + throws Exception + { + testModes(new BlowfishEngine(), new BlowfishEngine(), 16); + testModes(new DESEngine(), new DESEngine(), 8); + testModes(new DESedeEngine(), new DESedeEngine(), 24); + testModes(new TEAEngine(), new TEAEngine(), 16); + testModes(new CAST5Engine(), new CAST5Engine(), 16); + testModes(new RC2Engine(), new RC2Engine(), 16); + testModes(new XTEAEngine(), new XTEAEngine(), 16); + + testModes(new AESEngine(), new AESEngine(), 16); + testModes(new NoekeonEngine(), new NoekeonEngine(), 16); + testModes(new TwofishEngine(), new TwofishEngine(), 16); + testModes(new CAST6Engine(), new CAST6Engine(), 16); + testModes(new SEEDEngine(), new SEEDEngine(), 16); + testModes(new SerpentEngine(), new SerpentEngine(), 16); + testModes(new RC6Engine(), new RC6Engine(), 16); + testModes(new CamelliaEngine(), new CamelliaEngine(), 16); + testModes(new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), + new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), 64); + + testMode(new RC4Engine(), new KeyParameter(new byte[16])); + testMode(new Salsa20Engine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[8])); + testMode(new XSalsa20Engine(), new ParametersWithIV(new KeyParameter(new byte[32]), new byte[24])); + testMode(new ChaChaEngine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[8])); + testMode(new Grainv1Engine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[8])); + testMode(new Grain128Engine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[12])); + testMode(new HC128Engine(), new KeyParameter(new byte[16])); + testMode(new HC256Engine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + + testSkipping(new Salsa20Engine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[8])); + testSkipping(new SICBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + } + + private void testModes(BlockCipher cipher1, BlockCipher cipher2, int keySize) + throws Exception + { + final KeyParameter key = new KeyParameter(new byte[keySize]); + final int blockSize = getBlockSize(cipher1); + final CipherParameters withIv = new ParametersWithIV(key, new byte[blockSize]); + + if (blockSize > 1) + { + testMode(new PaddedBufferedBlockCipher(cipher1, new PKCS7Padding()), key); + + testMode(new PaddedBufferedBlockCipher(new CBCBlockCipher(cipher1), new PKCS7Padding()), withIv); + + testMode(new BufferedBlockCipher(new OFBBlockCipher(cipher1, blockSize)), withIv); + testMode(new BufferedBlockCipher(new CFBBlockCipher(cipher1, blockSize)), withIv); + testMode(new BufferedBlockCipher(new SICBlockCipher(cipher1)), withIv); + } + // CTS requires at least one block + if (blockSize <= 16 && streamSize >= blockSize) + { + testMode(new CTSBlockCipher(cipher1), key); + } + if (blockSize == 8 || blockSize == 16) + { + testMode(new EAXBlockCipher(cipher1), withIv); + } + if (blockSize == 16) + { + testMode(new CCMBlockCipher(cipher1), new ParametersWithIV(key, new byte[7])); + testMode(new GCMBlockCipher(cipher1), withIv); + testMode(new OCBBlockCipher(cipher1, cipher2), new ParametersWithIV(key, new byte[15])); + } + } + + private void testSkipping(StreamCipher cipher, CipherParameters params) + throws Exception + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + init(cipher, true, params); + + OutputStream cOut = createCipherOutputStream(bOut, cipher); + byte[] data = new byte[5000]; + + new SecureRandom().nextBytes(data); + + cOut.write(data); + + cOut.close(); + + init(cipher, false, params); + + InputStream cIn = createCipherInputStream(bOut.toByteArray(), cipher); + + long skip = cIn.skip(50); + if (skip != 50) + { + fail("wrong number of bytes skipped: " + skip); + } + + byte[] block = new byte[50]; + + cIn.read(block); + + if (!areEqual(data, 50, block, 0)) + { + fail("initial skip mismatch"); + } + + skip = cIn.skip(3000); + if (skip != 3000) + { + fail("wrong number of bytes skipped: " + skip); + } + + cIn.read(block); + + if (!areEqual(data, 3100, block, 0)) + { + fail("second skip mismatch"); + } + + cipher.reset(); + + cIn = createCipherInputStream(bOut.toByteArray(), cipher); + if (!cIn.markSupported()) + { + fail("marking not supported"); + } + + cIn.mark(100); + + cIn.read(block); + + if (!areEqual(data, 0, block, 0)) + { + fail("initial mark read failed"); + } + + cIn.reset(); + + cIn.read(block); + + if (!areEqual(data, 0, block, 0)) + { + fail(cipher.getAlgorithmName() + " initial reset read failed"); + } + + cIn.reset(); + + cIn.read(block); + + cIn.mark(100); + + cIn.read(block); + + if (!areEqual(data, 50, block, 0)) + { + fail("second mark read failed"); + } + + cIn.reset(); + + cIn.read(block); + + if (!areEqual(data, 50, block, 0)) + { + fail(cipher.getAlgorithmName() + " second reset read failed"); + } + + cIn.mark(3000); + + skip = cIn.skip(2050); + if (skip != 2050) + { + fail("wrong number of bytes skipped: " + skip); + } + + cIn.reset(); + + cIn.read(block); + + if (!areEqual(data, 100, block, 0)) + { + fail(cipher.getAlgorithmName() + " third reset read failed"); + } + + cIn.read(new byte[2150]); + + cIn.reset(); + + cIn.read(block); + + if (!areEqual(data, 100, block, 0)) + { + fail(cipher.getAlgorithmName() + " fourth reset read failed"); + } + + cIn.close(); + } + + private boolean areEqual(byte[] a, int aOff, byte[] b, int bOff) + { + for (int i = bOff; i != b.length; i++) + { + if (a[aOff + i - bOff] != b[i]) + { + return false; + } + } + + return true; + } + + public static void main(String[] args) + { + runTest(new CipherStreamTest()); + } + +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/CipherTest.java b/core/src/test/java/org/spongycastle/crypto/test/CipherTest.java new file mode 100644 index 00000000..6bd4c21f --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/CipherTest.java @@ -0,0 +1,117 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.test.SimpleTest; + +public abstract class CipherTest + extends SimpleTest +{ + private SimpleTest[] _tests; + private BlockCipher _engine; + private KeyParameter _validKey; + +// protected CipherTest( +// SimpleTest[] tests) +// { +// _tests = tests; +// } + + protected CipherTest( + SimpleTest[] tests, + BlockCipher engine, + KeyParameter validKey) + { + _tests = tests; + _engine = engine; + _validKey = validKey; + } + + public abstract String getName(); + + public void performTest() + throws Exception + { + for (int i = 0; i != _tests.length; i++) + { + _tests[i].performTest(); + } + + if (_engine != null) + { + // + // state tests + // + byte[] buf = new byte[128]; + + try + { + _engine.processBlock(buf, 0, buf, 0); + + fail("failed initialisation check"); + } + catch (IllegalStateException e) + { + // expected + } + + bufferSizeCheck((_engine)); + } + } + + private void bufferSizeCheck( + BlockCipher engine) + { + byte[] correctBuf = new byte[engine.getBlockSize()]; + byte[] shortBuf = new byte[correctBuf.length / 2]; + + engine.init(true, _validKey); + + try + { + engine.processBlock(shortBuf, 0, correctBuf, 0); + + fail("failed short input check"); + } + catch (DataLengthException e) + { + // expected + } + + try + { + engine.processBlock(correctBuf, 0, shortBuf, 0); + + fail("failed short output check"); + } + catch (DataLengthException e) + { + // expected + } + + engine.init(false, _validKey); + + try + { + engine.processBlock(shortBuf, 0, correctBuf, 0); + + fail("failed short input check"); + } + catch (DataLengthException e) + { + // expected + } + + try + { + engine.processBlock(correctBuf, 0, shortBuf, 0); + + fail("failed short output check"); + } + catch (DataLengthException e) + { + // expected + } + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/CramerShoupTest.java b/core/src/test/java/org/spongycastle/crypto/test/CramerShoupTest.java new file mode 100644 index 00000000..584fe9e1 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/CramerShoupTest.java @@ -0,0 +1,147 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.agreement.DHStandardGroups; +import org.spongycastle.crypto.engines.CramerShoupCiphertext; +import org.spongycastle.crypto.engines.CramerShoupCoreEngine; +import org.spongycastle.crypto.engines.CramerShoupCoreEngine.CramerShoupCiphertextException; +import org.spongycastle.crypto.generators.CramerShoupKeyPairGenerator; +import org.spongycastle.crypto.generators.CramerShoupParametersGenerator; +import org.spongycastle.crypto.params.CramerShoupKeyGenerationParameters; +import org.spongycastle.crypto.params.CramerShoupParameters; +import org.spongycastle.util.BigIntegers; +import org.spongycastle.util.test.SimpleTest; + +public class CramerShoupTest + extends SimpleTest +{ + private static final BigInteger ONE = BigInteger.valueOf(1); + + private static final SecureRandom RND = new SecureRandom(); + + private AsymmetricCipherKeyPair keyPair; + + public static void main(String[] args) + { + runTest(new CramerShoupTest()); + } + + public String getName() + { + return "CramerShoup"; + } + + + public void performTest() + throws Exception + { + BigInteger pSubOne = DHStandardGroups.rfc3526_2048.getP().subtract(ONE); + for (int i = 0; i < 10; ++i) + { + BigInteger message = BigIntegers.createRandomInRange(ONE, pSubOne, RND); + + BigInteger m1 = encDecTest(message); + BigInteger m2 = labelledEncDecTest(message, "myRandomLabel"); + BigInteger m3 = encDecEncodingTest(message); + BigInteger m4 = labelledEncDecEncodingTest(message, "myOtherCoolLabel"); + + if (!message.equals(m1) || !message.equals(m2) || !message.equals(m3) || !message.equals(m4)) + { + fail("decrypted message != original message"); + } + } + } + + private BigInteger encDecEncodingTest(BigInteger m) + { + CramerShoupCiphertext ciphertext = encrypt(m); + byte[] c = ciphertext.toByteArray(); + CramerShoupCiphertext decC = new CramerShoupCiphertext(c); + return decrypt(decC); + } + + private BigInteger labelledEncDecEncodingTest(BigInteger m, String l) + { + byte[] c = encrypt(m, l).toByteArray(); + return decrypt(new CramerShoupCiphertext(c), l); + } + + private BigInteger encDecTest(BigInteger m) + { + CramerShoupCiphertext c = encrypt(m); + return decrypt(c); + } + + private BigInteger labelledEncDecTest(BigInteger m, String l) + { + CramerShoupCiphertext c = encrypt(m, l); + return decrypt(c, l); + } + + + private BigInteger decrypt(CramerShoupCiphertext ciphertext) + { + return decrypt(ciphertext, null); + } + + private BigInteger decrypt(CramerShoupCiphertext ciphertext, String label) + { + + CramerShoupCoreEngine engine = new CramerShoupCoreEngine(); + if (label != null) + { + engine.init(false, keyPair.getPrivate(), label); + } + else + { + engine.init(false, keyPair.getPrivate()); + } + try + { + BigInteger m = engine.decryptBlock(ciphertext); + + return m; + } + catch (CramerShoupCiphertextException e) + { + e.printStackTrace(); + } + + return null; + } + + private CramerShoupCiphertext encrypt(BigInteger message) + { + return encrypt(message, null); + } + + private CramerShoupCiphertext encrypt(BigInteger message, String label) + { + CramerShoupKeyPairGenerator kpGen = new CramerShoupKeyPairGenerator(); + CramerShoupParametersGenerator pGen = new CramerShoupParametersGenerator(); + + pGen.init(2048, 1, RND); + CramerShoupParameters params = pGen.generateParameters(DHStandardGroups.rfc3526_2048); + CramerShoupKeyGenerationParameters param = new CramerShoupKeyGenerationParameters(RND, params); + + kpGen.init(param); + keyPair = kpGen.generateKeyPair(); + + CramerShoupCoreEngine engine = new CramerShoupCoreEngine(); + if (label != null) + { + engine.init(true, keyPair.getPublic(), label); + } + else + { + engine.init(true, keyPair.getPublic()); + } + + CramerShoupCiphertext ciphertext = engine.encryptBlock(message); + + return ciphertext; + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/DESTest.java b/core/src/test/java/org/spongycastle/crypto/test/DESTest.java new file mode 100644 index 00000000..aec63ef2 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/DESTest.java @@ -0,0 +1,206 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.KeyGenerationParameters; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.generators.DESKeyGenerator; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.modes.CFBBlockCipher; +import org.spongycastle.crypto.modes.OFBBlockCipher; +import org.spongycastle.crypto.params.DESParameters; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +import java.security.SecureRandom; + +class DESParityTest + extends SimpleTest +{ + public String getName() + { + return "DESParityTest"; + } + + public void performTest() + { + byte[] k1In = { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff }; + byte[] k1Out = { (byte)0xfe, (byte)0xfe, (byte)0xfe, (byte)0xfe, + (byte)0xfe, (byte)0xfe, (byte)0xfe, (byte)0xfe }; + + byte[] k2In = { (byte)0xef, (byte)0xcb, (byte)0xda, (byte)0x4f, + (byte)0xaa, (byte)0x99, (byte)0x7f, (byte)0x63 }; + byte[] k2Out = { (byte)0xef, (byte)0xcb, (byte)0xda, (byte)0x4f, + (byte)0xab, (byte)0x98, (byte)0x7f, (byte)0x62 }; + + DESParameters.setOddParity(k1In); + + for (int i = 0; i != k1In.length; i++) + { + if (k1In[i] != k1Out[i]) + { + fail("Failed " + + "got " + new String(Hex.encode(k1In)) + + " expected " + new String(Hex.encode(k1Out))); + } + } + + DESParameters.setOddParity(k2In); + + for (int i = 0; i != k2In.length; i++) + { + if (k2In[i] != k2Out[i]) + { + fail("Failed " + + "got " + new String(Hex.encode(k2In)) + + " expected " + new String(Hex.encode(k2Out))); + } + } + } +} + +class KeyGenTest + extends SimpleTest +{ + public String getName() + { + return "KeyGenTest"; + } + + public void performTest() + { + DESKeyGenerator keyGen = new DESKeyGenerator(); + + keyGen.init(new KeyGenerationParameters(new SecureRandom(), 56)); + + byte[] kB = keyGen.generateKey(); + + if (kB.length != 8) + { + fail("DES bit key wrong length."); + } + } +} + +class DESParametersTest + extends SimpleTest +{ + static private byte[] weakKeys = + { + (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, + (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e, + (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1, + (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, + /* semi-weak keys */ + (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, + (byte)0x1f,(byte)0xe0,(byte)0x1f,(byte)0xe0, (byte)0x0e,(byte)0xf1,(byte)0x0e,(byte)0xf1, + (byte)0x01,(byte)0xe0,(byte)0x01,(byte)0xe0, (byte)0x01,(byte)0xf1,(byte)0x01,(byte)0xf1, + (byte)0x1f,(byte)0xfe,(byte)0x1f,(byte)0xfe, (byte)0x0e,(byte)0xfe,(byte)0x0e,(byte)0xfe, + (byte)0x01,(byte)0x1f,(byte)0x01,(byte)0x1f, (byte)0x01,(byte)0x0e,(byte)0x01,(byte)0x0e, + (byte)0xe0,(byte)0xfe,(byte)0xe0,(byte)0xfe, (byte)0xf1,(byte)0xfe,(byte)0xf1,(byte)0xfe, + (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, + (byte)0xe0,(byte)0x1f,(byte)0xe0,(byte)0x1f, (byte)0xf1,(byte)0x0e,(byte)0xf1,(byte)0x0e, + (byte)0xe0,(byte)0x01,(byte)0xe0,(byte)0x01, (byte)0xf1,(byte)0x01,(byte)0xf1,(byte)0x01, + (byte)0xfe,(byte)0x1f,(byte)0xfe,(byte)0x1f, (byte)0xfe,(byte)0x0e,(byte)0xfe,(byte)0x0e, + (byte)0x1f,(byte)0x01,(byte)0x1f,(byte)0x01, (byte)0x0e,(byte)0x01,(byte)0x0e,(byte)0x01, + (byte)0xfe,(byte)0xe0,(byte)0xfe,(byte)0xe0, (byte)0xfe,(byte)0xf1,(byte)0xfe,(byte)0xf1 + }; + + public String getName() + { + return "DESParameters"; + } + + public void performTest() throws Exception + { + try + { + DESParameters.isWeakKey(new byte[4], 0); + fail("no exception on small key"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("key material too short.")) + { + fail("wrong exception"); + } + } + + try + { + new DESParameters(weakKeys); + fail("no exception on weak key"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("attempt to create weak DES key")) + { + fail("wrong exception"); + } + } + + for (int i = 0; i != weakKeys.length; i += 8) + { + if (!DESParameters.isWeakKey(weakKeys, i)) + { + fail("weakKey test failed"); + } + } + } +} + +/** + * DES tester - vectors from <a href=http://www.itl.nist.gov/fipspubs/fip81.htm>FIPS 81</a> + */ +public class DESTest + extends CipherTest +{ + static String input1 = "4e6f77206973207468652074696d6520666f7220616c6c20"; + static String input2 = "4e6f7720697320746865"; + static String input3 = "4e6f7720697320746865aabbcc"; + + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new DESEngine(), + new KeyParameter(Hex.decode("0123456789abcdef")), + input1, "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"), + new BlockCipherVectorTest(1, new CBCBlockCipher(new DESEngine()), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input1, "e5c7cdde872bf27c43e934008c389c0f683788499a7c05f6"), + new BlockCipherVectorTest(2, new CFBBlockCipher(new DESEngine(), 8), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input2, "f31fda07011462ee187f"), + new BlockCipherVectorTest(3, new CFBBlockCipher(new DESEngine(), 64), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input1, "f3096249c7f46e51a69e839b1a92f78403467133898ea622"), + new BlockCipherVectorTest(4, new OFBBlockCipher(new DESEngine(), 8), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input2, "f34a2850c9c64985d684"), + new BlockCipherVectorTest(5, new CFBBlockCipher(new DESEngine(), 64), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input3, "f3096249c7f46e51a69e0954bf"), + new BlockCipherVectorTest(6, new OFBBlockCipher(new DESEngine(), 64), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input3, "f3096249c7f46e5135f2c0eb8b"), + new DESParityTest(), + new DESParametersTest(), + new KeyGenTest() + }; + + public DESTest() + { + super(tests, new DESEngine(), new KeyParameter(new byte[8])); + } + + public String getName() + { + return "DES"; + } + + public static void main( + String[] args) + { + runTest(new DESTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/DESedeTest.java b/core/src/test/java/org/spongycastle/crypto/test/DESedeTest.java new file mode 100644 index 00000000..6fc4d0d0 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/DESedeTest.java @@ -0,0 +1,177 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.KeyGenerationParameters; +import org.spongycastle.crypto.Wrapper; +import org.spongycastle.crypto.engines.DESedeEngine; +import org.spongycastle.crypto.engines.DESedeWrapEngine; +import org.spongycastle.crypto.generators.DESedeKeyGenerator; +import org.spongycastle.crypto.params.DESedeParameters; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +import java.security.SecureRandom; + +/** + * DESede tester + */ +public class DESedeTest + extends CipherTest +{ + static private byte[] weakKey = // first 8 bytes non-weak + { + (byte)0x06,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, + (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e, + (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1, + }; + + static String input1 = "4e6f77206973207468652074696d6520666f7220616c6c20"; + static String input2 = "4e6f7720697320746865"; + + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new DESedeEngine(), + new DESedeParameters(Hex.decode("0123456789abcdef0123456789abcdef")), + input1, "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"), + new BlockCipherVectorTest(1, new DESedeEngine(), + new DESedeParameters(Hex.decode("0123456789abcdeffedcba9876543210")), + input1, "d80a0d8b2bae5e4e6a0094171abcfc2775d2235a706e232c"), + new BlockCipherVectorTest(2, new DESedeEngine(), + new DESedeParameters(Hex.decode("0123456789abcdef0123456789abcdef0123456789abcdef")), + input1, "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"), + new BlockCipherVectorTest(3, new DESedeEngine(), + new DESedeParameters(Hex.decode("0123456789abcdeffedcba98765432100123456789abcdef")), + input1, "d80a0d8b2bae5e4e6a0094171abcfc2775d2235a706e232c") + }; + + DESedeTest() + { + super(tests, new DESedeEngine(), new KeyParameter(new byte[16])); + } + + private void wrapTest( + int id, + byte[] kek, + byte[] iv, + byte[] in, + byte[] out) + { + Wrapper wrapper = new DESedeWrapEngine(); + + wrapper.init(true, new ParametersWithIV(new KeyParameter(kek), iv)); + + try + { + byte[] cText = wrapper.wrap(in, 0, in.length); + if (!areEqual(cText, out)) + { + fail(": failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + } + catch (Exception e) + { + fail("failed wrap test exception: " + e.toString(), e); + } + + wrapper.init(false, new KeyParameter(kek)); + + try + { + byte[] pText = wrapper.unwrap(out, 0, out.length); + if (!areEqual(pText, in)) + { + fail("failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText))); + } + } + catch (Exception e) + { + fail("failed unwrap test exception: " + e.toString(), e); + } + } + + public void performTest() + throws Exception + { + super.performTest(); + + byte[] kek1 = Hex.decode("255e0d1c07b646dfb3134cc843ba8aa71f025b7c0838251f"); + byte[] iv1 = Hex.decode("5dd4cbfc96f5453b"); + byte[] in1 = Hex.decode("2923bf85e06dd6ae529149f1f1bae9eab3a7da3d860d3e98"); + byte[] out1 = Hex.decode("690107618ef092b3b48ca1796b234ae9fa33ebb4159604037db5d6a84eb3aac2768c632775a467d4"); + + wrapTest(1, kek1, iv1, in1, out1); + + // + // key generation + // + SecureRandom random = new SecureRandom(); + DESedeKeyGenerator keyGen = new DESedeKeyGenerator(); + + keyGen.init(new KeyGenerationParameters(random, 112)); + + byte[] kB = keyGen.generateKey(); + + if (kB.length != 16) + { + fail("112 bit key wrong length."); + } + + keyGen.init(new KeyGenerationParameters(random, 168)); + + kB = keyGen.generateKey(); + + if (kB.length != 24) + { + fail("168 bit key wrong length."); + } + + try + { + keyGen.init(new KeyGenerationParameters(random, 200)); + + fail("invalid key length not detected."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + DESedeParameters.isWeakKey(new byte[4], 0); + fail("no exception on small key"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("key material too short.")) + { + fail("wrong exception"); + } + } + + try + { + new DESedeParameters(weakKey); + fail("no exception on weak key"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("attempt to create weak DESede key")) + { + fail("wrong exception"); + } + } + } + + public String getName() + { + return "DESede"; + } + + public static void main( + String[] args) + { + runTest(new DESedeTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/DHKEKGeneratorTest.java b/core/src/test/java/org/spongycastle/crypto/test/DHKEKGeneratorTest.java new file mode 100644 index 00000000..7a675739 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/DHKEKGeneratorTest.java @@ -0,0 +1,70 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.crypto.DerivationFunction; +import org.spongycastle.crypto.DerivationParameters; +import org.spongycastle.crypto.agreement.kdf.DHKDFParameters; +import org.spongycastle.crypto.agreement.kdf.DHKEKGenerator; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * DHKEK Generator tests - from RFC 2631. + */ +public class DHKEKGeneratorTest + extends SimpleTest +{ + private byte[] seed1 = Hex.decode("000102030405060708090a0b0c0d0e0f10111213"); + private ASN1ObjectIdentifier alg1 = PKCSObjectIdentifiers.id_alg_CMS3DESwrap; + private byte[] result1 = Hex.decode("a09661392376f7044d9052a397883246b67f5f1ef63eb5fb"); + + private byte[] seed2 = Hex.decode("000102030405060708090a0b0c0d0e0f10111213"); + private ASN1ObjectIdentifier alg2 = PKCSObjectIdentifiers.id_alg_CMSRC2wrap; + private byte[] partyAInfo = Hex.decode( + "0123456789abcdeffedcba9876543201" + + "0123456789abcdeffedcba9876543201" + + "0123456789abcdeffedcba9876543201" + + "0123456789abcdeffedcba9876543201"); + private byte[] result2 = Hex.decode("48950c46e0530075403cce72889604e0"); + + public DHKEKGeneratorTest() + { + } + + public void performTest() + { + checkMask(1, new DHKEKGenerator(new SHA1Digest()), new DHKDFParameters(alg1, 192, seed1), result1); + checkMask(2, new DHKEKGenerator(new SHA1Digest()), new DHKDFParameters(alg2, 128, seed2, partyAInfo), result2); + } + + private void checkMask( + int count, + DerivationFunction kdf, + DerivationParameters params, + byte[] result) + { + byte[] data = new byte[result.length]; + + kdf.init(params); + + kdf.generateBytes(data, 0, data.length); + + if (!areEqual(result, data)) + { + fail("DHKEKGenerator failed generator test " + count); + } + } + + public String getName() + { + return "DHKEKGenerator"; + } + + public static void main( + String[] args) + { + runTest(new DHKEKGeneratorTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/DHTest.java b/core/src/test/java/org/spongycastle/crypto/test/DHTest.java new file mode 100644 index 00000000..ce78961f --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/DHTest.java @@ -0,0 +1,414 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.agreement.DHAgreement; +import org.spongycastle.crypto.agreement.DHBasicAgreement; +import org.spongycastle.crypto.generators.DHBasicKeyPairGenerator; +import org.spongycastle.crypto.generators.DHKeyPairGenerator; +import org.spongycastle.crypto.generators.DHParametersGenerator; +import org.spongycastle.crypto.params.DHKeyGenerationParameters; +import org.spongycastle.crypto.params.DHParameters; +import org.spongycastle.crypto.params.DHPrivateKeyParameters; +import org.spongycastle.crypto.params.DHPublicKeyParameters; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.util.test.SimpleTest; + +public class DHTest + extends SimpleTest +{ + private BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + private BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + private BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16); + private BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16); + + private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16); + private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16); + + public String getName() + { + return "DH"; + } + + private void testDH( + int size, + BigInteger g, + BigInteger p) + { + DHKeyPairGenerator kpGen = getDHKeyPairGenerator(g, p); + + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + // + // generate second pair + // + pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.getPrivate(); + + // + // two way + // + DHAgreement e1 = new DHAgreement(); + DHAgreement e2 = new DHAgreement(); + + e1.init(pv1); + e2.init(pv2); + + BigInteger m1 = e1.calculateMessage(); + BigInteger m2 = e2.calculateMessage(); + + BigInteger k1 = e1.calculateAgreement(pu2, m2); + BigInteger k2 = e2.calculateAgreement(pu1, m1); + + if (!k1.equals(k2)) + { + fail(size + " bit 2-way test failed"); + } + } + + private void testDHBasic( + int size, + int privateValueSize, + BigInteger g, + BigInteger p) + { + DHBasicKeyPairGenerator kpGen = getDHBasicKeyPairGenerator(g, p, privateValueSize); + + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + + checkKeySize(privateValueSize, pv1); + // + // generate second pair + // + pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.getPrivate(); + + checkKeySize(privateValueSize, pv2); + // + // two way + // + DHBasicAgreement e1 = new DHBasicAgreement(); + DHBasicAgreement e2 = new DHBasicAgreement(); + + e1.init(pv1); + e2.init(pv2); + + BigInteger k1 = e1.calculateAgreement(pu2); + BigInteger k2 = e2.calculateAgreement(pu1); + + if (!k1.equals(k2)) + { + fail("basic " + size + " bit 2-way test failed"); + } + } + + private void checkKeySize( + int privateValueSize, + DHPrivateKeyParameters priv) + { + if (privateValueSize != 0) + { + if (priv.getX().bitLength() != privateValueSize) + { + fail("limited key check failed for key size " + privateValueSize); + } + } + } + + private void testGPWithRandom( + DHKeyPairGenerator kpGen) + { + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + // + // generate second pair + // + pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.getPrivate(); + + // + // two way + // + DHAgreement e1 = new DHAgreement(); + DHAgreement e2 = new DHAgreement(); + + e1.init(new ParametersWithRandom(pv1, new SecureRandom())); + e2.init(new ParametersWithRandom(pv2, new SecureRandom())); + + BigInteger m1 = e1.calculateMessage(); + BigInteger m2 = e2.calculateMessage(); + + BigInteger k1 = e1.calculateAgreement(pu2, m2); + BigInteger k2 = e2.calculateAgreement(pu1, m1); + + if (!k1.equals(k2)) + { + fail("basic with random 2-way test failed"); + } + } + + private void testSimpleWithRandom( + DHBasicKeyPairGenerator kpGen) + { + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + // + // generate second pair + // + pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.getPrivate(); + + // + // two way + // + DHBasicAgreement e1 = new DHBasicAgreement(); + DHBasicAgreement e2 = new DHBasicAgreement(); + + e1.init(new ParametersWithRandom(pv1, new SecureRandom())); + e2.init(new ParametersWithRandom(pv2, new SecureRandom())); + + BigInteger k1 = e1.calculateAgreement(pu2); + BigInteger k2 = e2.calculateAgreement(pu1); + + if (!k1.equals(k2)) + { + fail("basic with random 2-way test failed"); + } + } + + private DHBasicKeyPairGenerator getDHBasicKeyPairGenerator( + BigInteger g, + BigInteger p, + int privateValueSize) + { + DHParameters dhParams = new DHParameters(p, g, null, privateValueSize); + DHKeyGenerationParameters params = new DHKeyGenerationParameters(new SecureRandom(), dhParams); + DHBasicKeyPairGenerator kpGen = new DHBasicKeyPairGenerator(); + + kpGen.init(params); + + return kpGen; + } + + private DHKeyPairGenerator getDHKeyPairGenerator( + BigInteger g, + BigInteger p) + { + DHParameters dhParams = new DHParameters(p, g); + DHKeyGenerationParameters params = new DHKeyGenerationParameters(new SecureRandom(), dhParams); + DHKeyPairGenerator kpGen = new DHKeyPairGenerator(); + + kpGen.init(params); + + return kpGen; + } + + /** + * this test is can take quiet a while + */ + private void testGeneration( + int size) + { + DHParametersGenerator pGen = new DHParametersGenerator(); + + pGen.init(size, 10, new SecureRandom()); + + DHParameters dhParams = pGen.generateParameters(); + + if (dhParams.getL() != 0) + { + fail("DHParametersGenerator failed to set J to 0 in generated DHParameters"); + } + + DHKeyGenerationParameters params = new DHKeyGenerationParameters(new SecureRandom(), dhParams); + + DHBasicKeyPairGenerator kpGen = new DHBasicKeyPairGenerator(); + + kpGen.init(params); + + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + + // + // generate second pair + // + params = new DHKeyGenerationParameters(new SecureRandom(), pu1.getParameters()); + + kpGen.init(params); + + pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.getPrivate(); + + // + // two way + // + DHBasicAgreement e1 = new DHBasicAgreement(); + DHBasicAgreement e2 = new DHBasicAgreement(); + + e1.init(new ParametersWithRandom(pv1, new SecureRandom())); + e2.init(new ParametersWithRandom(pv2, new SecureRandom())); + + BigInteger k1 = e1.calculateAgreement(pu2); + BigInteger k2 = e2.calculateAgreement(pu1); + + if (!k1.equals(k2)) + { + fail("basic with " + size + " bit 2-way test failed"); + } + } + private void testBounds() + { + BigInteger p1 = new BigInteger("00C8028E9151C6B51BCDB35C1F6B2527986A72D8546AE7A4BF41DC4289FF9837EE01592D36C324A0F066149B8B940C86C87D194206A39038AE3396F8E12435BB74449B70222D117B8A2BB77CB0D67A5D664DDE7B75E0FEC13CE0CAF258DAF3ADA0773F6FF0F2051D1859929AAA53B07809E496B582A89C3D7DA8B6E38305626621", 16); + BigInteger g1 = new BigInteger("1F869713181464577FE4026B47102FA0D7675503A4FCDA810881FAEC3524E6DBAEA9B96561EF7F8BEA76466DF11C2F3EB1A90CC5851735BF860606481257EECE6418C0204E61004E85D7131CE54BCBC7AD67E53C79DCB715E7C8D083DCD85D728283EC8F96839B4C9FA7C0727C472BEB94E4613CAFA8D580119C0AF4BF8AF252", 16); + int l1 = 1023; + + BigInteger p2 = new BigInteger("00B333C98720220CC3946F494E25231B3E19F9AD5F6B19F4E7ABF80D8826C491C3224D4F7415A14A7C11D1BE584405FED12C3554F103E56A72D986CA5E325BB9DE07AC37D1EAE5E5AC724D32EF638F0E4462D4C1FC7A45B9FD3A5DF5EC36A1FA4DAA3FBB66AA42B1B71DF416AB547E987513426C7BB8634F5F4D37705514FDC1E1", 16); + BigInteger g2 = new BigInteger("2592F5A99FE46313650CCE66C94C15DBED9F4A45BD05C329986CF5D3E12139F0405A47C6385FEA27BFFEDC4CBABC5BB151F3BEE7CC3D51567F1E2B12A975AA9F48A70BDAAE7F5B87E70ADCF902490A3CBEFEDA41EBA8E12E02B56120B5FDEFBED07F5EAD3AE020DF3C8233216F8F0D35E13A7AE4DA5CBCC0D91EADBF20C281C6", 16); + int l2 = 1024; + + DHKeyGenerationParameters params1 = new DHKeyGenerationParameters(new SecureRandom(), new DHParameters(p1, g1, null, l1)); + DHKeyGenerationParameters params2 = new DHKeyGenerationParameters(new SecureRandom(), new DHParameters(p2, g2, null, l2)); + + DHBasicKeyPairGenerator kpGen = new DHBasicKeyPairGenerator(); + + kpGen.init(params1); + kpGen.init(params2); + } + + public void performTest() + { + testDHBasic(512, 0, g512, p512); + testDHBasic(768, 0, g768, p768); + testDHBasic(1024, 0, g1024, p1024); + + testDHBasic(512, 64, g512, p512); + testDHBasic(768, 128, g768, p768); + testDHBasic(1024, 256, g1024, p1024); + + testDH(512, g512, p512); + testDH(768, g768, p768); + testDH(1024, g1024, p1024); + + testBounds(); + + // + // generation test. + // + testGeneration(256); + + // + // with random test + // + DHBasicKeyPairGenerator kpBasicGen = getDHBasicKeyPairGenerator(g512, p512, 0); + + testSimpleWithRandom(kpBasicGen); + + DHKeyPairGenerator kpGen = getDHKeyPairGenerator(g512, p512); + + testGPWithRandom(kpGen); + + // + // parameter tests + // + DHAgreement dh = new DHAgreement(); + AsymmetricCipherKeyPair dhPair = kpGen.generateKeyPair(); + + try + { + dh.init(dhPair.getPublic()); + fail("DHAgreement key check failed"); + } + catch (IllegalArgumentException e) + { + // ignore + } + + DHKeyPairGenerator kpGen768 = getDHKeyPairGenerator(g768, p768); + + try + { + dh.init(dhPair.getPrivate()); + + dh.calculateAgreement((DHPublicKeyParameters)kpGen768.generateKeyPair().getPublic(), BigInteger.valueOf(100)); + + fail("DHAgreement agreement check failed"); + } + catch (IllegalArgumentException e) + { + // ignore + } + + DHBasicAgreement dhBasic = new DHBasicAgreement(); + AsymmetricCipherKeyPair dhBasicPair = kpBasicGen.generateKeyPair(); + + try + { + dhBasic.init(dhBasicPair.getPublic()); + fail("DHBasicAgreement key check failed"); + } + catch (IllegalArgumentException e) + { + // expected + } + + DHBasicKeyPairGenerator kpBasicGen768 = getDHBasicKeyPairGenerator(g768, p768, 0); + + try + { + dhBasic.init(dhPair.getPrivate()); + + dhBasic.calculateAgreement((DHPublicKeyParameters)kpBasicGen768.generateKeyPair().getPublic()); + + fail("DHBasicAgreement agreement check failed"); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + public static void main( + String[] args) + { + runTest(new DHTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/DSATest.java b/core/src/test/java/org/spongycastle/crypto/test/DSATest.java new file mode 100644 index 00000000..3d91dee9 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/DSATest.java @@ -0,0 +1,602 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.digests.SHA224Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.generators.DSAKeyPairGenerator; +import org.spongycastle.crypto.generators.DSAParametersGenerator; +import org.spongycastle.crypto.params.DSAKeyGenerationParameters; +import org.spongycastle.crypto.params.DSAParameterGenerationParameters; +import org.spongycastle.crypto.params.DSAParameters; +import org.spongycastle.crypto.params.DSAPrivateKeyParameters; +import org.spongycastle.crypto.params.DSAPublicKeyParameters; +import org.spongycastle.crypto.params.DSAValidationParameters; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.crypto.signers.DSASigner; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.BigIntegers; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.FixedSecureRandom; +import org.spongycastle.util.test.SimpleTest; + +/** + * Test based on FIPS 186-2, Appendix 5, an example of DSA, and FIPS 168-3 test vectors. + */ +public class DSATest + extends SimpleTest +{ + byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); + byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); + + SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2}); + + byte[] keyData = Hex.decode("b5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); + + SecureRandom keyRandom = new FixedSecureRandom(new byte[][] { keyData, keyData }); + + BigInteger pValue = new BigInteger("8df2a494492276aa3d25759bb06869cbeac0d83afb8d0cf7cbb8324f0d7882e5d0762fc5b7210eafc2e9adac32ab7aac49693dfbf83724c2ec0736ee31c80291", 16); + BigInteger qValue = new BigInteger("c773218c737ec8ee993b4f2ded30f48edace915f", 16); + + public String getName() + { + return "DSA"; + } + + public void performTest() + { + BigInteger r = new BigInteger("68076202252361894315274692543577577550894681403"); + BigInteger s = new BigInteger("1089214853334067536215539335472893651470583479365"); + DSAParametersGenerator pGen = new DSAParametersGenerator(); + + pGen.init(512, 80, random); + + DSAParameters params = pGen.generateParameters(); + DSAValidationParameters pValid = params.getValidationParameters(); + + if (pValid.getCounter() != 105) + { + fail("Counter wrong"); + } + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + fail("p or q wrong"); + } + + DSAKeyPairGenerator dsaKeyGen = new DSAKeyPairGenerator(); + DSAKeyGenerationParameters genParam = new DSAKeyGenerationParameters(keyRandom, params); + + dsaKeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = dsaKeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), keyRandom); + + DSASigner dsa = new DSASigner(); + + dsa.init(true, param); + + byte[] message = BigIntegers.asUnsignedByteArray(new BigInteger("968236873715988614170569073515315707566766479517")); + BigInteger[] sig = dsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong.", r, sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong.", s, sig[1]); + } + + dsa.init(false, pair.getPublic()); + + if (!dsa.verifySignature(message, sig[0], sig[1])) + { + fail("verification fails"); + } + + dsa2Test1(); + dsa2Test2(); + dsa2Test3(); + dsa2Test4(); + } + + private void dsa2Test1() + { + byte[] seed = Hex.decode("ED8BEE8D1CB89229D2903CBF0E51EE7377F48698"); + + DSAParametersGenerator pGen = new DSAParametersGenerator(); + + pGen.init(new DSAParameterGenerationParameters(1024, 160, 80, new DSATestSecureRandom(seed))); + + DSAParameters params = pGen.generateParameters(); + + DSAValidationParameters pv = params.getValidationParameters(); + + if (pv.getCounter() != 5) + { + fail("counter incorrect"); + } + + if (!Arrays.areEqual(seed, pv.getSeed())) + { + fail("seed incorrect"); + } + + if (!params.getQ().equals(new BigInteger("E950511EAB424B9A19A2AEB4E159B7844C589C4F", 16))) + { + fail("Q incorrect"); + } + + if (!params.getP().equals(new BigInteger( + "E0A67598CD1B763B" + + "C98C8ABB333E5DDA0CD3AA0E5E1FB5BA8A7B4EABC10BA338" + + "FAE06DD4B90FDA70D7CF0CB0C638BE3341BEC0AF8A7330A3" + + "307DED2299A0EE606DF035177A239C34A912C202AA5F83B9" + + "C4A7CF0235B5316BFC6EFB9A248411258B30B839AF172440" + + "F32563056CB67A861158DDD90E6A894C72A5BBEF9E286C6B", 16))) + { + fail("P incorrect"); + } + + if (!params.getG().equals(new BigInteger( + "D29D5121B0423C27" + + "69AB21843E5A3240FF19CACC792264E3BB6BE4F78EDD1B15" + + "C4DFF7F1D905431F0AB16790E1F773B5CE01C804E509066A" + + "9919F5195F4ABC58189FD9FF987389CB5BEDF21B4DAB4F8B" + + "76A055FFE2770988FE2EC2DE11AD92219F0B351869AC24DA" + + "3D7BA87011A701CE8EE7BFE49486ED4527B7186CA4610A75", 16))) + { + fail("G incorrect"); + } + + DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); + + kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("D0EC4E50BB290A42E9E355C73D8809345DE2E139")), params)); + + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic(); + DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate(); + + if (!pub.getY().equals(new BigInteger( + "25282217F5730501" + + "DD8DBA3EDFCF349AAFFEC20921128D70FAC44110332201BB" + + "A3F10986140CBB97C726938060473C8EC97B4731DB004293" + + "B5E730363609DF9780F8D883D8C4D41DED6A2F1E1BBBDC97" + + "9E1B9D6D3C940301F4E978D65B19041FCF1E8B518F5C0576" + + "C770FE5A7A485D8329EE2914A2DE1B5DA4A6128CEAB70F79", 16))) + { + fail("Y value incorrect"); + } + + if (!priv.getX().equals( + new BigInteger("D0EC4E50BB290A42E9E355C73D8809345DE2E139", 16))) + { + fail("X value incorrect"); + } + + DSASigner signer = new DSASigner(); + + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("349C55648DCF992F3F33E8026CFAC87C1D2BA075")))); + + byte[] msg = Hex.decode("A9993E364706816ABA3E25717850C26C9CD0D89D"); + + BigInteger[] sig = signer.generateSignature(msg); + + if (!sig[0].equals(new BigInteger("636155AC9A4633B4665D179F9E4117DF68601F34", 16))) + { + fail("R value incorrect"); + } + + if (!sig[1].equals(new BigInteger("6C540B02D9D4852F89DF8CFC99963204F4347704", 16))) + { + fail("S value incorrect"); + } + + signer.init(false, kp.getPublic()); + + if (!signer.verifySignature(msg, sig[0], sig[1])) + { + fail("signature not verified"); + } + + } + + private void dsa2Test2() + { + byte[] seed = Hex.decode("5AFCC1EFFC079A9CCA6ECA86D6E3CC3B18642D9BE1CC6207C84002A9"); + + DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA224Digest()); + + pGen.init(new DSAParameterGenerationParameters(2048, 224, 80, new DSATestSecureRandom(seed))); + + DSAParameters params = pGen.generateParameters(); + + DSAValidationParameters pv = params.getValidationParameters(); + + if (pv.getCounter() != 21) + { + fail("counter incorrect"); + } + + if (!Arrays.areEqual(seed, pv.getSeed())) + { + fail("seed incorrect"); + } + + if (!params.getQ().equals(new BigInteger("90EAF4D1AF0708B1B612FF35E0A2997EB9E9D263C9CE659528945C0D", 16))) + { + fail("Q incorrect"); + } + + if (!params.getP().equals(new BigInteger( + "C196BA05AC29E1F9C3C72D56DFFC6154" + + "A033F1477AC88EC37F09BE6C5BB95F51C296DD20D1A28A06" + + "7CCC4D4316A4BD1DCA55ED1066D438C35AEBAABF57E7DAE4" + + "28782A95ECA1C143DB701FD48533A3C18F0FE23557EA7AE6" + + "19ECACC7E0B51652A8776D02A425567DED36EABD90CA33A1" + + "E8D988F0BBB92D02D1D20290113BB562CE1FC856EEB7CDD9" + + "2D33EEA6F410859B179E7E789A8F75F645FAE2E136D252BF" + + "FAFF89528945C1ABE705A38DBC2D364AADE99BE0D0AAD82E" + + "5320121496DC65B3930E38047294FF877831A16D5228418D" + + "E8AB275D7D75651CEFED65F78AFC3EA7FE4D79B35F62A040" + + "2A1117599ADAC7B269A59F353CF450E6982D3B1702D9CA83", 16))) + { + fail("P incorrect"); + } + + if (!params.getG().equals(new BigInteger( + "A59A749A11242C58C894E9E5A91804E8"+ + "FA0AC64B56288F8D47D51B1EDC4D65444FECA0111D78F35F"+ + "C9FDD4CB1F1B79A3BA9CBEE83A3F811012503C8117F98E50"+ + "48B089E387AF6949BF8784EBD9EF45876F2E6A5A495BE64B"+ + "6E770409494B7FEE1DBB1E4B2BC2A53D4F893D418B715959"+ + "2E4FFFDF6969E91D770DAEBD0B5CB14C00AD68EC7DC1E574"+ + "5EA55C706C4A1C5C88964E34D09DEB753AD418C1AD0F4FDF"+ + "D049A955E5D78491C0B7A2F1575A008CCD727AB376DB6E69"+ + "5515B05BD412F5B8C2F4C77EE10DA48ABD53F5DD498927EE"+ + "7B692BBBCDA2FB23A516C5B4533D73980B2A3B60E384ED20"+ + "0AE21B40D273651AD6060C13D97FD69AA13C5611A51B9085", 16))) + { + fail("G incorrect"); + } + + DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); + + kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17")), params)); + + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic(); + DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate(); + + if (!pub.getY().equals(new BigInteger( + "70035C9A3B225B258F16741F3941FBF0" + + "6F3D056CD7BD864604CBB5EE9DD85304EE8E8E4ABD5E9032" + + "11DDF25CE149075510ACE166970AFDC7DF552B7244F342FA" + + "02F7A621405B754909D757F97290E1FE5036E904CF593446" + + "0C046D95659821E1597ED9F2B1F0E20863A6BBD0CE74DACB" + + "A5D8C68A90B29C2157CDEDB82EC12B81EE3068F9BF5F7F34" + + "6ECA41ED174CCCD7D154FA4F42F80FFE1BF46AE9D8125DEB" + + "5B4BA08A72BDD86596DBEDDC9550FDD650C58F5AE5133509" + + "A702F79A31ECB490F7A3C5581631F7C5BE4FF7F9E9F27FA3" + + "90E47347AD1183509FED6FCF198BA9A71AB3335B4F38BE8D" + + "15496A00B6DC2263E20A5F6B662320A3A1EC033AA61E3B68", 16))) + { + fail("Y value incorrect"); + } + + if (!priv.getX().equals( + new BigInteger("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17", 16))) + { + fail("X value incorrect"); + } + + DSASigner signer = new DSASigner(); + + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("735959CC4463B8B440E407EECA8A473BF6A6D1FE657546F67D401F05")))); + + byte[] msg = Hex.decode("23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); + + BigInteger[] sig = signer.generateSignature(msg); + + if (!sig[0].equals(new BigInteger("4400138D05F9639CAF54A583CAAF25D2B76D0C3EAD752CE17DBC85FE", 16))) + { + fail("R value incorrect"); + } + + if (!sig[1].equals(new BigInteger("874D4F12CB13B61732D398445698CFA9D92381D938AA57EE2C9327B3", 16))) + { + fail("S value incorrect"); + } + + signer.init(false, kp.getPublic()); + + if (!signer.verifySignature(msg, sig[0], sig[1])) + { + fail("signature not verified"); + } + } + + private void dsa2Test3() + { + byte[] seed = Hex.decode("4783081972865EA95D43318AB2EAF9C61A2FC7BBF1B772A09017BDF5A58F4FF0"); + + DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA256Digest()); + + pGen.init(new DSAParameterGenerationParameters(2048, 256, 80, new DSATestSecureRandom(seed))); + + DSAParameters params = pGen.generateParameters(); + + DSAValidationParameters pv = params.getValidationParameters(); + + if (pv.getCounter() != 12) + { + fail("counter incorrect"); + } + + if (!Arrays.areEqual(seed, pv.getSeed())) + { + fail("seed incorrect"); + } + + if (!params.getQ().equals(new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16))) + { + fail("Q incorrect"); + } + + if (!params.getP().equals(new BigInteger( + "F56C2A7D366E3EBDEAA1891FD2A0D099" + + "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" + + "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" + + "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" + + "5909132627F51A0C866877E672E555342BDF9355347DBD43" + + "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" + + "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" + + "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" + + "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" + + "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" + + "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16))) + { + fail("P incorrect"); + } + + if (!params.getG().equals(new BigInteger( + "8DC6CC814CAE4A1C05A3E186A6FE27EA" + + "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" + + "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" + + "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" + + "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" + + "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" + + "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" + + "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" + + "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" + + "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" + + "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16))) + { + fail("G incorrect"); + } + + DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); + + kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), params)); + + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic(); + DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate(); + + if (!pub.getY().equals(new BigInteger( + "2828003D7C747199143C370FDD07A286" + + "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" + + "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" + + "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" + + "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" + + "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" + + "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" + + "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" + + "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" + + "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" + + "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16))) + { + fail("Y value incorrect"); + } + + if (!priv.getX().equals( + new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16))) + { + fail("X value incorrect"); + } + + DSASigner signer = new DSASigner(); + + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")))); + + byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"); + + BigInteger[] sig = signer.generateSignature(msg); + + if (!sig[0].equals(new BigInteger("315C875DCD4850E948B8AC42824E9483A32D5BA5ABE0681B9B9448D444F2BE3C", 16))) + { + fail("R value incorrect"); + } + + if (!sig[1].equals(new BigInteger("89718D12E54A8D9ED066E4A55F7ED5A2229CD23B9A3CEE78F83ED6AA61F6BCB9", 16))) + { + fail("S value incorrect"); + } + + signer.init(false, kp.getPublic()); + + if (!signer.verifySignature(msg, sig[0], sig[1])) + { + fail("signature not verified"); + } + } + + private void dsa2Test4() + { + byte[] seed = Hex.decode("193AFCA7C1E77B3C1ECC618C81322E47B8B8B997C9C83515C59CC446C2D9BD47"); + + DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA256Digest()); + + pGen.init(new DSAParameterGenerationParameters(3072, 256, 80, new DSATestSecureRandom(seed))); + + DSAParameters params = pGen.generateParameters(); + + DSAValidationParameters pv = params.getValidationParameters(); + + if (pv.getCounter() != 20) + { + fail("counter incorrect"); + } + + if (!Arrays.areEqual(seed, pv.getSeed())) + { + fail("seed incorrect"); + } + + if (!params.getQ().equals(new BigInteger("CFA0478A54717B08CE64805B76E5B14249A77A4838469DF7F7DC987EFCCFB11D", 16))) + { + fail("Q incorrect"); + } + + if (!params.getP().equals(new BigInteger( + "90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD610" + + "37E56258A7795A1C7AD46076982CE6BB956936C6AB4DCFE0" + + "5E6784586940CA544B9B2140E1EB523F009D20A7E7880E4E" + + "5BFA690F1B9004A27811CD9904AF70420EEFD6EA11EF7DA1" + + "29F58835FF56B89FAA637BC9AC2EFAAB903402229F491D8D" + + "3485261CD068699B6BA58A1DDBBEF6DB51E8FE34E8A78E54" + + "2D7BA351C21EA8D8F1D29F5D5D15939487E27F4416B0CA63" + + "2C59EFD1B1EB66511A5A0FBF615B766C5862D0BD8A3FE7A0" + + "E0DA0FB2FE1FCB19E8F9996A8EA0FCCDE538175238FC8B0E" + + "E6F29AF7F642773EBE8CD5402415A01451A840476B2FCEB0" + + "E388D30D4B376C37FE401C2A2C2F941DAD179C540C1C8CE0" + + "30D460C4D983BE9AB0B20F69144C1AE13F9383EA1C08504F" + + "B0BF321503EFE43488310DD8DC77EC5B8349B8BFE97C2C56" + + "0EA878DE87C11E3D597F1FEA742D73EEC7F37BE43949EF1A" + + "0D15C3F3E3FC0A8335617055AC91328EC22B50FC15B941D3" + + "D1624CD88BC25F3E941FDDC6200689581BFEC416B4B2CB73", 16))) + { + fail("P incorrect"); + } + + if (!params.getG().equals(new BigInteger( + "5E5CBA992E0A680D885EB903AEA78E4A45A469103D448EDE" + + "3B7ACCC54D521E37F84A4BDD5B06B0970CC2D2BBB715F7B8" + + "2846F9A0C393914C792E6A923E2117AB805276A975AADB52" + + "61D91673EA9AAFFEECBFA6183DFCB5D3B7332AA19275AFA1" + + "F8EC0B60FB6F66CC23AE4870791D5982AAD1AA9485FD8F4A" + + "60126FEB2CF05DB8A7F0F09B3397F3937F2E90B9E5B9C9B6" + + "EFEF642BC48351C46FB171B9BFA9EF17A961CE96C7E7A7CC" + + "3D3D03DFAD1078BA21DA425198F07D2481622BCE45969D9C" + + "4D6063D72AB7A0F08B2F49A7CC6AF335E08C4720E31476B6" + + "7299E231F8BD90B39AC3AE3BE0C6B6CACEF8289A2E2873D5" + + "8E51E029CAFBD55E6841489AB66B5B4B9BA6E2F784660896" + + "AFF387D92844CCB8B69475496DE19DA2E58259B090489AC8" + + "E62363CDF82CFD8EF2A427ABCD65750B506F56DDE3B98856" + + "7A88126B914D7828E2B63A6D7ED0747EC59E0E0A23CE7D8A" + + "74C1D2C2A7AFB6A29799620F00E11C33787F7DED3B30E1A2" + + "2D09F1FBDA1ABBBFBF25CAE05A13F812E34563F99410E73B", 16))) + { + fail("G incorrect"); + } + + DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); + + kpGen.init(new DSAKeyGenerationParameters(new FixedSecureRandom(Hex.decode("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764")), params)); + + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic(); + DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate(); + + if (!pub.getY().equals(new BigInteger( + "8B891C8692D3DE875879390F2698B26FBECCA6B075535DCE" + + "6B0C862577F9FA0DEF6074E7A7624121224A595896ABD4CD" + + "A56B2CEFB942E025D2A4282FFAA98A48CDB47E1A6FCB5CFB" + + "393EF35AF9DF913102BB303C2B5C36C3F8FC04ED7B8B69FE" + + "FE0CF3E1FC05CFA713B3435B2656E913BA8874AEA9F93600" + + "6AEB448BCD005D18EC3562A33D04CF25C8D3D69844343442" + + "FA3DB7DE618C5E2DA064573E61E6D5581BFB694A23AC87FD" + + "5B52D62E954E1376DB8DDB524FFC0D469DF978792EE44173" + + "8E5DB05A7DC43E94C11A2E7A4FBE383071FA36D2A7EC8A93" + + "88FE1C4F79888A99D3B6105697C2556B79BB4D7E781CEBB3" + + "D4866AD825A5E830846072289FDBC941FA679CA82F5F78B7" + + "461B2404DB883D215F4E0676CF5493950AC5591697BFEA8D" + + "1EE6EC016B89BA51CAFB5F9C84C989FA117375E94578F28B" + + "E0B34CE0545DA46266FD77F62D8F2CEE92AB77012AFEBC11" + + "008985A821CD2D978C7E6FE7499D1AAF8DE632C21BB48CA5" + + "CBF9F31098FD3FD3854C49A65D9201744AACE540354974F9", 16))) + { + fail("Y value incorrect"); + } + + if (!priv.getX().equals( + new BigInteger("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764", 16))) + { + fail("X value incorrect"); + } + + DSASigner signer = new DSASigner(); + + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom(Hex.decode("A6902C1E6E3943C5628061588A8B007BCCEA91DBF12915483F04B24AB0678BEE")))); + + byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"); + + BigInteger[] sig = signer.generateSignature(msg); + + if (!sig[0].equals(new BigInteger("5F184E645A38BE8FB4A6871B6503A9D12924C7ABE04B71410066C2ECA6E3BE3E", 16))) + { + fail("R value incorrect"); + } + + if (!sig[1].equals(new BigInteger("91EB0C7BA3D4B9B60B825C3D9F2CADA8A2C9D7723267B033CBCDCF8803DB9C18", 16))) + { + fail("S value incorrect"); + } + + signer.init(false, kp.getPublic()); + + if (!signer.verifySignature(msg, sig[0], sig[1])) + { + fail("signature not verified"); + } + } + + public static void main( + String[] args) + { + runTest(new DSATest()); + } + + private class DSATestSecureRandom + extends FixedSecureRandom + { + private boolean first = true; + + public DSATestSecureRandom(byte[] value) + { + super(value); + } + + public void nextBytes(byte[] bytes) + { + if (first) + { + super.nextBytes(bytes); + first = false; + } + else + { + bytes[bytes.length - 1] = 2; + } + } + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/DSTU4145Test.java b/core/src/test/java/org/spongycastle/crypto/test/DSTU4145Test.java new file mode 100644 index 00000000..43d27f09 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/DSTU4145Test.java @@ -0,0 +1,278 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.params.ECDomainParameters; +import org.spongycastle.crypto.params.ECPrivateKeyParameters; +import org.spongycastle.crypto.params.ECPublicKeyParameters; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.crypto.signers.DSTU4145Signer; +import org.spongycastle.math.ec.ECCurve; +import org.spongycastle.math.ec.ECPoint; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.FixedSecureRandom; +import org.spongycastle.util.test.SimpleTest; + +public class DSTU4145Test + extends SimpleTest +{ + private static final BigInteger ZERO = BigInteger.valueOf(0); + private static final BigInteger ONE = BigInteger.valueOf(1); + + public static void main(String[] args) + { + runTest(new DSTU4145Test()); + } + + public String getName() + { + return "DSTU4145"; + } + + private void test163() + throws Exception + { + SecureRandom random = new FixedSecureRandom(Hex.decode("01025e40bd97db012b7a1d79de8e12932d247f61c6")); + + byte[] hash = Hex.decode("09c9c44277910c9aaee486883a2eb95b7180166ddf73532eeb76edaef52247ff"); + for (int i = 0; i < hash.length / 2; i++) + { + byte tmp = hash[i]; + hash[i] = hash[hash.length - 1 - i]; + hash[hash.length - 1 - i] = tmp; + } + + BigInteger r = new BigInteger("274ea2c0caa014a0d80a424f59ade7a93068d08a7", 16); + BigInteger s = new BigInteger("2100d86957331832b8e8c230f5bd6a332b3615aca", 16); + + ECCurve.F2m curve = new ECCurve.F2m(163, 3, 6, 7, ONE, new BigInteger("5FF6108462A2DC8210AB403925E638A19C1455D21", 16)); + ECPoint P = curve.createPoint(new BigInteger("72d867f93a93ac27df9ff01affe74885c8c540420", 16), new BigInteger("0224a9c3947852b97c5599d5f4ab81122adc3fd9b", 16)); + BigInteger n = new BigInteger("400000000000000000002BEC12BE2262D39BCF14D", 16); + + BigInteger d = new BigInteger("183f60fdf7951ff47d67193f8d073790c1c9b5a3e", 16); + ECPoint Q = P.multiply(d).negate(); + + ECDomainParameters domain = new ECDomainParameters(curve, P, n); + CipherParameters privKey = new ParametersWithRandom(new ECPrivateKeyParameters(d, domain), random); + ECPublicKeyParameters pubKey = new ECPublicKeyParameters(Q, domain); + + DSTU4145Signer dstuSigner = new DSTU4145Signer(); + dstuSigner.init(true, privKey); + BigInteger[] rs = dstuSigner.generateSignature(hash); + + if (rs[0].compareTo(r) != 0) + { + fail("r component wrong"); + } + + if (rs[1].compareTo(s) != 0) + { + fail("s component wrong"); + } + + dstuSigner.init(false, pubKey); + if (!dstuSigner.verifySignature(hash, r, s)) + { + fail("verification fails"); + } + } + + private void test173() + throws Exception + { + SecureRandom random = new FixedSecureRandom(Hex.decode("0000137449348C1249971759D99C252FFE1E14D8B31F")); + + byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8"); + for (int i = 0; i < hash.length / 2; i++) + { + byte tmp = hash[i]; + hash[i] = hash[hash.length - 1 - i]; + hash[hash.length - 1 - i] = tmp; + } + + BigInteger r = new BigInteger("13ae89746386709cdbd237cc5ec20ca30004a82ead8", 16); + BigInteger s = new BigInteger("3597912cdd093b3e711ccb74a79d3c4ab4c7cccdc60", 16); + + ECCurve.F2m curve = new ECCurve.F2m(173, 1, 2, 10, ZERO, new BigInteger("108576C80499DB2FC16EDDF6853BBB278F6B6FB437D9", 16)); + ECPoint P = curve.createPoint(new BigInteger("BE6628EC3E67A91A4E470894FBA72B52C515F8AEE9", 16), new BigInteger("D9DEEDF655CF5412313C11CA566CDC71F4DA57DB45C", 16)); + BigInteger n = new BigInteger("800000000000000000000189B4E67606E3825BB2831", 16); + + BigInteger d = new BigInteger("955CD7E344303D1034E66933DC21C8044D42ADB8", 16); + ECPoint Q = P.multiply(d).negate(); + + ECDomainParameters domain = new ECDomainParameters(curve, P, n); + CipherParameters privKey = new ParametersWithRandom(new ECPrivateKeyParameters(d, domain), random); + ECPublicKeyParameters pubKey = new ECPublicKeyParameters(Q, domain); + + DSTU4145Signer dstuSigner = new DSTU4145Signer(); + dstuSigner.init(true, privKey); + BigInteger[] rs = dstuSigner.generateSignature(hash); + + if (rs[0].compareTo(r) != 0) + { + fail("r component wrong"); + } + + if (rs[1].compareTo(s) != 0) + { + fail("s component wrong"); + } + + dstuSigner.init(false, pubKey); + if (!dstuSigner.verifySignature(hash, r, s)) + { + fail("verification fails"); + } + } + + private void test283() + throws Exception + { + SecureRandom random = new FixedSecureRandom(Hex.decode("00000000245383CB3AD41BF30F5F7E8FBA858509B2D5558C92D539A6D994BFA98BC6940E")); + + byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8"); + for (int i = 0; i < hash.length / 2; i++) + { + byte tmp = hash[i]; + hash[i] = hash[hash.length - 1 - i]; + hash[hash.length - 1 - i] = tmp; + } + + BigInteger r = new BigInteger("12a5edcc38d92208ff23036d75b000c7e4bc0f9af2d40b35f15d6fd15e01234e67781a8", 16); + BigInteger s = new BigInteger("2de0775577f75b643cf5afc80d4fe10b21100690f17e2cab7bdc9b50ec87c5727aeb515", 16); + + ECCurve.F2m curve = new ECCurve.F2m(283, 5, 7, 12, ONE, new BigInteger("27B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5", 16)); + ECPoint P = curve.createPoint(new BigInteger("4D95820ACE761110824CE425C8089129487389B7F0E0A9D043DDC0BB0A4CC9EB25", 16), new BigInteger("954C9C4029B2C62DE35C2B9C2A164984BF1101951E3A68ED03DF234DDE5BB2013152F2", 16)); + BigInteger n = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", 16); + + BigInteger d = new BigInteger("B844EEAF15213E4BAD4FB84796D68F2448DB8EB7B4621EC0D51929874892C43E", 16); + ECPoint Q = P.multiply(d).negate(); + + ECDomainParameters domain = new ECDomainParameters(curve, P, n); + CipherParameters privKey = new ParametersWithRandom(new ECPrivateKeyParameters(d, domain), random); + ECPublicKeyParameters pubKey = new ECPublicKeyParameters(Q, domain); + + DSTU4145Signer dstuSigner = new DSTU4145Signer(); + dstuSigner.init(true, privKey); + BigInteger[] rs = dstuSigner.generateSignature(hash); + + if (rs[0].compareTo(r) != 0) + { + fail("r component wrong"); + } + + if (rs[1].compareTo(s) != 0) + { + fail("s component wrong"); + } + + dstuSigner.init(false, pubKey); + if (!dstuSigner.verifySignature(hash, r, s)) + { + fail("verification fails"); + } + } + + private void test431() + throws Exception + { + SecureRandom random = new FixedSecureRandom(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457")); + + byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8"); + for (int i = 0; i < hash.length / 2; i++) + { + byte tmp = hash[i]; + hash[i] = hash[hash.length - 1 - i]; + hash[hash.length - 1 - i] = tmp; + } + + BigInteger r = new BigInteger("1911fefb1f494bebcf8dffdf5276946ff9c9f662192ee18c718db47310a439c784fe07577b16e1edbe16179876e0792a634f1c9c3a2e", 16); + BigInteger s = new BigInteger("3852170ee801c2083c52f1ea77b987a5432acecd9c654f064e87bf179e0a397151edbca430082e43bd38a67b55424b5bbc7f2713f620", 16); + + ECCurve.F2m curve = new ECCurve.F2m(431, 1, 3, 5, ONE, new BigInteger("3CE10490F6A708FC26DFE8C3D27C4F94E690134D5BFF988D8D28AAEAEDE975936C66BAC536B18AE2DC312CA493117DAA469C640CAF3", 16)); + ECPoint P = curve.createPoint(new BigInteger("9548BCDF314CEEEAF099C780FFEFBF93F9FE5B5F55547603C9C8FC1A2774170882B3BE35E892C6D4296B8DEA282EC30FB344272791", 16), new BigInteger("4C6CBD7C62A8EEEFDE17A8B5E196E49A22CE6DE128ABD9FBD81FA4411AD5A38E2A810BEDE09A7C6226BCDCB4A4A5DA37B4725E00AA74", 16)); + BigInteger n = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA3175458009A8C0A724F02F81AA8A1FCBAF80D90C7A95110504CF", 16); + + BigInteger d = new BigInteger("D0F97354E314191FD773E2404F478C8AEE0FF5109F39E6F37D1FEEC8B2ED1691D84C9882CC729E716A71CC013F66CAC60E29E22C", 16); + ECPoint Q = P.multiply(d).negate(); + + ECDomainParameters domain = new ECDomainParameters(curve, P, n); + CipherParameters privKey = new ParametersWithRandom(new ECPrivateKeyParameters(d, domain), random); + ECPublicKeyParameters pubKey = new ECPublicKeyParameters(Q, domain); + + DSTU4145Signer dstuSigner = new DSTU4145Signer(); + dstuSigner.init(true, privKey); + BigInteger[] rs = dstuSigner.generateSignature(hash); + + if (rs[0].compareTo(r) != 0) + { + fail("r component wrong"); + } + + if (rs[1].compareTo(s) != 0) + { + fail("s component wrong"); + } + + dstuSigner.init(false, pubKey); + if (!dstuSigner.verifySignature(hash, r, s)) + { + fail("verification fails"); + } + } + + private void testTruncation() + { + SecureRandom random = new FixedSecureRandom(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457")); + + // use extra long "hash" with set bits... + byte[] hash = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + + ECCurve.F2m curve = new ECCurve.F2m(173, 1, 2, 10, ZERO, new BigInteger("108576C80499DB2FC16EDDF6853BBB278F6B6FB437D9", 16)); + ECPoint P = curve.createPoint(new BigInteger("BE6628EC3E67A91A4E470894FBA72B52C515F8AEE9", 16), new BigInteger("D9DEEDF655CF5412313C11CA566CDC71F4DA57DB45C", 16)); + BigInteger n = new BigInteger("800000000000000000000189B4E67606E3825BB2831", 16); + + BigInteger d = new BigInteger("955CD7E344303D1034E66933DC21C8044D42ADB8", 16); + ECPoint Q = P.multiply(d).negate(); + + ECDomainParameters domain = new ECDomainParameters(curve, P, n); + CipherParameters privKey = new ParametersWithRandom(new ECPrivateKeyParameters(d, domain), random); + ECPublicKeyParameters pubKey = new ECPublicKeyParameters(Q, domain); + + DSTU4145Signer dstuSigner = new DSTU4145Signer(); + dstuSigner.init(true, privKey); + BigInteger[] rs = dstuSigner.generateSignature(hash); + + BigInteger r = new BigInteger("6bb5c0cb82e5067485458ebfe81025f03b687c63a27", 16); + BigInteger s = new BigInteger("34d6b1868969b86ecf934167c8fe352c63d1074bd", 16); + + if (rs[0].compareTo(r) != 0) + { + fail("r component wrong"); + } + + if (rs[1].compareTo(s) != 0) + { + fail("s component wrong"); + } + + dstuSigner.init(false, pubKey); + if (!dstuSigner.verifySignature(hash, rs[0], rs[1])) + { + fail("verification fails"); + } + } + + public void performTest() + throws Exception + { + test163(); + test173(); + test283(); + test431(); + testTruncation(); + } + +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/DeterministicDSATest.java b/core/src/test/java/org/spongycastle/crypto/test/DeterministicDSATest.java new file mode 100644 index 00000000..e5f61ec2 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/DeterministicDSATest.java @@ -0,0 +1,513 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; + +import org.spongycastle.asn1.nist.NISTNamedCurves; +import org.spongycastle.asn1.x9.X9ECParameters; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.DSA; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA224Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.digests.SHA384Digest; +import org.spongycastle.crypto.digests.SHA512Digest; +import org.spongycastle.crypto.params.DSAParameters; +import org.spongycastle.crypto.params.DSAPrivateKeyParameters; +import org.spongycastle.crypto.params.ECDomainParameters; +import org.spongycastle.crypto.params.ECPrivateKeyParameters; +import org.spongycastle.crypto.signers.DSASigner; +import org.spongycastle.crypto.signers.ECDSASigner; +import org.spongycastle.crypto.signers.HMacDSAKCalculator; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Tests are taken from RFC 6979 - "Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)" + */ +public class DeterministicDSATest + extends SimpleTest +{ + + public static final byte[] SAMPLE = Hex.decode("73616d706c65"); // "sample" + public static final byte[] TEST = Hex.decode("74657374"); // "test" + + // test vectors from appendix in RFC 6979 + private void testHMacDeterministic() + { + DSAParameters dsaParameters = new DSAParameters( + new BigInteger("86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447" + + "E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88" + + "73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C" + + "881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779", 16), + new BigInteger("996F967F6C8E388D9E28D01E205FBA957A5698B1", 16), + new BigInteger("07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D" + + "89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD" + + "87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4" + + "17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD", 16)); + + DSAPrivateKeyParameters privKey = new DSAPrivateKeyParameters(new BigInteger("411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", 16), dsaParameters); + + doTestHMACDetDSASample(new SHA1Digest(), privKey, new BigInteger("2E1A0C2562B2912CAAF89186FB0F42001585DA55", 16), new BigInteger("29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5", 16)); + doTestHMACDetDSASample(new SHA224Digest(), privKey, new BigInteger("4BC3B686AEA70145856814A6F1BB53346F02101E", 16), new BigInteger("410697B92295D994D21EDD2F4ADA85566F6F94C1", 16)); + doTestHMACDetDSASample(new SHA256Digest(), privKey, new BigInteger("81F2F5850BE5BC123C43F71A3033E9384611C545", 16), new BigInteger("4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89", 16)); + doTestHMACDetDSASample(new SHA384Digest(), privKey, new BigInteger("07F2108557EE0E3921BC1774F1CA9B410B4CE65A", 16), new BigInteger("54DF70456C86FAC10FAB47C1949AB83F2C6F7595", 16)); + doTestHMACDetDSASample(new SHA512Digest(), privKey, new BigInteger("16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B", 16), new BigInteger("02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C", 16)); + + doTestHMACDetDSATest(new SHA1Digest(), privKey, new BigInteger("42AB2052FD43E123F0607F115052A67DCD9C5C77", 16), new BigInteger("183916B0230D45B9931491D4C6B0BD2FB4AAF088", 16)); + doTestHMACDetDSATest(new SHA224Digest(), privKey, new BigInteger("6868E9964E36C1689F6037F91F28D5F2C30610F2", 16), new BigInteger("49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F", 16)); + doTestHMACDetDSATest(new SHA256Digest(), privKey, new BigInteger("22518C127299B0F6FDC9872B282B9E70D0790812", 16), new BigInteger("6837EC18F150D55DE95B5E29BE7AF5D01E4FE160", 16)); + doTestHMACDetDSATest(new SHA384Digest(), privKey, new BigInteger("854CF929B58D73C3CBFDC421E8D5430CD6DB5E66", 16), new BigInteger("91D0E0F53E22F898D158380676A871A157CDA622", 16)); + doTestHMACDetDSATest(new SHA512Digest(), privKey, new BigInteger("8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0", 16), new BigInteger("7C670C7AD72B6C050C109E1790008097125433E8", 16)); + + dsaParameters = new DSAParameters( + new BigInteger("9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" + + "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" + + "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" + + "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" + + "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" + + "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" + + "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" + + "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", 16), + new BigInteger("F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", 16), + new BigInteger("5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" + + "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" + + "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" + + "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" + + "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" + + "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" + + "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" + + "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", 16)); + + privKey = new DSAPrivateKeyParameters(new BigInteger("69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC", 16), dsaParameters); + + doTestHMACDetDSASample(new SHA1Digest(), privKey, new BigInteger("3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A", 16), new BigInteger("D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF", 16)); + doTestHMACDetDSASample(new SHA224Digest(), privKey, new BigInteger("DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C", 16), new BigInteger("A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC", 16)); + doTestHMACDetDSASample(new SHA256Digest(), privKey, new BigInteger("EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809", 16), new BigInteger("7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53", 16)); + doTestHMACDetDSASample(new SHA384Digest(), privKey, new BigInteger("B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B", 16), new BigInteger("19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B", 16)); + doTestHMACDetDSASample(new SHA512Digest(), privKey, new BigInteger("2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E", 16), new BigInteger("D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351", 16)); + + doTestHMACDetDSATest(new SHA1Digest(), privKey, new BigInteger("C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0", 16), new BigInteger("414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA", 16)); + doTestHMACDetDSATest(new SHA224Digest(), privKey, new BigInteger("272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3", 16), new BigInteger("E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806", 16)); + doTestHMACDetDSATest(new SHA256Digest(), privKey, new BigInteger("8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0", 16), new BigInteger("7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E", 16)); + doTestHMACDetDSATest(new SHA384Digest(), privKey, new BigInteger("239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE", 16), new BigInteger("6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961", 16)); + doTestHMACDetDSATest(new SHA512Digest(), privKey, new BigInteger("89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307", 16), new BigInteger("C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1", 16)); + } + + private void doTestHMACDetDSASample(Digest digest, DSAPrivateKeyParameters privKey, BigInteger r, BigInteger s) + { + doTestHMACDetECDSA(new DSASigner(new HMacDSAKCalculator(digest)), digest, SAMPLE, privKey, r, s); + } + + private void doTestHMACDetDSATest(Digest digest, DSAPrivateKeyParameters privKey, BigInteger r, BigInteger s) + { + doTestHMACDetECDSA(new DSASigner(new HMacDSAKCalculator(digest)), digest, TEST, privKey, r, s); + } + + // test vectors from appendix in RFC 6979 + private void testECHMacDeterministic() + { + X9ECParameters x9ECParameters = NISTNamedCurves.getByName("P-192"); + ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(new BigInteger("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("98C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF", 16), new BigInteger("57A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("A1F00DAD97AEEC91C95585F36200C65F3C01812AA60378F5", 16), new BigInteger("E07EC1304C7C6C9DEBBE980B9692668F81D4DE7922A0F97A", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55", 16), new BigInteger("CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("DA63BF0B9ABCF948FBB1E9167F136145F7A20426DCC287D5", 16), new BigInteger("C3AA2C960972BD7A2003A57E1C4C77F0578F8AE95E31EC5E", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8", 16), new BigInteger("3F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("0F2141A0EBBC44D2E1AF90A50EBCFCE5E197B3B7D4DE036D", 16), new BigInteger("EB18BC9E1F3D7387500CB99CF5F7C157070A8961E38700B7", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("6945A1C1D1B2206B8145548F633BB61CEF04891BAF26ED34", 16), new BigInteger("B7FB7FDFC339C0B9BD61A9F5A8EAF9BE58FC5CBA2CB15293", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE", 16), new BigInteger("5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("B234B60B4DB75A733E19280A7A6034BD6B1EE88AF5332367", 16), new BigInteger("7994090B2D59BB782BE57E74A44C9A1C700413F8ABEFE77A", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("FE4F4AE86A58B6507946715934FE2D8FF9D95B6B098FE739", 16), new BigInteger("74CF5605C98FBA0E1EF34D4B5A1577A7DCF59457CAE52290", 16)); + + x9ECParameters = NISTNamedCurves.getByName("P-224"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("F220266E1105BFE3083E03EC7A3A654651F45E37167E88600BF257C1", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("22226F9D40A96E19C4A301CE5B74B115303C0F3A4FD30FC257FB57AC", 16), new BigInteger("66D1CDD83E3AF75605DD6E2FEFF196D30AA7ED7A2EDF7AF475403D69", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("1CDFE6662DDE1E4A1EC4CDEDF6A1F5A2FB7FBD9145C12113E6ABFD3E", 16), new BigInteger("A6694FD7718A21053F225D3F46197CA699D45006C06F871808F43EBC", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("61AA3DA010E8E8406C656BC477A7A7189895E7E840CDFE8FF42307BA", 16), new BigInteger("BC814050DAB5D23770879494F9E0A680DC1AF7161991BDE692B10101", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("0B115E5E36F0F9EC81F1325A5952878D745E19D7BB3EABFABA77E953", 16), new BigInteger("830F34CCDFE826CCFDC81EB4129772E20E122348A2BBD889A1B1AF1D", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("074BD1D979D5F32BF958DDC61E4FB4872ADCAFEB2256497CDAC30397", 16), new BigInteger("A4CECA196C3D5A1FF31027B33185DC8EE43F288B21AB342E5D8EB084", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("DEAA646EC2AF2EA8AD53ED66B2E2DDAA49A12EFD8356561451F3E21C", 16), new BigInteger("95987796F6CF2062AB8135271DE56AE55366C045F6D9593F53787BD2", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("C441CE8E261DED634E4CF84910E4C5D1D22C5CF3B732BB204DBEF019", 16), new BigInteger("902F42847A63BDC5F6046ADA114953120F99442D76510150F372A3F4", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("AD04DDE87B84747A243A631EA47A1BA6D1FAA059149AD2440DE6FBA6", 16), new BigInteger("178D49B1AE90E3D8B629BE3DB5683915F4E8C99FDF6E666CF37ADCFD", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("389B92682E399B26518A95506B52C03BC9379A9DADF3391A21FB0EA4", 16), new BigInteger("414A718ED3249FF6DBC5B50C27F71F01F070944DA22AB1F78F559AAB", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("049F050477C5ADD858CAC56208394B5A55BAEBBE887FDF765047C17C", 16), new BigInteger("077EB13E7005929CEFA3CD0403C7CDCC077ADF4E44F3C41B2F60ECFF", 16)); + + x9ECParameters = NISTNamedCurves.getByName("P-256"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("61340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D32", 16), new BigInteger("6D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("53B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3F", 16), new BigInteger("B9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716", 16), new BigInteger("F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("0EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF7719", 16), new BigInteger("4861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F00", 16), new BigInteger("2362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("0CBCC86FD6ABD1D99E703E1EC50069EE5C0B4BA4B9AC60E409E8EC5910D81A89", 16), new BigInteger("01B9D7B73DFAA60D5651EC4591A0136F87653E0FD780C3B1BC872FFDEAE479B1", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("C37EDB6F0AE79D47C3C27E962FA269BB4F441770357E114EE511F662EC34A692", 16), new BigInteger("C820053A05791E521FCAAD6042D40AEA1D6B1A540138558F47D0719800E18F2D", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367", 16), new BigInteger("019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("83910E8B48BB0C74244EBDF7F07A1C5413D61472BD941EF3920E623FBCCEBEB6", 16), new BigInteger("8DDBEC54CF8CD5874883841D712142A56A8D0F218F5003CB0296B6B509619F2C", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("461D93F31B6540894788FD206C07CFA0CC35F46FA3C91816FFF1040AD1581A04", 16), new BigInteger("39AF9F15DE0DB8D97E72719C74820D304CE5226E32DEDAE67519E840D1194E55", 16)); + + x9ECParameters = NISTNamedCurves.getByName("P-384"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D8" + + "96D5724E4C70A825F872C9EA60D2EDF5", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA3" + + "7B9BA002899F6FDA3A4A9386790D4EB2", 16), + new BigInteger("A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF" + + "26F49CA031D4857570CCB5CA4424A443", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("42356E76B55A6D9B4631C865445DBE54E056D3B3431766D0509244793C3F9366" + + "450F76EE3DE43F5A125333A6BE060122", 16), + new BigInteger("9DA0C81787064021E78DF658F2FBB0B042BF304665DB721F077A4298B095E483" + + "4C082C03D83028EFBF93A3C23940CA8D", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("21B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33" + + "BDE1E888E63355D92FA2B3C36D8FB2CD", 16), + new BigInteger("F3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEB" + + "EFDC63ECCD1AC42EC0CB8668A4FA0AB0", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C" + + "81A648152E44ACF96E36DD1E80FABE46", 16), + new BigInteger("99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94F" + + "A329C145786E679E7B82C71A38628AC8", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799C" + + "FE30F35CC900056D7C99CD7882433709", 16), + new BigInteger("512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112" + + "DC7CC3EF3446DEFCEB01A45C2667FDD5", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("4BC35D3A50EF4E30576F58CD96CE6BF638025EE624004A1F7789A8B8E43D0678" + + "ACD9D29876DAF46638645F7F404B11C7", 16), + new BigInteger("D5A6326C494ED3FF614703878961C0FDE7B2C278F9A65FD8C4B7186201A29916" + + "95BA1C84541327E966FA7B50F7382282", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("E8C9D0B6EA72A0E7837FEA1D14A1A9557F29FAA45D3E7EE888FC5BF954B5E624" + + "64A9A817C47FF78B8C11066B24080E72", 16), + new BigInteger("07041D4A7A0379AC7232FF72E6F77B6DDB8F09B16CCE0EC3286B2BD43FA8C614" + + "1C53EA5ABEF0D8231077A04540A96B66", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("6D6DEFAC9AB64DABAFE36C6BF510352A4CC27001263638E5B16D9BB51D451559" + + "F918EEDAF2293BE5B475CC8F0188636B", 16), + new BigInteger("2D46F3BECBCC523D5F1A1256BF0C9B024D879BA9E838144C8BA6BAEB4B53B47D" + + "51AB373F9845C0514EEFB14024787265", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB" + + "0542A7F0812998DA8F1DD3CA3CF023DB", 16), + new BigInteger("DDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E0" + + "6A739F040649A667BF3B828246BAA5A5", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("A0D5D090C9980FAF3C2CE57B7AE951D31977DD11C775D314AF55F76C676447D0" + + "6FB6495CD21B4B6E340FC236584FB277", 16), + new BigInteger("976984E59B4C77B0E8E4460DCA3D9F20E07B9BB1F63BEEFAF576F6B2E8B22463" + + "4A2092CD3792E0159AD9CEE37659C736", 16)); + + x9ECParameters = NISTNamedCurves.getByName("P-521"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75C" + + "AA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83" + + "538", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("0343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910" + + "FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D" + + "75D", 16), + new BigInteger("0E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D" + + "5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5" + + "D16", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("1776331CFCDF927D666E032E00CF776187BC9FDD8E69D0DABB4109FFE1B5E2A3" + + "0715F4CC923A4A5E94D2503E9ACFED92857B7F31D7152E0F8C00C15FF3D87E2E" + + "D2E", 16), + new BigInteger("050CB5265417FE2320BBB5A122B8E1A32BD699089851128E360E620A30C7E17B" + + "A41A666AF126CE100E5799B153B60528D5300D08489CA9178FB610A2006C254B" + + "41F", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("1511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659" + + "D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E" + + "1A7", 16), + new BigInteger("04A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916" + + "E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7E" + + "CFC", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("1EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4" + + "B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C67" + + "451", 16), + new BigInteger("1F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5" + + "FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65" + + "D61", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("0C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F1" + + "74E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E37" + + "7FA", 16), + new BigInteger("0617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF2" + + "82623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A" + + "67A", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("13BAD9F29ABE20DE37EBEB823C252CA0F63361284015A3BF430A46AAA80B87B0" + + "693F0694BD88AFE4E661FC33B094CD3B7963BED5A727ED8BD6A3A202ABE009D0" + + "367", 16), + new BigInteger("1E9BB81FF7944CA409AD138DBBEE228E1AFCC0C890FC78EC8604639CB0DBDC90" + + "F717A99EAD9D272855D00162EE9527567DD6A92CBD629805C0445282BBC91679" + + "7FF", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("1C7ED902E123E6815546065A2C4AF977B22AA8EADDB68B2C1110E7EA44D42086" + + "BFE4A34B67DDC0E17E96536E358219B23A706C6A6E16BA77B65E1C595D43CAE1" + + "7FB", 16), + new BigInteger("177336676304FCB343CE028B38E7B4FBA76C1C1B277DA18CAD2A8478B2A9A9F5" + + "BEC0F3BA04F35DB3E4263569EC6AADE8C92746E4C82F8299AE1B8F1739F8FD51" + + "9A4", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("00E871C4A14F993C6C7369501900C4BC1E9C7B0B4BA44E04868B30B41D807104" + + "2EB28C4C250411D0CE08CD197E4188EA4876F279F90B3D8D74A3C76E6F1E4656" + + "AA8", 16), + new BigInteger("0CD52DBAA33B063C3A6CD8058A1FB0A46A4754B034FCC644766CA14DA8CA5CA9" + + "FDE00E88C1AD60CCBA759025299079D7A427EC3CC5B619BFBC828E7769BCD694" + + "E86", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("14BEE21A18B6D8B3C93FAB08D43E739707953244FDBE924FA926D76669E7AC8C" + + "89DF62ED8975C2D8397A65A49DCC09F6B0AC62272741924D479354D74FF60755" + + "78C", 16), + new BigInteger("133330865C067A0EAF72362A65E2D7BC4E461E8C8995C3B6226A21BD1AA78F0E" + + "D94FE536A0DCA35534F0CD1510C41525D163FE9D74D134881E35141ED5E8E95B" + + "979", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("13E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10" + + "CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47E" + + "E6D", 16), + new BigInteger("1FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78" + + "A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4D" + + "CE3", 16)); + + x9ECParameters = NISTNamedCurves.getByName("B-163"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("35318FC447D48D7E6BC93B48617DDDEDF26AA658F", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("153FEBD179A69B6122DEBF5BC61EB947B24C93526", 16), new BigInteger("37AC9C670F8CF18045049BAE7DD35553545C19E49", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("0A379E69C44F9C16EA3215EA39EB1A9B5D58CC955", 16), new BigInteger("04BAFF5308DA2A7FE2C1742769265AD3ED1D24E74", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("134E00F78FC1CB9501675D91C401DE20DDF228CDC", 16), new BigInteger("373273AEC6C36CB7BAFBB1903A5F5EA6A1D50B624", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("29430B935AF8E77519B0CA4F6903B0B82E6A21A66", 16), new BigInteger("1EA1415306E9353FA5AA54BC7C2581DFBB888440D", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("0B2F177A99F9DF2D51CCAF55F015F326E4B65E7A0", 16), new BigInteger("0DF1FB4487E9B120C5E970EFE48F55E406306C3A1", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("256D4079C6C7169B8BC92529D701776A269D56308", 16), new BigInteger("341D3FFEC9F1EB6A6ACBE88E3C86A1C8FDEB8B8E1", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("28ECC6F1272CE80EA59DCF32F7AC2D861BA803393", 16), new BigInteger("0AD4AE2C06E60183C1567D2B82F19421FE3053CE2", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("227DF377B3FA50F90C1CB3CDCBBDBA552C1D35104", 16), new BigInteger("1F7BEAD92583FE920D353F368C1960D0E88B46A56", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("11811DAFEEA441845B6118A0DFEE8A0061231337D", 16), new BigInteger("36258301865EE48C5C6F91D63F62695002AB55B57", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("3B6BB95CA823BE2ED8E3972FF516EB8972D765571", 16), new BigInteger("13DC6F420628969DF900C3FCC48220B38BE24A541", 16)); + + x9ECParameters = NISTNamedCurves.getByName("B-233"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("07ADC13DD5BF34D1DDEEB50B2CE23B5F5E6D18067306D60C5F6FF11E5D3", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("015CC6FD78BB06E0878E71465515EA5A21A2C18E6FC77B4B158DBEB3944", 16), new BigInteger("0822A4A6C2EB2DF213A5E90BF40377956365EE8C4B4A5A4E2EB9270CB6A", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("05D9920B53471148E10502AB49AB7A3F11084820A074FD89883CF51BC1A", 16), new BigInteger("04D3938900C0A9AAA7080D1DFEB56CFB0FADABE4214536C7ED5117ED13A", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("0A797F3B8AEFCE7456202DF1E46CCC291EA5A49DA3D4BDDA9A4B62D5E0D", 16), new BigInteger("01F6F81DA55C22DA4152134C661588F4BD6F82FDBAF0C5877096B070DC2", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("015E85A8D46225DD7E314A1C4289731FC14DECE949349FE535D11043B85", 16), new BigInteger("03F189D37F50493EFD5111A129443A662AB3C6B289129AD8C0CAC85119C", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("03B62A4BF783919098B1E42F496E65F7621F01D1D466C46940F0F132A95", 16), new BigInteger("0F4BE031C6E5239E7DAA014CBBF1ED19425E49DAEB426EC9DF4C28A2E30", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("02F1FEDC57BE203E4C8C6B8C1CEB35E13C1FCD956AB41E3BD4C8A6EFB1F", 16), new BigInteger("05738EC8A8EDEA8E435EE7266AD3EDE1EEFC2CEBE2BE1D614008D5D2951", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("0CCE175124D3586BA7486F7146894C65C2A4A5A1904658E5C7F9DF5FA5D", 16), new BigInteger("08804B456D847ACE5CA86D97BF79FD6335E5B17F6C0D964B5D0036C867E", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("035C3D6DFEEA1CFB29B93BE3FDB91A7B130951770C2690C16833A159677", 16), new BigInteger("0600F7301D12AB376B56D4459774159ADB51F97E282FF384406AFD53A02", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("061602FC8068BFD5FB86027B97455D200EC603057446CCE4D76DB8EF42C", 16), new BigInteger("03396DD0D59C067BB999B422D9883736CF9311DFD6951F91033BD03CA8D", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("07E12CB60FDD614958E8E34B3C12DDFF35D85A9C5800E31EA2CC2EF63B1", 16), new BigInteger("0E8970FD99D836F3CC1C807A2C58760DE6EDAA23705A82B9CB1CE93FECC", 16)); + + x9ECParameters = NISTNamedCurves.getByName("B-283"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("14510D4BC44F2D26F4553942C98073C1BD35545CEABB5CC138853C5158D2729EA408836", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("201E18D48C6DB3D5D097C4DCE1E25587E1501FC3CF47BDB5B4289D79E273D6A9" + + "ACB8285", 16), new BigInteger("151AE05712B024CE617358260774C8CA8B0E7A7E72EF8229BF2ACE7609560CB3" + + "0322C4F", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("143E878DDFD4DF40D97B8CD638B3C4706501C2201CF7108F2FB91478C11D6947" + + "3246925", 16), new BigInteger("0CBF1B9717FEEA3AABB09D9654110144267098E0E1E8D0289A6211BE0EEDFDD8" + + "6A3DB79", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("29FD82497FB3E5CEF65579272138DE59E2B666B8689466572B3B69A172CEE83B" + + "E145659", 16), new BigInteger("05A89D9166B40795AF0FE5958201B9C0523E500013CA12B4840EA2BC53F25F9B" + + "3CE87C0", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("2F00689C1BFCD2A8C7A41E0DE55AE182E6463A152828EF89FE3525139B660329" + + "4E69353", 16), new BigInteger("1744514FE0A37447250C8A329EAAADA81572226CABA16F39270EE5DD03F27B1F" + + "665EB5D", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("0DA43A9ADFAA6AD767998A054C6A8F1CF77A562924628D73C62761847AD8286E" + + "0D91B47", 16), new BigInteger("1D118733AE2C88357827CAFC6F68ABC25C80C640532925E95CFE66D40F8792F3" + + "AC44C42", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("05A408133919F2CDCDBE5E4C14FBC706C1F71BADAFEF41F5DE4EC27272FC1CA9" + + "366FBB2", 16), new BigInteger("012966272872C097FEA7BCE64FAB1A81982A773E26F6E4EF7C99969846E67CA9" + + "CBE1692", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("08F3824E40C16FF1DDA8DC992776D26F4A5981AB5092956C4FDBB4F1AE0A711E" + + "EAA10E5", 16), new BigInteger("0A64B91EFADB213E11483FB61C73E3EF63D3B44EEFC56EA401B99DCC60CC28E9" + + "9F0F1FA", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("3597B406F5329D11A79E887847E5EC60861CCBB19EC61F252DB7BD549C699951" + + "C182796", 16), new BigInteger("0A6A100B997BC622D91701D9F5C6F6D3815517E577622DA69D3A0E8917C1CBE6" + + "3ACD345", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("1BB490926E5A1FDC7C5AA86D0835F9B994EDA315CA408002AF54A298728D422E" + + "BF59E4C", 16), new BigInteger("36C682CFC9E2C89A782BFD3A191609D1F0C1910D5FD6981442070393159D65FB" + + "CC0A8BA", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("19944AA68F9778C2E3D6E240947613E6DA60EFCE9B9B2C063FF5466D72745B5A" + + "0B25BA2", 16), new BigInteger("03F1567B3C5B02DF15C874F0EE22850824693D5ADC4663BAA19E384E550B1DD4" + + "1F31EE6", 16)); + + x9ECParameters = NISTNamedCurves.getByName("B-409"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("0494994CC325B08E7B4CE038BD9436F90B5E59A2C13C3140CD3AE07C04A01FC489F572CE0569A6DB7B8060393DE76330C624177", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("0D8783188E1A540E2022D389E1D35B32F56F8C2BB5636B8ABF7718806B27A713" + + "EBAE37F63ECD4B61445CEF5801B62594EF3E982", 16), new BigInteger("03A6B4A80E204DB0DE12E7415C13C9EC091C52935658316B4A0C591216A38791" + + "54BEB1712560E346E7EF26517707435B55C3141", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("0EE4F39ACC2E03CE96C3D9FCBAFA5C22C89053662F8D4117752A9B10F09ADFDA" + + "59DB061E247FE5321D6B170EE758ACE1BE4D157", 16), new BigInteger("00A2B83265B456A430A8BF27DCC8A9488B3F126C10F0D6D64BF7B8A218FAAF20" + + "E51A295A3AE78F205E5A4A6AE224C3639F1BB34", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("02D8B1B31E33E74D7EB46C30FDE5AD2CA04EC8FE08FBA0E73BA5E568953AC5EA" + + "307C072942238DFC07F4A4D7C7C6A9F86436D17", 16), new BigInteger("079F7D471E6CB73234AF7F7C381D2CE15DE35BAF8BB68393B73235B3A26EC2DF" + + "4842CE433FB492D6E074E604D4870024D42189A", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("07BC638B7E7CE6FEE5E9C64A0F966D722D01BB4BC3F3A35F30D4CDDA92DFC5F7" + + "F0B4BBFE8065D9AD452FD77A1914BE3A2440C18", 16), new BigInteger("06D904429850521B28A32CBF55C7C0FDF35DC4E0BDA2552C7BF68A171E970E67" + + "88ACC0B9521EACB4796E057C70DD9B95FED5BFB", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("05D178DECAFD2D02A3DA0D8BA1C4C1D95EE083C760DF782193A9F7B4A8BE6FC5" + + "C21FD60613BCA65C063A61226E050A680B3ABD4", 16), new BigInteger("013B7581E98F6A63FBBCB3E49BCDA60F816DB230B888506D105DC229600497C3" + + "B46588C784BE3AA9343BEF82F7C9C80AEB63C3B", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("049F54E7C10D2732B4638473053782C6919218BBEFCEC8B51640FC193E832291" + + "F05FA12371E9B448417B3290193F08EE9319195", 16), new BigInteger("0499E267DEC84E02F6F108B10E82172C414F15B1B7364BE8BFD66ADC0C5DE23F" + + "EE3DF0D811134C25AFE0E05A6672F98889F28F1", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("0B1527FFAA7DD7C7E46B628587A5BEC0539A2D04D3CF27C54841C2544E1BBDB4" + + "2FDBDAAF8671A4CA86DFD619B1E3732D7BB56F2", 16), new BigInteger("0442C68C044868DF4832C807F1EDDEBF7F5052A64B826FD03451440794063F52" + + "B022DF304F47403D4069234CA9EB4C964B37C02", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("0BB27755B991D6D31757BCBF68CB01225A38E1CFA20F775E861055DD108ED7EA" + + "455E4B96B2F6F7CD6C6EC2B3C70C3EDDEB9743B", 16), new BigInteger("0C5BE90980E7F444B5F7A12C9E9AC7A04CA81412822DD5AD1BE7C45D5032555E" + + "A070864245CF69266871FEB8CD1B7EDC30EF6D5", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("04EFEB7098772187907C87B33E0FBBA4584226C50C11E98CA7AAC6986F8D3BE0" + + "44E5B52D201A410B852536527724CA5F8CE6549", 16), new BigInteger("09574102FEB3EF87E6D66B94119F5A6062950FF4F902EA1E6BD9E2037F33FF99" + + "1E31F5956C23AFE48FCDC557FD6F088C7C9B2B3", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("07E0249C68536AE2AEC2EC30090340DA49E6DC9E9EEC8F85E5AABFB234B6DA7D" + + "2E9524028CF821F21C6019770474CC40B01FAF6", 16), new BigInteger("08125B5A03FB44AE81EA46D446130C2A415ECCA265910CA69D55F2453E16CD7B" + + "2DFA4E28C50FA8137F9C0C6CEE4CD37ABCCF6D8", 16)); + + x9ECParameters = NISTNamedCurves.getByName("B-571"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("028A04857F24C1C082DF0D909C0E72F453F2E2340CCB071F0E389BCA2575DA19" + + "124198C57174929AD26E348CF63F78D28021EF5A9BF2D5CBEAF6B7CCB6C4DA82" + + "4DD5C82CFB24E11", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("147D3EB0EDA9F2152DFD014363D6A9CE816D7A1467D326A625FC4AB0C786E1B7" + + "4DDF7CD4D0E99541391B266C704BB6B6E8DCCD27B460802E0867143727AA4155" + + "55454321EFE5CB6", 16), + new BigInteger("17319571CAF533D90D2E78A64060B9C53169AB7FC908947B3EDADC54C79CCF0A" + + "7920B4C64A4EAB6282AFE9A459677CDA37FD6DD50BEF18709590FE18B923BDF7" + + "4A66B189A850819", 16)); + + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("10F4B63E79B2E54E4F4F6A2DBC786D8F4A143ECA7B2AD97810F6472AC6AE2085" + + "3222854553BE1D44A7974599DB7061AE8560DF57F2675BE5F9DD94ABAF3D47F1" + + "582B318E459748B", 16), + new BigInteger("3BBEA07C6B269C2B7FE9AE4DDB118338D0C2F0022920A7F9DCFCB7489594C03B" + + "536A9900C4EA6A10410007222D3DAE1A96F291C4C9275D75D98EB290DC0EEF17" + + "6037B2C7A7A39A3", 16)); + + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("213EF9F3B0CFC4BF996B8AF3A7E1F6CACD2B87C8C63820000800AC787F17EC99" + + "C04BCEDF29A8413CFF83142BB88A50EF8D9A086AF4EB03E97C567500C21D8657" + + "14D832E03C6D054", 16), + new BigInteger("3D32322559B094E20D8935E250B6EC139AC4AAB77920812C119AF419FB62B332" + + "C8D226C6C9362AE3C1E4AABE19359B8428EA74EC8FBE83C8618C2BCCB6B43FBA" + + "A0F2CCB7D303945", 16)); + + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("375D8F49C656A0BBD21D3F54CDA287D853C4BB1849983CD891EF6CD6BB56A62B" + + "687807C16685C2C9BCA2663C33696ACCE344C45F3910B1DF806204FF731ECB28" + + "9C100EF4D1805EC", 16), + new BigInteger("1CDEC6F46DFEEE44BCE71D41C60550DC67CF98D6C91363625AC2553E4368D2DF" + + "B734A8E8C72E118A76ACDB0E58697940A0F3DF49E72894BD799450FC9E550CC0" + + "4B9FF9B0380021C", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("1C26F40D940A7EAA0EB1E62991028057D91FEDA0366B606F6C434C361F04E545" + + "A6A51A435E26416F6838FFA260C617E798E946B57215284182BE55F29A355E60" + + "24FE32A47289CF0", 16), + new BigInteger("3691DE4369D921FE94EDDA67CB71FBBEC9A436787478063EB1CC778B3DCDC1C4" + + "162662752D28DEEDF6F32A269C82D1DB80C87CE4D3B662E03AC347806E3F19D1" + + "8D6D4DE7358DF7E", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("133F5414F2A9BC41466D339B79376038A64D045E5B0F792A98E5A7AA87E0AD01" + + "6419E5F8D176007D5C9C10B5FD9E2E0AB8331B195797C0358BA05ECBF24ACE59" + + "C5F368A6C0997CC", 16), + new BigInteger("3D16743AE9F00F0B1A500F738719C5582550FEB64689DA241665C4CE4F328BA0" + + "E34A7EF527ED13BFA5889FD2D1D214C11EB17D6BC338E05A56F41CAFF1AF7B8D" + + "574DB62EF0D0F21", 16)); + + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("3048E76506C5C43D92B2E33F62B33E3111CEEB87F6C7DF7C7C01E3CDA28FA5E8" + + "BE04B5B23AA03C0C70FEF8F723CBCEBFF0B7A52A3F5C8B84B741B4F6157E69A5" + + "FB0524B48F31828", 16), + new BigInteger("2C99078CCFE5C82102B8D006E3703E020C46C87C75163A2CD839C885550BA5CB" + + "501AC282D29A1C26D26773B60FBE05AAB62BFA0BA32127563D42F7669C97784C" + + "8897C22CFB4B8FA", 16)); + + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("184BC808506E11A65D628B457FDA60952803C604CC7181B59BD25AEE1411A66D" + + "12A777F3A0DC99E1190C58D0037807A95E5080FA1B2E5CCAA37B50D401CFFC34" + + "17C005AEE963469", 16), + new BigInteger("27280D45F81B19334DBDB07B7E63FE8F39AC7E9AE14DE1D2A6884D2101850289" + + "D70EE400F26ACA5E7D73F534A14568478E59D00594981ABE6A1BA18554C13EB5" + + "E03921E4DC98333", 16)); + + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("319EE57912E7B0FAA1FBB145B0505849A89C6DB1EC06EA20A6A7EDE072A6268A" + + "F6FD9C809C7E422A5F33C6C3326EAD7402467DF3272A1B2726C1C20975950F0F" + + "50D8324578F13EC", 16), + new BigInteger("2CF3EA27EADD0612DD2F96F46E89AB894B01A10DF985C5FC099CFFE0EA083EB4" + + "4BE682B08BFE405DAD5F37D0A2C59015BA41027E24B99F8F75A70B6B7385BF39" + + "BBEA02513EB880C", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("2AA1888EAB05F7B00B6A784C4F7081D2C833D50794D9FEAF6E22B8BE728A2A90" + + "BFCABDC803162020AA629718295A1489EE7ED0ECB8AAA197B9BDFC49D18DDD78" + + "FC85A48F9715544", 16), + new BigInteger("0AA5371FE5CA671D6ED9665849C37F394FED85D51FEF72DA2B5F28EDFB2C6479" + + "CA63320C19596F5E1101988E2C619E302DD05112F47E8823040CE540CD3E90DC" + + "F41DBC461744EE9", 16)); + + } + + private void doTestHMACDetECDSASample(Digest digest, ECPrivateKeyParameters privKey, BigInteger r, BigInteger s) + { + doTestHMACDetECDSA(new ECDSASigner(new HMacDSAKCalculator(digest)), digest, SAMPLE, privKey, r, s); + } + + private void doTestHMACDetECDSATest(Digest digest, ECPrivateKeyParameters privKey, BigInteger r, BigInteger s) + { + doTestHMACDetECDSA(new ECDSASigner(new HMacDSAKCalculator(digest)), digest, TEST, privKey, r, s); + } + + private void doTestHMACDetECDSA(DSA detSigner, Digest digest, byte[] data, CipherParameters privKey, BigInteger r, BigInteger s) + { + byte[] m = new byte[digest.getDigestSize()]; + + digest.update(data, 0, data.length); + + digest.doFinal(m, 0); + + detSigner.init(true, privKey); + + BigInteger[] rs = detSigner.generateSignature(m); + + if (!r.equals(rs[0])) + { + fail("r value wrong"); + } + if (!s.equals(rs[1])) + { + fail("s value wrong"); + } + } + + public String getName() + { + return "DeterministicDSA"; + } + + public void performTest() + { + testHMacDeterministic(); + testECHMacDeterministic(); + } + + + public static void main( + String[] args) + { + runTest(new DeterministicDSATest()); + } +} + diff --git a/core/src/test/java/org/spongycastle/crypto/test/DigestRandomNumberTest.java b/core/src/test/java/org/spongycastle/crypto/test/DigestRandomNumberTest.java new file mode 100644 index 00000000..b79eadd3 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/DigestRandomNumberTest.java @@ -0,0 +1,152 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.util.test.SimpleTest; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.Arrays; +import org.spongycastle.crypto.prng.DigestRandomGenerator; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.Digest; + +public class DigestRandomNumberTest + extends SimpleTest +{ + private static final byte[] ZERO_SEED = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + private static final byte[] TEST_SEED = Hex.decode("81dcfafc885914057876"); + + private static final byte[] expected0SHA1 = Hex.decode("95bca677b3d4ff793213c00892d2356ec729ee02"); + private static final byte[] noCycle0SHA1 = Hex.decode("d57ccd0eb12c3938d59226412bc1268037b6b846"); + private static final byte[] expected0SHA256 = Hex.decode("587e2dfd597d086e47ddcd343eac983a5c913bef8c6a1a560a5c1bc3a74b0991"); + private static final byte[] noCycle0SHA256 = Hex.decode("e5776c4483486ba7be081f4e1b9dafbab25c8fae290fd5474c1ceda2c16f9509"); + private static final byte[] expected100SHA1 = Hex.decode("b9d924092546e0876cafd4937d7364ebf9efa4be"); + private static final byte[] expected100SHA256 = Hex.decode("fbc4aa54b948b99de104c44563a552899d718bb75d1941cc62a2444b0506abaf"); + private static final byte[] expectedTestSHA1 = Hex.decode("e9ecef9f5306daf1ac51a89a211a64cb24415649"); + private static final byte[] expectedTestSHA256 = Hex.decode("bdab3ca831b472a2fa09bd1bade541ef16c96640a91fcec553679a136061de98"); + + private static final byte[] sha1Xors = Hex.decode("7edcc1216934f3891b03ffa65821611a3e2b1f79"); + private static final byte[] sha256Xors = Hex.decode("5ec48189cc0aa71e79c707bc3c33ffd47bbba368a83d6cfebf3cd3969d7f3eed"); + + public String getName() + { + return "DigestRandomNumber"; + } + + private void doExpectedTest(Digest digest, int seed, byte[] expected) + { + doExpectedTest(digest, seed, expected, null); + } + + private void doExpectedTest(Digest digest, int seed, byte[] expected, byte[] noCycle) + { + DigestRandomGenerator rGen = new DigestRandomGenerator(digest); + byte[] output = new byte[digest.getDigestSize()]; + + rGen.addSeedMaterial(seed); + + for (int i = 0; i != 1024; i++) + { + rGen.nextBytes(output); + } + + if (noCycle != null) + { + if (Arrays.areEqual(noCycle, output)) + { + fail("seed not being cycled!"); + } + } + + if (!Arrays.areEqual(expected, output)) + { + fail("expected output doesn't match"); + } + } + + private void doExpectedTest(Digest digest, byte[] seed, byte[] expected) + { + DigestRandomGenerator rGen = new DigestRandomGenerator(digest); + byte[] output = new byte[digest.getDigestSize()]; + + rGen.addSeedMaterial(seed); + + for (int i = 0; i != 1024; i++) + { + rGen.nextBytes(output); + } + + if (!Arrays.areEqual(expected, output)) + { + fail("expected output doesn't match"); + } + } + + private void doCountTest(Digest digest, byte[] seed, byte[] expectedXors) + { + DigestRandomGenerator rGen = new DigestRandomGenerator(digest); + byte[] output = new byte[digest.getDigestSize()]; + int[] averages = new int[digest.getDigestSize()]; + byte[] ands = new byte[digest.getDigestSize()]; + byte[] xors = new byte[digest.getDigestSize()]; + byte[] ors = new byte[digest.getDigestSize()]; + + rGen.addSeedMaterial(seed); + + for (int i = 0; i != 1000000; i++) + { + rGen.nextBytes(output); + for (int j = 0; j != output.length; j++) + { + averages[j] += output[j] & 0xff; + ands[j] &= output[j]; + xors[j] ^= output[j]; + ors[j] |= output[j]; + } + } + + for (int i = 0; i != output.length; i++) + { + if ((averages[i] / 1000000) != 127) + { + fail("average test failed for " + digest.getAlgorithmName()); + } + if (ands[i] != 0) + { + fail("and test failed for " + digest.getAlgorithmName()); + } + if ((ors[i] & 0xff) != 0xff) + { + fail("or test failed for " + digest.getAlgorithmName()); + } + if (xors[i] != expectedXors[i]) + { + fail("xor test failed for " + digest.getAlgorithmName()); + } + } + } + + public void performTest() + throws Exception + { + doExpectedTest(new SHA1Digest(), 0, expected0SHA1, noCycle0SHA1); + doExpectedTest(new SHA256Digest(), 0, expected0SHA256, noCycle0SHA256); + + doExpectedTest(new SHA1Digest(), 100, expected100SHA1); + doExpectedTest(new SHA256Digest(), 100, expected100SHA256); + + doExpectedTest(new SHA1Digest(), ZERO_SEED, expected0SHA1); + doExpectedTest(new SHA256Digest(), ZERO_SEED, expected0SHA256); + + doExpectedTest(new SHA1Digest(), TEST_SEED, expectedTestSHA1); + doExpectedTest(new SHA256Digest(), TEST_SEED, expectedTestSHA256); + + doCountTest(new SHA1Digest(), TEST_SEED, sha1Xors); + doCountTest(new SHA256Digest(), TEST_SEED, sha256Xors); + } + + public static void main( + String[] args) + { + runTest(new DigestRandomNumberTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/DigestTest.java new file mode 100644 index 00000000..b293ba77 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/DigestTest.java @@ -0,0 +1,226 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.EncodableDigest; +import org.spongycastle.util.Memoable; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public abstract class DigestTest + extends SimpleTest +{ + private Digest digest; + private String[] input; + private String[] results; + + DigestTest( + Digest digest, + String[] input, + String[] results) + { + this.digest = digest; + this.input = input; + this.results = results; + } + + public String getName() + { + return digest.getAlgorithmName(); + } + + public void performTest() + { + byte[] resBuf = new byte[digest.getDigestSize()]; + + for (int i = 0; i < input.length - 1; i++) + { + byte[] m = toByteArray(input[i]); + + vectorTest(digest, i, resBuf, m, Hex.decode(results[i])); + } + + byte[] lastV = toByteArray(input[input.length - 1]); + byte[] lastDigest = Hex.decode(results[input.length - 1]); + + vectorTest(digest, input.length - 1, resBuf, lastV, Hex.decode(results[input.length - 1])); + + testClone(resBuf, lastV, lastDigest); + testMemo(resBuf, lastV, lastDigest); + if (digest instanceof EncodableDigest) + { + testEncodedState(resBuf, lastV, lastDigest); + } + } + + private void testEncodedState(byte[] resBuf, byte[] input, byte[] expected) + { + // test state encoding; + digest.update(input, 0, input.length / 2); + + // copy the Digest + Digest copy1 = cloneDigest(((EncodableDigest)digest).getEncodedState()); + Digest copy2 = cloneDigest(((EncodableDigest)copy1).getEncodedState()); + + digest.update(input, input.length / 2, input.length - input.length / 2); + + digest.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing state vector test", expected, new String(Hex.encode(resBuf))); + } + + copy1.update(input, input.length / 2, input.length - input.length / 2); + copy1.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing state copy1 vector test", expected, new String(Hex.encode(resBuf))); + } + + copy2.update(input, input.length / 2, input.length - input.length / 2); + copy2.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing state copy2 vector test", expected, new String(Hex.encode(resBuf))); + } + } + + private void testMemo(byte[] resBuf, byte[] input, byte[] expected) + { + Memoable m = (Memoable)digest; + + digest.update(input, 0, input.length/2); + + // copy the Digest + Memoable copy1 = m.copy(); + Memoable copy2 = copy1.copy(); + + digest.update(input, input.length/2, input.length - input.length/2); + digest.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing memo vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } + + m.reset(copy1); + + digest.update(input, input.length/2, input.length - input.length/2); + digest.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing memo reset vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } + + Digest md = (Digest)copy2; + + md.update(input, input.length/2, input.length - input.length/2); + md.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing memo copy vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } + } + + private void testClone(byte[] resBuf, byte[] input, byte[] expected) + { + digest.update(input, 0, input.length/2); + + // clone the Digest + Digest d = cloneDigest(digest); + + digest.update(input, input.length/2, input.length - input.length/2); + digest.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing clone vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } + + d.update(input, input.length/2, input.length - input.length/2); + d.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing second clone vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } + } + + protected byte[] toByteArray(String input) + { + byte[] bytes = new byte[input.length()]; + + for (int i = 0; i != bytes.length; i++) + { + bytes[i] = (byte)input.charAt(i); + } + + return bytes; + } + + private void vectorTest( + Digest digest, + int count, + byte[] resBuf, + byte[] input, + byte[] expected) + { + digest.update(input, 0, input.length); + digest.doFinal(resBuf, 0); + + if (!areEqual(resBuf, expected)) + { + fail("Vector " + count + " failed got " + new String(Hex.encode(resBuf))); + } + } + + protected abstract Digest cloneDigest(Digest digest); + + protected Digest cloneDigest(byte[] encodedState) + { + throw new IllegalStateException("Unsupported"); + } + + // + // optional tests + // + protected void millionATest( + String expected) + { + byte[] resBuf = new byte[digest.getDigestSize()]; + + for (int i = 0; i < 1000000; i++) + { + digest.update((byte)'a'); + } + + digest.doFinal(resBuf, 0); + + if (!areEqual(resBuf, Hex.decode(expected))) + { + fail("Million a's failed", expected, new String(Hex.encode(resBuf))); + } + } + + protected void sixtyFourKTest( + String expected) + { + byte[] resBuf = new byte[digest.getDigestSize()]; + + for (int i = 0; i < 65536; i++) + { + digest.update((byte)(i & 0xff)); + } + + digest.doFinal(resBuf, 0); + + if (!areEqual(resBuf, Hex.decode(expected))) + { + fail("64k test failed", expected, new String(Hex.encode(resBuf))); + } + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/EAXTest.java b/core/src/test/java/org/spongycastle/crypto/test/EAXTest.java new file mode 100644 index 00000000..38c0a685 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/EAXTest.java @@ -0,0 +1,355 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.AESEngine; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.modes.AEADBlockCipher; +import org.spongycastle.crypto.modes.EAXBlockCipher; +import org.spongycastle.crypto.params.AEADParameters; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Strings; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class EAXTest + extends SimpleTest +{ + private byte[] K1 = Hex.decode("233952DEE4D5ED5F9B9C6D6FF80FF478"); + private byte[] N1 = Hex.decode("62EC67F9C3A4A407FCB2A8C49031A8B3"); + private byte[] A1 = Hex.decode("6BFB914FD07EAE6B"); + private byte[] P1 = Hex.decode(""); + private byte[] C1 = Hex.decode("E037830E8389F27B025A2D6527E79D01"); + private byte[] T1 = Hex.decode("E037830E8389F27B025A2D6527E79D01"); + + private byte[] K2 = Hex.decode("91945D3F4DCBEE0BF45EF52255F095A4"); + private byte[] N2 = Hex.decode("BECAF043B0A23D843194BA972C66DEBD"); + private byte[] A2 = Hex.decode("FA3BFD4806EB53FA"); + private byte[] P2 = Hex.decode("F7FB"); + private byte[] C2 = Hex.decode("19DD5C4C9331049D0BDAB0277408F67967E5"); + private byte[] T2 = Hex.decode("5C4C9331049D0BDAB0277408F67967E5"); + + private byte[] K3 = Hex.decode("01F74AD64077F2E704C0F60ADA3DD523"); + private byte[] N3 = Hex.decode("70C3DB4F0D26368400A10ED05D2BFF5E"); + private byte[] A3 = Hex.decode("234A3463C1264AC6"); + private byte[] P3 = Hex.decode("1A47CB4933"); + private byte[] C3 = Hex.decode("D851D5BAE03A59F238A23E39199DC9266626C40F80"); + private byte[] T3 = Hex.decode("3A59F238A23E39199DC9266626C40F80"); + + private byte[] K4 = Hex.decode("D07CF6CBB7F313BDDE66B727AFD3C5E8"); + private byte[] N4 = Hex.decode("8408DFFF3C1A2B1292DC199E46B7D617"); + private byte[] A4 = Hex.decode("33CCE2EABFF5A79D"); + private byte[] P4 = Hex.decode("481C9E39B1"); + private byte[] C4 = Hex.decode("632A9D131AD4C168A4225D8E1FF755939974A7BEDE"); + private byte[] T4 = Hex.decode("D4C168A4225D8E1FF755939974A7BEDE"); + + private byte[] K5 = Hex.decode("35B6D0580005BBC12B0587124557D2C2"); + private byte[] N5 = Hex.decode("FDB6B06676EEDC5C61D74276E1F8E816"); + private byte[] A5 = Hex.decode("AEB96EAEBE2970E9"); + private byte[] P5 = Hex.decode("40D0C07DA5E4"); + private byte[] C5 = Hex.decode("071DFE16C675CB0677E536F73AFE6A14B74EE49844DD"); + private byte[] T5 = Hex.decode("CB0677E536F73AFE6A14B74EE49844DD"); + + private byte[] K6 = Hex.decode("BD8E6E11475E60B268784C38C62FEB22"); + private byte[] N6 = Hex.decode("6EAC5C93072D8E8513F750935E46DA1B"); + private byte[] A6 = Hex.decode("D4482D1CA78DCE0F"); + private byte[] P6 = Hex.decode("4DE3B35C3FC039245BD1FB7D"); + private byte[] C6 = Hex.decode("835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F"); + private byte[] T6 = Hex.decode("ABB8644FD6CCB86947C5E10590210A4F"); + + private byte[] K7 = Hex.decode("7C77D6E813BED5AC98BAA417477A2E7D"); + private byte[] N7 = Hex.decode("1A8C98DCD73D38393B2BF1569DEEFC19"); + private byte[] A7 = Hex.decode("65D2017990D62528"); + private byte[] P7 = Hex.decode("8B0A79306C9CE7ED99DAE4F87F8DD61636"); + private byte[] C7 = Hex.decode("02083E3979DA014812F59F11D52630DA30137327D10649B0AA6E1C181DB617D7F2"); + private byte[] T7 = Hex.decode("137327D10649B0AA6E1C181DB617D7F2"); + + private byte[] K8 = Hex.decode("5FFF20CAFAB119CA2FC73549E20F5B0D"); + private byte[] N8 = Hex.decode("DDE59B97D722156D4D9AFF2BC7559826"); + private byte[] A8 = Hex.decode("54B9F04E6A09189A"); + private byte[] P8 = Hex.decode("1BDA122BCE8A8DBAF1877D962B8592DD2D56"); + private byte[] C8 = Hex.decode("2EC47B2C4954A489AFC7BA4897EDCDAE8CC33B60450599BD02C96382902AEF7F832A"); + private byte[] T8 = Hex.decode("3B60450599BD02C96382902AEF7F832A"); + + private byte[] K9 = Hex.decode("A4A4782BCFFD3EC5E7EF6D8C34A56123"); + private byte[] N9 = Hex.decode("B781FCF2F75FA5A8DE97A9CA48E522EC"); + private byte[] A9 = Hex.decode("899A175897561D7E"); + private byte[] P9 = Hex.decode("6CF36720872B8513F6EAB1A8A44438D5EF11"); + private byte[] C9 = Hex.decode("0DE18FD0FDD91E7AF19F1D8EE8733938B1E8E7F6D2231618102FDB7FE55FF1991700"); + private byte[] T9 = Hex.decode("E7F6D2231618102FDB7FE55FF1991700"); + + private byte[] K10 = Hex.decode("8395FCF1E95BEBD697BD010BC766AAC3"); + private byte[] N10 = Hex.decode("22E7ADD93CFC6393C57EC0B3C17D6B44"); + private byte[] A10 = Hex.decode("126735FCC320D25A"); + private byte[] P10 = Hex.decode("CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7"); + private byte[] C10 = Hex.decode("CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E"); + private byte[] T10 = Hex.decode("CFC46AFC253B4652B1AF3795B124AB6E"); + + private byte[] K11 = Hex.decode("8395FCF1E95BEBD697BD010BC766AAC3"); + private byte[] N11 = Hex.decode("22E7ADD93CFC6393C57EC0B3C17D6B44"); + private byte[] A11 = Hex.decode("126735FCC320D25A"); + private byte[] P11 = Hex.decode("CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7"); + private byte[] C11 = Hex.decode("CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC"); + private byte[] T11 = Hex.decode("CFC46AFC"); + + private static final int NONCE_LEN = 8; + private static final int MAC_LEN = 8; + private static final int AUTHEN_LEN = 20; + + public String getName() + { + return "EAX"; + } + + public void performTest() + throws Exception + { + checkVectors(1, K1, 128, N1, A1, P1, T1, C1); + checkVectors(2, K2, 128, N2, A2, P2, T2, C2); + checkVectors(3, K3, 128, N3, A3, P3, T3, C3); + checkVectors(4, K4, 128, N4, A4, P4, T4, C4); + checkVectors(5, K5, 128, N5, A5, P5, T5, C5); + checkVectors(6, K6, 128, N6, A6, P6, T6, C6); + checkVectors(7, K7, 128, N7, A7, P7, T7, C7); + checkVectors(8, K8, 128, N8, A8, P8, T8, C8); + checkVectors(9, K9, 128, N9, A9, P9, T9, C9); + checkVectors(10, K10, 128, N10, A10, P10, T10, C10); + checkVectors(11, K11, 32, N11, A11, P11, T11, C11); + + EAXBlockCipher eax = new EAXBlockCipher(new AESFastEngine()); + ivParamTest(1, eax, K1, N1); + + // + // exception tests + // + + try + { + eax.init(false, new AEADParameters(new KeyParameter(K1), 32, N2, A2)); + + byte[] enc = new byte[C2.length]; + int len = eax.processBytes(C2, 0, C2.length, enc, 0); + + len += eax.doFinal(enc, len); + + fail("invalid cipher text not picked up"); + } + catch (InvalidCipherTextException e) + { + // expected + } + + try + { + eax.init(false, new KeyParameter(K1)); + + fail("illegal argument not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + randomTests(); + AEADTestUtil.testReset(this, new EAXBlockCipher(new AESEngine()), new EAXBlockCipher(new AESEngine()), new AEADParameters(new KeyParameter(K1), 32, N2)); + AEADTestUtil.testTampering(this, eax, new AEADParameters(new KeyParameter(K1), 32, N2)); + AEADTestUtil.testOutputSizes(this, new EAXBlockCipher(new AESEngine()), new AEADParameters( + new KeyParameter(K1), 32, N2)); + AEADTestUtil.testBufferSizeChecks(this, new EAXBlockCipher(new AESEngine()), new AEADParameters( + new KeyParameter(K1), 32, N2)); + } + + private void checkVectors( + int count, + byte[] k, + int macSize, + byte[] n, + byte[] a, + byte[] p, + byte[] t, + byte[] c) + throws InvalidCipherTextException + { + byte[] fa = new byte[a.length / 2]; + byte[] la = new byte[a.length - (a.length / 2)]; + System.arraycopy(a, 0, fa, 0, fa.length); + System.arraycopy(a, fa.length, la, 0, la.length); + + checkVectors(count, "all initial associated data", k, macSize, n, a, null, p, t, c); + checkVectors(count, "subsequent associated data", k, macSize, n, null, a, p, t, c); + checkVectors(count, "split associated data", k, macSize, n, fa, la, p, t, c); + } + + private void checkVectors( + int count, + String additionalDataType, + byte[] k, + int macSize, + byte[] n, + byte[] a, + byte[] sa, + byte[] p, + byte[] t, + byte[] c) + throws InvalidCipherTextException + { + EAXBlockCipher encEax = new EAXBlockCipher(new AESFastEngine()); + EAXBlockCipher decEax = new EAXBlockCipher(new AESFastEngine()); + + AEADParameters parameters = new AEADParameters(new KeyParameter(k), macSize, n, a); + encEax.init(true, parameters); + decEax.init(false, parameters); + + runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c); + runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c); + + // key reuse test + parameters = new AEADParameters(null, macSize, n, a); + encEax.init(true, parameters); + decEax.init(false, parameters); + + runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c); + runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c); + } + + private void runCheckVectors( + int count, + EAXBlockCipher encEax, + EAXBlockCipher decEax, + String additionalDataType, + byte[] sa, + byte[] p, + byte[] t, + byte[] c) + throws InvalidCipherTextException + { + byte[] enc = new byte[c.length]; + + if (sa != null) + { + encEax.processAADBytes(sa, 0, sa.length); + } + + int len = encEax.processBytes(p, 0, p.length, enc, 0); + + len += encEax.doFinal(enc, len); + + if (!areEqual(c, enc)) + { + fail("encrypted stream fails to match in test " + count + " with " + additionalDataType); + } + + byte[] tmp = new byte[enc.length]; + + if (sa != null) + { + decEax.processAADBytes(sa, 0, sa.length); + } + + len = decEax.processBytes(enc, 0, enc.length, tmp, 0); + + len += decEax.doFinal(tmp, len); + + byte[] dec = new byte[len]; + + System.arraycopy(tmp, 0, dec, 0, len); + + if (!areEqual(p, dec)) + { + fail("decrypted stream fails to match in test " + count + " with " + additionalDataType); + } + + if (!areEqual(t, decEax.getMac())) + { + fail("MAC fails to match in test " + count + " with " + additionalDataType); + } + } + + private void ivParamTest( + int count, + AEADBlockCipher eax, + byte[] k, + byte[] n) + throws InvalidCipherTextException + { + byte[] p = Strings.toByteArray("hello world!!"); + + eax.init(true, new ParametersWithIV(new KeyParameter(k), n)); + + byte[] enc = new byte[p.length + 8]; + + int len = eax.processBytes(p, 0, p.length, enc, 0); + + len += eax.doFinal(enc, len); + + eax.init(false, new ParametersWithIV(new KeyParameter(k), n)); + + byte[] tmp = new byte[enc.length]; + + len = eax.processBytes(enc, 0, enc.length, tmp, 0); + + len += eax.doFinal(tmp, len); + + byte[] dec = new byte[len]; + + System.arraycopy(tmp, 0, dec, 0, len); + + if (!areEqual(p, dec)) + { + fail("decrypted stream fails to match in test " + count); + } + } + + private void randomTests() + throws InvalidCipherTextException + { + SecureRandom srng = new SecureRandom(); + for (int i = 0; i < 10; ++i) + { + randomTest(srng); + } + } + + private void randomTest( + SecureRandom srng) + throws InvalidCipherTextException + { + int DAT_LEN = srng.nextInt() >>> 22; // Note: JDK1.0 compatibility + byte[] nonce = new byte[NONCE_LEN]; + byte[] authen = new byte[AUTHEN_LEN]; + byte[] datIn = new byte[DAT_LEN]; + byte[] key = new byte[16]; + srng.nextBytes(nonce); + srng.nextBytes(authen); + srng.nextBytes(datIn); + srng.nextBytes(key); + + AESFastEngine engine = new AESFastEngine(); + KeyParameter sessKey = new KeyParameter(key); + EAXBlockCipher eaxCipher = new EAXBlockCipher(engine); + + AEADParameters params = new AEADParameters(sessKey, MAC_LEN * 8, nonce, authen); + eaxCipher.init(true, params); + + byte[] intrDat = new byte[eaxCipher.getOutputSize(datIn.length)]; + int outOff = eaxCipher.processBytes(datIn, 0, DAT_LEN, intrDat, 0); + outOff += eaxCipher.doFinal(intrDat, outOff); + + eaxCipher.init(false, params); + byte[] datOut = new byte[eaxCipher.getOutputSize(outOff)]; + int resultLen = eaxCipher.processBytes(intrDat, 0, outOff, datOut, 0); + eaxCipher.doFinal(datOut, resultLen); + + if (!areEqual(datIn, datOut)) + { + fail("EAX roundtrip failed to match"); + } + } + + public static void main(String[] args) + { + runTest(new EAXTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ECDHKEKGeneratorTest.java b/core/src/test/java/org/spongycastle/crypto/test/ECDHKEKGeneratorTest.java new file mode 100644 index 00000000..46e9dca8 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ECDHKEKGeneratorTest.java @@ -0,0 +1,71 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.asn1.ASN1ObjectIdentifier; +import org.spongycastle.asn1.nist.NISTObjectIdentifiers; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.crypto.DerivationFunction; +import org.spongycastle.crypto.DerivationParameters; +import org.spongycastle.crypto.agreement.kdf.DHKDFParameters; +import org.spongycastle.crypto.agreement.kdf.ECDHKEKGenerator; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * ECDHKEK Generator tests. + */ +public class ECDHKEKGeneratorTest + extends SimpleTest +{ + private byte[] seed1 = Hex.decode("db4a8daba1f98791d54e940175dd1a5f3a0826a1066aa9b668d4dc1e1e0790158dcad1533c03b44214d1b61fefa8b579"); + private ASN1ObjectIdentifier alg1 = NISTObjectIdentifiers.id_aes256_wrap; + private byte[] result1 = Hex.decode("8ecc6d85caf25eaba823a7d620d4ab0d33e4c645f2"); + + private byte[] seed2 = Hex.decode("75d7487b5d3d2bfb3c69ce0365fe64e3bfab5d0d63731628a9f47eb8fddfa28c65decaf228a0b38f0c51c6a3356d7c56"); + private ASN1ObjectIdentifier alg2 = NISTObjectIdentifiers.id_aes128_wrap; + private byte[] result2 = Hex.decode("042be1faca3a4a8fc859241bfb87ba35"); + + private byte[] seed3 = Hex.decode("fdeb6d809f997e8ac174d638734dc36d37aaf7e876e39967cd82b1cada3de772449788461ee7f856bad9305627f8e48b"); + private ASN1ObjectIdentifier alg3 = PKCSObjectIdentifiers.id_alg_CMS3DESwrap; + private byte[] result3 = Hex.decode("bcd701fc92109b1b9d6f3b6497ad5ca9627fa8a597010305"); + + public ECDHKEKGeneratorTest() + { + } + + public void performTest() + { + checkMask(1, new ECDHKEKGenerator(new SHA1Digest()), new DHKDFParameters(alg1, 256, seed1), result1); + checkMask(2, new ECDHKEKGenerator(new SHA1Digest()), new DHKDFParameters(alg2, 128, seed2), result2); + checkMask(3, new ECDHKEKGenerator(new SHA1Digest()), new DHKDFParameters(alg3, 192, seed3), result3); + } + + private void checkMask( + int count, + DerivationFunction kdf, + DerivationParameters params, + byte[] result) + { + byte[] data = new byte[result.length]; + + kdf.init(params); + + kdf.generateBytes(data, 0, data.length); + + if (!areEqual(result, data)) + { + fail("ECDHKEKGenerator failed generator test " + count); + } + } + + public String getName() + { + return "ECDHKEKGenerator"; + } + + public static void main( + String[] args) + { + runTest(new ECDHKEKGeneratorTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ECGOST3410Test.java b/core/src/test/java/org/spongycastle/crypto/test/ECGOST3410Test.java new file mode 100644 index 00000000..2d7900d9 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ECGOST3410Test.java @@ -0,0 +1,327 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.digests.GOST3411Digest; +import org.spongycastle.crypto.generators.ECKeyPairGenerator; +import org.spongycastle.crypto.params.ECDomainParameters; +import org.spongycastle.crypto.params.ECKeyGenerationParameters; +import org.spongycastle.crypto.params.ECPrivateKeyParameters; +import org.spongycastle.crypto.params.ECPublicKeyParameters; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.crypto.signers.ECGOST3410Signer; +import org.spongycastle.math.ec.ECConstants; +import org.spongycastle.math.ec.ECCurve; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.FixedSecureRandom; +import org.spongycastle.util.test.SimpleTest; + +/** + * ECGOST3410 tests are taken from GOST R 34.10-2001. + */ +public class ECGOST3410Test + extends SimpleTest + { + byte[] hashmessage = Hex.decode("3042453136414534424341374533364339313734453431443642453241453435"); + + /** + * ECGOST3410 over the field Fp<br> + */ + BigInteger r = new BigInteger("29700980915817952874371204983938256990422752107994319651632687982059210933395"); + BigInteger s = new BigInteger("574973400270084654178925310019147038455227042649098563933718999175515839552"); + + byte[] kData = new BigInteger("53854137677348463731403841147996619241504003434302020712960838528893196233395").toByteArray(); + + SecureRandom k = new FixedSecureRandom(kData); + + private void ecGOST3410_TEST() + { + BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p + BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("7"), // a + new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b + mod_q, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.createPoint( + new BigInteger("2"), // x + new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y + mod_q); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("55441196065363246126355624130324183196576709222340016572108097750006097525544"), // d + params); + + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ECGOST3410Signer ecgost3410 = new ECGOST3410Signer(); + + ecgost3410.init(true, param); + + byte[] mVal = new BigInteger("20798893674476452017134061561508270130637142515379653289952617252661468872421").toByteArray(); + byte[] message = new byte[mVal.length]; + + for (int i = 0; i != mVal.length; i++) + { + message[i] = mVal[mVal.length - 1 - i]; + } + + BigInteger[] sig = ecgost3410.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong.", r, sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong.", s, sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.createPoint( + new BigInteger("57520216126176808443631405023338071176630104906313632182896741342206604859403"), // x + new BigInteger("17614944419213781543809391949654080031942662045363639260709847859438286763994")), // y + params); + + ecgost3410.init(false, pubKey); + if (!ecgost3410.verifySignature(message, sig[0], sig[1])) + { + fail("verification fails"); + } + } + + /** + * Test Sign & Verify with test parameters + * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt + * gostR3410-2001-TestParamSet P.46 + */ + private void ecGOST3410_TestParam() + { + SecureRandom random = new SecureRandom(); + + BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p + BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("7"), // a + new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b + mod_q, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.createPoint( + new BigInteger("2"), // x + new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y + mod_q); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + ECGOST3410Signer ecgost3410 = new ECGOST3410Signer(); + + ecgost3410.init(true, param); + + //get hash message using the digest GOST3411. + byte[] message = "Message for sign".getBytes(); + GOST3411Digest gost3411 = new GOST3411Digest(); + gost3411.update(message, 0, message.length); + byte[] hashmessage = new byte[gost3411.getDigestSize()]; + gost3411.doFinal(hashmessage, 0); + + BigInteger[] sig = ecgost3410.generateSignature(hashmessage); + + ecgost3410.init(false, pair.getPublic()); + + if (!ecgost3410.verifySignature(hashmessage, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * Test Sign & Verify with A parameters + * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt + * gostR3410-2001-CryptoPro-A-ParamSet P.47 + */ + public void ecGOST3410_AParam() + { + SecureRandom random = new SecureRandom(); + + BigInteger mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); //p + BigInteger mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a + new BigInteger("166"), // b + mod_q, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.createPoint( + new BigInteger("1"), // x + new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y + mod_q); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + ECGOST3410Signer ecgost3410 = new ECGOST3410Signer(); + + ecgost3410.init(true, param); + + BigInteger[] sig = ecgost3410.generateSignature(hashmessage); + + ecgost3410.init(false, pair.getPublic()); + + if (!ecgost3410.verifySignature(hashmessage, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * Test Sign & Verify with B parameters + * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt + * gostR3410-2001-CryptoPro-B-ParamSet P.47-48 + */ + private void ecGOST3410_BParam() + { + SecureRandom random = new SecureRandom(); + + BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823193"); //p + BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927102133160255826820068844496087732066703"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a + new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595"), // b + mod_q, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.createPoint( + new BigInteger("1"), // x + new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124")), // y + mod_q); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + ECGOST3410Signer ecgost3410 = new ECGOST3410Signer(); + + ecgost3410.init(true, param); + + BigInteger[] sig = ecgost3410.generateSignature(hashmessage); + + ecgost3410.init(false, pair.getPublic()); + + if (!ecgost3410.verifySignature(hashmessage, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * Test Sign & Verify with C parameters + * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt + * gostR3410-2001-CryptoPro-C-ParamSet P.48 + */ + private void ecGOST3410_CParam() + { + SecureRandom random = new SecureRandom(); + + BigInteger mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); //p + BigInteger mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a + new BigInteger("32858"), // b + mod_q, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.createPoint( + new BigInteger("0"), // x + new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), // y + mod_q); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + ECGOST3410Signer ecgost3410 = new ECGOST3410Signer(); + + ecgost3410.init(true, param); + + BigInteger[] sig = ecgost3410.generateSignature(hashmessage); + + ecgost3410.init(false, pair.getPublic()); + + if (!ecgost3410.verifySignature(hashmessage, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + public String getName() + { + return "ECGOST3410"; + } + + public void performTest() + { + ecGOST3410_TEST(); + ecGOST3410_TestParam(); + ecGOST3410_AParam(); + ecGOST3410_BParam(); + ecGOST3410_CParam(); + } + + public static void main( + String[] args) + { + runTest(new ECGOST3410Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ECIESKeyEncapsulationTest.java b/core/src/test/java/org/spongycastle/crypto/test/ECIESKeyEncapsulationTest.java new file mode 100755 index 00000000..10a73411 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ECIESKeyEncapsulationTest.java @@ -0,0 +1,138 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.asn1.sec.SECNamedCurves; +import org.spongycastle.asn1.x9.X9ECParameters; +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.generators.ECKeyPairGenerator; +import org.spongycastle.crypto.generators.KDF2BytesGenerator; +import org.spongycastle.crypto.kems.ECIESKeyEncapsulation; +import org.spongycastle.crypto.params.ECDomainParameters; +import org.spongycastle.crypto.params.ECKeyGenerationParameters; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.test.SimpleTest; + +/** + * Tests for the ECIES Key Encapsulation Mechanism + */ +public class ECIESKeyEncapsulationTest + extends SimpleTest +{ + public String getName() + { + return "ECIESKeyEncapsulation"; + } + + public void performTest() + throws Exception + { + + // Set EC domain parameters and generate key pair + X9ECParameters spec = SECNamedCurves.getByName("secp224r1"); + ECDomainParameters ecDomain = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN()); + ECKeyPairGenerator ecGen = new ECKeyPairGenerator(); + + ecGen.init(new ECKeyGenerationParameters(ecDomain, new SecureRandom())); + + AsymmetricCipherKeyPair keys = ecGen.generateKeyPair(); + + // Set ECIES-KEM parameters + ECIESKeyEncapsulation kem; + KDF2BytesGenerator kdf = new KDF2BytesGenerator(new SHA1Digest()); + SecureRandom rnd = new SecureRandom(); + byte[] out = new byte[57]; + KeyParameter key1, key2; + + // Test basic ECIES-KEM + kem = new ECIESKeyEncapsulation(kdf, rnd); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed basic test"); + } + + // Test ECIES-KEM using new cofactor mode + kem = new ECIESKeyEncapsulation(kdf, rnd, true, false, false); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed cofactor test"); + } + + // Test ECIES-KEM using old cofactor mode + kem = new ECIESKeyEncapsulation(kdf, rnd, false, true, false); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed old cofactor test"); + } + + // Test ECIES-KEM using single hash mode + kem = new ECIESKeyEncapsulation(kdf, rnd, false, false, true); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed single hash test"); + } + + // Test ECIES-KEM using new cofactor mode and single hash mode + kem = new ECIESKeyEncapsulation(kdf, rnd, true, false, true); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed cofactor and single hash test"); + } + + // Test ECIES-KEM using old cofactor mode and single hash mode + kem = new ECIESKeyEncapsulation(kdf, rnd, false, true, true); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed old cofactor and single hash test"); + } + } + + public static void main( + String[] args) + { + runTest(new ECIESKeyEncapsulationTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ECIESTest.java b/core/src/test/java/org/spongycastle/crypto/test/ECIESTest.java new file mode 100644 index 00000000..98593ae6 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ECIESTest.java @@ -0,0 +1,377 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.KeyEncoder; +import org.spongycastle.crypto.KeyGenerationParameters; +import org.spongycastle.crypto.agreement.ECDHBasicAgreement; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.engines.IESEngine; +import org.spongycastle.crypto.engines.TwofishEngine; +import org.spongycastle.crypto.generators.ECKeyPairGenerator; +import org.spongycastle.crypto.generators.EphemeralKeyPairGenerator; +import org.spongycastle.crypto.generators.KDF2BytesGenerator; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.params.ECDomainParameters; +import org.spongycastle.crypto.params.ECKeyGenerationParameters; +import org.spongycastle.crypto.params.ECPrivateKeyParameters; +import org.spongycastle.crypto.params.ECPublicKeyParameters; +import org.spongycastle.crypto.params.IESParameters; +import org.spongycastle.crypto.params.IESWithCipherParameters; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.crypto.parsers.ECIESPublicKeyParser; +import org.spongycastle.math.ec.ECConstants; +import org.spongycastle.math.ec.ECCurve; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * test for ECIES - Elliptic Curve Integrated Encryption Scheme + */ +public class ECIESTest + extends SimpleTest +{ + private static byte[] TWOFISH_IV = Hex.decode("000102030405060708090a0b0c0d0e0f"); + + ECIESTest() + { + } + + public String getName() + { + return "ECIES"; + } + + private void doStaticTest(byte[] iv) + throws Exception + { + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + AsymmetricCipherKeyPair p1 = new AsymmetricCipherKeyPair(pubKey, priKey); + AsymmetricCipherKeyPair p2 = new AsymmetricCipherKeyPair(pubKey, priKey); + + // + // stream test + // + IESEngine i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + IESEngine i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + CipherParameters p = new IESParameters(d, e, 64); + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + byte[] message = Hex.decode("1234567890abcdef"); + + byte[] out1 = i1.processBlock(message, 0, message.length); + + if (!areEqual(out1, Hex.decode("468d89877e8238802403ec4cb6b329faeccfa6f3a730f2cdb3c0a8e8"))) + { + fail("stream cipher test failed on enc"); + } + + byte[] out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + // + // twofish with CBC + // + BufferedBlockCipher c1 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + BufferedBlockCipher c2 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c1); + i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c2); + d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + p = new IESWithCipherParameters(d, e, 64, 128); + + if (iv != null) + { + p = new ParametersWithIV(p, iv); + } + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + message = Hex.decode("1234567890abcdef"); + + out1 = i1.processBlock(message, 0, message.length); + + if (!areEqual(out1, (iv == null) ? + Hex.decode("b8a06ea5c2b9df28b58a0a90a734cde8c9c02903e5c220021fe4417410d1e53a32a71696") + : Hex.decode("f246b0e26a2711992cac9c590d08e45c5e730b7c0f4218bb064e27b7dd7c8a3bd8bf01c3"))) + { + fail("twofish cipher test failed on enc"); + } + + out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("twofish cipher test failed"); + } + } + + private void doEphemeralTest(byte[] iv) + throws Exception + { + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + AsymmetricCipherKeyPair p1 = new AsymmetricCipherKeyPair(pubKey, priKey); + AsymmetricCipherKeyPair p2 = new AsymmetricCipherKeyPair(pubKey, priKey); + + // Generate the ephemeral key pair + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + gen.init(new ECKeyGenerationParameters(params, new SecureRandom())); + + EphemeralKeyPairGenerator ephKeyGen = new EphemeralKeyPairGenerator(gen, new KeyEncoder() + { + public byte[] getEncoded(AsymmetricKeyParameter keyParameter) + { + return ((ECPublicKeyParameters)keyParameter).getQ().getEncoded(); + } + }); + + // + // stream test + // + IESEngine i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + IESEngine i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + + byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + CipherParameters p = new IESParameters(d, e, 64); + + i1.init(p2.getPublic(), p, ephKeyGen); + i2.init(p2.getPrivate(), p, new ECIESPublicKeyParser(params)); + + byte[] message = Hex.decode("1234567890abcdef"); + + byte[] out1 = i1.processBlock(message, 0, message.length); + + byte[] out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + // + // twofish with CBC + // + BufferedBlockCipher c1 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + BufferedBlockCipher c2 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c1); + i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c2); + d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + p = new IESWithCipherParameters(d, e, 64, 128); + + if (iv != null) + { + p = new ParametersWithIV(p, iv); + } + + i1.init(p2.getPublic(), p, ephKeyGen); + i2.init(p2.getPrivate(), p, new ECIESPublicKeyParser(params)); + + message = Hex.decode("1234567890abcdef"); + + out1 = i1.processBlock(message, 0, message.length); + + out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("twofish cipher test failed"); + } + } + + private void doTest(AsymmetricCipherKeyPair p1, AsymmetricCipherKeyPair p2) + throws Exception + { + // + // stream test + // + IESEngine i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + IESEngine i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + IESParameters p = new IESParameters(d, e, 64); + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + byte[] message = Hex.decode("1234567890abcdef"); + + byte[] out1 = i1.processBlock(message, 0, message.length); + + byte[] out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + // + // twofish with CBC + // + BufferedBlockCipher c1 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + BufferedBlockCipher c2 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c1); + i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c2); + d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + p = new IESWithCipherParameters(d, e, 64, 128); + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + message = Hex.decode("1234567890abcdef"); + + out1 = i1.processBlock(message, 0, message.length); + + out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("twofish cipher test failed"); + } + } + + public void performTest() + throws Exception + { + doStaticTest(null); + doStaticTest(TWOFISH_IV); + + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECKeyPairGenerator eGen = new ECKeyPairGenerator(); + KeyGenerationParameters gParam = new ECKeyGenerationParameters(params, new SecureRandom()); + + eGen.init(gParam); + + AsymmetricCipherKeyPair p1 = eGen.generateKeyPair(); + AsymmetricCipherKeyPair p2 = eGen.generateKeyPair(); + + doTest(p1, p2); + + doEphemeralTest(null); + doEphemeralTest(TWOFISH_IV); + } + + public static void main( + String[] args) + { + runTest(new ECIESTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ECNRTest.java b/core/src/test/java/org/spongycastle/crypto/test/ECNRTest.java new file mode 100644 index 00000000..5a91f05a --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ECNRTest.java @@ -0,0 +1,99 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.params.ECDomainParameters; +import org.spongycastle.crypto.params.ECPrivateKeyParameters; +import org.spongycastle.crypto.params.ECPublicKeyParameters; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.crypto.signers.ECNRSigner; +import org.spongycastle.math.ec.ECConstants; +import org.spongycastle.math.ec.ECCurve; +import org.spongycastle.util.BigIntegers; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.FixedSecureRandom; +import org.spongycastle.util.test.SimpleTest; + +/** + * ECNR tests. + */ +public class ECNRTest + extends SimpleTest +{ + /** + * a basic regression test with 239 bit prime + */ + BigInteger r = new BigInteger("308636143175167811492623515537541734843573549327605293463169625072911693"); + BigInteger s = new BigInteger("852401710738814635664888632022555967400445256405412579597015412971797143"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); + + SecureRandom k = new FixedSecureRandom(true, kData); + + private void ecNR239bitPrime() + { + BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d + params); + + ECNRSigner ecnr = new ECNRSigner(); + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ecnr.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecnr.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong.", r, sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong.", s, sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q + params); + + ecnr.init(false, pubKey); + if (!ecnr.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + public String getName() + { + return "ECNR"; + } + + public void performTest() + { + ecNR239bitPrime(); + } + + public static void main( + String[] args) + { + runTest(new ECNRTest()); + } +} + diff --git a/core/src/test/java/org/spongycastle/crypto/test/ECTest.java b/core/src/test/java/org/spongycastle/crypto/test/ECTest.java new file mode 100644 index 00000000..01fb3304 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ECTest.java @@ -0,0 +1,926 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.asn1.nist.NISTNamedCurves; +import org.spongycastle.asn1.sec.SECNamedCurves; +import org.spongycastle.asn1.x9.X9ECParameters; +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.BasicAgreement; +import org.spongycastle.crypto.agreement.ECDHBasicAgreement; +import org.spongycastle.crypto.agreement.ECDHCBasicAgreement; +import org.spongycastle.crypto.agreement.ECMQVBasicAgreement; +import org.spongycastle.crypto.generators.ECKeyPairGenerator; +import org.spongycastle.crypto.params.ECDomainParameters; +import org.spongycastle.crypto.params.ECKeyGenerationParameters; +import org.spongycastle.crypto.params.ECPrivateKeyParameters; +import org.spongycastle.crypto.params.ECPublicKeyParameters; +import org.spongycastle.crypto.params.MQVPrivateParameters; +import org.spongycastle.crypto.params.MQVPublicParameters; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.crypto.signers.ECDSASigner; +import org.spongycastle.math.ec.ECConstants; +import org.spongycastle.math.ec.ECCurve; +import org.spongycastle.math.ec.ECPoint; +import org.spongycastle.util.BigIntegers; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.FixedSecureRandom; +import org.spongycastle.util.test.SimpleTest; + +/** + * ECDSA tests are taken from X9.62. + */ +public class ECTest + extends SimpleTest +{ + /** + * X9.62 - 1998,<br> + * J.3.1, Page 152, ECDSA over the field Fp<br> + * an example with 192 bit prime + */ + private void testECDSA192bitPrime() + { + BigInteger r = new BigInteger("3342403536405981729393488334694600415596881826869351677613"); + BigInteger s = new BigInteger("5735822328888155254683894997897571951568553642892029982342"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("6140507067065001063065065565667405560006161556565665656654")); + + SecureRandom k = new FixedSecureRandom(kData); + + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ECDSASigner ecdsa = new ECDSASigner(); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + System.getProperty("line.separator") + + " expecting: " + r + System.getProperty("line.separator") + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + System.getProperty("line.separator") + + " expecting: " + s + System.getProperty("line.separator") + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + ecdsa.init(false, pubKey); + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("verification fails"); + } + } + + private void decodeTest() + { + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b + + ECPoint p = curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")).normalize(); + + if (!p.getAffineXCoord().toBigInteger().equals(new BigInteger("188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", 16))) + { + fail("x uncompressed incorrectly"); + } + + if (!p.getAffineYCoord().toBigInteger().equals(new BigInteger("7192b95ffc8da78631011ed6b24cdd573f977a11e794811", 16))) + { + fail("y uncompressed incorrectly"); + } + + byte[] encoding = p.getEncoded(); + + if (!areEqual(encoding, Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"))) + { + fail("point compressed incorrectly"); + } + } + + /** + * X9.62 - 1998,<br> + * J.3.2, Page 155, ECDSA over the field Fp<br> + * an example with 239 bit prime + */ + private void testECDSA239bitPrime() + { + BigInteger r = new BigInteger("308636143175167811492622547300668018854959378758531778147462058306432176"); + BigInteger s = new BigInteger("323813553209797357708078776831250505931891051755007842781978505179448783"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); + + SecureRandom k = new FixedSecureRandom(true, kData); + + BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d + params); + + ECDSASigner ecdsa = new ECDSASigner(); + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + System.getProperty("line.separator") + + " expecting: " + r + System.getProperty("line.separator") + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + System.getProperty("line.separator") + + " expecting: " + s + System.getProperty("line.separator") + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q + params); + + ecdsa.init(false, pubKey); + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + + /** + * X9.62 - 1998,<br> + * J.2.1, Page 100, ECDSA over the field F2m<br> + * an example with 191 bit binary field + */ + private void testECDSA191bitBinary() + { + BigInteger r = new BigInteger("87194383164871543355722284926904419997237591535066528048"); + BigInteger s = new BigInteger("308992691965804947361541664549085895292153777025772063598"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("1542725565216523985789236956265265265235675811949404040041")); + + SecureRandom k = new FixedSecureRandom(kData); + + BigInteger n = new BigInteger("1569275433846670190958947355803350458831205595451630533029"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve.F2m curve = new ECCurve.F2m( + 191, // m + 9, //k + new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16), // a + new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16), // b + n, h); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("0436B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D765BE73433B3F95E332932E70EA245CA2418EA0EF98018FB")), // G + n, h); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("1275552191113212300012030439187146164646146646466749494799"), // d + params); + + ECDSASigner ecdsa = new ECDSASigner(); + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + System.getProperty("line.separator") + + " expecting: " + r + System.getProperty("line.separator") + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + System.getProperty("line.separator") + + " expecting: " + s + System.getProperty("line.separator") + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("045DE37E756BD55D72E3768CB396FFEB962614DEA4CE28A2E755C0E0E02F5FB132CAF416EF85B229BBB8E1352003125BA1")), // Q + params); + + ecdsa.init(false, pubKey); + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + + /** + * X9.62 - 1998,<br> + * J.2.1, Page 100, ECDSA over the field F2m<br> + * an example with 191 bit binary field + */ + private void testECDSA239bitBinary() + { + BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552"); + BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); + + SecureRandom k = new FixedSecureRandom(kData); + + BigInteger n = new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve.F2m curve = new ECCurve.F2m( + 239, // m + 36, //k + new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a + new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16), // b + n, h); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G + n, h); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d + params); + + ECDSASigner ecdsa = new ECDSASigner(); + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + System.getProperty("line.separator") + + " expecting: " + r + System.getProperty("line.separator") + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + System.getProperty("line.separator") + + " expecting: " + s + System.getProperty("line.separator") + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q + params); + + ecdsa.init(false, pubKey); + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + // L 4.1 X9.62 2005 + private void testECDSAP224sha224() + { + X9ECParameters p = NISTNamedCurves.getByName("P-224"); + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("6081831502424510080126737029209236539191290354021104541805484120491"), // d + params); + SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601"))); + + byte[] M = Hex.decode("8797A3C693CC292441039A4E6BAB7387F3B4F2A63D00ED384B378C79"); + + ECDSASigner dsa = new ECDSASigner(); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + BigInteger[] sig = dsa.generateSignature(M); + + BigInteger r = new BigInteger("26477406756127720855365980332052585411804331993436302005017227573742"); + BigInteger s = new BigInteger("17694958233103667059888193972742186995283044672015112738919822429978"); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + System.getProperty("line.separator") + + " expecting: " + r + System.getProperty("line.separator") + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + System.getProperty("line.separator") + + " expecting: " + s + System.getProperty("line.separator") + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + params.getCurve().decodePoint(Hex.decode("03FD44EC11F9D43D9D23B1E1D1C9ED6519B40ECF0C79F48CF476CC43F1")), // Q + params); + + dsa.init(false, pubKey); + if (!dsa.verifySignature(M, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + private void testECDSASecP224k1sha256() + { + X9ECParameters p = SECNamedCurves.getByName("secp224k1"); + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("BE6F6E91FE96840A6518B56F3FE21689903A64FA729057AB872A9F51", 16), // d + params); + SecureRandom k = new FixedSecureRandom(Hex.decode("00c39beac93db21c3266084429eb9b846b787c094f23a4de66447efbb3")); + + byte[] M = Hex.decode("E5D5A7ADF73C5476FAEE93A2C76CE94DC0557DB04CDC189504779117920B896D"); + + ECDSASigner dsa = new ECDSASigner(); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + BigInteger[] sig = dsa.generateSignature(M); + + BigInteger r = new BigInteger("8163E5941BED41DA441B33E653C632A55A110893133351E20CE7CB75", 16); + BigInteger s = new BigInteger("D12C3FC289DDD5F6890DCE26B65792C8C50E68BF551D617D47DF15A8", 16); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + System.getProperty("line.separator") + + " expecting: " + r + System.getProperty("line.separator") + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + System.getProperty("line.separator") + + " expecting: " + s + System.getProperty("line.separator") + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + params.getCurve().decodePoint(Hex.decode("04C5C9B38D3603FCCD6994CBB9594E152B658721E483669BB42728520F484B537647EC816E58A8284D3B89DFEDB173AFDC214ECA95A836FA7C")), // Q + params); + + dsa.init(false, pubKey); + if (!dsa.verifySignature(M, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + // L4.2 X9.62 2005 + private void testECDSAP256sha256() + { + X9ECParameters p = NISTNamedCurves.getByName("P-256"); + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("20186677036482506117540275567393538695075300175221296989956723148347484984008"), // d + params); + SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); + + byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); + + ECDSASigner dsa = new ECDSASigner(); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + BigInteger[] sig = dsa.generateSignature(M); + + BigInteger r = new BigInteger("97354732615802252173078420023658453040116611318111190383344590814578738210384"); + BigInteger s = new BigInteger("98506158880355671805367324764306888225238061309262649376965428126566081727535"); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + System.getProperty("line.separator") + + " expecting: " + r + System.getProperty("line.separator") + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + System.getProperty("line.separator") + + " expecting: " + s + System.getProperty("line.separator") + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + params.getCurve().decodePoint(Hex.decode("03596375E6CE57E0F20294FC46BDFCFD19A39F8161B58695B3EC5B3D16427C274D")), // Q + params); + + dsa.init(false, pubKey); + if (!dsa.verifySignature(M, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + private void testECDSAP224OneByteOver() + { + X9ECParameters p = NISTNamedCurves.getByName("P-224"); + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("6081831502424510080126737029209236539191290354021104541805484120491"), // d + params); + SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601"))); + + byte[] M = Hex.decode("8797A3C693CC292441039A4E6BAB7387F3B4F2A63D00ED384B378C79FF"); + + ECDSASigner dsa = new ECDSASigner(); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + BigInteger[] sig = dsa.generateSignature(M); + + BigInteger r = new BigInteger("26477406756127720855365980332052585411804331993436302005017227573742"); + BigInteger s = new BigInteger("17694958233103667059888193972742186995283044672015112738919822429978"); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + System.getProperty("line.separator") + + " expecting: " + r + System.getProperty("line.separator") + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + System.getProperty("line.separator") + + " expecting: " + s + System.getProperty("line.separator") + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + params.getCurve().decodePoint(Hex.decode("03FD44EC11F9D43D9D23B1E1D1C9ED6519B40ECF0C79F48CF476CC43F1")), // Q + params); + + dsa.init(false, pubKey); + if (!dsa.verifySignature(M, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + // L4.3 X9.62 2005 + private void testECDSAP521sha512() + { + X9ECParameters p = NISTNamedCurves.getByName("P-521"); + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("617573726813476282316253885608633222275541026607493641741273231656161177732180358888434629562647985511298272498852936680947729040673640492310550142822667389"), // d + params); + SecureRandom k = new FixedSecureRandom(BigIntegers.asUnsignedByteArray(new BigInteger("6806532878215503520845109818432174847616958675335397773700324097584974639728725689481598054743894544060040710846048585856076812050552869216017728862957612913"))); + + byte[] M = Hex.decode("6893B64BD3A9615C39C3E62DDD269C2BAAF1D85915526083183CE14C2E883B48B193607C1ED871852C9DF9C3147B574DC1526C55DE1FE263A676346A20028A66"); + + ECDSASigner dsa = new ECDSASigner(); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + BigInteger[] sig = dsa.generateSignature(M); + + BigInteger r = new BigInteger("1368926195812127407956140744722257403535864168182534321188553460365652865686040549247096155740756318290773648848859639978618869784291633651685766829574104630"); + BigInteger s = new BigInteger("1624754720348883715608122151214003032398685415003935734485445999065609979304811509538477657407457976246218976767156629169821116579317401249024208611945405790"); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + System.getProperty("line.separator") + + " expecting: " + r + System.getProperty("line.separator") + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + System.getProperty("line.separator") + + " expecting: " + s + System.getProperty("line.separator") + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + params.getCurve().decodePoint(Hex.decode("020145E221AB9F71C5FE740D8D2B94939A09E2816E2167A7D058125A06A80C014F553E8D6764B048FB6F2B687CEC72F39738F223D4CE6AFCBFF2E34774AA5D3C342CB3")), // Q + params); + + dsa.init(false, pubKey); + if (!dsa.verifySignature(M, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * General test for long digest. + */ + private void testECDSA239bitBinaryAndLargeDigest() + { + BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552"); + BigInteger s = new BigInteger("144940322424411242416373536877786566515839911620497068645600824084578597"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); + + SecureRandom k = new FixedSecureRandom(kData); + + BigInteger n = new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve.F2m curve = new ECCurve.F2m( + 239, // m + 36, //k + new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a + new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16), // b + n, h); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G + n, h); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d + params); + + ECDSASigner ecdsa = new ECDSASigner(); + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517968236873715988614170569073515315707566766479517968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + System.getProperty("line.separator") + + " expecting: " + r + System.getProperty("line.separator") + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + System.getProperty("line.separator") + + " expecting: " + s + System.getProperty("line.separator") + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q + params); + + ecdsa.init(false, pubKey); + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * key generation test + */ + private void testECDSAKeyGenTest() + { + SecureRandom random = new SecureRandom(); + + BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + n); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + ECDSASigner ecdsa = new ECDSASigner(); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + ecdsa.init(false, pair.getPublic()); + + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * Basic Key Agreement Test + */ + private void testECBasicAgreementTest() + { + SecureRandom random = new SecureRandom(); + + BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + n); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair p1 = pGen.generateKeyPair(); + AsymmetricCipherKeyPair p2 = pGen.generateKeyPair(); + + // + // two way + // + BasicAgreement e1 = new ECDHBasicAgreement(); + BasicAgreement e2 = new ECDHBasicAgreement(); + + e1.init(p1.getPrivate()); + e2.init(p2.getPrivate()); + + BigInteger k1 = e1.calculateAgreement(p2.getPublic()); + BigInteger k2 = e2.calculateAgreement(p1.getPublic()); + + if (!k1.equals(k2)) + { + fail("calculated agreement test failed"); + } + + // + // two way + // + e1 = new ECDHCBasicAgreement(); + e2 = new ECDHCBasicAgreement(); + + e1.init(p1.getPrivate()); + e2.init(p2.getPrivate()); + + k1 = e1.calculateAgreement(p2.getPublic()); + k2 = e2.calculateAgreement(p1.getPublic()); + + if (!k1.equals(k2)) + { + fail("calculated agreement test failed"); + } + } + + private void testECMQVTestVector1() + { + // Test Vector from GEC-2 + + X9ECParameters x9 = SECNamedCurves.getByName("secp160r1"); + ECDomainParameters p = new ECDomainParameters( + x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + + AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("0251B4496FECC406ED0E75A24A3C03206251419DC0")), p), + new ECPrivateKeyParameters( + new BigInteger("AA374FFC3CE144E6B073307972CB6D57B2A4E982", 16), p)); + + AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("03D99CE4D8BF52FA20BD21A962C6556B0F71F4CA1F")), p), + new ECPrivateKeyParameters( + new BigInteger("149EC7EA3A220A887619B3F9E5B4CA51C7D1779C", 16), p)); + + AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("0349B41E0E9C0369C2328739D90F63D56707C6E5BC")), p), + new ECPrivateKeyParameters( + new BigInteger("45FB58A92A17AD4B15101C66E74F277E2B460866", 16), p)); + + AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("02706E5D6E1F640C6E9C804E75DBC14521B1E5F3B5")), p), + new ECPrivateKeyParameters( + new BigInteger("18C13FCED9EADF884F7C595C8CB565DEFD0CB41E", 16), p)); + + BigInteger x = calculateAgreement(U1, U2, V1, V2); + + if (x == null + || !x.equals(new BigInteger("5A6955CEFDB4E43255FB7FCF718611E4DF8E05AC", 16))) + { + fail("MQV Test Vector #1 agreement failed"); + } + } + + private void testECMQVTestVector2() + { + // Test Vector from GEC-2 + + X9ECParameters x9 = SECNamedCurves.getByName("sect163k1"); + ECDomainParameters p = new ECDomainParameters( + x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + + AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("03037D529FA37E42195F10111127FFB2BB38644806BC")), p), + new ECPrivateKeyParameters( + new BigInteger("03A41434AA99C2EF40C8495B2ED9739CB2155A1E0D", 16), p)); + + AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("02015198E74BC2F1E5C9A62B80248DF0D62B9ADF8429")), p), + new ECPrivateKeyParameters( + new BigInteger("032FC4C61A8211E6A7C4B8B0C03CF35F7CF20DBD52", 16), p)); + + AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("03072783FAAB9549002B4F13140B88132D1C75B3886C")), p), + new ECPrivateKeyParameters( + new BigInteger("57E8A78E842BF4ACD5C315AA0569DB1703541D96", 16), p)); + + AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("03067E3AEA3510D69E8EDD19CB2A703DDC6CF5E56E32")), p), + new ECPrivateKeyParameters( + new BigInteger("02BD198B83A667A8D908EA1E6F90FD5C6D695DE94F", 16), p)); + + BigInteger x = calculateAgreement(U1, U2, V1, V2); + + if (x == null + || !x.equals(new BigInteger("038359FFD30C0D5FC1E6154F483B73D43E5CF2B503", 16))) + { + fail("MQV Test Vector #2 agreement failed"); + } + } + + private void testECMQVRandom() + { + SecureRandom random = new SecureRandom(); + + BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + n, ECConstants.ONE); + + ECDomainParameters parameters = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + n); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + + pGen.init(new ECKeyGenerationParameters(parameters, random)); + + + // Pre-established key pairs + AsymmetricCipherKeyPair U1 = pGen.generateKeyPair(); + AsymmetricCipherKeyPair V1 = pGen.generateKeyPair(); + + // Ephemeral key pairs + AsymmetricCipherKeyPair U2 = pGen.generateKeyPair(); + AsymmetricCipherKeyPair V2 = pGen.generateKeyPair(); + + BigInteger x = calculateAgreement(U1, U2, V1, V2); + + if (x == null) + { + fail("MQV Test Vector (random) agreement failed"); + } + } + + private static BigInteger calculateAgreement( + AsymmetricCipherKeyPair U1, + AsymmetricCipherKeyPair U2, + AsymmetricCipherKeyPair V1, + AsymmetricCipherKeyPair V2) + { + ECMQVBasicAgreement u = new ECMQVBasicAgreement(); + u.init(new MQVPrivateParameters( + (ECPrivateKeyParameters)U1.getPrivate(), + (ECPrivateKeyParameters)U2.getPrivate(), + (ECPublicKeyParameters)U2.getPublic())); + BigInteger ux = u.calculateAgreement(new MQVPublicParameters( + (ECPublicKeyParameters)V1.getPublic(), + (ECPublicKeyParameters)V2.getPublic())); + + ECMQVBasicAgreement v = new ECMQVBasicAgreement(); + v.init(new MQVPrivateParameters( + (ECPrivateKeyParameters)V1.getPrivate(), + (ECPrivateKeyParameters)V2.getPrivate(), + (ECPublicKeyParameters)V2.getPublic())); + BigInteger vx = v.calculateAgreement(new MQVPublicParameters( + (ECPublicKeyParameters)U1.getPublic(), + (ECPublicKeyParameters)U2.getPublic())); + + if (ux.equals(vx)) + { + return ux; + } + + return null; + } + + public String getName() + { + return "EC"; + } + + public void performTest() + { + decodeTest(); + testECDSA192bitPrime(); + testECDSA239bitPrime(); + testECDSA191bitBinary(); + testECDSA239bitBinary(); + testECDSAKeyGenTest(); + testECBasicAgreementTest(); + + testECDSAP224sha224(); + testECDSAP224OneByteOver(); + testECDSAP256sha256(); + testECDSAP521sha512(); + testECDSASecP224k1sha256(); + testECDSA239bitBinaryAndLargeDigest(); + + testECMQVTestVector1(); + testECMQVTestVector2(); + testECMQVRandom(); + } + + + public static void main( + String[] args) + { + runTest(new ECTest()); + } +} + diff --git a/core/src/test/java/org/spongycastle/crypto/test/ElGamalTest.java b/core/src/test/java/org/spongycastle/crypto/test/ElGamalTest.java new file mode 100644 index 00000000..08c029af --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ElGamalTest.java @@ -0,0 +1,285 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.engines.ElGamalEngine; +import org.spongycastle.crypto.generators.ElGamalKeyPairGenerator; +import org.spongycastle.crypto.generators.ElGamalParametersGenerator; +import org.spongycastle.crypto.params.ElGamalKeyGenerationParameters; +import org.spongycastle.crypto.params.ElGamalParameters; +import org.spongycastle.crypto.params.ElGamalPrivateKeyParameters; +import org.spongycastle.crypto.params.ElGamalPublicKeyParameters; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.BigIntegers; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class ElGamalTest + extends SimpleTest +{ + private BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + private BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + private BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16); + private BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16); + + private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16); + private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16); + + private BigInteger yPgpBogusPSamp = new BigInteger("de4688497cc05b45fe8559bc9918c45afcad69b74123a7236eba409fd9de8ea34c7869839ee9df35e3d97576145d089841aa65b5b4e061fae52c37e430354269a02496b8ed8456f2d0d7c9b0db985fbcb21ae9f78507ed6e3a29db595b201b1a4f931c7d791eede65ccf918e8a61cf146859151c78c41ad48853694623467d78", 16); + private BigInteger xPgpBogusPSamp = new BigInteger("cbaf780f2cfe4f987bbc5fcb0738bbd7912060ccfdf37cbfeea65c0fd857e74a8df6cc359375f28cf5725d081813c614410a78cbe4b06d677beea9ff0fa10b1dbc47a6ed8c5b8466d6a95d6574029dbdf72596392e1b6b230faf9916dc8455821c10527a375a4d1c8a54947d1fe714d321aca25ad486b4b456506999fd2fd11a", 16); + private BigInteger gPgpBogusPSamp = new BigInteger("153ffe9522076d1cbd6e75f0816a0fc2ebd8b0e0091406587387a1763022088a03b411eed07ff50efb82b21f1608c352d10f63ba7e7e981a2f3387cec8af2915953d00493857663ae8919f517fe90f1d2abe7af4305a344b10d1a25d75f65902cd7fd775853d3ac43d7c5253ad666e1e63ee98cdcb10af81273d4ff053ff07d51", 16); + private BigInteger pPgpBogusPSamp = new BigInteger("15061b26cdab4e865098a01c86f13b03220104c5443e950658b36b85245aa0c616a0c0d8d99c454bea087c172315e45b3bc9b925443948a2b6ba47608a6035b9a79a4ef34a78d7274a12ede8364f02d5030db864988643d7e92753df603bd69fbd2682ab0af64d1a866d1131a2cb13333cedb0a9e6eefddd9fff8154d34c2daab", 16); + private int lPgpBogusPSamp = 0; + + public String getName() + { + return "ElGamal"; + } + + private void testEnc( + int size, + int privateValueSize, + BigInteger g, + BigInteger p) + { + ElGamalParameters dhParams = new ElGamalParameters(p, g, privateValueSize); + ElGamalKeyGenerationParameters params = new ElGamalKeyGenerationParameters(new SecureRandom(), dhParams); + ElGamalKeyPairGenerator kpGen = new ElGamalKeyPairGenerator(); + + kpGen.init(params); + + // + // generate pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + ElGamalPublicKeyParameters pu = (ElGamalPublicKeyParameters)pair.getPublic(); + ElGamalPrivateKeyParameters pv = (ElGamalPrivateKeyParameters)pair.getPrivate(); + + checkKeySize(privateValueSize, pv); + + ElGamalEngine e = new ElGamalEngine(); + + e.init(true, pu); + + if (e.getOutputBlockSize() != size / 4) + { + fail(size + " getOutputBlockSize() on encryption failed."); + } + + byte[] message = Hex.decode("5468697320697320612074657374"); + + byte[] pText = message; + byte[] cText = e.processBlock(pText, 0, pText.length); + + e.init(false, pv); + + if (e.getOutputBlockSize() != (size / 8) - 1) + { + fail(size + " getOutputBlockSize() on decryption failed."); + } + + pText = e.processBlock(cText, 0, cText.length); + + if (!Arrays.areEqual(message, pText)) + { + fail(size + " bit test failed"); + } + + e.init(true, pu); + + byte[] bytes = new byte[e.getInputBlockSize() + 2]; + + try + { + e.processBlock(bytes, 0, bytes.length); + + fail("out of range block not detected"); + } + catch (DataLengthException ex) + { + // expected + } + + try + { + bytes[0] = (byte)0xff; + + e.processBlock(bytes, 0, bytes.length - 1); + + fail("out of range block not detected"); + } + catch (DataLengthException ex) + { + // expected + } + + try + { + bytes[0] = (byte)0x7f; + + e.processBlock(bytes, 0, bytes.length - 1); + } + catch (DataLengthException ex) + { + fail("in range block failed"); + } + + try + { + bytes = BigIntegers.asUnsignedByteArray(p); + + e.processBlock(bytes, 0, bytes.length); + + fail("out of range block not detected"); + } + catch (DataLengthException ex) + { + // expected + } + + try + { + bytes = BigIntegers.asUnsignedByteArray(p.subtract(BigInteger.valueOf(1))); + + e.processBlock(bytes, 0, bytes.length); + } + catch (DataLengthException ex) + { + fail("boundary block rejected"); + } + } + + private void checkKeySize( + int privateValueSize, + ElGamalPrivateKeyParameters priv) + { + if (privateValueSize != 0) + { + if (priv.getX().bitLength() != privateValueSize) + { + fail("limited key check failed for key size " + privateValueSize); + } + } + } + + /** + * this test is can take quiet a while + * + * @param size size of key in bits. + */ + private void testGeneration( + int size) + { + ElGamalParametersGenerator pGen = new ElGamalParametersGenerator(); + + pGen.init(size, 10, new SecureRandom()); + + ElGamalParameters elParams = pGen.generateParameters(); + + if (elParams.getL() != 0) + { + fail("ElGamalParametersGenerator failed to set L to 0 in generated ElGamalParameters"); + } + + ElGamalKeyGenerationParameters params = new ElGamalKeyGenerationParameters(new SecureRandom(), elParams); + + ElGamalKeyPairGenerator kpGen = new ElGamalKeyPairGenerator(); + + kpGen.init(params); + + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + ElGamalPublicKeyParameters pu = (ElGamalPublicKeyParameters)pair.getPublic(); + ElGamalPrivateKeyParameters pv = (ElGamalPrivateKeyParameters)pair.getPrivate(); + + ElGamalEngine e = new ElGamalEngine(); + + e.init(true, new ParametersWithRandom(pu, new SecureRandom())); + + byte[] message = Hex.decode("5468697320697320612074657374"); + + byte[] pText = message; + byte[] cText = e.processBlock(pText, 0, pText.length); + + e.init(false, pv); + + pText = e.processBlock(cText, 0, cText.length); + + if (!Arrays.areEqual(message, pText)) + { + fail("generation test failed"); + } + } + + private void testInitCheck() + { + try + { + new ElGamalEngine().processBlock(new byte[]{ 1 }, 0, 1); + fail("failed initialisation check"); + } + catch (IllegalStateException e) + { + // expected + } + } + + private void testInvalidP() + { + ElGamalParameters dhParams = new ElGamalParameters(pPgpBogusPSamp, gPgpBogusPSamp, lPgpBogusPSamp); + ElGamalPublicKeyParameters pu = new ElGamalPublicKeyParameters(yPgpBogusPSamp, dhParams); + ElGamalPrivateKeyParameters pv = new ElGamalPrivateKeyParameters(xPgpBogusPSamp, dhParams); + + ElGamalEngine e = new ElGamalEngine(); + + e.init(true, pu); + + byte[] message = Hex.decode("5468697320697320612074657374"); + + byte[] pText = message; + byte[] cText = e.processBlock(pText, 0, pText.length); + + e.init(false, pv); + + pText = e.processBlock(cText, 0, cText.length); + + if (Arrays.areEqual(message, pText)) + { + fail("invalid test failed"); + } + } + + public void performTest() + { + testInvalidP(); + + testEnc(512, 0, g512, p512); + testEnc(768, 0, g768, p768); + testEnc(1024, 0, g1024, p1024); + + testEnc(512, 64, g512, p512); + testEnc(768, 128, g768, p768); + + // + // generation test. + // + testGeneration(258); + + testInitCheck(); + } + + public static void main( + String[] args) + { + runTest(new ElGamalTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/EqualsHashCodeTest.java b/core/src/test/java/org/spongycastle/crypto/test/EqualsHashCodeTest.java new file mode 100644 index 00000000..3966f8e8 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/EqualsHashCodeTest.java @@ -0,0 +1,261 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.generators.DHKeyPairGenerator; +import org.spongycastle.crypto.generators.ElGamalKeyPairGenerator; +import org.spongycastle.crypto.params.DHKeyGenerationParameters; +import org.spongycastle.crypto.params.DHKeyParameters; +import org.spongycastle.crypto.params.DHParameters; +import org.spongycastle.crypto.params.DHPrivateKeyParameters; +import org.spongycastle.crypto.params.DHPublicKeyParameters; +import org.spongycastle.crypto.params.DHValidationParameters; +import org.spongycastle.crypto.params.DSAParameters; +import org.spongycastle.crypto.params.DSAValidationParameters; +import org.spongycastle.crypto.params.ElGamalKeyGenerationParameters; +import org.spongycastle.crypto.params.ElGamalKeyParameters; +import org.spongycastle.crypto.params.ElGamalParameters; +import org.spongycastle.crypto.params.ElGamalPrivateKeyParameters; +import org.spongycastle.crypto.params.ElGamalPublicKeyParameters; +import org.spongycastle.crypto.params.GOST3410Parameters; +import org.spongycastle.crypto.params.GOST3410ValidationParameters; +import org.spongycastle.util.test.SimpleTest; + +import java.math.BigInteger; +import java.security.SecureRandom; + +class DHTestKeyParameters + extends DHKeyParameters +{ + protected DHTestKeyParameters(boolean isPrivate, DHParameters params) + { + super(isPrivate, params); + } +} + +class ElGamalTestKeyParameters + extends ElGamalKeyParameters +{ + protected ElGamalTestKeyParameters(boolean isPrivate, ElGamalParameters params) + { + super(isPrivate, params); + } +} + +public class EqualsHashCodeTest + extends SimpleTest +{ + private static Object OTHER = new Object(); + + public String getName() + { + return "EqualsHashCode"; + } + + private void doTest(Object a, Object equalsA, Object notEqualsA) + { + if (a.equals(null)) + { + fail("a equaled null"); + } + + if (!a.equals(equalsA) || !equalsA.equals(a)) + { + fail("equality failed"); + } + + if (a.equals(OTHER)) + { + fail("other inequality failed"); + } + + if (a.equals(notEqualsA) || notEqualsA.equals(a)) + { + fail("inequality failed"); + } + + if (a.hashCode() != equalsA.hashCode()) + { + fail("hashCode equality failed"); + } + } + + private void dhTest() + { + BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + DHParameters dhParams = new DHParameters(p512, g512); + DHKeyGenerationParameters params = new DHKeyGenerationParameters(new SecureRandom(), dhParams); DHKeyPairGenerator kpGen = new DHKeyPairGenerator(); + + kpGen.init(params); + + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + + DHPublicKeyParameters pu2 = new DHPublicKeyParameters(pu1.getY(), pu1.getParameters()); + DHPrivateKeyParameters pv2 = new DHPrivateKeyParameters(pv1.getX(), pv1.getParameters()); + DHPublicKeyParameters pu3 = new DHPublicKeyParameters(pv1.getX(), pu1.getParameters()); + DHPrivateKeyParameters pv3 = new DHPrivateKeyParameters(pu1.getY(), pu1.getParameters()); + + doTest(pu1, pu2, pu3); + doTest(pv1, pv2, pv3); + + DHParameters pr1 = pu1.getParameters(); + DHParameters pr2 = new DHParameters(pr1.getP(), pr1.getG(), pr1.getQ(), pr1.getM(), pr1.getL(), pr1.getJ(), pr1.getValidationParameters()); + DHParameters pr3 = new DHParameters(pr1.getG(), pr1.getP(), pr1.getQ(), pr1.getM(), pr1.getL(), pr1.getJ(), pr1.getValidationParameters()); + + doTest(pr1, pr2, pr3); + + pr3 = new DHParameters(pr1.getG(), pr1.getP(), null, pr1.getM(), pr1.getL(), pr1.getJ(), pr1.getValidationParameters()); + + doTest(pr1, pr2, pr3); + + pu2 = new DHPublicKeyParameters(pu1.getY(), pr2); + pv2 = new DHPrivateKeyParameters(pv1.getX(), pr2); + + doTest(pu1, pu2, pu3); + doTest(pv1, pv2, pv3); + + DHValidationParameters vp1 = new DHValidationParameters(new byte[20], 1024); + DHValidationParameters vp2 = new DHValidationParameters(new byte[20], 1024); + DHValidationParameters vp3 = new DHValidationParameters(new byte[24], 1024); + + doTest(vp1, vp1, vp3); + doTest(vp1, vp2, vp3); + + byte[] bytes = new byte[20]; + bytes[0] = 1; + + vp3 = new DHValidationParameters(bytes, 1024); + + doTest(vp1, vp2, vp3); + + vp3 = new DHValidationParameters(new byte[20], 2048); + + doTest(vp1, vp2, vp3); + + DHTestKeyParameters k1 = new DHTestKeyParameters(false, null); + DHTestKeyParameters k2 = new DHTestKeyParameters(false, null); + DHTestKeyParameters k3 = new DHTestKeyParameters(false, pu1.getParameters()); + + doTest(k1, k2, k3); + } + + private void elGamalTest() + { + BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + ElGamalParameters dhParams = new ElGamalParameters(p512, g512); + ElGamalKeyGenerationParameters params = new ElGamalKeyGenerationParameters(new SecureRandom(), dhParams); ElGamalKeyPairGenerator kpGen = new ElGamalKeyPairGenerator(); + + kpGen.init(params); + + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + ElGamalPublicKeyParameters pu1 = (ElGamalPublicKeyParameters)pair.getPublic(); + ElGamalPrivateKeyParameters pv1 = (ElGamalPrivateKeyParameters)pair.getPrivate(); + + ElGamalPublicKeyParameters pu2 = new ElGamalPublicKeyParameters(pu1.getY(), pu1.getParameters()); + ElGamalPrivateKeyParameters pv2 = new ElGamalPrivateKeyParameters(pv1.getX(), pv1.getParameters()); + ElGamalPublicKeyParameters pu3 = new ElGamalPublicKeyParameters(pv1.getX(), pu1.getParameters()); + ElGamalPrivateKeyParameters pv3 = new ElGamalPrivateKeyParameters(pu1.getY(), pu1.getParameters()); + + doTest(pu1, pu2, pu3); + doTest(pv1, pv2, pv3); + + ElGamalParameters pr1 = pu1.getParameters(); + ElGamalParameters pr2 = new ElGamalParameters(pr1.getP(), pr1.getG()); + ElGamalParameters pr3 = new ElGamalParameters(pr1.getG(), pr1.getP()); + + doTest(pr1, pr2, pr3); + + pu2 = new ElGamalPublicKeyParameters(pu1.getY(), pr2); + pv2 = new ElGamalPrivateKeyParameters(pv1.getX(), pr2); + + doTest(pu1, pu2, pu3); + doTest(pv1, pv2, pv3); + + ElGamalTestKeyParameters k1 = new ElGamalTestKeyParameters(false, null); + ElGamalTestKeyParameters k2 = new ElGamalTestKeyParameters(false, null); + ElGamalTestKeyParameters k3 = new ElGamalTestKeyParameters(false, pu1.getParameters()); + + doTest(k1, k2, k3); + } + + private void dsaTest() + { + BigInteger a = BigInteger.valueOf(1), b = BigInteger.valueOf(2), c = BigInteger.valueOf(3); + + DSAParameters dsaP1 = new DSAParameters(a, b, c); + DSAParameters dsaP2 = new DSAParameters(a, b, c); + DSAParameters dsaP3 = new DSAParameters(b, c, a); + + doTest(dsaP1, dsaP2, dsaP3); + + DSAValidationParameters vp1 = new DSAValidationParameters(new byte[20], 1024); + DSAValidationParameters vp2 = new DSAValidationParameters(new byte[20], 1024); + DSAValidationParameters vp3 = new DSAValidationParameters(new byte[24], 1024); + + doTest(vp1, vp1, vp3); + doTest(vp1, vp2, vp3); + + byte[] bytes = new byte[20]; + bytes[0] = 1; + + vp3 = new DSAValidationParameters(bytes, 1024); + + doTest(vp1, vp2, vp3); + + vp3 = new DSAValidationParameters(new byte[20], 2048); + + doTest(vp1, vp2, vp3); + } + + private void gost3410Test() + { + BigInteger a = BigInteger.valueOf(1), b = BigInteger.valueOf(2), c = BigInteger.valueOf(3); + + GOST3410Parameters g1 = new GOST3410Parameters(a, b, c); + GOST3410Parameters g2 = new GOST3410Parameters(a, b, c); + GOST3410Parameters g3 = new GOST3410Parameters(a, c, c); + + doTest(g1, g2, g3); + + GOST3410ValidationParameters v1 = new GOST3410ValidationParameters(100, 1); + GOST3410ValidationParameters v2 = new GOST3410ValidationParameters(100, 1); + GOST3410ValidationParameters v3 = new GOST3410ValidationParameters(101, 1); + + doTest(v1, v2, v3); + + v3 = new GOST3410ValidationParameters(100, 2); + + doTest(v1, v2, v3); + + v1 = new GOST3410ValidationParameters(100L, 1L); + v2 = new GOST3410ValidationParameters(100L, 1L); + v3 = new GOST3410ValidationParameters(101L, 1L); + + doTest(v1, v2, v3); + + v3 = new GOST3410ValidationParameters(100L, 2L); + + doTest(v1, v2, v3); + + } + + public void performTest() + throws Exception + { + dhTest(); + elGamalTest(); + gost3410Test(); + dsaTest(); + } + + public static void main( + String[] args) + { + runTest(new EqualsHashCodeTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/GCMReorderTest.java b/core/src/test/java/org/spongycastle/crypto/test/GCMReorderTest.java new file mode 100644 index 00000000..adddcf61 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/GCMReorderTest.java @@ -0,0 +1,347 @@ +package org.spongycastle.crypto.test; + +import java.io.IOException; +import java.security.SecureRandom; + +import junit.framework.TestCase; +import org.spongycastle.crypto.modes.gcm.GCMExponentiator; +import org.spongycastle.crypto.modes.gcm.GCMMultiplier; +import org.spongycastle.crypto.modes.gcm.Tables1kGCMExponentiator; +import org.spongycastle.crypto.modes.gcm.Tables64kGCMMultiplier; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.Pack; +import org.spongycastle.util.encoders.Hex; + +public class GCMReorderTest + extends TestCase +{ + private static final byte[] H; + private static final SecureRandom random = new SecureRandom(); + private static final GCMMultiplier mul = new Tables64kGCMMultiplier(); + private static final GCMExponentiator exp = new Tables1kGCMExponentiator(); + private static final byte[] EMPTY = new byte[0]; + + static + { + H = new byte[16]; + random.nextBytes(H); + mul.init(Arrays.clone(H)); + exp.init(Arrays.clone(H)); + } + + public void testCombine() throws Exception + { + for (int count = 0; count < 10; ++count) + { + byte[] A = randomBytes(1000); + byte[] C = randomBytes(1000); + + byte[] ghashA_ = GHASH(A, EMPTY); + byte[] ghash_C = GHASH(EMPTY, C); + byte[] ghashAC = GHASH(A, C); + + byte[] ghashCombine = combine_GHASH(ghashA_, (long)A.length * 8, ghash_C, (long)C.length * 8); + + assertTrue(Arrays.areEqual(ghashAC, ghashCombine)); + } + } + + public void testConcatAuth() throws Exception + { + for (int count = 0; count < 10; ++count) + { + byte[] P = randomBlocks(100); + byte[] A = randomBytes(1000); + byte[] PA = concatArrays(P, A); + + byte[] ghashP_ = GHASH(P, EMPTY); + byte[] ghashA_ = GHASH(A, EMPTY); + byte[] ghashPA_ = GHASH(PA, EMPTY); + byte[] ghashConcat = concatAuth_GHASH(ghashP_, (long)P.length * 8, ghashA_, (long)A.length * 8); + + assertTrue(Arrays.areEqual(ghashPA_, ghashConcat)); + } + } + + public void testConcatCrypt() throws Exception + { + for (int count = 0; count < 10; ++count) + { + byte[] P = randomBlocks(100); + byte[] A = randomBytes(1000); + byte[] PA = concatArrays(P, A); + + byte[] ghash_P = GHASH(EMPTY, P); + byte[] ghash_A = GHASH(EMPTY, A); + byte[] ghash_PA = GHASH(EMPTY, PA); + byte[] ghashConcat = concatCrypt_GHASH(ghash_P, (long)P.length * 8, ghash_A, (long)A.length * 8); + + assertTrue(Arrays.areEqual(ghash_PA, ghashConcat)); + } + } + + public void testExp() + { + { + byte[] buf1 = new byte[16]; + buf1[0] = (byte)0x80; + + byte[] buf2 = new byte[16]; + + for (int pow = 0; pow != 100; ++pow) + { + exp.exponentiateX(pow, buf2); + + assertTrue(Arrays.areEqual(buf1, buf2)); + + mul.multiplyH(buf1); + } + } + + long[] testPow = new long[]{ 10, 1, 8, 17, 24, 13, 2, 13, 2, 3 }; + byte[][] testData = new byte[][]{ + Hex.decode("9185848a877bd87ba071e281f476e8e7"), + Hex.decode("697ce3052137d80745d524474fb6b290"), + Hex.decode("2696fc47198bb23b11296e4f88720a17"), + Hex.decode("01f2f0ead011a4ae0cf3572f1b76dd8e"), + Hex.decode("a53060694a044e4b7fa1e661c5a7bb6b"), + Hex.decode("39c0392e8b6b0e04a7565c85394c2c4c"), + Hex.decode("519c362d502e07f2d8b7597a359a5214"), + Hex.decode("5a527a393675705e19b2117f67695af4"), + Hex.decode("27fc0901d1d332a53ba4d4386c2109d2"), + Hex.decode("93ca9b57174aabedf8220e83366d7df6"), + }; + + for (int i = 0; i != 10; ++i) + { + long pow = testPow[i]; + byte[] data = Arrays.clone(testData[i]); + + byte[] expected = Arrays.clone(data); + for (int j = 0; j < pow; ++j) + { + mul.multiplyH(expected); + } + + byte[] H_a = new byte[16]; + exp.exponentiateX(pow, H_a); + byte[] actual = multiply(data, H_a); + + assertTrue(Arrays.areEqual(expected, actual)); + } + } + + public void testMultiply() + { + byte[] expected = Arrays.clone(H); + mul.multiplyH(expected); + + assertTrue(Arrays.areEqual(expected, multiply(H, H))); + + for (int count = 0; count < 10; ++count) + { + byte[] a = new byte[16]; + random.nextBytes(a); + + byte[] b = new byte[16]; + random.nextBytes(b); + + expected = Arrays.clone(a); + mul.multiplyH(expected); + assertTrue(Arrays.areEqual(expected, multiply(a, H))); + assertTrue(Arrays.areEqual(expected, multiply(H, a))); + + expected = Arrays.clone(b); + mul.multiplyH(expected); + assertTrue(Arrays.areEqual(expected, multiply(b, H))); + assertTrue(Arrays.areEqual(expected, multiply(H, b))); + + assertTrue(Arrays.areEqual(multiply(a, b), multiply(b, a))); + } + } + + private byte[] randomBlocks(int upper) + { + byte[] bs = new byte[16 * random.nextInt(upper)]; + random.nextBytes(bs); + return bs; + } + + private byte[] randomBytes(int upper) + { + byte[] bs = new byte[random.nextInt(upper)]; + random.nextBytes(bs); + return bs; + } + + private byte[] concatArrays(byte[] a, byte[] b) throws IOException + { + byte[] ab = new byte[a.length + b.length]; + System.arraycopy(a, 0, ab, 0, a.length); + System.arraycopy(b, 0, ab, a.length, b.length); + return ab; + } + + private byte[] combine_GHASH(byte[] ghashA_, long bitlenA, byte[] ghash_C, long bitlenC) + { + // Note: bitlenA must be aligned to the block size + + long c = (bitlenC + 127) >>> 7; + + byte[] H_c = new byte[16]; + exp.exponentiateX(c, H_c); + + byte[] tmp1 = lengthBlock(bitlenA, 0); + mul.multiplyH(tmp1); + + byte[] ghashAC = Arrays.clone(ghashA_); + xor(ghashAC, tmp1); + ghashAC = multiply(ghashAC, H_c); + // No need to touch the len(C) part (second 8 bytes) + xor(ghashAC, tmp1); + xor(ghashAC, ghash_C); + + return ghashAC; + } + + private byte[] concatAuth_GHASH(byte[] ghashP, long bitlenP, byte[] ghashA, long bitlenA) + { + // Note: bitlenP must be aligned to the block size + + long a = (bitlenA + 127) >>> 7; + + byte[] tmp1 = lengthBlock(bitlenP, 0); + mul.multiplyH(tmp1); + + byte[] tmp2 = lengthBlock(bitlenA ^ (bitlenP + bitlenA), 0); + mul.multiplyH(tmp2); + + byte[] H_a = new byte[16]; + exp.exponentiateX(a, H_a); + + byte[] ghashC = Arrays.clone(ghashP); + xor(ghashC, tmp1); + ghashC = multiply(ghashC, H_a); + xor(ghashC, tmp2); + xor(ghashC, ghashA); + return ghashC; + } + + private byte[] concatCrypt_GHASH(byte[] ghashP, long bitlenP, byte[] ghashA, long bitlenA) + { + // Note: bitlenP must be aligned to the block size + + long a = (bitlenA + 127) >>> 7; + + byte[] tmp1 = lengthBlock(0, bitlenP); + mul.multiplyH(tmp1); + + byte[] tmp2 = lengthBlock(0, bitlenA ^ (bitlenP + bitlenA)); + mul.multiplyH(tmp2); + + byte[] H_a = new byte[16]; + exp.exponentiateX(a, H_a); + + byte[] ghashC = Arrays.clone(ghashP); + xor(ghashC, tmp1); + ghashC = multiply(ghashC, H_a); + xor(ghashC, tmp2); + xor(ghashC, ghashA); + return ghashC; + } + + private byte[] GHASH(byte[] A, byte[] C) + { + byte[] X = new byte[16]; + + { + for (int pos = 0; pos < A.length; pos += 16) + { + byte[] tmp = new byte[16]; + int num = Math.min(A.length - pos, 16); + System.arraycopy(A, pos, tmp, 0, num); + xor(X, tmp); + mul.multiplyH(X); + } + } + + { + for (int pos = 0; pos < C.length; pos += 16) + { + byte[] tmp = new byte[16]; + int num = Math.min(C.length - pos, 16); + System.arraycopy(C, pos, tmp, 0, num); + xor(X, tmp); + mul.multiplyH(X); + } + } + + { + xor(X, lengthBlock((long)A.length * 8, (long)C.length * 8)); + mul.multiplyH(X); + } + + return X; + } + + private static byte[] lengthBlock(long bitlenA, long bitlenC) + { + byte[] tmp = new byte[16]; + Pack.longToBigEndian(bitlenA, tmp, 0); + Pack.longToBigEndian(bitlenC, tmp, 8); + return tmp; + } + + private static void xor(byte[] block, byte[] val) + { + for (int i = 15; i >= 0; --i) + { + block[i] ^= val[i]; + } + } + + private static byte[] multiply(byte[] a, byte[] b) + { + byte[] c = new byte[16]; + byte[] tmp = Arrays.clone(b); + + for (int i = 0; i < 16; ++i) + { + byte bits = a[i]; + for (int j = 7; j >= 0; --j) + { + if ((bits & (1 << j)) != 0) + { + xor(c, tmp); + } + + boolean lsb = (tmp[15] & 1) != 0; + shiftRight(tmp); + if (lsb) + { + // R = new byte[]{ 0xe1, ... }; +// GCMUtil.xor(v, R); + tmp[0] ^= (byte)0xe1; + } + } + } + + return c; + } + + private static void shiftRight(byte[] block) + { + int i = 0; + int bit = 0; + for (;;) + { + int b = block[i] & 0xff; + block[i] = (byte) ((b >>> 1) | bit); + if (++i == 16) + { + break; + } + bit = (b & 1) << 7; + } + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/GCMTest.java b/core/src/test/java/org/spongycastle/crypto/test/GCMTest.java new file mode 100644 index 00000000..0a28dd18 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/GCMTest.java @@ -0,0 +1,687 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.modes.GCMBlockCipher; +import org.spongycastle.crypto.modes.gcm.BasicGCMMultiplier; +import org.spongycastle.crypto.modes.gcm.GCMMultiplier; +import org.spongycastle.crypto.modes.gcm.Tables64kGCMMultiplier; +import org.spongycastle.crypto.modes.gcm.Tables8kGCMMultiplier; +import org.spongycastle.crypto.params.AEADParameters; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Times; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Test vectors from "The Galois/Counter Mode of Operation (GCM)", McGrew/Viega, Appendix B + */ +public class GCMTest + extends SimpleTest +{ + private static final String[][] TEST_VECTORS = new String[][] { + { + "Test Case 1", + "00000000000000000000000000000000", + "", + "", + "000000000000000000000000", + "", + "58e2fccefa7e3061367f1d57a4e7455a", + }, + { + "Test Case 2", + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "", + "000000000000000000000000", + "0388dace60b6a392f328c2b971b2fe78", + "ab6e47d42cec13bdf53a67b21257bddf", + }, + { + "Test Case 3", + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b391aafd255", + "", + "cafebabefacedbaddecaf888", + "42831ec2217774244b7221b784d0d49c" + + "e3aa212f2c02a4e035c17e2329aca12e" + + "21d514b25466931c7d8f6a5aac84aa05" + + "1ba30b396a0aac973d58e091473f5985", + "4d5c2af327cd64a62cf35abd2ba6fab4", + }, + { + "Test Case 4", + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbaddecaf888", + "42831ec2217774244b7221b784d0d49c" + + "e3aa212f2c02a4e035c17e2329aca12e" + + "21d514b25466931c7d8f6a5aac84aa05" + + "1ba30b396a0aac973d58e091", + "5bc94fbc3221a5db94fae95ae7121a47", + }, + { + "Test Case 5", + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbad", + "61353b4c2806934a777ff51fa22a4755" + + "699b2a714fcdc6f83766e5f97b6c7423" + + "73806900e49f24b22b097544d4896b42" + + "4989b5e1ebac0f07c23f4598", + "3612d2e79e3b0785561be14aaca2fccb", + }, + { + "Test Case 6", + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "9313225df88406e555909c5aff5269aa" + + "6a7a9538534f7da1e4c303d2a318a728" + + "c3c0c95156809539fcf0e2429a6b5254" + + "16aedbf5a0de6a57a637b39b", + "8ce24998625615b603a033aca13fb894" + + "be9112a5c3a211a8ba262a3cca7e2ca7" + + "01e4a9a4fba43c90ccdcb281d48c7c6f" + + "d62875d2aca417034c34aee5", + "619cc5aefffe0bfa462af43c1699d050", + }, + { + "Test Case 7", + "00000000000000000000000000000000" + + "0000000000000000", + "", + "", + "000000000000000000000000", + "", + "cd33b28ac773f74ba00ed1f312572435", + }, + { + "Test Case 8", + "00000000000000000000000000000000" + + "0000000000000000", + "00000000000000000000000000000000", + "", + "000000000000000000000000", + "98e7247c07f0fe411c267e4384b0f600", + "2ff58d80033927ab8ef4d4587514f0fb", + }, + { + "Test Case 9", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b391aafd255", + "", + "cafebabefacedbaddecaf888", + "3980ca0b3c00e841eb06fac4872a2757" + + "859e1ceaa6efd984628593b40ca1e19c" + + "7d773d00c144c525ac619d18c84a3f47" + + "18e2448b2fe324d9ccda2710acade256", + "9924a7c8587336bfb118024db8674a14", + }, + { + "Test Case 10", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbaddecaf888", + "3980ca0b3c00e841eb06fac4872a2757" + + "859e1ceaa6efd984628593b40ca1e19c" + + "7d773d00c144c525ac619d18c84a3f47" + + "18e2448b2fe324d9ccda2710", + "2519498e80f1478f37ba55bd6d27618c", + }, + { + "Test Case 11", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbad", + "0f10f599ae14a154ed24b36e25324db8" + + "c566632ef2bbb34f8347280fc4507057" + + "fddc29df9a471f75c66541d4d4dad1c9" + + "e93a19a58e8b473fa0f062f7", + "65dcc57fcf623a24094fcca40d3533f8", + }, + { + "Test Case 12", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "9313225df88406e555909c5aff5269aa" + + "6a7a9538534f7da1e4c303d2a318a728" + + "c3c0c95156809539fcf0e2429a6b5254" + + "16aedbf5a0de6a57a637b39b", + "d27e88681ce3243c4830165a8fdcf9ff" + + "1de9a1d8e6b447ef6ef7b79828666e45" + + "81e79012af34ddd9e2f037589b292db3" + + "e67c036745fa22e7e9b7373b", + "dcf566ff291c25bbb8568fc3d376a6d9", + }, + { + "Test Case 13", + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + "", + "", + "000000000000000000000000", + "", + "530f8afbc74536b9a963b4f1c4cb738b", + }, + { + "Test Case 14", + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "", + "000000000000000000000000", + "cea7403d4d606b6e074ec5d3baf39d18", + "d0d1c8a799996bf0265b98b5d48ab919", + }, + { + "Test Case 15", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b391aafd255", + "", + "cafebabefacedbaddecaf888", + "522dc1f099567d07f47f37a32a84427d" + + "643a8cdcbfe5c0c97598a2bd2555d1aa" + + "8cb08e48590dbb3da7b08b1056828838" + + "c5f61e6393ba7a0abcc9f662898015ad", + "b094dac5d93471bdec1a502270e3cc6c", + }, + { + "Test Case 16", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbaddecaf888", + "522dc1f099567d07f47f37a32a84427d" + + "643a8cdcbfe5c0c97598a2bd2555d1aa" + + "8cb08e48590dbb3da7b08b1056828838" + + "c5f61e6393ba7a0abcc9f662", + "76fc6ece0f4e1768cddf8853bb2d551b", + }, + { + "Test Case 17", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbad", + "c3762df1ca787d32ae47c13bf19844cb" + + "af1ae14d0b976afac52ff7d79bba9de0" + + "feb582d33934a4f0954cc2363bc73f78" + + "62ac430e64abe499f47c9b1f", + "3a337dbf46a792c45e454913fe2ea8f2", + }, + { + "Test Case 18", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "9313225df88406e555909c5aff5269aa" + + "6a7a9538534f7da1e4c303d2a318a728" + + "c3c0c95156809539fcf0e2429a6b5254" + + "16aedbf5a0de6a57a637b39b", + "5a8def2f0c9e53f1f75d7853659e2a20" + + "eeb2b22aafde6419a058ab4f6f746bf4" + + "0fc0c3b780f244452da3ebf1c5d82cde" + + "a2418997200ef82e44ae7e3f", + "a44a8266ee1c8eb0c8b5d4cf5ae9f19a", + }, + }; + + public String getName() + { + return "GCM"; + } + + public void performTest() throws Exception + { + for (int i = 0; i < TEST_VECTORS.length; ++i) + { + runTestCase(TEST_VECTORS[i]); + } + + randomTests(); + outputSizeTests(); + testExceptions(); + } + + protected BlockCipher createAESEngine() + { + return new AESFastEngine(); + } + + private void testExceptions() throws InvalidCipherTextException + { + GCMBlockCipher gcm = new GCMBlockCipher(createAESEngine()); + + try + { + gcm = new GCMBlockCipher(new DESEngine()); + + fail("incorrect block size not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + gcm.init(false, new KeyParameter(new byte[16])); + + fail("illegal argument not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + 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) + throws InvalidCipherTextException + { + for (int macLength = 12; macLength <= 16; ++macLength) + { + runTestCase(testVector, macLength); + } + } + + private void runTestCase(String[] testVector, int macLength) + throws InvalidCipherTextException + { + int pos = 0; + String testName = testVector[pos++]; + byte[] K = Hex.decode(testVector[pos++]); + byte[] P = Hex.decode(testVector[pos++]); + byte[] A = Hex.decode(testVector[pos++]); + byte[] IV = Hex.decode(testVector[pos++]); + byte[] C = Hex.decode(testVector[pos++]); + + // For short MAC, take leading bytes + byte[] t = Hex.decode(testVector[pos++]); + byte[] T = new byte[macLength]; + System.arraycopy(t, 0, T, 0, T.length); + + // Default multiplier + 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); + } + + private void runTestCase( + GCMMultiplier encM, + GCMMultiplier decM, + String testName, + byte[] K, + byte[] IV, + byte[] A, + byte[] P, + byte[] C, + byte[] T) + throws InvalidCipherTextException + { + byte[] fa = new byte[A.length / 2]; + byte[] la = new byte[A.length - (A.length / 2)]; + System.arraycopy(A, 0, fa, 0, fa.length); + System.arraycopy(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); + } + + private void runTestCase( + GCMMultiplier encM, + GCMMultiplier decM, + String testName, + byte[] K, + byte[] IV, + byte[] A, + byte[] SA, + byte[] P, + byte[] C, + byte[] T) + throws InvalidCipherTextException + { + 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); + + // Key reuse + AEADParameters keyReuseParams = AEADTestUtil.reuseKey(parameters); + encCipher.init(true, keyReuseParams); + decCipher.init(false, keyReuseParams); + checkTestCase(encCipher, decCipher, testName + " (key reuse)", SA, P, C, T); + } + + private GCMBlockCipher initCipher(GCMMultiplier m, boolean forEncryption, AEADParameters parameters) + { + GCMBlockCipher c = new GCMBlockCipher(createAESEngine(), m); + c.init(forEncryption, parameters); + return c; + } + + private void checkTestCase( + GCMBlockCipher encCipher, + GCMBlockCipher decCipher, + String testName, + byte[] SA, + byte[] P, + byte[] C, + byte[] T) + throws InvalidCipherTextException + { + byte[] enc = new byte[encCipher.getOutputSize(P.length)]; + if (SA != null) + { + encCipher.processAADBytes(SA, 0, SA.length); + } + int len = encCipher.processBytes(P, 0, P.length, enc, 0); + len += encCipher.doFinal(enc, len); + + if (enc.length != len) + { +// System.out.println("" + enc.length + "/" + len); + fail("encryption reported incorrect length: " + testName); + } + + byte[] mac = encCipher.getMac(); + + byte[] data = new byte[P.length]; + System.arraycopy(enc, 0, data, 0, data.length); + byte[] tail = new byte[enc.length - P.length]; + System.arraycopy(enc, P.length, tail, 0, tail.length); + + if (!areEqual(C, data)) + { + fail("incorrect encrypt in: " + testName); + } + + if (!areEqual(T, mac)) + { + fail("getMac() returned wrong mac in: " + testName); + } + + if (!areEqual(T, tail)) + { + fail("stream contained wrong mac in: " + testName); + } + + byte[] dec = new byte[decCipher.getOutputSize(enc.length)]; + if (SA != null) + { + decCipher.processAADBytes(SA, 0, SA.length); + } + len = decCipher.processBytes(enc, 0, enc.length, dec, 0); + len += decCipher.doFinal(dec, len); + mac = decCipher.getMac(); + + data = new byte[C.length]; + System.arraycopy(dec, 0, data, 0, data.length); + + if (!areEqual(P, data)) + { + fail("incorrect decrypt in: " + testName); + } + } + + private void randomTests() + throws InvalidCipherTextException + { + SecureRandom srng = new SecureRandom(); + srng.setSeed(Times.nanoTime()); + randomTests(srng, null); + randomTests(srng, new BasicGCMMultiplier()); + randomTests(srng, new Tables8kGCMMultiplier()); + randomTests(srng, new Tables64kGCMMultiplier()); + } + + private void randomTests(SecureRandom srng, GCMMultiplier m) + throws InvalidCipherTextException + { + for (int i = 0; i < 10; ++i) + { + randomTest(srng, m); + } + } + + private void randomTest(SecureRandom srng, GCMMultiplier m) + throws InvalidCipherTextException + { + int kLength = 16 + 8 * (Math.abs(srng.nextInt()) % 3); + byte[] K = new byte[kLength]; + srng.nextBytes(K); + + int pLength = srng.nextInt() >>> 16; + byte[] P = new byte[pLength]; + srng.nextBytes(P); + + int aLength = srng.nextInt() >>> 24; + byte[] A = new byte[aLength]; + srng.nextBytes(A); + + int saLength = srng.nextInt() >>> 24; + byte[] SA = new byte[saLength]; + srng.nextBytes(SA); + + int ivLength = 1 + (srng.nextInt() >>> 24); + byte[] IV = new byte[ivLength]; + srng.nextBytes(IV); + + AEADParameters parameters = new AEADParameters(new KeyParameter(K), 16 * 8, IV, A); + GCMBlockCipher cipher = initCipher(m, 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]; + System.arraycopy(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, AEADTestUtil.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)((n * (long)(rand.nextInt() >>> 1)) >> 31); + } + + int bits, value; + do + { + bits = rand.nextInt() >>> 1; + value = bits % n; + } + while (bits - value + (n - 1) < 0); + + return value; + } + + public static void main(String[] args) + { + runTest(new GCMTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/GMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/GMacTest.java new file mode 100644 index 00000000..6d766e3d --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/GMacTest.java @@ -0,0 +1,174 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.macs.GMac; +import org.spongycastle.crypto.modes.GCMBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Test vectors for AES-GMAC, extracted from <a + * href="http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip">NIST CAVP GCM test + * vectors</a>. + * + */ +public class GMacTest extends SimpleTest +{ + private static class TestCase + { + private byte[] key; + private byte[] iv; + private byte[] ad; + private byte[] tag; + private String name; + + private TestCase(final String name, final String key, final String iv, final String ad, final String tag) + { + this.name = name; + this.key = Hex.decode(key); + this.iv = Hex.decode(iv); + this.ad = Hex.decode(ad); + this.tag = Hex.decode(tag); + } + + public String getName() + { + return name; + } + + public byte[] getKey() + { + return key; + } + + public byte[] getIv() + { + return iv; + } + + public byte[] getAd() + { + return ad; + } + + public byte[] getTag() + { + return tag; + } + } + + private static TestCase[] TEST_VECTORS = new TestCase[] { + // Count = 0, from each of the PTlen = 0 test vector sequences + new TestCase("128/96/0/128", "11754cd72aec309bf52f7687212e8957", "3c819d9a9bed087615030b65", "", + "250327c674aaf477aef2675748cf6971"), + new TestCase("128/96/0/120", "272f16edb81a7abbea887357a58c1917", "794ec588176c703d3d2a7a07", "", + "b6e6f197168f5049aeda32dafbdaeb"), + new TestCase("128/96/0/112", "81b6844aab6a568c4556a2eb7eae752f", "ce600f59618315a6829bef4d", "", + "89b43e9dbc1b4f597dbbc7655bb5"), + new TestCase("128/96/0/104", "cde2f9a9b1a004165ef9dc981f18651b", "29512c29566c7322e1e33e8e", "", + "2e58ce7dabd107c82759c66a75"), + new TestCase("128/96/0/96", "b01e45cc3088aaba9fa43d81d481823f", "5a2c4a66468713456a4bd5e1", "", + "014280f944f53c681164b2ff"), + + new TestCase("128/96/128/128", "77be63708971c4e240d1cb79e8d77feb", "e0e00f19fed7ba0136a797f3", + "7a43ec1d9c0a5a78a0b16533a6213cab", "209fcc8d3675ed938e9c7166709dd946"), + new TestCase("128/96/128/96", "bea48ae4980d27f357611014d4486625", "32bddb5c3aa998a08556454c", + "8a50b0b8c7654bced884f7f3afda2ead", "8e0f6d8bf05ffebe6f500eb1"), + + new TestCase("128/96/384/128", "99e3e8793e686e571d8285c564f75e2b", "c2dd0ab868da6aa8ad9c0d23", + "b668e42d4e444ca8b23cfdd95a9fedd5178aa521144890b093733cf5cf22526c5917ee476541809ac6867a8c399309fc", + "3f4fba100eaf1f34b0baadaae9995d85"), + new TestCase("128/96/384/96", "c77acd1b0918e87053cb3e51651e7013", "39ff857a81745d10f718ac00", + "407992f82ea23b56875d9a3cb843ceb83fd27cb954f7c5534d58539fe96fb534502a1b38ea4fac134db0a42de4be1137", + "2a5dc173285375dc82835876"), + + new TestCase( + "128/1024/0/128", + "d0f1f4defa1e8c08b4b26d576392027c", + "42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac", + "", "7ab49b57ddf5f62c427950111c5c4f0d"), + new TestCase( + "128/1024/384/96", + "3cce72d37933394a8cac8a82deada8f0", + "aa2f0d676d705d9733c434e481972d4888129cf7ea55c66511b9c0d25a92a174b1e28aa072f27d4de82302828955aadcb817c4907361869bd657b45ff4a6f323871987fcf9413b0702d46667380cd493ed24331a28b9ce5bbfa82d3a6e7679fcce81254ba64abcad14fd18b22c560a9d2c1cd1d3c42dac44c683edf92aced894", + "5686b458e9c176f4de8428d9ebd8e12f569d1c7595cf49a4b0654ab194409f86c0dd3fdb8eb18033bb4338c70f0b97d1", + "a3a9444b21f330c3df64c8b6"), }; + + public void performTest() + { + for (int i = 0; i < TEST_VECTORS.length; i++) + { + TestCase testCase = TEST_VECTORS[i]; + + Mac mac = new GMac(new GCMBlockCipher(new AESFastEngine()), testCase.getTag().length * 8); + CipherParameters key = new KeyParameter(testCase.getKey()); + mac.init(new ParametersWithIV(key, testCase.getIv())); + + testSingleByte(mac, testCase); + testMultibyte(mac, testCase); + } + + // Invalid mac size + testInvalidMacSize(97); + testInvalidMacSize(136); + testInvalidMacSize(24); + } + + private void testInvalidMacSize(int size) + { + try + { + GMac mac = new GMac(new GCMBlockCipher(new AESFastEngine()), size); + mac.init(new ParametersWithIV(null, new byte[16])); + fail("Expected failure for illegal mac size " + size); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().startsWith("Invalid value for MAC size")) + { + fail("Illegal mac size failed with unexpected message"); + } + } + } + + private void testMultibyte(Mac mac, TestCase testCase) + { + mac.update(testCase.getAd(), 0, testCase.getAd().length); + checkMac(mac, testCase); + } + + private void testSingleByte(Mac mac, TestCase testCase) + { + final byte[] ad = testCase.getAd(); + for (int i = 0; i < ad.length; i++) + { + mac.update(ad[i]); + } + checkMac(mac, testCase); + } + + private void checkMac(Mac mac, TestCase testCase) + { + final byte[] generatedMac = new byte[mac.getMacSize()]; + mac.doFinal(generatedMac, 0); + if (!areEqual(testCase.getTag(), generatedMac)) + { + fail("Failed " + testCase.getName() + " - expected " + new String(Hex.encode(testCase.getTag())) + " got " + + new String(Hex.encode(generatedMac))); + } + } + + public String getName() + { + return "GMac"; + } + + public static void main(String[] args) + { + runTest(new GMacTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/GOST28147MacTest.java b/core/src/test/java/org/spongycastle/crypto/test/GOST28147MacTest.java new file mode 100644 index 00000000..4ed50783 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/GOST28147MacTest.java @@ -0,0 +1,89 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.engines.GOST28147Engine; +import org.spongycastle.crypto.macs.GOST28147Mac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithSBox; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * GOST 28147 MAC tester + */ +public class GOST28147MacTest + implements Test +{ + // + // these GOSTMac for testing. + // + static byte[] gkeyBytes1 = Hex.decode("6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49"); + static byte[] gkeyBytes2 = Hex.decode("6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49"); + + static byte[] input3 = Hex.decode("7768617420646f2079612077616e7420666f72206e6f7468696e673f"); + static byte[] input4 = Hex.decode("7768617420646f2079612077616e7420666f72206e6f7468696e673f"); + + static byte[] output7 = Hex.decode("93468a46"); + static byte[] output8 = Hex.decode("93468a46"); + + public GOST28147MacTest() + { + } + + public TestResult perform() + { + // test1 + Mac mac = new GOST28147Mac(); + KeyParameter key = new KeyParameter(gkeyBytes1); + + mac.init(key); + + mac.update(input3, 0, input3.length); + + byte[] out = new byte[4]; + + mac.doFinal(out, 0); + + if (!Arrays.areEqual(out, output7)) + { + return new SimpleTestResult(false, getName() + ": Failed test 1 - expected " + new String(Hex.encode(output7)) + " got " + new String(Hex.encode(out))); + } + + // test2 + key = new KeyParameter(gkeyBytes2); + + ParametersWithSBox gparam = new ParametersWithSBox(key, GOST28147Engine.getSBox("E-A")); + + mac.init(gparam); + + mac.update(input4, 0, input4.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!Arrays.areEqual(out, output8)) + { + return new SimpleTestResult(false, getName() + ": Failed test 2 - expected " + new String(Hex.encode(output8)) + " got " + new String(Hex.encode(out))); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public String getName() + { + return "GOST28147Mac"; + } + + public static void main( + String[] args) + { + GOST28147MacTest test = new GOST28147MacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/GOST28147Test.java b/core/src/test/java/org/spongycastle/crypto/test/GOST28147Test.java new file mode 100644 index 00000000..a89f2e63 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/GOST28147Test.java @@ -0,0 +1,328 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.CryptoException; +import org.spongycastle.crypto.digests.GOST3411Digest; +import org.spongycastle.crypto.engines.GOST28147Engine; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.modes.CFBBlockCipher; +import org.spongycastle.crypto.modes.GOFBBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.crypto.params.ParametersWithSBox; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class GOST28147Test + extends CipherTest +{ + static String input1 = "0000000000000000"; + static String output1 = "1b0bbc32cebcab42"; + static String input2 = "bc350e71aac5f5c2"; + static String output2 = "d35ab653493b49f5"; + static String input3 = "bc350e71aa11345709acde"; + static String output3 = "8824c124c4fd14301fb1e8"; + static String input4 = "000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"; + static String output4 = "29b7083e0a6d955ca0ec5b04fdb4ea41949f1dd2efdf17baffc1780b031f3934"; + + static byte TestSBox[] = { + 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF, + 0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0, + 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF, + 0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0, + 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF, + 0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0, + 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF, + 0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0 + }; + + static SimpleTest[] tests = + { new BlockCipherVectorTest(1, new GOST28147Engine(), + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), + input1, output1), + new BlockCipherVectorTest(2, new CBCBlockCipher(new GOST28147Engine()), + new ParametersWithIV(new KeyParameter(Hex.decode("00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF")), + Hex.decode("1234567890abcdef")), input2, output2), + new BlockCipherVectorTest(3, new GOFBBlockCipher(new GOST28147Engine()), + new ParametersWithIV(new KeyParameter(Hex.decode("0011223344556677889900112233445566778899001122334455667788990011")), + Hex.decode("1234567890abcdef")), //IV + input3, output3), + new BlockCipherVectorTest(4, new CFBBlockCipher(new GOST28147Engine(), 64), + new ParametersWithIV(new KeyParameter(Hex.decode("aafd12f659cae63489b479e5076ddec2f06cb58faafd12f659cae63489b479e5")), + Hex.decode("aafd12f659cae634")), input4, output4), + + //tests with parameters, set S-box. + new BlockCipherVectorTest(5, new GOST28147Engine(), + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")),//key , default parameter S-box set to D-Test + input1, output1), + new BlockCipherVectorTest(6, new CFBBlockCipher(new GOST28147Engine(), 64), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("D-Test")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "b587f7a0814c911d"), //encrypt message + new BlockCipherVectorTest(7, new CFBBlockCipher(new GOST28147Engine(), 64), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("E-Test")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "e8287f53f991d52b"), //encrypt message + new BlockCipherVectorTest(8, new CFBBlockCipher(new GOST28147Engine(), 64), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("E-A")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "c41009dba22ebe35"), //encrypt message + new BlockCipherVectorTest(9, new CFBBlockCipher(new GOST28147Engine(), 8), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("E-B")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "80d8723fcd3aba28"), //encrypt message + new BlockCipherVectorTest(10, new CFBBlockCipher(new GOST28147Engine(), 8), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("E-C")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "739f6f95068499b5"), //encrypt message + new BlockCipherVectorTest(11, new CFBBlockCipher(new GOST28147Engine(), 8), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("E-D")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "4663f720f4340f57"), //encrypt message + new BlockCipherVectorTest(12, new CFBBlockCipher(new GOST28147Engine(), 8), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("D-A")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "5bb0a31d218ed564"), //encrypt message + new BlockCipherVectorTest(13, new CFBBlockCipher(new GOST28147Engine(), 8), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + TestSBox), //set own S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "c3af96ef788667c5"), //encrypt message + new BlockCipherVectorTest(14, new GOFBBlockCipher(new GOST28147Engine()), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("4ef72b778f0b0bebeef4f077551cb74a927b470ad7d7f2513454569a247e989d")), //key + GOST28147Engine.getSBox("E-A")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "bc350e71aa11345709acde", //input message + "1bcc2282707c676fb656dc"), //encrypt message + + }; + + static private final int GOST28147_KEY_LENGTH = 32; + + private byte[] generateKey(byte[] startkey) + { + byte[] newKey = new byte[GOST28147_KEY_LENGTH]; + + GOST3411Digest digest = new GOST3411Digest(); + + digest.update(startkey, 0, startkey.length); + digest.doFinal(newKey, 0); + + return newKey; + } + + GOST28147Test() + { + super(tests, new GOST28147Engine(), new KeyParameter(new byte[32])); + } + + public void performTest() + throws Exception + { + super.performTest(); + + //advanced tests with GOST28147KeyGenerator: + //encrypt on hesh message; ECB mode: + byte[] in = Hex.decode("4e6f77206973207468652074696d6520666f7220616c6c20"); + byte[] output = Hex.decode("8ad3c8f56b27ff1fbd46409359bdc796bc350e71aac5f5c0"); + byte[] out = new byte[in.length]; + + byte[] key = generateKey(Hex.decode("0123456789abcdef")); //!!! heshing start_key - get 256 bits !!! +// System.out.println(new String(Hex.encode(key))); + CipherParameters param = new ParametersWithSBox(new KeyParameter(key), GOST28147Engine.getSBox("E-A")); + //CipherParameters param = new GOST28147Parameters(key,"D-Test"); + BufferedBlockCipher cipher = new BufferedBlockCipher(new GOST28147Engine()); + + cipher.init(true, param); + int len1 = cipher.processBytes(in, 0, in.length, out, 0); + try + { + cipher.doFinal(out, len1); + } + catch (CryptoException e) + { + fail("failed - exception " + e.toString(), e); + } + if (out.length != output.length) + { + fail("failed - " + + "expected " + new String(Hex.encode(output)) + " got " + + new String(Hex.encode(out))); + } + for (int i = 0; i != out.length; i++) + { + if (out[i] != output[i]) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + + //encrypt on hesh message; CFB mode: + in = Hex.decode("bc350e71aac5f5c2"); + output = Hex.decode("0ebbbafcf38f14a5"); + out = new byte[in.length]; + + key = generateKey(Hex.decode("0123456789abcdef")); //!!! heshing start_key - get 256 bits !!! + param = new ParametersWithIV(new ParametersWithSBox( + new KeyParameter(key), //key + GOST28147Engine.getSBox("E-A")), //type S-box + Hex.decode("1234567890abcdef")); //IV + + cipher = new BufferedBlockCipher(new CFBBlockCipher(new GOST28147Engine(), 64)); + + cipher.init(true, param); + len1 = cipher.processBytes(in, 0, in.length, out, 0); + try + { + cipher.doFinal(out, len1); + } + catch (CryptoException e) + { + fail("failed - exception " + e.toString(), e); + } + if (out.length != output.length) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + for (int i = 0; i != out.length; i++) + { + if (out[i] != output[i]) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + + //encrypt on hesh message; CFB mode: + in = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); + output = Hex.decode("64988982819f0a1655e226e19ecad79d10cc73bac95c5d7da034786c12294225"); + out = new byte[in.length]; + + key = generateKey(Hex.decode("aafd12f659cae63489b479e5076ddec2f06cb58faafd12f659cae63489b479e5")); //!!! heshing start_key - get 256 bits !!! + param = new ParametersWithIV(new ParametersWithSBox( + new KeyParameter(key), //key + GOST28147Engine.getSBox("E-A")), //type S-box + Hex.decode("aafd12f659cae634")); //IV + + cipher = new BufferedBlockCipher(new CFBBlockCipher(new GOST28147Engine(), 64)); + + cipher.init(true, param); + len1 = cipher.processBytes(in, 0, in.length, out, 0); + + cipher.doFinal(out, len1); + + if (out.length != output.length) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + for (int i = 0; i != out.length; i++) + { + if (out[i] != output[i]) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + //encrypt on hesh message; OFB mode: + in = Hex.decode("bc350e71aa11345709acde"); + output = Hex.decode("1bcc2282707c676fb656dc"); + out = new byte[in.length]; + + key = generateKey(Hex.decode("0123456789abcdef")); //!!! heshing start_key - get 256 bits !!! + param = new ParametersWithIV(new ParametersWithSBox( + new KeyParameter(key), //key + GOST28147Engine.getSBox("E-A")), //type S-box + Hex.decode("1234567890abcdef")); //IV + + cipher = new BufferedBlockCipher(new GOFBBlockCipher(new GOST28147Engine())); + + cipher.init(true, param); + len1 = cipher.processBytes(in, 0, in.length, out, 0); + + cipher.doFinal(out, len1); + + if (out.length != output.length) + { + fail("failed - " + "expected " + + new String(Hex.encode(output)) + " got " + + new String(Hex.encode(out))); + } + for (int i = 0; i != out.length; i++) + { + if (out[i] != output[i]) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + // key reuse test + param = new ParametersWithIV(null, // key and sbox reused + Hex.decode("1234567890abcdef")); //IV + + cipher.init(true, param); + len1 = cipher.processBytes(in, 0, in.length, out, 0); + + cipher.doFinal(out, len1); + + if (out.length != output.length) + { + fail("failed - " + "expected " + + new String(Hex.encode(output)) + " got " + + new String(Hex.encode(out))); + } + for (int i = 0; i != out.length; i++) + { + if (out[i] != output[i]) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + } + + public String getName() + { + return "GOST28147"; + } + + public static void main( + String[] args) + { + runTest(new GOST28147Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/GOST3410Test.java b/core/src/test/java/org/spongycastle/crypto/test/GOST3410Test.java new file mode 100644 index 00000000..08ce0b01 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/GOST3410Test.java @@ -0,0 +1,1570 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.generators.GOST3410KeyPairGenerator; +import org.spongycastle.crypto.generators.GOST3410ParametersGenerator; +import org.spongycastle.crypto.params.GOST3410KeyGenerationParameters; +import org.spongycastle.crypto.params.GOST3410Parameters; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.crypto.signers.GOST3410Signer; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.FixedSecureRandom; +import org.spongycastle.util.test.NumberParsing; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +import java.math.BigInteger; +import java.security.SecureRandom; + +public class GOST3410Test + implements Test +{ + byte[] hashmessage = Hex.decode("3042453136414534424341374533364339313734453431443642453241453435"); + + private byte[] zeroTwo(int length) + { + byte[] data = new byte[length]; + data[data.length - 1] = 0x02; + return data; + } + + private class GOST3410_TEST1_512 + implements Test + { + public String getName() + { + return "GOST3410-TEST1-512"; + } + + FixedSecureRandom init_random = new FixedSecureRandom(new byte[][] { Hex.decode("00005EC900007341"), zeroTwo(64) }); + FixedSecureRandom random = new FixedSecureRandom(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A")); + FixedSecureRandom keyRandom = new FixedSecureRandom(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046")); + + BigInteger pValue = new BigInteger("EE8172AE8996608FB69359B89EB82A69854510E2977A4D63BC97322CE5DC3386EA0A12B343E9190F23177539845839786BB0C345D165976EF2195EC9B1C379E3", 16); + BigInteger qValue = new BigInteger("98915E7EC8265EDFCDA31E88F24809DDB064BDC7285DD50D7289F0AC6F49DD2D", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("3e5f895e276d81d2d52c0763270a458157b784c57abdbd807bc44fd43a32ac06",16); + BigInteger s = new BigInteger("3f0dd5d4400d47c08e4ce505ff7434b6dbf729592e37c74856dab85115a60955",16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(512, 1, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (params.getValidationParameters() == null) + { + return new SimpleTestResult(false, getName() + "validation parameters wrong"); + } + if (params.getValidationParameters().getC() != 29505 + || params.getValidationParameters().getX0() != 24265) + { + return new SimpleTestResult(false, getName() + "validation parameters values wrong"); + } + if (!init_random.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'init_random'."); + } + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + if (!keyRandom.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'keyRandom'."); + } + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer gost3410 = new GOST3410Signer(); + + gost3410.init(true, param); + + BigInteger[] sig = gost3410.generateSignature(hashmessage); + + if (!random.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'random'."); + } + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + System.getProperty("line.separator") + + " expecting: " + r.toString(16) + System.getProperty("line.separator") + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + System.getProperty("line.separator") + + " expecting: " + s.toString(16) + System.getProperty("line.separator") + + " got : " + sig[1].toString(16)); + } + + gost3410.init(false, pair.getPublic()); + + if (gost3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_TEST2_512 + implements Test + { + public String getName() + { + return "GOST3410-TEST2-512"; + } + + FixedSecureRandom init_random = new FixedSecureRandom(new byte[][] { Hex.decode("000000003DFC46F1000000000000000D"), zeroTwo(64) }); + FixedSecureRandom random = new FixedSecureRandom(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A")); + FixedSecureRandom keyRandom = new FixedSecureRandom(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046")); + + BigInteger pValue = new BigInteger("8b08eb135af966aab39df294538580c7da26765d6d38d30cf1c06aae0d1228c3316a0e29198460fad2b19dc381c15c888c6dfd0fc2c565abb0bf1faff9518f85", 16); + BigInteger qValue = new BigInteger("931a58fb6f0dcdf2fe7549bc3f19f4724b56898f7f921a076601edb18c93dc75", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("7c07c8cf035c2a1cb2b7fae5807ac7cd623dfca7a1a68f6d858317822f1ea00d",16); + BigInteger s = new BigInteger("7e9e036a6ff87dbf9b004818252b1f6fc310bdd4d17cb8c37d9c36c7884de60c",16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(512, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!init_random.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'init_random'."); + } + + if (params.getValidationParameters() == null) + { + return new SimpleTestResult(false, getName() + ": validation parameters wrong"); + } + + if (params.getValidationParameters().getCL() != 13 + || params.getValidationParameters().getX0L() != 1039943409) + { + return new SimpleTestResult(false, getName() + ": validation parameters values wrong"); + } + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + if (!keyRandom.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'keyRandom'."); + } + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!random.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'random'."); + } + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + System.getProperty("line.separator") + + " expecting: " + r.toString(16) + System.getProperty("line.separator") + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + System.getProperty("line.separator") + + " expecting: " + s.toString(16) + System.getProperty("line.separator") + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_TEST1_1024 + implements Test + { + public String getName() + { + return "GOST3410-TEST1-1024"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstInt = true; + + public int nextInt() + { + String x0 = "0xA565"; + String c = "0x538B"; + + if (firstInt) + { + firstInt = false; + return NumberParsing.decodeIntFromHex(x0); + } + return NumberParsing.decodeIntFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + + byte[] d = Hex.decode("02"); + + System.arraycopy(d, 0, bytes, bytes.length-d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("ab8f37938356529e871514c1f48c5cbce77b2f4fc9a2673ac2c1653da8984090c0ac73775159a26bef59909d4c9846631270e16653a6234668f2a52a01a39b921490e694c0f104b58d2e14970fccb478f98d01e975a1028b9536d912de5236d2dd2fc396b77153594d4178780e5f16f718471e2111c8ce64a7d7e196fa57142d", 16); + BigInteger qValue = new BigInteger("bcc02ca0ce4f0753ec16105ee5d530aa00d39f3171842ab2c334a26b5f576e0f", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("a8790aabbd5a998ff524bad048ac69cd1faff2dab048265c8d60d1471c44a9ee",16); + BigInteger s = new BigInteger("30df5ba32ac77170b9632559bef7d37620017756dff3fea1088b4267db0944b8",16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 1, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + System.getProperty("line.separator") + + " expecting: " + r.toString(16) + System.getProperty("line.separator") + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + System.getProperty("line.separator") + + " expecting: " + s.toString(16) + System.getProperty("line.separator") + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_TEST2_1024 + implements Test + { + public String getName() + { + return "GOST3410-TEST2-1024"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x3DFC46F1"; + String c = "0xD"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + + byte[] d = Hex.decode("02"); + + System.arraycopy(d, 0, bytes, bytes.length-d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("e2c4191c4b5f222f9ac2732562f6d9b4f18e7fb67a290ea1e03d750f0b9806755fc730d975bf3faa606d05c218b35a6c3706919aab92e0c58b1de4531c8fa8e7af43c2bff016251e21b2870897f6a27ac4450bca235a5b748ad386e4a0e4dfcb09152435abcfe48bd0b126a8122c7382f285a9864615c66decddf6afd355dfb7", 16); + BigInteger qValue = new BigInteger("931a58fb6f0dcdf2fe7549bc3f19f4724b56898f7f921a076601edb18c93dc75", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("81d69a192e9c7ac21fc07da41bd07e230ba6a94eb9f3c1fd104c7bd976733ca5",16); + BigInteger s = new BigInteger("315c879c8414f35feb4deb15e7cc0278c48e6ca1596325d6959338d860b0c47a",16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + System.getProperty("line.separator") + + " expecting: " + r.toString(16) + System.getProperty("line.separator") + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + System.getProperty("line.separator") + + " expecting: " + s.toString(16) + System.getProperty("line.separator") + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_AParam + implements Test + { + public String getName() + { + return "GOST3410-AParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x520874F5"; + String c = "0xEE39ADB3"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + + byte[] d = Hex.decode("02"); + + System.arraycopy(d, 0, bytes, bytes.length-d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("b4e25efb018e3c8b87505e2a67553c5edc56c2914b7e4f89d23f03f03377e70a2903489dd60e78418d3d851edb5317c4871e40b04228c3b7902963c4b7d85d52b9aa88f2afdbeb28da8869d6df846a1d98924e925561bd69300b9ddd05d247b5922d967cbb02671881c57d10e5ef72d3e6dad4223dc82aa1f7d0294651a480df", 16); + BigInteger qValue = new BigInteger("972432a437178b30bd96195b773789ab2fff15594b176dd175b63256ee5af2cf", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("64a8856628e5669d85f62cd763dd4a99bc56d33dc0e1859122855d141e9e4774",16); + BigInteger s = new BigInteger("319ebac97092b288d469a4b988248794f60c865bc97858d9a3135c6d1a1bf2dd",16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + System.getProperty("line.separator") + + " expecting: " + r.toString(16) + System.getProperty("line.separator") + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + System.getProperty("line.separator") + + " expecting: " + s.toString(16) + System.getProperty("line.separator") + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_BParam + implements Test + { + public String getName() + { + return "GOST3410-BParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x5B977CDB"; + String c = "0x6E9692DD"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + byte[] d = Hex.decode("bc3cbbdb7e6f848286e19ad9a27a8e297e5b71c53dd974cdf60f937356df69cbc97a300ccc71685c553046147f11568c4fddf363d9d886438345a62c3b75963d6546adfabf31b31290d12cae65ecb8309ef66782"); + + System.arraycopy(d, 0, bytes, bytes.length-d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("c6971fc57524b30c9018c5e621de15499736854f56a6f8aee65a7a404632b3540f09020f67f04dc2e6783b141dceffd21a703035b7d0187c6e12cb4229922bafdb2225b73e6b23a0de36e20047065aea000c1a374283d0ad8dc1981e3995f0bb8c72526041fcb98ae6163e1e71a669d8364e9c4c3188f673c5f8ee6fadb41abf", 16); + BigInteger qValue = new BigInteger("b09d634c10899cd7d4c3a7657403e05810b07c61a688bab2c37f475e308b0607", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("860d82c60e9502cd00c0e9e1f6563feafec304801974d745c5e02079946f729e",16); + BigInteger s = new BigInteger("7ef49264ef022801aaa03033cd97915235fbab4c823ed936b0f360c22114688a",16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + System.getProperty("line.separator") + + " expecting: " + r.toString(16) + System.getProperty("line.separator") + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + System.getProperty("line.separator") + + " expecting: " + s.toString(16) + System.getProperty("line.separator") + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_CParam + implements Test + { + public String getName() + { + return "GOST3410-CParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x43848744"; + String c = "0xB50A826D"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + byte[] d = Hex.decode("7F575E8194BC5BDF"); + + System.arraycopy(d, 0, bytes, bytes.length-d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("9d88e6d7fe3313bd2e745c7cdd2ab9ee4af3c8899e847de74a33783ea68bc30588ba1f738c6aaf8ab350531f1854c3837cc3c860ffd7e2e106c3f63b3d8a4c034ce73942a6c3d585b599cf695ed7a3c4a93b2b947b7157bb1a1c043ab41ec8566c6145e938a611906de0d32e562494569d7e999a0dda5c879bdd91fe124df1e9", 16); + BigInteger qValue = new BigInteger("fadd197abd19a1b4653eecf7eca4d6a22b1f7f893b641f901641fbb555354faf", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("4deb95a0b35e7ed7edebe9bef5a0f93739e16b7ff27fe794d989d0c13159cfbc",16); + BigInteger s = new BigInteger("e1d0d30345c24cfeb33efde3deee5fbbda78ddc822b719d860cd0ba1fb6bd43b",16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + System.getProperty("line.separator") + + " expecting: " + r.toString(16) + System.getProperty("line.separator") + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + System.getProperty("line.separator") + + " expecting: " + s.toString(16) + System.getProperty("line.separator") + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_DParam + implements Test + { + public String getName() + { + return "GOST3410-DParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x13DA8B9D"; + String c = "0xA0E9DE4B"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + + byte[] d = Hex.decode("41ab97857f42614355d32db0b1069f109a4da283676c7c53a68185b4"); + + System.arraycopy(d, 0, bytes, bytes.length-d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("80f102d32b0fd167d069c27a307adad2c466091904dbaa55d5b8cc7026f2f7a1919b890cb652c40e054e1e9306735b43d7b279eddf9102001cd9e1a831fe8a163eed89ab07cf2abe8242ac9dedddbf98d62cddd1ea4f5f15d3a42a6677bdd293b24260c0f27c0f1d15948614d567b66fa902baa11a69ae3bceadbb83e399c9b5", 16); + BigInteger qValue = new BigInteger("f0f544c418aac234f683f033511b65c21651a6078bda2d69bb9f732867502149", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("712592d285b792e33b8a9a11e8e6c4f512ddf0042972bbfd1abb0a93e8fc6f54",16); + BigInteger s = new BigInteger("2cf26758321258b130d5612111339f09ceb8668241f3482e38baa56529963f07",16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + System.getProperty("line.separator") + + " expecting: " + r.toString(16) + System.getProperty("line.separator") + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + System.getProperty("line.separator") + + " expecting: " + s.toString(16) + System.getProperty("line.separator") + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_AExParam + implements Test + { + public String getName() + { + return "GOST3410-AExParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0xD05E9F14"; + String c = "0x46304C5F"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + byte[] d = Hex.decode("35ab875399cda33c146ca629660e5a5e5c07714ca326db032dd6751995cdb90a612b9228932d8302704ec24a5def7739c5813d83"); + + System.arraycopy(d, 0, bytes, bytes.length-d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("ca3b3f2eee9fd46317d49595a9e7518e6c63d8f4eb4d22d10d28af0b8839f079f8289e603b03530784b9bb5a1e76859e4850c670c7b71c0df84ca3e0d6c177fe9f78a9d8433230a883cd82a2b2b5c7a3306980278570cdb79bf01074a69c9623348824b0c53791d53c6a78cab69e1cfb28368611a397f50f541e16db348dbe5f", 16); + BigInteger qValue = new BigInteger("cae4d85f80c147704b0ca48e85fb00a9057aa4acc44668e17f1996d7152690d9", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("90892707282f433398488f19d31ac48523a8e2ded68944e0da91c6895ee7045e",16); + BigInteger s = new BigInteger("3be4620ee88f1ee8f9dd63c7d145b7e554839feeca125049118262ea4651e9de",16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + System.getProperty("line.separator") + + " expecting: " + r.toString(16) + System.getProperty("line.separator") + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + System.getProperty("line.separator") + + " expecting: " + s.toString(16) + System.getProperty("line.separator") + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_BExParam + implements Test + { + public String getName() + { + return "GOST3410-BExParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x7A007804"; + String c = "0xD31A4FF7"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + byte[] d = Hex.decode("7ec123d161477762838c2bea9dbdf33074af6d41d108a066a1e7a07ab3048de2"); + + System.arraycopy(d, 0, bytes, bytes.length-d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("9286dbda91eccfc3060aa5598318e2a639f5ba90a4ca656157b2673fb191cd0589ee05f4cef1bd13508408271458c30851ce7a4ef534742bfb11f4743c8f787b11193ba304c0e6bca25701bf88af1cb9b8fd4711d89f88e32b37d95316541bf1e5dbb4989b3df13659b88c0f97a3c1087b9f2d5317d557dcd4afc6d0a754e279", 16); + BigInteger qValue = new BigInteger("c966e9b3b8b7cdd82ff0f83af87036c38f42238ec50a876cd390e43d67b6013f", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("8f79a582513df84dc247bcb624340cc0e5a34c4324a20ce7fe3ab8ff38a9db71",16); + BigInteger s = new BigInteger("7508d22fd6cbb45efd438cb875e43f137247088d0f54b29a7c91f68a65b5fa85",16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + System.getProperty("line.separator") + + " expecting: " + r.toString(16) + System.getProperty("line.separator") + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + System.getProperty("line.separator") + + " expecting: " + s.toString(16) + System.getProperty("line.separator") + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_CExParam + implements Test + { + public String getName() + { + return "GOST3410-CExParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x162AB910"; + String c = "0x93F828D3"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + byte[] d = Hex.decode("ca82cce78a738bc46f103d53b9bf809745ec845e4f6da462606c51f60ecf302e31204b81"); + + System.arraycopy(d, 0, bytes, bytes.length-d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("b194036ace14139d36d64295ae6c50fc4b7d65d8b340711366ca93f383653908ee637be428051d86612670ad7b402c09b820fa77d9da29c8111a8496da6c261a53ed252e4d8a69a20376e6addb3bdcd331749a491a184b8fda6d84c31cf05f9119b5ed35246ea4562d85928ba1136a8d0e5a7e5c764ba8902029a1336c631a1d", 16); + BigInteger qValue = new BigInteger("96120477df0f3896628e6f4a88d83c93204c210ff262bccb7dae450355125259", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("169fdb2dc09f690b71332432bfec806042e258fa9a21dafe73c6abfbc71407d9",16); + BigInteger s = new BigInteger("9002551808ae40d19f6f31fb67e4563101243cf07cffd5f2f8ff4c537b0c9866",16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + System.getProperty("line.separator") + + " expecting: " + r.toString(16) + System.getProperty("line.separator") + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + System.getProperty("line.separator") + + " expecting: " + s.toString(16) + System.getProperty("line.separator") + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + Test tests[] = + { + new GOST3410_TEST1_512(), + new GOST3410_TEST2_512(), +// new GOST3410_TEST1_1024(), +// new GOST3410_TEST2_1024(), +// new GOST3410_AParam(), +// new GOST3410_BParam(), +// new GOST3410_CParam(), +// new GOST3410_DParam(), +// new GOST3410_AExParam(), +// new GOST3410_BExParam(), +// new GOST3410_CExParam() + }; + + public String getName() + { + return "GOST3410"; + } + + public TestResult perform() + { + for (int i = 0; i != tests.length; i++) + { + TestResult result = tests[i].perform(); + + if (!result.isSuccessful()) + { + return result; + } + } + + return new SimpleTestResult(true, "GOST3410: Okay"); + } + + public static void main( + String[] args) + { + GOST3410Test test = new GOST3410Test(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/GOST3411DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/GOST3411DigestTest.java new file mode 100644 index 00000000..b3121e82 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/GOST3411DigestTest.java @@ -0,0 +1,74 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.GOST3411Digest; +import org.spongycastle.crypto.generators.PKCS5S1ParametersGenerator; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; + +public class GOST3411DigestTest + extends DigestTest +{ + private static final String[] messages = + { + "", + "This is message, length=32 bytes", + "Suppose the original message has length = 50 bytes", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + }; + +// If S-box = D-A (see: digest/GOST3411Digest.java; function: E(byte[] in, byte[] key); string: CipherParameters param = new GOST28147Parameters(key,"D-A");) + private static final String[] digests = + { + "981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", + "2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", + "c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011", + "73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61" + }; + +// If S-box = D-Test (see: digest/GOST3411Digest.java; function:E(byte[] in, byte[] key); string: CipherParameters param = new GOST28147Parameters(key,"D-Test");) +// private static final String[] digests = +// { +// "ce85b99cc46752fffee35cab9a7b0278abb4c2d2055cff685af4912c49490f8d", +// "b1c466d37519b82e8319819ff32595e047a28cb6f83eff1c6916a815a637fffa", +// "471aba57a60a770d3a76130635c1fbea4ef14de51f78b4ae57dd893b62f55208", +// "95c1af627c356496d80274330b2cff6a10c67b5f597087202f94d06d2338cf8e" +// }; + + // 1 million 'a' + static private String million_a_digest = "8693287aa62f9478f7cb312ec0866b6c4e4a0f11160441e8f4ffcd2715dd554f"; + + GOST3411DigestTest() + { + super(new GOST3411Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + + HMac gMac = new HMac(new GOST3411Digest()); + + gMac.init(new KeyParameter(PKCS5S1ParametersGenerator.PKCS5PasswordToUTF8Bytes("1".toCharArray()))); + + byte[] data = "fred".getBytes(); + + gMac.update(data, 0, data.length); + byte[] mac = new byte[gMac.getMacSize()]; + + gMac.doFinal(mac, 0); + } + + protected Digest cloneDigest(Digest digest) + { + return new GOST3411Digest((GOST3411Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new GOST3411DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/Grain128Test.java b/core/src/test/java/org/spongycastle/crypto/test/Grain128Test.java new file mode 100644 index 00000000..7ac877c1 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/Grain128Test.java @@ -0,0 +1,117 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.engines.Grain128Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Grain-128 Test + */ +public class Grain128Test + extends SimpleTest +{ + + String keyStream1 = "f09b7bf7d7f6b5c2de2ffc73ac21397f"; + String keyStream2 = "afb5babfa8de896b4b9c6acaf7c4fbfd"; + + public String getName() + { + return "Grain-128"; + } + + public void performTest() + { + Grain128Test1(new ParametersWithIV(new KeyParameter(Hex + .decode("00000000000000000000000000000000")), Hex + .decode("000000000000000000000000"))); + Grain128Test2(new ParametersWithIV(new KeyParameter(Hex + .decode("0123456789abcdef123456789abcdef0")), Hex + .decode("0123456789abcdef12345678"))); + Grain128Test3(new ParametersWithIV(new KeyParameter(Hex + .decode("0123456789abcdef123456789abcdef0")), Hex + .decode("0123456789abcdef12345678"))); + } + + private void Grain128Test1(CipherParameters params) + { + StreamCipher grain = new Grain128Engine(); + byte[] in = new byte[16]; + byte[] out = new byte[16]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream1))) + { + mismatch("Keystream 1", keyStream1, out); + } + + grain.reset(); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream1))) + { + mismatch("Keystream 1", keyStream1, out); + } + } + + private void Grain128Test2(CipherParameters params) + { + StreamCipher grain = new Grain128Engine(); + byte[] in = new byte[16]; + byte[] out = new byte[16]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream2))) + { + mismatch("Keystream 2", keyStream2, out); + } + + grain.reset(); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream2))) + { + mismatch("Keystream 2", keyStream2, out); + } + } + + private void Grain128Test3(CipherParameters params) + { + StreamCipher grain = new Grain128Engine(); + byte[] in = "Encrypt me!".getBytes(); + byte[] cipher = new byte[in.length]; + byte[] clear = new byte[in.length]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, cipher, 0); + grain.reset(); + grain.processBytes(cipher, 0, cipher.length, clear, 0); + + if (!areEqual(in, clear)) + { + mismatch("Test 3", new String(Hex.encode(in)), clear); + } + } + + private void mismatch(String name, String expected, byte[] found) + { + fail("mismatch on " + name, expected, new String(Hex.encode(found))); + } + + public static void main(String[] args) + { + runTest(new Grain128Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/Grainv1Test.java b/core/src/test/java/org/spongycastle/crypto/test/Grainv1Test.java new file mode 100644 index 00000000..a9847d0e --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/Grainv1Test.java @@ -0,0 +1,140 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.engines.Grainv1Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Grain v1 Test + */ +public class Grainv1Test + extends SimpleTest +{ + + String keyStream1 = "dee931cf1662a72f77d0"; + String keyStream2 = "7f362bd3f7abae203664"; + String keyStream4 = "017D13ECB20AE0C9ACF784CB06525F72" + + "CE6D52BEBB948F124668C35064559024" + + "49EEA505C19F3EE4D052C3D19DA9C4D1" + + "B92DBC7F07AFEA6A3D845DE60D8471FD"; + + public String getName() + { + return "Grain v1"; + } + + public void performTest() + { + Grainv1Test1(new ParametersWithIV(new KeyParameter(Hex + .decode("00000000000000000000")), Hex + .decode("0000000000000000"))); + Grainv1Test2(new ParametersWithIV(new KeyParameter(Hex + .decode("0123456789abcdef1234")), Hex + .decode("0123456789abcdef"))); + Grainv1Test3(new ParametersWithIV(new KeyParameter(Hex + .decode("0123456789abcdef1234")), Hex + .decode("0123456789abcdef"))); + Grainv1Test4(new ParametersWithIV(new KeyParameter(Hex + .decode("0F62B5085BAE0154A7FA")), Hex + .decode("288FF65DC42B92F9"))); + } + + private void Grainv1Test1(CipherParameters params) + { + StreamCipher grain = new Grainv1Engine(); + byte[] in = new byte[10]; + byte[] out = new byte[10]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream1))) + { + mismatch("Keystream 1", keyStream1, out); + } + + grain.reset(); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream1))) + { + mismatch("Keystream 1", keyStream1, out); + } + } + + private void Grainv1Test2(CipherParameters params) + { + StreamCipher grain = new Grainv1Engine(); + byte[] in = new byte[10]; + byte[] out = new byte[10]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream2))) + { + mismatch("Keystream 2", keyStream2, out); + } + + grain.reset(); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream2))) + { + mismatch("Keystream 2", keyStream2, out); + } + } + + private void Grainv1Test3(CipherParameters params) + { + StreamCipher grain = new Grainv1Engine(); + byte[] in = "Encrypt me!".getBytes(); + byte[] cipher = new byte[in.length]; + byte[] clear = new byte[in.length]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, cipher, 0); + grain.reset(); + grain.processBytes(cipher, 0, cipher.length, clear, 0); + + if (!areEqual(in, clear)) + { + mismatch("Test 3", new String(Hex.encode(in)), clear); + } + } + + private void Grainv1Test4(CipherParameters params) + { + StreamCipher grain = new Grainv1Engine(); + byte[] in = new byte[keyStream4.length() / 2]; + byte[] out = new byte[in.length]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream4))) + { + mismatch("Keystream 4", keyStream4, out); + } + } + + private void mismatch(String name, String expected, byte[] found) + { + fail("mismatch on " + name, expected, new String(Hex.encode(found))); + } + + public static void main(String[] args) + { + runTest(new Grainv1Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/HCFamilyTest.java b/core/src/test/java/org/spongycastle/crypto/test/HCFamilyTest.java new file mode 100644 index 00000000..1032c443 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/HCFamilyTest.java @@ -0,0 +1,192 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.engines.HC128Engine; +import org.spongycastle.crypto.engines.HC256Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * HC-128 and HC-256 Tests. Based on the test vectors in the official reference + * papers, respectively: + * <pre> + * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf + * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf + * </pre> + * See HCFamilyVecTest for a more exhaustive test based on the ecrypt vectors. + */ +public class HCFamilyTest + extends SimpleTest +{ + private static final byte[] MSG = new byte[64]; + + private static String[][] HC128_VerifiedTest = + { + { + "Set 2, vector# 0", + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "82001573A003FD3B7FD72FFB0EAF63AA" + + "C62F12DEB629DCA72785A66268EC758B" + + "1EDB36900560898178E0AD009ABF1F49" + + "1330DC1C246E3D6CB264F6900271D59C" + }, + { + "Set 6, vector# 0", + "0053A6F94C9FF24598EB3E91E4378ADD", + "0D74DB42A91077DE45AC137AE148AF16", + "2E1ED12A8551C05AF41FF39D8F9DF933" + + "122B5235D48FC2A6F20037E69BDBBCE8" + + "05782EFC16C455A4B3FF06142317535E" + + "F876104C32445138CB26EBC2F88A684C" + }, + { + "Set 6, vector# 1", + "0558ABFE51A4F74A9DF04396E93C8FE2", + "167DE44BB21980E74EB51C83EA51B81F", + "4F864BF3C96D0363B1903F0739189138" + + "F6ED2BC0AF583FEEA0CEA66BA7E06E63" + + "FB28BF8B3CA0031D24ABB511C57DD17B" + + "FC2861C32400072CB680DF2E58A5CECC" + }, + { + "Set 6, vector# 2", + "0A5DB00356A9FC4FA2F5489BEE4194E7", + "1F86ED54BB2289F057BE258CF35AC128", + "82168AB0023B79AAF1E6B4D823855E14" + + "A7084378036A951B1CFEF35173875ED8" + + "6CB66AB8410491A08582BE40080C3102" + + "193BA567F9E95D096C3CC60927DD7901" + }, + { + "Set 6, vector# 3", + "0F62B5085BAE0154A7FA4DA0F34699EC", + "288FF65DC42B92F960C72E95FC63CA31", + "1CD8AEDDFE52E217E835D0B7E84E2922" + + "D04B1ADBCA53C4522B1AA604C42856A9" + + "0AF83E2614BCE65C0AECABDD8975B557" + + "00D6A26D52FFF0888DA38F1DE20B77B7" + } + }; + + private static String[][] HC256_VerifiedTest = + { + { + "Set 2, vector# 0", + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "5B078985D8F6F30D42C5C02FA6B67951" + + "53F06534801F89F24E74248B720B4818" + + "CD9227ECEBCF4DBF8DBF6977E4AE14FA" + + "E8504C7BC8A9F3EA6C0106F5327E6981" + }, + { + "Set 2, vector# 9", + "09090909090909090909090909090909", + "00000000000000000000000000000000", + "F5C2926651AEED9AF1A9C2F04C03D081" + + "2145B56AEA46EB283A25A4C9E3D8BEB4" + + "821B418F06F2B9DCDF1A85AB8C02CD14" + + "62E1BBCAEC9AB0E99AA6AFF918BA627C" + }, + { + "Set 2, vector#135", + "87878787878787878787878787878787", + "00000000000000000000000000000000", + "CEC0C3852E3B98233EBCB975C10B1191" + + "3C69F2275EB97A1402EDF16C6FBE19BE" + + "79D65360445BCB63676E6553B609A065" + + "0155C3B22DD1975AC0F3F65063A2E16E" + }, + { + "Set 6, vector# 0", + "0053A6F94C9FF24598EB3E91E4378ADD" + + "3083D6297CCF2275C81B6EC11467BA0D", + "0D74DB42A91077DE45AC137AE148AF16" + + "7DE44BB21980E74EB51C83EA51B81F86", + "23D9E70A45EB0127884D66D9F6F23C01" + + "D1F88AFD629270127247256C1FFF91E9" + + "1A797BD98ADD23AE15BEE6EEA3CEFDBF" + + "A3ED6D22D9C4F459DB10C40CDF4F4DFF" + }, + { + "Set 6, vector# 1", + "0558ABFE51A4F74A9DF04396E93C8FE2" + + "3588DB2E81D4277ACD2073C6196CBF12", + "167DE44BB21980E74EB51C83EA51B81F" + + "86ED54BB2289F057BE258CF35AC1288F", + "C44B5262F2EAD9C018213127686DB742" + + "A72D3F2D61D18F0F4E7DE5B4F7ADABE0" + + "7E0C82033B139F02BAACB4E2F2D0BE30" + + "110C3A8A2B621523756692877C905DD0" + }, + { + "Set 6, vector# 2", + "0A5DB00356A9FC4FA2F5489BEE4194E7" + + "3A8DE03386D92C7FD22578CB1E71C417", + "1F86ED54BB2289F057BE258CF35AC128" + + "8FF65DC42B92F960C72E95FC63CA3198", + "9D13AA06122F4F03AE60D507701F1ED0" + + "63D7530FF35EE76CAEDCBFB01D8A239E" + + "FA4A44B272DE9B4092E2AD56E87C3A60" + + "89F5A074D1F6E5B8FC6FABEE0C936F06" + }, + { + "Set 6, vector# 3", + "0F62B5085BAE0154A7FA4DA0F34699EC" + + "3F92E5388BDE3184D72A7DD02376C91C", + "288FF65DC42B92F960C72E95FC63CA31" + + "98FF66CD349B0269D0379E056CD33AA1", + "C8632038DA61679C4685288B37D3E232" + + "7BC2D28C266B041FE0CA0D3CFEED8FD5" + + "753259BAB757168F85EA96ADABD823CA" + + "4684E918423E091565713FEDDE2CCFE0" + } + }; + + public String getName() + { + return "HC-128 and HC-256"; + } + + public void performTest() + { + StreamCipher hc = new HC256Engine(); + + for (int i = 0; i != HC256_VerifiedTest.length; i++) + { + String[] test = HC256_VerifiedTest[i]; + HCTest(hc, "HC-256 - " + test[0], Hex.decode(test[1]), Hex.decode(test[2]), Hex.decode(test[3])); + } + + hc = new HC128Engine(); + + for (int i = 0; i != HC128_VerifiedTest.length; i++) + { + String[] test = HC128_VerifiedTest[i]; + HCTest(hc, "HC-128 - " + test[0], Hex.decode(test[1]), Hex.decode(test[2]), Hex.decode(test[3])); + } + } + + private void HCTest(StreamCipher hc, String test, byte[] key, byte[] IV, byte[] expected) + { + KeyParameter kp = new KeyParameter(key); + ParametersWithIV ivp = new ParametersWithIV(kp, IV); + + hc.init(true, ivp); + for (int i = 0; i < 64; i++) + { + if (hc.returnByte(MSG[i]) != expected[i]) + { + fail(test + " failure at byte " + i); + } + } + } + + public static void main(String[] args) + { + runTest(new HCFamilyTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/HCFamilyVecTest.java b/core/src/test/java/org/spongycastle/crypto/test/HCFamilyVecTest.java new file mode 100644 index 00000000..a3c954f8 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/HCFamilyVecTest.java @@ -0,0 +1,199 @@ +package org.spongycastle.crypto.test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.engines.HC128Engine; +import org.spongycastle.crypto.engines.HC256Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * HC-128 and HC-256 Tests. Based on the test vectors in the official reference + * papers, respectively: + * + * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf + * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf + */ +public class HCFamilyVecTest + extends SimpleTest +{ + private static class PeekableLineReader extends BufferedReader + { + public PeekableLineReader(Reader r) throws IOException + { + super(r); + + peek = super.readLine(); + } + + public String peekLine() + { + return peek; + } + + public String readLine() throws IOException + { + String tmp = peek; + peek = super.readLine(); + return tmp; + } + + private String peek; + } + + public String getName() + { + return "HC-128 and HC-256 (ecrypt)"; + } + + public void performTest() throws Exception + { + runTests(new HC128Engine(), "ecrypt_HC-128.txt"); + runTests(new HC256Engine(), "ecrypt_HC-256_128K_128IV.txt"); + runTests(new HC256Engine(), "ecrypt_HC-256_256K_128IV.txt"); + runTests(new HC256Engine(), "ecrypt_HC-256_128K_256IV.txt"); + runTests(new HC256Engine(), "ecrypt_HC-256_256K_256IV.txt"); + } + + private void runTests(StreamCipher hc, String fileName) throws IOException + { + Reader resource = new InputStreamReader(getClass().getResourceAsStream(fileName)); + PeekableLineReader r = new PeekableLineReader(resource); + runAllVectors(hc, fileName, r); + } + + private void runAllVectors(StreamCipher hc, String fileName, PeekableLineReader r) + throws IOException + { + for (;;) + { + String line = r.readLine(); + if (line == null) + { + break; + } + + line = line.trim(); + + if (line.startsWith("Set ")) + { + runVector(hc, fileName, r, dellChar(line, ':')); + } + } + } + + private String dellChar(String s, char c) + { + StringBuffer b = new StringBuffer(); + + for (int i = 0; i != s.length(); i++) + { + if (s.charAt(i) != c) + { + b.append(s.charAt(i)); + } + } + + return b.toString(); + } + + private void runVector(StreamCipher hc, String fileName, PeekableLineReader r, String vectorName) + throws IOException + { +// System.out.println(fileName + " => " + vectorName); + String hexKey = readBlock(r); + String hexIV = readBlock(r); + + CipherParameters cp = new KeyParameter(Hex.decode(hexKey)); + cp = new ParametersWithIV(cp, Hex.decode(hexIV)); + hc.init(true, cp); + + byte[] input = new byte[64]; + byte[] output = new byte[64]; + byte[] digest = new byte[64]; + int pos = 0; + + for (;;) + { + String line1 = r.peekLine().trim(); + int equalsPos = line1.indexOf('='); + String lead = line1.substring(0, equalsPos - 1); + + String hexData = readBlock(r); + byte[] data = Hex.decode(hexData); + + if (lead.equals("xor-digest")) + { + if (!Arrays.areEqual(data, digest)) + { + fail("Failed in " + fileName + " for test vector: " + vectorName + " at " + lead); +// System.out.println(fileName + " => " + vectorName + " failed at " + lead); return; + } + break; + } + + int posA = lead.indexOf('['); + int posB = lead.indexOf(".."); + int posC = lead.indexOf(']'); + int start = Integer.parseInt(lead.substring(posA + 1, posB)); + int end = Integer.parseInt(lead.substring(posB + 2, posC)); + + if (start % 64 != 0 || (end - start != 63)) + { + throw new IllegalStateException(vectorName + ": " + lead + " not on 64 byte boundaries"); + } + + while (pos < end) + { + hc.processBytes(input, 0, input.length, output, 0); + xor(digest, output); + pos += 64; + } + + if (!Arrays.areEqual(data, output)) + { + fail("Failed in " + fileName + " for test vector: " + vectorName + " at " + lead); +// System.out.println(fileName + " => " + vectorName + " failed at " + lead); return; + } + } + } + + private static String readBlock(PeekableLineReader r) throws IOException + { + String first = r.readLine().trim(); + String result = first.substring(first.lastIndexOf(' ') + 1); + + for (;;) + { + String peek = r.peekLine().trim(); + if (peek.length() < 1 || peek.indexOf('=') >= 0) + { + break; + } + result += r.readLine().trim(); + } + + return result; + } + + private static void xor(byte[] digest, byte[] block) + { + for (int i = 0; i < digest.length; ++i) + { + digest[i] ^= block[i]; + } + } + + public static void main(String[] args) + { + runTest(new HCFamilyVecTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/HKDFGeneratorTest.java b/core/src/test/java/org/spongycastle/crypto/test/HKDFGeneratorTest.java new file mode 100644 index 00000000..00564eb6 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/HKDFGeneratorTest.java @@ -0,0 +1,304 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.generators.HKDFBytesGenerator; +import org.spongycastle.crypto.params.HKDFParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * HKDF tests - vectors from RFC 5869, + 2 more, 101 and 102 + */ +public class HKDFGeneratorTest + extends SimpleTest +{ + + public HKDFGeneratorTest() + { + } + + private void compareOKM(int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!areEqual(calculatedOKM, testOKM)) + { + fail("HKDF failed generator test " + test); + } + } + + public void performTest() + { + { + // === A.1. Test Case 1 - Basic test case with SHA-256 === + + Digest hash = new SHA256Digest(); + byte[] ikm = Hex + .decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); + byte[] salt = Hex.decode("000102030405060708090a0b0c"); + byte[] info = Hex.decode("f0f1f2f3f4f5f6f7f8f9"); + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(1, okm, Hex.decode( + "3cb25f25faacd57a90434f64d0362f2a" + + "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" + + "34007208d5b887185865")); + } + + // === A.2. Test Case 2 - Test with SHA-256 and longer inputs/outputs + // === + { + Digest hash = new SHA256Digest(); + byte[] ikm = Hex.decode("000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f" + + "202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f" + + "404142434445464748494a4b4c4d4e4f"); + byte[] salt = Hex.decode("606162636465666768696a6b6c6d6e6f" + + "707172737475767778797a7b7c7d7e7f" + + "808182838485868788898a8b8c8d8e8f" + + "909192939495969798999a9b9c9d9e9f" + + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"); + byte[] info = Hex.decode("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); + int l = 82; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(2, okm, Hex.decode( + "b11e398dc80327a1c8e7f78c596a4934" + + "4f012eda2d4efad8a050cc4c19afa97c" + + "59045a99cac7827271cb41c65e590e09" + + "da3275600c2f09b8367793a9aca3db71" + + "cc30c58179ec3e87c14c01d5c1f3434f" + + "1d87")); + } + + { + // === A.3. Test Case 3 - Test with SHA-256 and zero-length + // salt/info === + + // setting salt to an empty byte array means that the salt is set to + // HashLen zero valued bytes + // setting info to null generates an empty byte array as info + // structure + + Digest hash = new SHA256Digest(); + byte[] ikm = Hex + .decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); + byte[] salt = new byte[0]; + byte[] info = null; + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(3, okm, Hex.decode( + "8da4e775a563c18f715f802a063c5a31" + + "b8a11f5c5ee1879ec3454e5f3c738d2d" + + "9d201395faa4b61a96c8")); + } + + { + // === A.4. Test Case 4 - Basic test case with SHA-1 === + + Digest hash = new SHA1Digest(); + byte[] ikm = Hex.decode("0b0b0b0b0b0b0b0b0b0b0b"); + byte[] salt = Hex.decode("000102030405060708090a0b0c"); + byte[] info = Hex.decode("f0f1f2f3f4f5f6f7f8f9"); + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(4, okm, Hex.decode( + "085a01ea1b10f36933068b56efa5ad81" + + "a4f14b822f5b091568a9cdd4f155fda2" + + "c22e422478d305f3f896")); + } + + // === A.5. Test Case 5 - Test with SHA-1 and longer inputs/outputs === + { + Digest hash = new SHA1Digest(); + byte[] ikm = Hex.decode("000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f" + + "202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f" + + "404142434445464748494a4b4c4d4e4f"); + byte[] salt = Hex.decode("606162636465666768696a6b6c6d6e6f" + + "707172737475767778797a7b7c7d7e7f" + + "808182838485868788898a8b8c8d8e8f" + + "909192939495969798999a9b9c9d9e9f" + + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"); + byte[] info = Hex.decode("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); + int l = 82; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(5, okm, Hex.decode( + "0bd770a74d1160f7c9f12cd5912a06eb" + + "ff6adcae899d92191fe4305673ba2ffe" + + "8fa3f1a4e5ad79f3f334b3b202b2173c" + + "486ea37ce3d397ed034c7f9dfeb15c5e" + + "927336d0441f4c4300e2cff0d0900b52" + + "d3b4")); + } + + { + // === A.6. Test Case 6 - Test with SHA-1 and zero-length salt/info + // === + + // setting salt to null should generate a new salt of HashLen zero + // valued bytes + + Digest hash = new SHA1Digest(); + byte[] ikm = Hex + .decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); + byte[] salt = null; + byte[] info = new byte[0]; + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(6, okm, Hex.decode( + "0ac1af7002b3d761d1e55298da9d0506" + + "b9ae52057220a306e07b6b87e8df21d0" + + "ea00033de03984d34918")); + } + + { + // === A.7. Test Case 7 - Test with SHA-1, salt not provided, + // zero-length info === + // (salt defaults to HashLen zero octets) + + // this test is identical to test 6 in all ways bar the IKM value + + Digest hash = new SHA1Digest(); + byte[] ikm = Hex + .decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"); + byte[] salt = null; + byte[] info = new byte[0]; + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(7, okm, Hex.decode( + "2c91117204d745f3500d636a62f64f0a" + + "b3bae548aa53d423b0d1f27ebba6f5e5" + + "673a081d70cce7acfc48")); + } + + { + // === A.101. Additional Test Case - Test with SHA-1, skipping extract + // zero-length info === + // (salt defaults to HashLen zero octets) + + // this test is identical to test 7 in all ways bar the IKM value + // which is set to the PRK value + + Digest hash = new SHA1Digest(); + byte[] ikm = Hex + .decode("2adccada18779e7c2077ad2eb19d3f3e731385dd"); + byte[] info = new byte[0]; + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = HKDFParameters.skipExtractParameters(ikm, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(101, okm, Hex.decode( + "2c91117204d745f3500d636a62f64f0a" + + "b3bae548aa53d423b0d1f27ebba6f5e5" + + "673a081d70cce7acfc48")); + } + + // === A.102. Additional Test Case - Test with SHA-1, maximum output === + // (salt defaults to HashLen zero octets) + + // this test is identical to test 7 in all ways bar the IKM value + + Digest hash = new SHA1Digest(); + byte[] ikm = Hex + .decode("2adccada18779e7c2077ad2eb19d3f3e731385dd"); + byte[] info = new byte[0]; + int l = 255 * hash.getDigestSize(); + byte[] okm = new byte[l]; + + HKDFParameters params = HKDFParameters.skipExtractParameters(ikm, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + int zeros = 0; + for (int i = 0; i < hash.getDigestSize(); i++) + { + if (okm[i] == 0) + { + zeros++; + } + } + + if (zeros == hash.getDigestSize()) + { + fail("HKDF failed generator test " + 102); + } + } + + public String getName() + { + return "HKDF"; + } + + public static void main( + String[] args) + { + runTest(new HKDFGeneratorTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/HashCommitmentTest.java b/core/src/test/java/org/spongycastle/crypto/test/HashCommitmentTest.java new file mode 100644 index 00000000..d4c1c076 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/HashCommitmentTest.java @@ -0,0 +1,152 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.Commitment; +import org.spongycastle.crypto.Committer; +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.commitments.GeneralHashCommitter; +import org.spongycastle.crypto.commitments.HashCommitter; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class HashCommitmentTest + extends SimpleTest +{ + public String getName() + { + return "HashCommitmentTest"; + } + + public void performBasicTest() + throws Exception + { + byte[] data = Hex.decode("4e6f77206973207468652074696d6520666f7220616c6c20"); + + Committer committer = new HashCommitter(new SHA256Digest(), new SecureRandom()); + + Commitment c = committer.commit(data); + + committer = new HashCommitter(new SHA256Digest(), new SecureRandom()); + + if (!committer.isRevealed(c, data)) + { + fail("commitment failed to validate"); + } + + committer = new HashCommitter(new SHA1Digest(), new SecureRandom()); + + if (committer.isRevealed(c, data)) + { + fail("commitment validated!!"); + } + + try + { + committer.isRevealed(c, new byte[data.length + 1]); + } + catch (Exception e) + { + if (!e.getMessage().equals("Message and witness secret lengths do not match.")) + { + fail("exception thrown but wrong message"); + } + } + + // SHA1 has a block size of 512 bits, try a message that's too big + + try + { + c = committer.commit(new byte[33]); + } + catch (DataLengthException e) + { + if (!e.getMessage().equals("Message to be committed to too large for digest.")) + { + fail("exception thrown but wrong message"); + } + } + } + + public void performGeneralTest() + throws Exception + { + byte[] data = Hex.decode("4e6f77206973207468652074696d6520666f7220616c6c20"); + + Committer committer = new GeneralHashCommitter(new SHA256Digest(), new SecureRandom()); + + Commitment c = committer.commit(data); + + committer = new GeneralHashCommitter(new SHA256Digest(), new SecureRandom()); + + if (!committer.isRevealed(c, data)) + { + fail("general commitment failed to validate"); + } + + committer = new GeneralHashCommitter(new SHA1Digest(), new SecureRandom()); + + if (committer.isRevealed(c, data)) + { + fail("general commitment validated!!"); + } + + c = committer.commit(data); + + // try and fool it. + byte[] s = c.getSecret(); + byte[] newS = Arrays.copyOfRange(s, 0, s.length - 1); + byte[] newData = new byte[data.length + 1]; + + newData[0] = s[s.length - 1]; + System.arraycopy(data, 0, newData, 1, data.length); + + c = new Commitment(newS, c.getCommitment()); + + if (committer.isRevealed(c, newData)) + { + fail("general commitment validated!!"); + } + + try + { + committer.isRevealed(c, new byte[data.length + 1]); + } + catch (Exception e) + { + if (!e.getMessage().equals("Message and witness secret lengths do not match.")) + { + fail("exception thrown but wrong message"); + } + } + + // SHA1 has a block size of 512 bits, try a message that's too big + + try + { + c = committer.commit(new byte[33]); + } + catch (DataLengthException e) + { + if (!e.getMessage().equals("Message to be committed to too large for digest.")) + { + fail("exception thrown but wrong message"); + } + } + } + + public void performTest() + throws Exception + { + performBasicTest(); + performGeneralTest(); + } + + public static void main(String[] args) + { + runTest(new HashCommitmentTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/IDEATest.java b/core/src/test/java/org/spongycastle/crypto/test/IDEATest.java new file mode 100644 index 00000000..beb0e489 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/IDEATest.java @@ -0,0 +1,38 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.IDEAEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + */ +public class IDEATest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new IDEAEngine(), + new KeyParameter(Hex.decode("00112233445566778899AABBCCDDEEFF")), + "000102030405060708090a0b0c0d0e0f", "ed732271a7b39f475b4b2b6719f194bf"), + new BlockCipherVectorTest(0, new IDEAEngine(), + new KeyParameter(Hex.decode("00112233445566778899AABBCCDDEEFF")), + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", "b8bc6ed5c899265d2bcfad1fc6d4287d") + }; + + IDEATest() + { + super(tests, new IDEAEngine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "IDEA"; + } + + public static void main( + String[] args) + { + runTest(new IDEATest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ISAACTest.java b/core/src/test/java/org/spongycastle/crypto/test/ISAACTest.java new file mode 100644 index 00000000..e2f9f124 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ISAACTest.java @@ -0,0 +1,180 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.ISAACEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * ISAAC Test - see http://www.burtleburtle.net/bob/rand/isaacafa.html + */ +public class ISAACTest + extends SimpleTest +{ + byte[] out = Hex.decode( + "f650e4c8e448e96d98db2fb4f5fad54f433f1afbedec154ad837048746ca4f9a" + + "5de3743e88381097f1d444eb823cedb66a83e1e04a5f6355c744243325890e2e" + + "7452e31957161df638a824f3002ed71329f5544951c08d83d78cb99ea0cc74f3" + + "8f651659cbc8b7c2f5f71c6912ad6419e5792e1b860536b809b3ce98d45d6d81" + + "f3b2612917e38f8529cf72ce349947b0c998f9ffb5e13dae32ae2a2bf7cf814c" + + "8ebfa303cf22e0640b923200eca4d58aef53cec4d0f7b37d9c411a2affdf8a80" + + "b40e27bcb4d2f97644b89b08f37c71d51a70e7e90bdb9c3060dc5207b3c3f24b" + + "d7386806229749b54e232cd091dabc65a70e11018b87437e5781414fcdbc62e2" + + "8107c9ff69d2e4ae3b18e752b143b6886f4e077295138769943c3c74afc17a97" + + "0fd439636a529b0bd8c58a6aa8bcc22d2db35dfea7a2f4026cb167db538e1f4e" + + "7275e2771d3b8e97ecc5dc9115e3a5b90369661430ab93ecac9fe69d7bc76811" + + "60eda8da28833522d5295ebc5adb60e7f7e1cdd097166d14b67ec13a210f3925" + + "64af0fef0d0286843aea3decb058bafbb8b0ccfcf2b5cc05e3a662d9814bc24c" + + "2364a1aa37c0ed052b36505c451e7ec85d2a542fe43d0fbb91c8d92560d4d5f8" + + "12a0594b9e8a51dacd49ebdb1b0dcdc1cd57c7f7e63444517ded386f2f36fa86" + + "a6d1210133bc405db388d96cdb6dbe96fe29661c13edc0cbcb0eee4a70cc94ae" + + "de11ed340606cf9f3a6ce38923d74f4ea37f63ff917bdec2d73f72d40e7e0e67" + + "3d77d9a213add9228891b3db01a9bd7056a001e3d51f093dcc033ce35ad0d3b0" + + "34105a8c6a123f57bd2e50247364944be89b1a3b21835c4d9f39e2d9d405ded8" + + "294d37e5bccaaeed35a124b56708a2bcb00960ba2a98121a4d8fae820bb3263f" + + "12595a196a1075890809e49421c171ec884d682514c8009bb0b84e7b03fb88f4" + + "28e7cb789388b13bdd2dc1d5848f520a07c28cd168a3935872c9137d127dd430" + + "c613f1578c2f0d55f7d3f39f309bfb788406b13746c0a6f53718d59708607f04" + + "76904b6d04db4e13cd7411a7b510ce0ebfc7f7ccb83f957afdfef62dc35e4580" + + "3ff1e5244112d96c02c9b944d5990dfbe7e265810d9c7e7e826dfa8966f1e0ab" + + "30bcc764eadebeaced35e5ee0c571a7de4f3a26af7f58f7badf6bc235d023e65" + + "1ed3ff4eec46b0b6d2a93b51e75b41c97e315aeb61119a5a53245b7933f6d7b1" + + "cae8deba50fc8194afa92a6dc87c80064188bfcd8bace62e78ffa5685597ec0f" + + "b4415f7d08294766ad56764309c36f903dde9f394a0a283c18080c8e080c79ec" + + "79ae4c10cb9e15637cdd662f62d31911a4ca0cf15cf824cd3b708f991e16614c" + + "b6b9d7665de87abb7229ea81d5b2d75056e6cd21fe1e42d596da2655c2b9aa36" + + "b8f6fd4a6a158d1001913fd3af7d1fb80b5e435f90c107576554abda7a68710f" + + "82ac484fd7e1c7be95c85eaa94a302f44d3cfbda786b29081010b27582d53d12" + + "21e2a51c3d1e9150b059261dd0638e1a31860f0581f2864dff4cfc350451516d" + + "bd086f26bc5654c165dfa427a82427f5582e3014b8d2486dc79a17499a1d7745" + + "8766bb541e04a7f73d3dff8ad5ec6bf4dbef7d9f36ec0ea31feb2e4f15cfcc5c" + + "d8c423fbd0ef3cc9eb244925ba5590c8a5f48ac433c5321c613b67b2479c3a22" + + "e21339cc10d210aa931dd7e2ef05ee06b82f2703a385cb2c5d67133c877eb7b4" + + "1e3437f75afb43ae53c078f394d904811d96458908063a85e13222281956b1e5" + + "31860f132e7b022f21182ca396f703ac46819e2e0d28fe523724d4dca0eabe6b" + + "c66699fdc6112fdd19c1e69c04d3658a4b55dd9931907d62f854b5224d678f26" + + "22ae0582eafed133e4a51d2184bd6dd6c1a513753f28ee63fb737b1a70a1660e" + + "8a8dfaa31be79937f7476978513c1764531ac6bf12c06908001cdb951a4b6a53" + + "d067fce512b2cfb69ddb477f740e006639ddf25acc8bfa2df1b20eaf64f2632c" + + "9783cdee63bfd4d80084cfe575f4e9e219b48fd06c48ddd87a36af9371865c4c" + + "9ce0199d867027d72cb7b77f84ef01da72f5972f040f7074df9afa29c921f94e" + + "75c08a3618c1ef9ad649a428c5b719378a30738ad97cd348858129a6239e3b0a" + + "bbb8abc480fac4c2ecfcf20bd9d711f9e2a4ef71b5fe87c0be8b06b2aafef5a7" + + "9c15db3b0aeb81654389a84a253b1d7a19047c797cdc78a2d20adf0356f55a71" + + "3e730fa8fd8650d8959e234eb7546681dad1b22a142a6e858ef4bce668235b9d" + + "85a13f8574096ae7a949bea229322d0dd568385882846526403dae086dd1943a" + + "e1279bff9e7e4f041c3a4524484525e481d4cc5fe24124c0037464c0bf1bd691" + + "26ceb003275ead3ac5bde90826414ff3a30519add7b43abe2ce5d3d588412761" + + "97ca2070e5fbb9c7276df0b4308f751f37a97df6c9cd808cfe4cb3803d469303" + + "aee19096c0d5d42a4e823ad3f5f9cc3b4286619c9ca45e1c66c97340891aec49" + + "45bae606c798f04752649d6cce86fdfc80c6e402d6ec2f2b27c822821fe26ce0" + + "92f57ea7de462f4d07497cae5a48755c721502dd6cbe7935836d80039ead7f70" + + "9ab3a42f4c8652d632e39273e8fa38601da4f25a0cd6ef8102503f7d8854a0a1" + + "9a30c4e88815715305efe29457c4c9252887d96fc1a71e3ce9f841632d0985de" + + "d21e796c6fb5ce5602614abfc3c7be2cb54fed6fa617a083c3142d8f6079e4ce" + + "ceffc1471d0cb81bdc153e5fe36ef5bbd531161a165b10157aa114ed3f7579b3" + + "f7f395f1bc6172c7a86f875e0e6c51b3cdfec2af73c0e762824c2009c5a87748" + + "94d401258aba3ffbd32be0608c17eff021e2547e07cffad905340e15f3310c92" + + "9d8d190886ba527ff943f672ef73fbf046d95ca5c54cd95b9d855e894bb5af29"); + + byte[] outFFFFFFFF = Hex.decode( + "de3b3f3c19e0629c1fc8b7836695d523e7804edd86ff7ce9b106f52caebae9d9" + + "72f845d49ce17d7da44e49bae954aac0d0b1284b98a88eec1524fb6bc91a16b5" + + "1192ac5334131446ac2442de9ff3d5867b9b9148881ee30a6e87dd88e5d1f7cd" + + "98db31ff36f70d9850cfefaef42abb00ecc39ed308bf4b8030cdc2b6b7e42f0e" + + "908030dd282f96edacc888b3a986e109c129998f89baa1b5da8970b07a6ab012" + + "f10264f23c315c9c8e0c164955c68517b6a4f982b2626db70787f869ac6d551b" + + "e34931627c7058e965c502e18d2cd370e6db3b70d947d61aa9717cf8394f48c6" + + "3c796f3a154950846badb28b70d982f29bc670254e3e5e0f8e36b0a5f6da0a04" + + "6b235ed6a42988c012bde74d879fa8eb5d59f5f40ed5e76601c9847b3edb2690"); + + byte[] outFFFF0000 = Hex.decode( + "26c54b1f8c4e3fc582e9e8180f7aba5380463dcf58b03cbeda0ecc8ba90ccff8" + + "5bd50896313d7efed44015faeac6964b241a7fb8a2e37127a7cbea0fd7c020f2" + + "406371b87ef5185089504751e5e44352eff63e00e5c28f5dff0616a9a3a00f1f" + + "4a1350e3a17be9abddfc2c94571450a0dc4c3c0c7c7f98e80c95f607d50c676a" + + "9a3006f9d279a79a4d66b2ab0c52930c9ee84bc09895e70fa041b1a3a2966f11" + + "6a47fd09705124b1f5c7ae055e54536e66584b1608f3612d81b72f109a385831" + + "121945b207b90ac72437a248f27a121c2801f4153a8699fb047e193f7ba69e1b" + + "b117869675d4c963e6070c2ca3d332ce830cb5e3d9ed2eee7faf0acc20fbe154" + + "188ae789e95bd5c1f459dbd150aab6eb833170257084bc5d44e9df09f5624f9d" + + "afecd0c9340ac8587f8625d343f7efd1cc8abcf7a6f90eabd4e8e2d906278d6e" + + "431fcade165c8c467887fbf5c26d341557b064b98c60dd40ab262dc046d69647" + + "56f3ddc1a07ae5f87be878b9334fcde40add68d2ca1dc05fb1670f998c7c4607" + + "9a6e48bdb330ad8d30b61b5cc8dc156f5733905931949783f89ac396b65aa4b8" + + "51f746b53ed8ea66130e1d75e8eab136e60450e3e600226bc8e17d03744ce94c" + + "0eec9234fea5f18eef65d81f2f10cfbc0b112b8cde17c32eb33ed81d7356eac3" + + "eb1cb9cefa6604c2d707949b6e5a83e60705bf6aae76dcc7d35d68ff149c1ac5" + + "424bb4a39e2f496f886637fce3db4ba4ad12c1a32d25e1606f6635ff636486f6" + + "714997b45477f38813c02afce4bebf196b813332f0decd567c745f441e736364"); + + byte[] out0000FFFF = Hex.decode( + "bc31712f2a2f467a5abc737c57ce0f8d49d2f775eb850fc8f856daf19310fee2"+ + "5bab40e78403c9ef4ccd971418992faf4e85ca643fa6b482f30c4659066158a6"+ + "5bc3e620ba7ea5c34dd0eac5aabb2cf078d915fd1f8c437ed00423076c10f701"+ + "eefa7fc7c461aca5db8a87be29d925c4212d4adcfa71ff5b06af15c048aa0dfd"+ + "f0e645bc09fea200c430a88eb38c466ff358b836f1159656a078f6fc752f6db1"+ + "6680bb30fc771a6a785bbb2298e947d7b3500e557775962248bedf4e82c16e66"+ + "f39283ccb95e5399061056a11c4a280f00f7487888199487905273c7aa13012b"+ + "4849eca626cbf071c782e084f9fded57de92313e5f61a6e81117fb1115eff275"+ + "66fd5c755bb3b01bba69aeb8f1b1b1cc9709734be31b35bc707d372ba6fe70d1"+ + "e2c3b0e5e74a7058faff6b11d3a168f19fecc9fcb36b3e6a5f828c01c22ac0c2"+ + "5da2a3a9eec7e0ebbbf51472e430ed4cf1c7ab57ef9aea511e40250846d260b6"+ + "17a3fdeba16cf4afaf700144d3296b58b22a3c79ed96f3e2fc8d9e3c660ae153"+ + "8e0c285ccdc48b59117e80413bd0ad24c6a8d4f133fe1496f14351bb89904fa5"+ + "e10c4b8d50e0604578389c336a9ab3d292beb90ce640fc028e697cf54e021e2f"+ + "c0ca3fe0471fde5e5462f221739a74f5a13ae0621fe2a82e752bc294f63de48d"+ + "e85430af71307a30441b861ab5380e6a6dbe1251c9baa567da14e38e5a0ccddf"+ + "0127205c38fc3b77065e98101d219246103438d223ec7f8f533d4bb3a3d3407a"+ + "944910f11e8e5492e86de7a0471250eca32f0838b3db02fffe71898712af3261"); + + public String getName() + { + return "ISAAC"; + } + + public void performTest() + { + ISAACEngine engine = new ISAACEngine(); + + doTest(engine, Hex.decode("00000000"), out); + doTest(engine, Hex.decode("ffffffff"), outFFFFFFFF); + + byte[] k = new byte[256 * 4]; + for (int i = 0; i != k.length; i++) + { + k[i] = (byte)((i % 4 == 0 || i % 4 == 1) ? 0xff : 0x00); + } + doTest(engine, k, outFFFF0000); + k = new byte[256 * 4]; + for (int i = 0; i != k.length; i++) + { + k[i] = (byte)((i % 4 == 2 || i % 4 == 3) ? 0xff : 0x00); + } + doTest(engine, k, out0000FFFF); + } + + private void doTest(ISAACEngine engine, byte[] key, byte[] output) + { + byte[] in = new byte[output.length]; + byte[] enc = new byte[output.length]; + engine.init(true, new KeyParameter(key)); + engine.processBytes(in, 0, in.length, enc, 0); + if (!areEqual(enc, output)) + { + fail("ciphertext mismatch"); + } + engine.init(false, new KeyParameter(key)); + engine.processBytes(enc, 0, enc.length, enc, 0); + if (!areEqual(enc, in)) + { + fail("plaintext mismatch"); + } + } + + public static void main( + String[] args) + { + runTest(new ISAACTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ISO9796Test.java b/core/src/test/java/org/spongycastle/crypto/test/ISO9796Test.java new file mode 100644 index 00000000..109696bc --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ISO9796Test.java @@ -0,0 +1,972 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.AsymmetricBlockCipher; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.RIPEMD128Digest; +import org.spongycastle.crypto.digests.RIPEMD160Digest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.encodings.ISO9796d1Encoding; +import org.spongycastle.crypto.engines.RSABlindedEngine; +import org.spongycastle.crypto.engines.RSAEngine; +import org.spongycastle.crypto.params.AsymmetricKeyParameter; +import org.spongycastle.crypto.params.ParametersWithSalt; +import org.spongycastle.crypto.params.RSAKeyParameters; +import org.spongycastle.crypto.signers.ISO9796d2PSSSigner; +import org.spongycastle.crypto.signers.ISO9796d2Signer; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * test vectors from ISO 9796-1 and ISO 9796-2 edition 1. + */ +public class ISO9796Test + extends SimpleTest +{ + static BigInteger mod1 = new BigInteger("0100000000000000000000000000000000bba2d15dbb303c8a21c5ebbcbae52b7125087920dd7cdf358ea119fd66fb064012ec8ce692f0a0b8e8321b041acd40b7", 16); + + static BigInteger pub1 = new BigInteger("03", 16); + + static BigInteger pri1 = new BigInteger("2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac9f0783a49dd5f6c5af651f4c9d0dc9281c96a3f16a85f9572d7cc3f2d0f25a9dbf1149e4cdc32273faadd3fda5dcda7", 16); + + static BigInteger mod2 = new BigInteger("ffffff7fa27087c35ebead78412d2bdffe0301edd494df13458974ea89b364708f7d0f5a00a50779ddf9f7d4cb80b8891324da251a860c4ec9ef288104b3858d", 16); + + static BigInteger pub2 = new BigInteger("03", 16); + + static BigInteger pri2 = new BigInteger("2aaaaa9545bd6bf5e51fc7940adcdca5550080524e18cfd88b96e8d1c19de6121b13fac0eb0495d47928e047724d91d1740f6968457ce53ec8e24c9362ce84b5", 16); + + static byte msg1[] = Hex.decode("0cbbaa99887766554433221100"); + + // + // you'll need to see the ISO 9796 to make sense of this + // + static byte sig1[] = mod1.subtract(new BigInteger("309f873d8ded8379490f6097eaafdabc137d3ebfd8f25ab5f138d56a719cdc526bdd022ea65dabab920a81013a85d092e04d3e421caab717c90d89ea45a8d23a", 16)).toByteArray(); + + static byte msg2[] = Hex.decode("fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"); + + static byte sig2[] = new BigInteger("319bb9becb49f3ed1bca26d0fcf09b0b0a508e4d0bd43b350f959b72cd25b3af47d608fdcd248eada74fbe19990dbeb9bf0da4b4e1200243a14e5cab3f7e610c", 16).toByteArray(); + + static byte msg3[] = Hex.decode("0112233445566778899aabbccd"); + + static byte sig3[] = mod2.subtract(new BigInteger("58e59ffb4b1fb1bcdbf8d1fe9afa3730c78a318a1134f5791b7313d480ff07ac319b068edf8f212945cb09cf33df30ace54f4a063fcca0b732f4b662dc4e2454", 16)).toByteArray(); + + // + // ISO 9796-2 + // + static BigInteger mod3 = new BigInteger("ffffffff78f6c55506c59785e871211ee120b0b5dd644aa796d82413a47b24573f1be5745b5cd9950f6b389b52350d4e01e90009669a8720bf265a2865994190a661dea3c7828e2e7ca1b19651adc2d5", 16); + + static BigInteger pub3 = new BigInteger("03", 16); + + static BigInteger pri3 = new BigInteger("2aaaaaaa942920e38120ee965168302fd0301d73a4e60c7143ceb0adf0bf30b9352f50e8b9e4ceedd65343b2179005b2f099915e4b0c37e41314bb0821ad8330d23cba7f589e0f129b04c46b67dfce9d", 16); + + static BigInteger mod4 = new BigInteger("FFFFFFFF45f1903ebb83d4d363f70dc647b839f2a84e119b8830b2dec424a1ce0c9fd667966b81407e89278283f27ca8857d40979407fc6da4cc8a20ecb4b8913b5813332409bc1f391a94c9c328dfe46695daf922259174544e2bfbe45cc5cd", 16); + static BigInteger pub4 = new BigInteger("02", 16); + static BigInteger pri4 = new BigInteger("1fffffffe8be3207d7707a9a6c7ee1b8c8f7073e5509c2337106165bd8849439c193faccf2cd70280fd124f0507e4f94cb66447680c6b87b6599d1b61c8f3600854a618262e9c1cb1438e485e47437be036d94b906087a61ee74ab0d9a1accd8", 16); + + static byte msg4[] = Hex.decode("6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071"); + static byte sig4[] = Hex.decode("374695b7ee8b273925b4656cc2e008d41463996534aa5aa5afe72a52ffd84e118085f8558f36631471d043ad342de268b94b080bee18a068c10965f581e7f32899ad378835477064abed8ef3bd530fce"); + + static byte msg5[] = Hex.decode("fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"); + static byte sig5[] = Hex.decode("5cf9a01854dbacaec83aae8efc563d74538192e95466babacd361d7c86000fe42dcb4581e48e4feb862d04698da9203b1803b262105104d510b365ee9c660857ba1c001aa57abfd1c8de92e47c275cae"); + + // + // scheme 2 data + // + static BigInteger mod6 = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16); + static BigInteger pub6 = new BigInteger("11", 16); + static BigInteger pri6 = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16); + + static byte sig6[] = new BigInteger("0073FEAF13EB12914A43FE635022BB4AB8188A8F3ABD8D8A9E4AD6C355EE920359C7F237AE36B1212FE947F676C68FE362247D27D1F298CA9302EB21F4A64C26CE44471EF8C0DFE1A54606F0BA8E63E87CDACA993BFA62973B567473B4D38FAE73AB228600934A9CC1D3263E632E21FD52D2B95C5F7023DA63DE9509C01F6C7BBC", 16).modPow(pri6, mod6).toByteArray(); + + static byte msg7[] = Hex.decode("6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70716F70717270717273"); + static byte sig7[] = new BigInteger("296B06224010E1EC230D4560A5F88F03550AAFCE31C805CE81E811E5E53E5F71AE64FC2A2A486B193E87972D90C54B807A862F21A21919A43ECF067240A8C8C641DE8DCDF1942CF790D136728FFC0D98FB906E7939C1EC0E64C0E067F0A7443D6170E411DF91F797D1FFD74009C4638462E69D5923E7433AEC028B9A90E633CC", 16).modPow(pri6, mod6).toByteArray(); + + static byte msg8[] = Hex.decode("FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA98"); + static byte sig8[] = new BigInteger("01402B29ABA104079677CE7FC3D5A84DB24494D6F9508B4596484F5B3CC7E8AFCC4DDE7081F21CAE9D4F94D6D2CCCB43FCEDA0988FFD4EF2EAE72CFDEB4A2638F0A34A0C49664CD9DB723315759D758836C8BA26AC4348B66958AC94AE0B5A75195B57ABFB9971E21337A4B517F2E820B81F26BCE7C66F48A2DB12A8F3D731CC", 16).modPow(pri6, mod6).toByteArray(); + + static byte msg9[] = Hex.decode("6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70716F707172707172737172737472737475737475767475767775767778767778797778797A78797A61797A61627A6162636162636462636465"); + static byte sig9[] = new BigInteger("6F2BB97571FE2EF205B66000E9DD06656655C1977F374E8666D636556A5FEEEEAF645555B25F45567C4EE5341F96FED86508C90A9E3F11B26E8D496139ED3E55ECE42860A6FB3A0817DAFBF13019D93E1D382DA07264FE99D9797D2F0B7779357CA7E74EE440D8855B7DDF15F000AC58EE3FFF144845E771907C0C83324A6FBC", 16).modPow(pri6, mod6).toByteArray(); + + public String getName() + { + return "ISO9796"; + } + + private boolean isSameAs( + byte[] a, + int off, + byte[] b) + { + if ((a.length - off) != b.length) + { + return false; + } + + for (int i = 0; i != b.length; i++) + { + if (a[i + off] != b[i]) + { + return false; + } + } + + return true; + } + + private boolean startsWith( + byte[] a, + byte[] b) + { + if (a.length < b.length) + { + return false; + } + + for (int i = 0; i != b.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + private void doTest1() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod1, pub1); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod1, pri1); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-1 - public encrypt, private decrypt + // + ISO9796d1Encoding eng = new ISO9796d1Encoding(rsa); + + eng.init(true, privParameters); + + eng.setPadBits(4); + + data = eng.processBlock(msg1, 0, msg1.length); + + eng.init(false, pubParameters); + + if (!areEqual(sig1, data)) + { + fail("failed ISO9796-1 generation Test 1"); + } + + data = eng.processBlock(data, 0, data.length); + + if (!areEqual(msg1, data)) + { + fail("failed ISO9796-1 retrieve Test 1"); + } + } + + private void doTest2() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod1, pub1); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod1, pri1); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-1 - public encrypt, private decrypt + // + ISO9796d1Encoding eng = new ISO9796d1Encoding(rsa); + + eng.init(true, privParameters); + + data = eng.processBlock(msg2, 0, msg2.length); + + eng.init(false, pubParameters); + + if (!isSameAs(data, 1, sig2)) + { + fail("failed ISO9796-1 generation Test 2"); + } + + data = eng.processBlock(data, 0, data.length); + + + if (!areEqual(msg2, data)) + { + fail("failed ISO9796-1 retrieve Test 2"); + } + } + + public void doTest3() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod2, pub2); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod2, pri2); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-1 - public encrypt, private decrypt + // + ISO9796d1Encoding eng = new ISO9796d1Encoding(rsa); + + eng.init(true, privParameters); + + eng.setPadBits(4); + + data = eng.processBlock(msg3, 0, msg3.length); + + eng.init(false, pubParameters); + + if (!isSameAs(sig3, 1, data)) + { + fail("failed ISO9796-1 generation Test 3"); + } + + data = eng.processBlock(data, 0, data.length); + + if (!isSameAs(msg3, 0, data)) + { + fail("failed ISO9796-1 retrieve Test 3"); + } + } + + public void doTest4() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod3, pub3); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod3, pri3); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - Signing + // + ISO9796d2Signer eng = new ISO9796d2Signer(rsa, new RIPEMD128Digest()); + + eng.init(true, privParameters); + + eng.update(msg4[0]); + eng.update(msg4, 1, msg4.length - 1); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + if (!isSameAs(sig4, 0, data)) + { + fail("failed ISO9796-2 generation Test 4"); + } + + eng.update(msg4[0]); + eng.update(msg4, 1, msg4.length - 1); + + if (!eng.verifySignature(sig4)) + { + fail("failed ISO9796-2 verify Test 4"); + } + + if (eng.hasFullMessage()) + { + eng = new ISO9796d2Signer(rsa, new RIPEMD128Digest()); + + eng.init(false, pubParameters); + + if (!eng.verifySignature(sig4)) + { + fail("failed ISO9796-2 verify and recover Test 4"); + } + + if (!isSameAs(eng.getRecoveredMessage(), 0, msg4)) + { + fail("failed ISO9796-2 recovered message Test 4"); + } + + // try update with recovered + eng.updateWithRecoveredMessage(sig4); + + if (!isSameAs(eng.getRecoveredMessage(), 0, msg4)) + { + fail("failed ISO9796-2 updateWithRecovered recovered message Test 4"); + } + + if (!eng.verifySignature(sig4)) + { + fail("failed ISO9796-2 updateWithRecovered verify and recover Test 4"); + } + + if (!isSameAs(eng.getRecoveredMessage(), 0, msg4)) + { + fail("failed ISO9796-2 updateWithRecovered recovered verify message Test 4"); + } + + // should fail + eng.updateWithRecoveredMessage(sig4); + + eng.update(msg4, 0, msg4.length); + + if (eng.verifySignature(sig4)) + { + fail("failed ISO9796-2 updateWithRecovered verify and recover Test 4"); + } + } + else + { + fail("full message flag false - Test 4"); + } + } + + public void doTest5() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod3, pub3); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod3, pri3); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - Signing + // + ISO9796d2Signer eng = new ISO9796d2Signer(rsa, new RIPEMD160Digest(), true); + + eng.init(true, privParameters); + + eng.update(msg5[0]); + eng.update(msg5, 1, msg5.length - 1); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + if (!isSameAs(sig5, 0, data)) + { + fail("failed ISO9796-2 generation Test 5"); + } + + eng.update(msg5[0]); + eng.update(msg5, 1, msg5.length - 1); + + if (!eng.verifySignature(sig5)) + { + fail("failed ISO9796-2 verify Test 5"); + } + + if (eng.hasFullMessage()) + { + fail("fullMessage true - Test 5"); + } + + if (!startsWith(msg5, eng.getRecoveredMessage())) + { + fail("failed ISO9796-2 partial recovered message Test 5"); + } + + int length = eng.getRecoveredMessage().length; + + if (length >= msg5.length) + { + fail("Test 5 recovered message too long"); + } + + eng = new ISO9796d2Signer(rsa, new RIPEMD160Digest(), true); + + eng.init(false, pubParameters); + + eng.updateWithRecoveredMessage(sig5); + + if (!startsWith(msg5, eng.getRecoveredMessage())) + { + fail("failed ISO9796-2 updateWithRecovered partial recovered message Test 5"); + } + + if (eng.hasFullMessage()) + { + fail("fullMessage updateWithRecovered true - Test 5"); + } + + for (int i = length; i != msg5.length; i++) + { + eng.update(msg5[i]); + } + + if (!eng.verifySignature(sig5)) + { + fail("failed ISO9796-2 verify Test 5"); + } + + if (eng.hasFullMessage()) + { + fail("fullMessage updateWithRecovered true - Test 5"); + } + + // should fail + eng.updateWithRecoveredMessage(sig5); + + eng.update(msg5, 0, msg5.length); + + if (eng.verifySignature(sig5)) + { + fail("failed ISO9796-2 updateWithRecovered verify fail Test 5"); + } + } + + // + // against a zero length string + // + + public void doTest6() + throws Exception + { + byte[] salt = Hex.decode("61DF870C4890FE85D6E3DD87C3DCE3723F91DB49"); + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod6, pub6); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod6, pri6); + ParametersWithSalt sigParameters = new ParametersWithSalt(privParameters, salt); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - PSS Signing + // + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, new RIPEMD160Digest(), 20, true); + + eng.init(true, sigParameters); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + if (!isSameAs(sig6, 1, data)) + { + fail("failed ISO9796-2 generation Test 6"); + } + + if (!eng.verifySignature(data)) + { + fail("failed ISO9796-2 verify Test 6"); + } + } + + public void doTest7() + throws Exception + { + byte[] salt = new byte[0]; + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod6, pub6); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod6, pri6); + ParametersWithSalt sigParameters = new ParametersWithSalt(privParameters, salt); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - PSS Signing + // + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, new SHA1Digest(), 0, false); + + eng.init(true, sigParameters); + + eng.update(msg7[0]); + eng.update(msg7, 1, msg7.length - 1); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + if (!isSameAs(sig7, 0, data)) + { + fail("failed ISO9796-2 generation Test 7"); + } + + eng.update(msg7[0]); + eng.update(msg7, 1, msg7.length - 1); + + if (!eng.verifySignature(sig7)) + { + fail("failed ISO9796-2 verify Test 7"); + } + + if (!isSameAs(msg7, 0, eng.getRecoveredMessage())) + { + fail("failed ISO9796-2 recovery Test 7"); + } + } + + public void doTest8() + throws Exception + { + byte[] salt = Hex.decode("78E293203CBA1B7F92F05F4D171FF8CA3E738FF8"); + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod6, pub6); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod6, pri6); + ParametersWithSalt sigParameters = new ParametersWithSalt(privParameters, salt); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - PSS Signing + // + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, new RIPEMD160Digest(), 20, false); + + eng.init(true, sigParameters); + + eng.update(msg8[0]); + eng.update(msg8, 1, msg8.length - 1); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + if (!isSameAs(sig8, 0, data)) + { + fail("failed ISO9796-2 generation Test 8"); + } + + eng.update(msg8[0]); + eng.update(msg8, 1, msg8.length - 1); + + if (!eng.verifySignature(sig8)) + { + fail("failed ISO9796-2 verify Test 8"); + } + } + + public void doTest9() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod6, pub6); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod6, pri6); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - PSS Signing + // + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, new RIPEMD160Digest(), 0, true); + + eng.init(true, privParameters); + + eng.update(msg9[0]); + eng.update(msg9, 1, msg9.length - 1); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + if (!isSameAs(sig9, 0, data)) + { + fail("failed ISO9796-2 generation Test 9"); + } + + eng.update(msg9[0]); + eng.update(msg9, 1, msg9.length - 1); + + if (!eng.verifySignature(sig9)) + { + fail("failed ISO9796-2 verify Test 9"); + } + } + + public void doTest10() + throws Exception + { + BigInteger mod = new BigInteger("B3ABE6D91A4020920F8B3847764ECB34C4EB64151A96FDE7B614DC986C810FF2FD73575BDF8532C06004C8B4C8B64F700A50AEC68C0701ED10E8D211A4EA554D", 16); + BigInteger pubExp = new BigInteger("65537", 10); + BigInteger priExp = new BigInteger("AEE76AE4716F77C5782838F328327012C097BD67E5E892E75C1356E372CCF8EE1AA2D2CBDFB4DA19F703743F7C0BA42B2D69202BA7338C294D1F8B6A5771FF41", 16); + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod, priExp); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - PSS Signing + // + Digest dig = new SHA1Digest(); + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, dig, dig.getDigestSize()); + + // + // as the padding is random this test needs to repeat a few times to + // make sure + // + for (int i = 0; i != 500; i++) + { + eng.init(true, privParameters); + + eng.update(msg9[0]); + eng.update(msg9, 1, msg9.length - 1); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + eng.update(msg9[0]); + eng.update(msg9, 1, msg9.length - 1); + + if (!eng.verifySignature(data)) + { + fail("failed ISO9796-2 verify Test 10"); + } + } + } + + public void doTest11() + throws Exception + { + BigInteger mod = new BigInteger("B3ABE6D91A4020920F8B3847764ECB34C4EB64151A96FDE7B614DC986C810FF2FD73575BDF8532C06004C8B4C8B64F700A50AEC68C0701ED10E8D211A4EA554D", 16); + BigInteger pubExp = new BigInteger("65537", 10); + BigInteger priExp = new BigInteger("AEE76AE4716F77C5782838F328327012C097BD67E5E892E75C1356E372CCF8EE1AA2D2CBDFB4DA19F703743F7C0BA42B2D69202BA7338C294D1F8B6A5771FF41", 16); + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod, priExp); + RSAEngine rsa = new RSAEngine(); + byte[] data; + byte[] m1 = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + byte[] m2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + byte[] m3 = {1, 2, 3, 4, 5, 6, 7, 8}; + + // + // ISO 9796-2 - PSS Signing + // + Digest dig = new SHA1Digest(); + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, dig, dig.getDigestSize()); + + // + // check message bounds + // + eng.init(true, privParameters); + + eng.update(m1, 0, m1.length); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + eng.update(m2, 0, m2.length); + + if (eng.verifySignature(data)) + { + fail("failed ISO9796-2 m2 verify Test 11"); + } + + eng.init(false, pubParameters); + + eng.update(m3, 0, m3.length); + + if (eng.verifySignature(data)) + { + fail("failed ISO9796-2 m3 verify Test 11"); + } + + eng.init(false, pubParameters); + + eng.update(m1, 0, m1.length); + + if (!eng.verifySignature(data)) + { + fail("failed ISO9796-2 verify Test 11"); + } + } + + public void doTest12() + throws Exception + { + BigInteger mod = new BigInteger("B3ABE6D91A4020920F8B3847764ECB34C4EB64151A96FDE7B614DC986C810FF2FD73575BDF8532C06004C8B4C8B64F700A50AEC68C0701ED10E8D211A4EA554D", 16); + BigInteger pubExp = new BigInteger("65537", 10); + BigInteger priExp = new BigInteger("AEE76AE4716F77C5782838F328327012C097BD67E5E892E75C1356E372CCF8EE1AA2D2CBDFB4DA19F703743F7C0BA42B2D69202BA7338C294D1F8B6A5771FF41", 16); + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod, priExp); + RSAEngine rsa = new RSAEngine(); + byte[] data; + byte[] m1 = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + byte[] m2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + byte[] m3 = {1, 2, 3, 4, 5, 6, 7, 8}; + + // + // ISO 9796-2 - Signing + // + Digest dig = new SHA1Digest(); + ISO9796d2Signer eng = new ISO9796d2Signer(rsa, dig); + + // + // check message bounds + // + eng.init(true, privParameters); + + eng.update(m1, 0, m1.length); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + eng.update(m2, 0, m2.length); + + if (eng.verifySignature(data)) + { + fail("failed ISO9796-2 m2 verify Test 12"); + } + + eng.init(false, pubParameters); + + eng.update(m3, 0, m3.length); + + if (eng.verifySignature(data)) + { + fail("failed ISO9796-2 m3 verify Test 12"); + } + + eng.init(false, pubParameters); + + eng.update(m1, 0, m1.length); + + if (!eng.verifySignature(data)) + { + fail("failed ISO9796-2 verify Test 12"); + } + } + + private void doTest13() + throws Exception + { + BigInteger modulus = new BigInteger(1, Hex.decode("CDCBDABBF93BE8E8294E32B055256BBD0397735189BF75816341BB0D488D05D627991221DF7D59835C76A4BB4808ADEEB779E7794504E956ADC2A661B46904CDC71337DD29DDDD454124EF79CFDD7BC2C21952573CEFBA485CC38C6BD2428809B5A31A898A6B5648CAA4ED678D9743B589134B7187478996300EDBA16271A861")); + BigInteger pubExp = new BigInteger(1, Hex.decode("010001")); + BigInteger privExp = new BigInteger(1, Hex.decode("4BA6432AD42C74AA5AFCB6DF60FD57846CBC909489994ABD9C59FE439CC6D23D6DE2F3EA65B8335E796FD7904CA37C248367997257AFBD82B26F1A30525C447A236C65E6ADE43ECAAF7283584B2570FA07B340D9C9380D88EAACFFAEEFE7F472DBC9735C3FF3A3211E8A6BBFD94456B6A33C17A2C4EC18CE6335150548ED126D")); + + RSAKeyParameters pubParams = new RSAKeyParameters(false, modulus, pubExp); + RSAKeyParameters privParams = new RSAKeyParameters(true, modulus, privExp); + + AsymmetricBlockCipher rsaEngine = new RSABlindedEngine(); + Digest digest = new SHA256Digest(); + + // set challenge to all zero's for verification + byte[] challenge = new byte[8]; + + // DOES NOT USE FINAL BOOLEAN TO INDICATE RECOVERY + ISO9796d2Signer signer = new ISO9796d2Signer(rsaEngine, digest, false); + + // sign + signer.init(true, privParams); + signer.update(challenge, 0, challenge.length); + + byte[] sig = signer.generateSignature(); + + // verify + signer.init(false, pubParams); + signer.update(challenge, 0, challenge.length); + + if (!signer.verifySignature(sig)) + { + fail("basic verification failed"); + } + + // === LETS ACTUALLY DO SOME RECOVERY, USING INPUT FROM INTERNAL AUTHENTICATE === + + signer.reset(); + + final String args0 = "482E20D1EDDED34359C38F5E7C01203F9D6B2641CDCA5C404D49ADAEDE034C7481D781D043722587761C90468DE69C6585A1E8B9C322F90E1B580EEDAB3F6007D0C366CF92B4DB8B41C8314929DCE2BE889C0129123484D2FD3D12763D2EBFD12AC8E51D7061AFCA1A53DEDEC7B9A617472A78C952CCC72467AE008E5F132994"; + + digest = new SHA1Digest(); + + signer = new ISO9796d2Signer(rsaEngine, digest, true); + + + signer.init(false, pubParams); + final byte[] signature = Hex.decode(args0); + signer.updateWithRecoveredMessage(signature); + signer.update(challenge, 0, challenge.length); + + if (!signer.verifySignature(signature)) + { + fail("recovered + challenge signature failed"); + } + + // === FINALLY, USING SHA-256 === + + signer.reset(); + + digest = new SHA256Digest(); + + // NOTE setting implit to false does not actually do anything for verification !!! + signer = new ISO9796d2Signer(rsaEngine, digest, false); + + + signer.init(true, privParams); + // generate NONCE of correct length using some inner knowledge + int nonceLength = modulus.bitLength() / 8 - 1 - digest.getDigestSize() - 2; + final byte[] nonce = new byte[nonceLength]; + SecureRandom rnd = new SecureRandom(); + + rnd.nextBytes(nonce); + + signer.update(nonce, 0, nonce.length); + signer.update(challenge, 0, challenge.length); + byte[] sig3 = signer.generateSignature(); + + signer.init(false, pubParams); + signer.updateWithRecoveredMessage(sig3); + signer.update(challenge, 0, challenge.length); + if (signer.verifySignature(sig3)) + { + if (signer.hasFullMessage()) + { + fail("signer indicates full message"); + } + byte[] recoverableMessage = signer.getRecoveredMessage(); + + // sanity check, normally the nonce is ignored in eMRTD specs (PKI Technical Report) + if (!Arrays.areEqual(nonce, recoverableMessage)) + { + fail("Nonce compare with recoverable part of message failed"); + } + } + else + { + fail("recoverable + nonce failed."); + } + } + + private static final byte[] longMessage = Base64.decode( + "VVNIKzErU0U2ODAxNTMyOTcxOSsyKzErNisyKzErMTo6OTk5OTk5OTk5OTk5" + + "OTo6OSsyOjo3Nzc3Nzc3Nzc3Nzc3Ojo5Kys1OjIwMTMwNDA1OjExMzUyMCdV" + + "U0ErMTo6OjE2OjEnVVNDKzRmYjk3YzFhNDI5ZGIyZDYnVVNBKzY6MTY6MTox" + + "MDoxKzE0OjIwNDgrMTI6/vn3S0h96eNhfmPN6OZUxXhd815h0tP871Hl+V1r" + + "fHHUXvrPXmjHV0vdb8fYY1zxwvnQUcFBWXT43PFi7Xbow0/9e9l6/mhs1UJq" + + "VPvp+ELbeXfn4Nj02ttk0e3H5Hfa69NYRuHv1WBO6lfizNnM9m9XYmh9TOrg" + + "f9rDRtd+ZNbf4lz9fPTt9OXyxOJWRPr/0FLzxUVsddplfHxM3ndETFD7ffjI" + + "/mhRYuL8WXZ733LeWFRCeOzKzmDz/HvT3GZx/XJMbFpqyOZjedzh6vZr1vrD" + + "615TQfN7wtJJ29bN2Hvzb2f1xGHaXl7af0/w9dpR2dr7/HzuZEJKYc7JSkv4" + + "/k37yERIbcrfbVTeVtR+dcVoeeRT41fmzMfzf8RnWOX4YMNifl0rMTM68EFA" + + "QSdCR00rMzgwKzk5OTk5OTk5J0RUTSsxMzc6MjAxMzA0MDU6MTAyJ0ZUWCtB" + + "QUkrKytJTlZPSUNFIFRFU1QnUkZGK09OOjEyMzQ1NidSRkYrRFE6MjIyMjIy" + + "MjIyJ0RUTSsxNzE6MjAxMzA0MDE6MTAyJ05BRCtTVSs5OTk5OTk5OTk5OTk5" + + "Ojo5KytURVNUIFNVUFBMSUVSOjpUcmFzZSByZWdpc3RlciBYWFhYWFhYK1Rl" + + "c3QgYWRkcmVzcyBzdXBwbGllcitDaXR5KysxMjM0NStERSdSRkYrVkE6QTEy" + + "MzQ1Njc4J05BRCtTQ08rOTk5OTk5OTk5OTk5OTo6OSsrVEVTVCBTVVBQTElF" + + "Ujo6VHJhc2UgcmVnaXN0ZXIgWFhYWFhYWCtUZXN0IGFkZHJlc3Mgc3VwcGxp" + + "ZXIrQ2l0eSsrMTIzNDUrREUnUkZGK1ZBOkExMjM0NTY3OCdOQUQrQlkrODg4" + + "ODg4ODg4ODg4ODo6OSdOQUQrSVYrNzc3Nzc3Nzc3Nzc3Nzo6OSsrVEVTVCBC" + + "VVlFUitUZXN0IGFkZHJlc3MgYnV5ZXIrQ2l0eTIrKzU0MzIxK0RFJ1JGRitW" + + "QTpKODc2NTQzMjEnTkFEK0JDTys3Nzc3Nzc3Nzc3Nzc3Ojo5KytURVNUIEJV" + + "WUVSK1Rlc3QgYWRkcmVzcyBidXllcitDaXR5MisrNTQzMjErREUnUkZGK1ZB" + + "Oko4NzY1NDMyMSdOQUQrRFArODg4ODg4ODg4ODg4ODo6OSdOQUQrUFIrNzc3" + + "Nzc3Nzc3Nzc3Nzo6OSdDVVgrMjpFVVI6NCdQQVQrMzUnRFRNKzEzOjIwMTMw" + + "NjI0OjEwMidMSU4rMSsrMTExMTExMTExMTExMTpFTidQSUErMStBQUFBQUFB" + + "OlNBJ0lNRCtGK00rOjo6UFJPRFVDVCBURVNUIDEnUVRZKzQ3OjEwLjAwMCdN" + + "T0ErNjY6Ny4wMCdQUkkrQUFCOjEuMDAnUFJJK0FBQTowLjcwJ1JGRitPTjox" + + "MjM0NTYnUkZGK0RROjIyMjIyMjIyMidUQVgrNytWQVQrKys6OjoyMS4wMDAn" + + "QUxDK0ErKysxK1REJ1BDRCsxOjMwLjAwMCdNT0ErMjA0OjMuMDAnTElOKzIr" + + "KzIyMjIyMjIyMjIyMjI6RU4nUElBKzErQkJCQkJCQjpTQSdJTUQrRitNKzo6" + + "OlBST0RVQ1QgVEVTVCAyJ1FUWSs0NzoyMC4wMDAnTU9BKzY2OjgwLjAwJ1BS" + + "SStBQUI6NS4wMCdQUkkrQUFBOjQuMDAnUkZGK09OOjEyMzQ1NidSRkYrRFE6" + + "MjIyMjIyMjIyJ1RBWCs3K1ZBVCsrKzo6OjIxLjAwMCdBTEMrQSsrKzErVEQn" + + "UENEKzE6MjAuMDAwJ01PQSsyMDQ6MjAuMDAnVU5TK1MnQ05UKzI6MidNT0Er" + + "Nzk6ODcuMDAnTU9BKzEzOToxMDUuMjcnTU9BKzEyNTo4Ny4wMCdNT0ErMjYw" + + "OjAuMDAnTU9BKzI1OTowLjAwJ01PQSsxNzY6MTguMjcnVEFYKzcrVkFUKysr" + + "Ojo6MjEuMDAwJ01PQSsxNzY6MTguMjcnTU9BKzEyNTo4Ny4wMCc="); + + private static final byte[] shortPartialSig = Base64.decode( + "sb8yyKk6HM1cJhICScMx7QRQunRyrZ1fbI42+T+TBGNjOknvzKuvG7aftGX7" + + "O/RXuYgk6LTxpXv7+O5noUhMBsR2PKaHveuylU1WSPmDxDCui3kp4frqVH0w" + + "8Vjpl5CsKqBsmKkbGCKE+smM0xFXhYxV8QUTB2XsWNCQiFiHPgwbpfWzZUNY" + + "QPWd0A99P64EuUIYz1tkkDnLFmwQ19/PJu1a8orIQInmkVYWSsBsZ/7Ks6lx" + + "nDHpAvgiRe+OXmJ/yuQy1O3FJYdyoqvjYRPBu3qYeBK9+9L3lExLilImH5aD" + + "nJznaXcO8QFOxVPbrF2s4GdPIMDonEyAHdrnzoghlg=="); + + private void doShortPartialTest() + throws Exception + { + byte[] recovered = Hex.decode("5553482b312b534536383031353332393731392b322b312b362b322b312b313a3a393939393939393939393939393a3a392b323a3a373737373737373737373737373a3a392b2b353a32303133303430353a313133"); + BigInteger exp = new BigInteger("10001", 16); + BigInteger mod = new BigInteger("b9b70b083da9e37e23cde8e654855db31e21d2d3fc11a5f91d2b3c311efa8f5e28c757dd6fc798631cb1b9d051c14119749cb122ad76e8c3fd7bd93abe282c026a14fba9f8023977a7a0d8b49a24d1ad87e4379a931846a1ef9520ea57e28c998cf65722683d0caaa0da8306973e2496a25cbd3cb4adb4b284e25604fabf12f385456c75da7c3c4cde37440cfb7db8c8fe6851e2bc59767b9f7218540238ac8acef3bc7bd3dc6671320c2c1a2ac8a6799ce1eaf62b9683ab1e1341b37b9249dbd6cd987b2f27b5c4619a1eda7f0fb0b59a519afbbc3cee640261cec90a4bb8fefbc844082dca9f549e56943e758579a453a357e6ccb37fc46718a5b8c3227e5d", 16); + + AsymmetricKeyParameter pubKey = new RSAKeyParameters(false, mod, exp); + + ISO9796d2PSSSigner pssSign = new ISO9796d2PSSSigner(new RSAEngine(), new SHA1Digest(), 20); + + pssSign.init(false, pubKey); + + pssSign.updateWithRecoveredMessage(shortPartialSig); + + pssSign.update(longMessage, pssSign.getRecoveredMessage().length, longMessage.length - pssSign.getRecoveredMessage().length); + + if (!pssSign.verifySignature(shortPartialSig)) + { + fail("short partial PSS sig verification failed."); + } + + byte[] mm = pssSign.getRecoveredMessage(); + + if (!Arrays.areEqual(recovered, mm)) + { + fail("short partial PSS recovery failed"); + } + } + + private void doFullMessageTest() + throws Exception + { + BigInteger modulus = new BigInteger(1, Hex.decode("CDCBDABBF93BE8E8294E32B055256BBD0397735189BF75816341BB0D488D05D627991221DF7D59835C76A4BB4808ADEEB779E7794504E956ADC2A661B46904CDC71337DD29DDDD454124EF79CFDD7BC2C21952573CEFBA485CC38C6BD2428809B5A31A898A6B5648CAA4ED678D9743B589134B7187478996300EDBA16271A861")); + BigInteger pubExp = new BigInteger(1, Hex.decode("010001")); + BigInteger privExp = new BigInteger(1, Hex.decode("4BA6432AD42C74AA5AFCB6DF60FD57846CBC909489994ABD9C59FE439CC6D23D6DE2F3EA65B8335E796FD7904CA37C248367997257AFBD82B26F1A30525C447A236C65E6ADE43ECAAF7283584B2570FA07B340D9C9380D88EAACFFAEEFE7F472DBC9735C3FF3A3211E8A6BBFD94456B6A33C17A2C4EC18CE6335150548ED126D")); + + RSAKeyParameters pubParams = new RSAKeyParameters(false, modulus, pubExp); + RSAKeyParameters privParams = new RSAKeyParameters(true, modulus, privExp); + + AsymmetricBlockCipher rsaEngine = new RSABlindedEngine(); + + // set challenge to all zero's for verification + byte[] challenge = new byte[8]; + + ISO9796d2PSSSigner pssSign = new ISO9796d2PSSSigner(new RSAEngine(), new SHA256Digest(), 20, true); + + pssSign.init(true, privParams); + + pssSign.update(challenge, 0, challenge.length); + + byte[] sig = pssSign.generateSignature(); + + pssSign.init(false, pubParams); + + pssSign.updateWithRecoveredMessage(sig); + + if (!pssSign.verifySignature(sig)) + { + fail("challenge PSS sig verification failed."); + } + + byte[] mm = pssSign.getRecoveredMessage(); + + if (!Arrays.areEqual(challenge, mm)) + { + fail("challenge partial PSS recovery failed"); + } + } + + public void performTest() + throws Exception + { + doTest1(); + doTest2(); + doTest3(); + doTest4(); + doTest5(); + doTest6(); + doTest7(); + doTest8(); + doTest9(); + doTest10(); + doTest11(); + doTest12(); + doTest13(); + doShortPartialTest(); + doFullMessageTest(); + } + + public static void main( + String[] args) + { + runTest(new ISO9796Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ISO9797Alg3MacTest.java b/core/src/test/java/org/spongycastle/crypto/test/ISO9797Alg3MacTest.java new file mode 100644 index 00000000..1a2aee97 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ISO9797Alg3MacTest.java @@ -0,0 +1,126 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.macs.ISO9797Alg3Mac; +import org.spongycastle.crypto.paddings.ISO7816d4Padding; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class ISO9797Alg3MacTest + extends SimpleTest +{ + static byte[] keyBytes = Hex.decode("7CA110454A1A6E570131D9619DC1376E"); + + static byte[] input1 = "Hello World !!!!".getBytes(); + + static byte[] output1 = Hex.decode("F09B856213BAB83B"); + + public ISO9797Alg3MacTest() + { + } + + public void performTest() + { + KeyParameter key = new KeyParameter(keyBytes); + BlockCipher cipher = new DESEngine(); + Mac mac = new ISO9797Alg3Mac(cipher); + + // + // standard DAC - zero IV + // + mac.init(key); + + mac.update(input1, 0, input1.length); + + byte[] out = new byte[8]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output1)) + { + fail("Failed - expected " + new String(Hex.encode(output1)) + " got " + new String(Hex.encode(out))); + } + + // + // reset + // + mac.reset(); + + mac.init(key); + + for (int i = 0; i != input1.length / 2; i++) + { + mac.update(input1[i]); + } + + mac.update(input1, input1.length / 2, input1.length - (input1.length / 2)); + + mac.doFinal(out, 0); + + if (!areEqual(out, output1)) + { + fail("Reset failed - expected " + new String(Hex.encode(output1)) + " got " + new String(Hex.encode(out))); + } + + testMacWithIv(); + } + + private void testMacWithIv() + { + byte[] inputData = new byte[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}; + byte[] key = new byte[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}; + byte[] zeroIv = new byte[8]; + byte[] nonZeroIv = new byte[]{0x5, 0x6, 0x7, 0x8, 0x1, 0x2, 0x3, 0x4}; + + KeyParameter simpleParameter = new KeyParameter(key); + ParametersWithIV zeroIvParameter = new ParametersWithIV(new KeyParameter(key), zeroIv); + + ISO9797Alg3Mac mac1 = new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()); + + // we calculate a reference MAC with a null IV + mac1.init(simpleParameter); + mac1.update(inputData, 0, inputData.length); + byte[] output1 = new byte[mac1.getMacSize()]; + mac1.doFinal(output1, 0); + + // we then check that passing a vector of 0s is the same as not using any IV + ISO9797Alg3Mac mac2 = new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()); + mac2.init(zeroIvParameter); + mac2.update(inputData, 0, inputData.length); + byte[] output2 = new byte[mac2.getMacSize()]; + mac2.doFinal(output2, 0); + if (!Arrays.areEqual(output1, output2)) + { + fail("zero IV test failed"); + } + + // and then check that a non zero IV parameter produces a different results. + ParametersWithIV nonZeroIvParameter = new ParametersWithIV(new KeyParameter(key), nonZeroIv); + mac2 = new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()); + mac2.init(nonZeroIvParameter); + mac2.update(inputData, 0, inputData.length); + output2 = new byte[mac2.getMacSize()]; + mac2.doFinal(output2, 0); + if (Arrays.areEqual(output1, output2)) + { + fail("non-zero IV test failed"); + } + } + + public String getName() + { + return "ISO9797Alg3Mac"; + } + + public static void main( + String[] args) + { + runTest(new ISO9797Alg3MacTest()); + } +} + diff --git a/core/src/test/java/org/spongycastle/crypto/test/KDF1GeneratorTest.java b/core/src/test/java/org/spongycastle/crypto/test/KDF1GeneratorTest.java new file mode 100644 index 00000000..0671ef8b --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/KDF1GeneratorTest.java @@ -0,0 +1,93 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.DerivationFunction; +import org.spongycastle.crypto.digests.ShortenedDigest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.generators.KDF1BytesGenerator; +import org.spongycastle.crypto.params.ISO18033KDFParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * KDF1 tests - vectors from ISO 18033. + */ +public class KDF1GeneratorTest + extends SimpleTest +{ + private byte[] seed1 = Hex.decode("d6e168c5f256a2dcff7ef12facd390f393c7a88d"); + private byte[] mask1 = Hex.decode( + "0742ba966813af75536bb6149cc44fc256fd6406df79665bc31dc5" + + "a62f70535e52c53015b9d37d412ff3c1193439599e1b628774c50d9c" + + "cb78d82c425e4521ee47b8c36a4bcffe8b8112a89312fc04420a39de" + + "99223890e74ce10378bc515a212b97b8a6447ba6a8870278"); + + private byte[] seed2 = Hex.decode( + "032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d7643741" + + "52e0ac009e509e7ba30cd2f1778e113b64e135cf4e2292c75efe5288edfda4"); + private byte[] mask2 = Hex.decode( + "5f8de105b5e96b2e490ddecbd147dd1def7e3b8e0e6a26eb7b956ccb8b3bdc1ca9" + + "75bc57c3989e8fbad31a224655d800c46954840ff32052cdf0d640562bdfadfa263c" + + "fccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842dbff8e13efee5b7e" + + "7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837eea4e0a2f04"); + + private byte[] seed3 = seed2; + private byte[] mask3= Hex.decode( + "09e2decf2a6e1666c2f6071ff4298305e2643fd510a2403db42a8743cb989de86e" + + "668d168cbe604611ac179f819a3d18412e9eb45668f2923c087c12fee0c5a0d2a8aa" + + "70185401fbbd99379ec76c663e875a60b4aacb1319fa11c3365a8b79a44669f26fb5" + + "55c80391847b05eca1cb5cf8c2d531448d33fbaca19f6410ee1fcb"); + + + public KDF1GeneratorTest() + { + } + + public void performTest() + { + checkMask(1, new KDF1BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed1, mask1); + checkMask(2, new KDF1BytesGenerator(new SHA1Digest()), seed2, mask2); + checkMask(3, new KDF1BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed3, mask3); + + try + { + new KDF1BytesGenerator(new SHA1Digest()).generateBytes(new byte[10], 0, 20); + + fail("short input array not caught"); + } + catch (DataLengthException e) + { + // expected + } + } + + private void checkMask( + int count, + DerivationFunction kdf, + byte[] seed, + byte[] result) + { + byte[] data = new byte[result.length]; + + kdf.init(new ISO18033KDFParameters(seed)); + + kdf.generateBytes(data, 0, data.length); + + if (!areEqual(result, data)) + { + fail("KDF1 failed generator test " + count); + } + } + + public String getName() + { + return "KDF1"; + } + + public static void main( + String[] args) + { + runTest(new KDF1GeneratorTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/KDF2GeneratorTest.java b/core/src/test/java/org/spongycastle/crypto/test/KDF2GeneratorTest.java new file mode 100644 index 00000000..676f22b1 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/KDF2GeneratorTest.java @@ -0,0 +1,105 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.DerivationFunction; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.digests.ShortenedDigest; +import org.spongycastle.crypto.generators.KDF2BytesGenerator; +import org.spongycastle.crypto.params.KDFParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * KDF2 tests - vectors from ISO 18033. + */ +public class KDF2GeneratorTest + extends SimpleTest +{ + private byte[] seed1 = Hex.decode("d6e168c5f256a2dcff7ef12facd390f393c7a88d"); + private byte[] mask1 = Hex.decode( + "df79665bc31dc5a62f70535e52c53015b9d37d412ff3c119343959" + + "9e1b628774c50d9ccb78d82c425e4521ee47b8c36a4bcffe8b8112a8" + + "9312fc04420a39de99223890e74ce10378bc515a212b97b8a6447ba6" + + "a8870278f0262727ca041fa1aa9f7b5d1cf7f308232fe861"); + + private byte[] seed2 = Hex.decode( + "032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d7643741" + + "52e0ac009e509e7ba30cd2f1778e113b64e135cf4e2292c75efe5288edfda4"); + private byte[] mask2 = Hex.decode( + "10a2403db42a8743cb989de86e668d168cbe604611ac179f819a3d18412e9eb456" + + "68f2923c087c12fee0c5a0d2a8aa70185401fbbd99379ec76c663e875a60b4aacb13" + + "19fa11c3365a8b79a44669f26fb555c80391847b05eca1cb5cf8c2d531448d33fbac" + + "a19f6410ee1fcb260892670e0814c348664f6a7248aaf998a3acc6"); + private byte[] adjustedMask2 = Hex.decode( + "10a2403db42a8743cb989de86e668d168cbe6046e23ff26f741e87949a3bba1311ac1" + + "79f819a3d18412e9eb45668f2923c087c1299005f8d5fd42ca257bc93e8fee0c5a0d2" + + "a8aa70185401fbbd99379ec76c663e9a29d0b70f3fe261a59cdc24875a60b4aacb131" + + "9fa11c3365a8b79a44669f26fba933d012db213d7e3b16349"); + + private byte[] sha1Mask = Hex.decode( + "0e6a26eb7b956ccb8b3bdc1ca975bc57c3989e8fbad31a224655d800c46954840ff32" + + "052cdf0d640562bdfadfa263cfccf3c52b29f2af4a1869959bc77f854cf15bd7a2519" + + "2985a842dbff8e13efee5b7e7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837ee" + + "a4e0a2f04b53ca8f50fb31225c1be2d0126c8c7a4753b0807"); + + private byte[] seed3 = Hex.decode("CA7C0F8C3FFA87A96E1B74AC8E6AF594347BB40A"); + private byte[] mask3 = Hex.decode("744AB703F5BC082E59185F6D049D2D367DB245C2"); + + private byte[] seed4 = Hex.decode("0499B502FC8B5BAFB0F4047E731D1F9FD8CD0D8881"); + private byte[] mask4 = Hex.decode("03C62280C894E103C680B13CD4B4AE740A5EF0C72547292F82DC6B1777F47D63BA9D1EA732DBF386"); + + public KDF2GeneratorTest() + { + } + + public void performTest() + { + checkMask(1, new KDF2BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed1, mask1); + checkMask(2, new KDF2BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed2, mask2); + checkMask(3, new KDF2BytesGenerator(new SHA256Digest()), seed2, adjustedMask2); + checkMask(4, new KDF2BytesGenerator(new SHA1Digest()), seed2, sha1Mask); + checkMask(5, new KDF2BytesGenerator(new SHA1Digest()), seed3, mask3); + checkMask(6, new KDF2BytesGenerator(new SHA1Digest()), seed4, mask4); + + try + { + new KDF2BytesGenerator(new SHA1Digest()).generateBytes(new byte[10], 0, 20); + + fail("short input array not caught"); + } + catch (DataLengthException e) + { + // expected + } + } + + private void checkMask( + int count, + DerivationFunction kdf, + byte[] seed, + byte[] result) + { + byte[] data = new byte[result.length]; + + kdf.init(new KDFParameters(seed, new byte[0])); + + kdf.generateBytes(data, 0, data.length); + + if (!areEqual(result, data)) + { + fail("KDF2 failed generator test " + count); + } + } + + public String getName() + { + return "KDF2"; + } + + public static void main( + String[] args) + { + runTest(new KDF2GeneratorTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/KDFCounterGeneratorTest.java b/core/src/test/java/org/spongycastle/crypto/test/KDFCounterGeneratorTest.java new file mode 100644 index 00000000..3b58db2a --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/KDFCounterGeneratorTest.java @@ -0,0 +1,51 @@ +package org.spongycastle.crypto.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +import org.spongycastle.crypto.test.cavp.CAVPReader; +import org.spongycastle.crypto.test.cavp.KDFCounterTests; +import org.spongycastle.util.test.SimpleTest; + +public class KDFCounterGeneratorTest + extends SimpleTest +{ + + private static void testCounter() + { + + CAVPReader cavpReader = new CAVPReader(new KDFCounterTests()); + + final InputStream stream = CAVPReader.class.getResourceAsStream("KDFCTR_gen.rsp"); + final Reader reader = new InputStreamReader(stream, Charset.forName("UTF-8")); + cavpReader.setInput("KDFCounter", reader); + + try + { + cavpReader.readAll(); + } + catch (IOException e) + { + throw new IllegalStateException("Something is rotten in the state of Denmark", e); + } + } + + public String getName() + { + return this.getClass().getSimpleName(); + } + + public void performTest() + throws Exception + { + testCounter(); + } + + public static void main(String[] args) + { + runTest(new KDFCounterGeneratorTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/KDFDoublePipelineIteratorGeneratorTest.java b/core/src/test/java/org/spongycastle/crypto/test/KDFDoublePipelineIteratorGeneratorTest.java new file mode 100644 index 00000000..d44d1cab --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/KDFDoublePipelineIteratorGeneratorTest.java @@ -0,0 +1,72 @@ +package org.spongycastle.crypto.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +import org.spongycastle.crypto.test.cavp.CAVPReader; +import org.spongycastle.crypto.test.cavp.KDFDoublePipelineCounterTests; +import org.spongycastle.crypto.test.cavp.KDFDoublePipelineIterationNoCounterTests; +import org.spongycastle.util.test.SimpleTest; + +public class KDFDoublePipelineIteratorGeneratorTest + extends SimpleTest +{ + public String getName() + { + return this.getClass().getSimpleName(); + } + + public void performTest() + throws Exception + { + testDoublePipelineIterationCounter(); + testDoublePipelineIterationNoCounter(); + } + + private static void testDoublePipelineIterationCounter() + { + + CAVPReader cavpReader = new CAVPReader(new KDFDoublePipelineCounterTests()); + + final InputStream stream = CAVPReader.class.getResourceAsStream("KDFDblPipelineCounter_gen.rsp"); + final Reader reader = new InputStreamReader(stream, Charset.forName("UTF-8")); + cavpReader.setInput("KDFDoublePipelineIterationCounter", reader); + + try + { + cavpReader.readAll(); + } + catch (IOException e) + { + throw new IllegalStateException("Something is rotten in the state of Denmark", e); + } + } + + private static void testDoublePipelineIterationNoCounter() + { + + CAVPReader cavpReader = new CAVPReader(new KDFDoublePipelineIterationNoCounterTests()); + + final InputStream stream = CAVPReader.class.getResourceAsStream("KDFDblPipelineNoCounter_gen.rsp"); + final Reader reader = new InputStreamReader(stream, Charset.forName("UTF-8")); + cavpReader.setInput("KDFDblPipelineIterationNoCounter", reader); + + try + { + cavpReader.readAll(); + } + catch (IOException e) + { + throw new IllegalStateException("Something is rotten in the state of Denmark", e); + } + } + + public static void main(String[] args) + { + runTest(new KDFDoublePipelineIteratorGeneratorTest()); + } + +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/KDFFeedbackGeneratorTest.java b/core/src/test/java/org/spongycastle/crypto/test/KDFFeedbackGeneratorTest.java new file mode 100644 index 00000000..fa850985 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/KDFFeedbackGeneratorTest.java @@ -0,0 +1,71 @@ +package org.spongycastle.crypto.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +import org.spongycastle.crypto.test.cavp.CAVPReader; +import org.spongycastle.crypto.test.cavp.KDFFeedbackCounterTests; +import org.spongycastle.crypto.test.cavp.KDFFeedbackNoCounterTests; +import org.spongycastle.util.test.SimpleTest; + +public class KDFFeedbackGeneratorTest + extends SimpleTest +{ + public String getName() + { + return this.getClass().getSimpleName(); + } + + public void performTest() + throws Exception + { + testFeedbackCounter(); + testFeedbackNoCounter(); + } + + private static void testFeedbackCounter() + { + + CAVPReader cavpReader = new CAVPReader(new KDFFeedbackCounterTests()); + + final InputStream stream = CAVPReader.class.getResourceAsStream("KDFFeedbackCounter_gen.rsp"); + final Reader reader = new InputStreamReader(stream, Charset.forName("UTF-8")); + cavpReader.setInput("KDFFeedbackCounter", reader); + + try + { + cavpReader.readAll(); + } + catch (IOException e) + { + throw new IllegalStateException("Something is rotten in the state of Denmark ", e); + } + } + + private static void testFeedbackNoCounter() + { + + CAVPReader cavpReader = new CAVPReader(new KDFFeedbackNoCounterTests()); + + final InputStream stream = CAVPReader.class.getResourceAsStream("KDFFeedbackNoCounter_gen.rsp"); + final Reader reader = new InputStreamReader(stream, Charset.forName("UTF-8")); + cavpReader.setInput("KDFFeedbackNoCounter", reader); + + try + { + cavpReader.readAll(); + } + catch (IOException e) + { + throw new IllegalStateException("Something is rotten in the state of Denmark", e); + } + } + + public static void main(String[] args) + { + runTest(new KDFDoublePipelineIteratorGeneratorTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/MD2DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/MD2DigestTest.java new file mode 100644 index 00000000..e393f799 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/MD2DigestTest.java @@ -0,0 +1,52 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.MD2Digest; + +/** + * standard vector test for MD2 + * from RFC1319 by B.Kaliski of RSA Laboratories April 1992 + * + */ +public class MD2DigestTest + extends DigestTest +{ + static final String messages[] = + { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + static final String digests[] = + { + "8350e5a3e24c153df2275c9f80692773", + "32ec01ec4a6dac72c0ab96fb34c0b5d1", + "da853b0d3f88d99b30283a69e6ded6bb", + "ab4f496bfb2a530b219ff33031fe06b0", + "4e8ddff3650292ab5a4108c3aa47940b", + "da33def2a42df13975352846c30338cd", + "d5976f79d83d3a0dc9806c3c66f3efd8" + }; + + MD2DigestTest() + { + super(new MD2Digest(), messages, digests); + } + + protected Digest cloneDigest( + Digest digest) + { + return new MD2Digest((MD2Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new MD2DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/MD4DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/MD4DigestTest.java new file mode 100644 index 00000000..9175e2fe --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/MD4DigestTest.java @@ -0,0 +1,43 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.MD4Digest; + +/** + * standard vector test for MD4 from RFC 1320. + */ +public class MD4DigestTest + extends DigestTest +{ + static private String[] messages = + { + "", + "a", + "abc", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + static private String[] digests = + { + "31d6cfe0d16ae931b73c59d7e0c089c0", + "bde52cb31de33e46245e05fbdbd6fb24", + "a448017aaf21d8525fc10ae87aa6729d", + "e33b4ddc9c38f2199c3e7b164fcc0536" + }; + + MD4DigestTest() + { + super(new MD4Digest(), messages, digests); + } + + protected Digest cloneDigest(Digest digest) + { + return new MD4Digest((MD4Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new MD4DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/MD5DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/MD5DigestTest.java new file mode 100644 index 00000000..f39944d1 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/MD5DigestTest.java @@ -0,0 +1,43 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.MD5Digest; + +/** + * standard vector test for MD5 from "Handbook of Applied Cryptography", page 345. + */ +public class MD5DigestTest + extends DigestTest +{ + static final String[] messages = + { + "", + "a", + "abc", + "abcdefghijklmnopqrstuvwxyz" + }; + + static final String[] digests = + { + "d41d8cd98f00b204e9800998ecf8427e", + "0cc175b9c0f1b6a831c399e269772661", + "900150983cd24fb0d6963f7d28e17f72", + "c3fcd3d76192e4007dfb496cca67e13b" + }; + + MD5DigestTest() + { + super(new MD5Digest(), messages, digests); + } + + protected Digest cloneDigest(Digest digest) + { + return new MD5Digest((MD5Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new MD5DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/MD5HMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/MD5HMacTest.java new file mode 100644 index 00000000..76d8e214 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/MD5HMacTest.java @@ -0,0 +1,98 @@ + +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.digests.MD5Digest; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * MD5 HMac Test, test vectors from RFC 2202 + */ +public class MD5HMacTest + extends SimpleTest +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "9294727a3638bb1c13f48ef8158bfc9d", + "750c783e6ab0b503eaa86e310a5db738", + "56be34521d144c88dbb8c733f0e8b3f6", + "697eaf0aca3a3aea3a75164746ffaa79", + "56461ef2342edc00f9bab995690efd4c", + "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd", + "6f630fad67cda0ee1fb1f562db3aa53e" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" + }; + + public String getName() + { + return "MD5HMac"; + } + + public void performTest() + { + HMac hmac = new HMac(new MD5Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!areEqual(resBuf, Hex.decode(digests[i]))) + { + fail("Vector " + i + " failed"); + } + } + + // test reset + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!areEqual(resBuf, Hex.decode(digests[vector]))) + { + fail("Reset with vector " + vector + " failed"); + } + } + + public static void main( + String[] args) + { + runTest(new MD5HMacTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/MGF1GeneratorTest.java b/core/src/test/java/org/spongycastle/crypto/test/MGF1GeneratorTest.java new file mode 100644 index 00000000..0c7a2fec --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/MGF1GeneratorTest.java @@ -0,0 +1,88 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.DerivationFunction; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.digests.ShortenedDigest; +import org.spongycastle.crypto.generators.MGF1BytesGenerator; +import org.spongycastle.crypto.params.MGFParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * MGF1 tests - vectors from ISO 18033 for KDF1 (equivalent). + */ +public class MGF1GeneratorTest + extends SimpleTest +{ + private byte[] seed1 = Hex.decode("d6e168c5f256a2dcff7ef12facd390f393c7a88d"); + private byte[] mask1 = Hex.decode( + "0742ba966813af75536bb6149cc44fc256fd6406df79665bc31dc5" + + "a62f70535e52c53015b9d37d412ff3c1193439599e1b628774c50d9c" + + "cb78d82c425e4521ee47b8c36a4bcffe8b8112a89312fc04420a39de" + + "99223890e74ce10378bc515a212b97b8a6447ba6a8870278"); + + private byte[] seed2 = Hex.decode( + "032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d7643741" + + "52e0ac009e509e7ba30cd2f1778e113b64e135cf4e2292c75efe5288edfda4"); + private byte[] mask2 = Hex.decode( + "5f8de105b5e96b2e490ddecbd147dd1def7e3b8e0e6a26eb7b956ccb8b3bdc1ca9" + + "75bc57c3989e8fbad31a224655d800c46954840ff32052cdf0d640562bdfadfa263c" + + "fccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842dbff8e13efee5b7e" + + "7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837eea4e0a2f04"); + + private byte[] seed3 = seed2; + private byte[] mask3= Hex.decode( + "09e2decf2a6e1666c2f6071ff4298305e2643fd510a2403db42a8743cb989de86e" + + "668d168cbe604611ac179f819a3d18412e9eb45668f2923c087c12fee0c5a0d2a8aa" + + "70185401fbbd99379ec76c663e875a60b4aacb1319fa11c3365a8b79a44669f26fb5" + + "55c80391847b05eca1cb5cf8c2d531448d33fbaca19f6410ee1fcb"); + + public void performTest() + { + checkMask(1, new MGF1BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed1, mask1); + checkMask(2, new MGF1BytesGenerator(new SHA1Digest()), seed2, mask2); + checkMask(3, new MGF1BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed3, mask3); + + try + { + new MGF1BytesGenerator(new SHA1Digest()).generateBytes(new byte[10], 0, 20); + + fail("short input array not caught"); + } + catch (DataLengthException e) + { + // expected + } + } + + private void checkMask( + int count, + DerivationFunction kdf, + byte[] seed, + byte[] result) + { + byte[] data = new byte[result.length]; + + kdf.init(new MGFParameters(seed)); + + kdf.generateBytes(data, 0, data.length); + + if (!areEqual(result, data)) + { + fail("MGF1 failed generator test " + count); + } + } + + public String getName() + { + return "MGF1"; + } + + public static void main( + String[] args) + { + runTest(new MGF1GeneratorTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/MacTest.java b/core/src/test/java/org/spongycastle/crypto/test/MacTest.java new file mode 100644 index 00000000..1ae2bca1 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/MacTest.java @@ -0,0 +1,181 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.macs.CBCBlockCipherMac; +import org.spongycastle.crypto.macs.CFBBlockCipherMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.crypto.paddings.PKCS7Padding; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * MAC tester - vectors from + * <a href=http://www.itl.nist.gov/fipspubs/fip81.htm>FIP 81</a> and + * <a href=http://www.itl.nist.gov/fipspubs/fip113.htm>FIP 113</a>. + */ +public class MacTest + extends SimpleTest +{ + static byte[] keyBytes = Hex.decode("0123456789abcdef"); + static byte[] ivBytes = Hex.decode("1234567890abcdef"); + + static byte[] input1 = Hex.decode("37363534333231204e6f77206973207468652074696d6520666f7220"); + + static byte[] output1 = Hex.decode("f1d30f68"); + static byte[] output2 = Hex.decode("58d2e77e"); + static byte[] output3 = Hex.decode("cd647403"); + + // + // these aren't NIST vectors, just for regression testing. + // + static byte[] input2 = Hex.decode("3736353433323120"); + + static byte[] output4 = Hex.decode("3af549c9"); + static byte[] output5 = Hex.decode("188fbdd5"); + static byte[] output6 = Hex.decode("7045eecd"); + + public MacTest() + { + } + + public void performTest() + { + KeyParameter key = new KeyParameter(keyBytes); + BlockCipher cipher = new DESEngine(); + Mac mac = new CBCBlockCipherMac(cipher); + + // + // standard DAC - zero IV + // + mac.init(key); + + mac.update(input1, 0, input1.length); + + byte[] out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output1)) + { + fail("Failed - expected " + new String(Hex.encode(output1)) + " got " + new String(Hex.encode(out))); + } + + // + // mac with IV. + // + ParametersWithIV param = new ParametersWithIV(key, ivBytes); + + mac.init(param); + + mac.update(input1, 0, input1.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output2)) + { + fail("Failed - expected " + new String(Hex.encode(output2)) + " got " + new String(Hex.encode(out))); + } + + // + // CFB mac with IV - 8 bit CFB mode + // + param = new ParametersWithIV(key, ivBytes); + + mac = new CFBBlockCipherMac(cipher); + + mac.init(param); + + mac.update(input1, 0, input1.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output3)) + { + fail("Failed - expected " + new String(Hex.encode(output3)) + " got " + new String(Hex.encode(out))); + } + + // + // word aligned data - zero IV + // + mac.init(key); + + mac.update(input2, 0, input2.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output4)) + { + fail("Failed - expected " + new String(Hex.encode(output4)) + " got " + new String(Hex.encode(out))); + } + + // + // word aligned data - zero IV - CBC padding + // + mac = new CBCBlockCipherMac(cipher, new PKCS7Padding()); + + mac.init(key); + + mac.update(input2, 0, input2.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output5)) + { + fail("Failed - expected " + new String(Hex.encode(output5)) + " got " + new String(Hex.encode(out))); + } + + // + // non-word aligned data - zero IV - CBC padding + // + mac.reset(); + + mac.update(input1, 0, input1.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output6)) + { + fail("Failed - expected " + new String(Hex.encode(output6)) + " got " + new String(Hex.encode(out))); + } + + // + // non-word aligned data - zero IV - CBC padding + // + mac.init(key); + + mac.update(input1, 0, input1.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output6)) + { + fail("Failed - expected " + new String(Hex.encode(output6)) + " got " + new String(Hex.encode(out))); + } + } + + public String getName() + { + return "Mac"; + } + + public static void main( + String[] args) + { + runTest(new MacTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ModeTest.java b/core/src/test/java/org/spongycastle/crypto/test/ModeTest.java new file mode 100644 index 00000000..19fe1932 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ModeTest.java @@ -0,0 +1,115 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.modes.CFBBlockCipher; +import org.spongycastle.crypto.modes.OFBBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * CFB/OFB Mode test of IV padding. + */ +public class ModeTest + implements Test +{ + public ModeTest() + { + } + + private boolean isEqualTo( + byte[] a, + byte[] b) + { + for (int i = 0; i != a.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + public TestResult perform() + { + KeyParameter key = new KeyParameter(Hex.decode("0011223344556677")); + byte[] input = Hex.decode("4e6f7720"); + byte[] out1 = new byte[4]; + byte[] out2 = new byte[4]; + + + BlockCipher ofb = new OFBBlockCipher(new DESEngine(), 32); + + ofb.init(true, new ParametersWithIV(key, Hex.decode("1122334455667788"))); + + ofb.processBlock(input, 0, out1, 0); + + ofb.init(false, new ParametersWithIV(key, Hex.decode("1122334455667788"))); + ofb.processBlock(out1, 0, out2, 0); + + if (!isEqualTo(out2, input)) + { + return new SimpleTestResult(false, getName() + ": test 1 - in != out"); + } + + ofb.init(true, new ParametersWithIV(key, Hex.decode("11223344"))); + + ofb.processBlock(input, 0, out1, 0); + + ofb.init(false, new ParametersWithIV(key, Hex.decode("0000000011223344"))); + ofb.processBlock(out1, 0, out2, 0); + + if (!isEqualTo(out2, input)) + { + return new SimpleTestResult(false, getName() + ": test 2 - in != out"); + } + + BlockCipher cfb = new CFBBlockCipher(new DESEngine(), 32); + + cfb.init(true, new ParametersWithIV(key, Hex.decode("1122334455667788"))); + + cfb.processBlock(input, 0, out1, 0); + + cfb.init(false, new ParametersWithIV(key, Hex.decode("1122334455667788"))); + cfb.processBlock(out1, 0, out2, 0); + + if (!isEqualTo(out2, input)) + { + return new SimpleTestResult(false, getName() + ": test 3 - in != out"); + } + + cfb.init(true, new ParametersWithIV(key, Hex.decode("11223344"))); + + cfb.processBlock(input, 0, out1, 0); + + cfb.init(false, new ParametersWithIV(key, Hex.decode("0000000011223344"))); + cfb.processBlock(out1, 0, out2, 0); + + if (!isEqualTo(out2, input)) + { + return new SimpleTestResult(false, getName() + ": test 4 - in != out"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public String getName() + { + return "ModeTest"; + } + + public static void main( + String[] args) + { + ModeTest test = new ModeTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/NaccacheSternTest.java b/core/src/test/java/org/spongycastle/crypto/test/NaccacheSternTest.java new file mode 100644 index 00000000..1bde2f45 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/NaccacheSternTest.java @@ -0,0 +1,354 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Vector; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.NaccacheSternEngine; +import org.spongycastle.crypto.generators.NaccacheSternKeyPairGenerator; +import org.spongycastle.crypto.params.NaccacheSternKeyGenerationParameters; +import org.spongycastle.crypto.params.NaccacheSternKeyParameters; +import org.spongycastle.crypto.params.NaccacheSternPrivateKeyParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Test case for NaccacheStern cipher. For details on this cipher, please see + * + * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf + * + * Performs the following tests: + * <ul> + * <li> Toy example from the NaccacheSternPaper </li> + * <li> 768 bit test with text "Now is the time for all good men." (ripped from RSA test) and + * the same test with the first byte replaced by 0xFF </li> + * <li> 1024 bit test analog to 768 bit test </li> + * </ul> + */ +public class NaccacheSternTest + extends SimpleTest +{ + static final boolean debug = false; + + static final NaccacheSternEngine cryptEng = new NaccacheSternEngine(); + + static final NaccacheSternEngine decryptEng = new NaccacheSternEngine(); + + static + { + cryptEng.setDebug(debug); + decryptEng.setDebug(debug); + } + + // Values from NaccacheStern paper + static final BigInteger a = BigInteger.valueOf(101); + + static final BigInteger u1 = BigInteger.valueOf(3); + + static final BigInteger u2 = BigInteger.valueOf(5); + + static final BigInteger u3 = BigInteger.valueOf(7); + + static final BigInteger b = BigInteger.valueOf(191); + + static final BigInteger v1 = BigInteger.valueOf(11); + + static final BigInteger v2 = BigInteger.valueOf(13); + + static final BigInteger v3 = BigInteger.valueOf(17); + + static final BigInteger ONE = BigInteger.valueOf(1); + + static final BigInteger TWO = BigInteger.valueOf(2); + + static final BigInteger sigma = u1.multiply(u2).multiply(u3).multiply(v1) + .multiply(v2).multiply(v3); + + static final BigInteger p = TWO.multiply(a).multiply(u1).multiply(u2) + .multiply(u3).add(ONE); + + static final BigInteger q = TWO.multiply(b).multiply(v1).multiply(v2) + .multiply(v3).add(ONE); + + static final BigInteger n = p.multiply(q); + + static final BigInteger phi_n = p.subtract(ONE).multiply(q.subtract(ONE)); + + static final BigInteger g = BigInteger.valueOf(131); + + static final Vector smallPrimes = new Vector(); + + // static final BigInteger paperTest = BigInteger.valueOf(202); + + static final String input = "4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + static final BigInteger paperTest = BigInteger.valueOf(202); + + // + // to check that we handling byte extension by big number correctly. + // + static final String edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + public String getName() + { + return "NaccacheStern"; + } + + public void performTest() + { + // Test with given key from NaccacheSternPaper (totally insecure) + + // First the Parameters from the NaccacheStern Paper + // (see http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf ) + + smallPrimes.addElement(u1); + smallPrimes.addElement(u2); + smallPrimes.addElement(u3); + smallPrimes.addElement(v1); + smallPrimes.addElement(v2); + smallPrimes.addElement(v3); + + NaccacheSternKeyParameters pubParameters = new NaccacheSternKeyParameters(false, g, n, sigma.bitLength()); + + NaccacheSternPrivateKeyParameters privParameters = new NaccacheSternPrivateKeyParameters(g, n, sigma.bitLength(), smallPrimes, phi_n); + + AsymmetricCipherKeyPair pair = new AsymmetricCipherKeyPair(pubParameters, privParameters); + + // Initialize Engines with KeyPair + + if (debug) + { + System.out.println("initializing encryption engine"); + } + cryptEng.init(true, pair.getPublic()); + + if (debug) + { + System.out.println("initializing decryption engine"); + } + decryptEng.init(false, pair.getPrivate()); + + byte[] data = paperTest.toByteArray(); + + if (!new BigInteger(data).equals(new BigInteger(enDeCrypt(data)))) + { + fail("failed NaccacheStern paper test"); + } + + // + // key generation test + // + + // + // 768 Bit test + // + + if (debug) + { + System.out.println(); + System.out.println("768 Bit TEST"); + } + + // specify key generation parameters + NaccacheSternKeyGenerationParameters genParam + = new NaccacheSternKeyGenerationParameters(new SecureRandom(), 768, 8, 30, debug); + + // Initialize Key generator and generate key pair + NaccacheSternKeyPairGenerator pGen = new NaccacheSternKeyPairGenerator(); + pGen.init(genParam); + + pair = pGen.generateKeyPair(); + + if (((NaccacheSternKeyParameters)pair.getPublic()).getModulus().bitLength() < 768) + { + System.out.println("FAILED: key size is <786 bit, exactly " + + ((NaccacheSternKeyParameters)pair.getPublic()).getModulus().bitLength() + " bit"); + fail("failed key generation (768) length test"); + } + + // Initialize Engines with KeyPair + + if (debug) + { + System.out.println("initializing " + genParam.getStrength() + " bit encryption engine"); + } + cryptEng.init(true, pair.getPublic()); + + if (debug) + { + System.out.println("initializing " + genParam.getStrength() + " bit decryption engine"); + } + decryptEng.init(false, pair.getPrivate()); + + // Basic data input + data = Hex.decode(input); + + if (!new BigInteger(1, data).equals(new BigInteger(1, enDeCrypt(data)))) + { + fail("failed encryption decryption (" + genParam.getStrength() + ") basic test"); + } + + // Data starting with FF byte (would be interpreted as negative + // BigInteger) + + data = Hex.decode(edgeInput); + + if (!new BigInteger(1, data).equals(new BigInteger(1, enDeCrypt(data)))) + { + fail("failed encryption decryption (" + genParam.getStrength() + ") edgeInput test"); + } + + // + // 1024 Bit Test + // +/* + if (debug) + { + System.out.println(); + System.out.println("1024 Bit TEST"); + } + + // specify key generation parameters + genParam = new NaccacheSternKeyGenerationParameters(new SecureRandom(), 1024, 8, 40); + + pGen.init(genParam); + pair = pGen.generateKeyPair(); + + if (((NaccacheSternKeyParameters)pair.getPublic()).getModulus().bitLength() < 1024) + { + if (debug) + { + System.out.println("FAILED: key size is <1024 bit, exactly " + + ((NaccacheSternKeyParameters)pair.getPublic()).getModulus().bitLength() + " bit"); + } + fail("failed key generation (1024) length test"); + } + + // Initialize Engines with KeyPair + + if (debug) + { + System.out.println("initializing " + genParam.getStrength() + " bit encryption engine"); + } + cryptEng.init(true, pair.getPublic()); + + if (debug) + { + System.out.println("initializing " + genParam.getStrength() + " bit decryption engine"); + } + decryptEng.init(false, pair.getPrivate()); + + if (debug) + { + System.out.println("Data is " + new BigInteger(1, data)); + } + + // Basic data input + data = Hex.decode(input); + + if (!new BigInteger(1, data).equals(new BigInteger(1, enDeCrypt(data)))) + { + fail("failed encryption decryption (" + genParam.getStrength() + ") basic test"); + } + + // Data starting with FF byte (would be interpreted as negative + // BigInteger) + + data = Hex.decode(edgeInput); + + if (!new BigInteger(1, data).equals(new BigInteger(1, enDeCrypt(data)))) + { + fail("failed encryption decryption (" + genParam.getStrength() + ") edgeInput test"); + } +*/ + // END OF TEST CASE + + try + { + new NaccacheSternEngine().processBlock(new byte[]{ 1 }, 0, 1); + fail("failed initialisation check"); + } + catch (IllegalStateException e) + { + // expected + } + catch (InvalidCipherTextException e) + { + fail("failed initialisation check"); + } + + if (debug) + { + System.out.println("All tests successful"); + } + } + + private byte[] enDeCrypt(byte[] input) + { + + // create work array + byte[] data = new byte[input.length]; + System.arraycopy(input, 0, data, 0, data.length); + + // Perform encryption like in the paper from Naccache-Stern + if (debug) + { + System.out.println("encrypting data. Data representation\n" + // + "As String:.... " + new String(data) + "\n" + + "As BigInteger: " + new BigInteger(1, data)); + System.out.println("data length is " + data.length); + } + + try + { + data = cryptEng.processData(data); + } + catch (InvalidCipherTextException e) + { + if (debug) + { + System.out.println("failed - exception " + e.toString() + "\n" + e.getMessage()); + } + fail("failed - exception " + e.toString() + "\n" + e.getMessage()); + } + + if (debug) + { + System.out.println("enrypted data representation\n" + // + "As String:.... " + new String(data) + "\n" + + "As BigInteger: " + new BigInteger(1, data)); + System.out.println("data length is " + data.length); + } + + try + { + data = decryptEng.processData(data); + } + catch (InvalidCipherTextException e) + { + if (debug) + { + System.out.println("failed - exception " + e.toString() + "\n" + e.getMessage()); + } + fail("failed - exception " + e.toString() + "\n" + e.getMessage()); + } + + if (debug) + { + System.out.println("decrypted data representation\n" + // + "As String:.... " + new String(data) + "\n" + + "As BigInteger: " + new BigInteger(1, data)); + System.out.println("data length is " + data.length); + } + + return data; + + } + + public static void main(String[] args) + { + runTest(new NaccacheSternTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/NoekeonTest.java b/core/src/test/java/org/spongycastle/crypto/test/NoekeonTest.java new file mode 100644 index 00000000..f17ff0ff --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/NoekeonTest.java @@ -0,0 +1,45 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.NoekeonEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Noekeon tester + */ +public class NoekeonTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new NoekeonEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", + "b1656851699e29fa24b70148503d2dfc"), + new BlockCipherVectorTest(1, new NoekeonEngine(), + new KeyParameter(Hex.decode("ffffffffffffffffffffffffffffffff")), + "ffffffffffffffffffffffffffffffff", + "2a78421b87c7d0924f26113f1d1349b2"), + new BlockCipherVectorTest(2, new NoekeonEngine(), + new KeyParameter(Hex.decode("b1656851699e29fa24b70148503d2dfc")), + "2a78421b87c7d0924f26113f1d1349b2", + "e2f687e07b75660ffc372233bc47532c") + }; + + NoekeonTest() + { + super(tests, new NoekeonEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "Noekeon"; + } + + public static void main( + String[] args) + { + runTest(new NoekeonTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/NonMemoableDigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/NonMemoableDigestTest.java new file mode 100644 index 00000000..8abb0229 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/NonMemoableDigestTest.java @@ -0,0 +1,112 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.digests.NonMemoableDigest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * SHA1 HMac Test, test vectors from RFC 2202 + */ +public class NonMemoableDigestTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "b617318655057264e28bc0b6fb378c8ef146be00", + "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", + "125d7342b9ac11cd91a39af48aa17b4f63f175d3", + "4c9007f4026250c6bc8414f9bf50c86c2d7235da", + "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", + "aa4ae5e15272d00e95705637ce8a3b55ed402112", + "e8e99d0f45237d786d6bbaa7965c7808bbff1a91", + "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", + "aa4ae5e15272d00e95705637ce8a3b55ed402112", + "e8e99d0f45237d786d6bbaa7965c7808bbff1a91" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" + }; + + public String getName() + { + return "NonMemoableDigest"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new NonMemoableDigest(new SHA1Digest())); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed"); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + "Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + NonMemoableDigestTest test = new NonMemoableDigestTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/NullTest.java b/core/src/test/java/org/spongycastle/crypto/test/NullTest.java new file mode 100644 index 00000000..f384cfc4 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/NullTest.java @@ -0,0 +1,77 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.engines.NullEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class NullTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new NullEngine(), + new KeyParameter(Hex.decode("00")), "00", "00") + }; + + NullTest() + { + super(tests, new NullEngine(), new KeyParameter(new byte[2])); + } + + public String getName() + { + return "Null"; + } + + public void performTest() + throws Exception + { + super.performTest(); + + BlockCipher engine = new NullEngine(); + + engine.init(true, null); + + byte[] buf = new byte[1]; + + engine.processBlock(buf, 0, buf, 0); + + if (buf[0] != 0) + { + fail("NullCipher changed data!"); + } + + byte[] shortBuf = new byte[0]; + + try + { + engine.processBlock(shortBuf, 0, buf, 0); + + fail("failed short input check"); + } + catch (DataLengthException e) + { + // expected + } + + try + { + engine.processBlock(buf, 0, shortBuf, 0); + + fail("failed short output check"); + } + catch (DataLengthException e) + { + // expected + } + } + + public static void main( + String[] args) + { + runTest(new NullTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/OAEPTest.java b/core/src/test/java/org/spongycastle/crypto/test/OAEPTest.java new file mode 100644 index 00000000..30c575de --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/OAEPTest.java @@ -0,0 +1,830 @@ +package org.spongycastle.crypto.test; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1Sequence; +import org.spongycastle.asn1.pkcs.PrivateKeyInfo; +import org.spongycastle.asn1.pkcs.RSAPrivateKey; +import org.spongycastle.asn1.pkcs.RSAPublicKey; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.crypto.AsymmetricBlockCipher; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.encodings.OAEPEncoding; +import org.spongycastle.crypto.engines.RSAEngine; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.crypto.params.RSAKeyParameters; +import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class OAEPTest + extends SimpleTest +{ + static byte[] pubKeyEnc1 = + { + (byte)0x30, (byte)0x5a, (byte)0x30, (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, + (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, + (byte)0x00, (byte)0x03, (byte)0x49, (byte)0x00, (byte)0x30, (byte)0x46, (byte)0x02, (byte)0x41, + (byte)0x00, (byte)0xaa, (byte)0x36, (byte)0xab, (byte)0xce, (byte)0x88, (byte)0xac, (byte)0xfd, + (byte)0xff, (byte)0x55, (byte)0x52, (byte)0x3c, (byte)0x7f, (byte)0xc4, (byte)0x52, (byte)0x3f, + (byte)0x90, (byte)0xef, (byte)0xa0, (byte)0x0d, (byte)0xf3, (byte)0x77, (byte)0x4a, (byte)0x25, + (byte)0x9f, (byte)0x2e, (byte)0x62, (byte)0xb4, (byte)0xc5, (byte)0xd9, (byte)0x9c, (byte)0xb5, + (byte)0xad, (byte)0xb3, (byte)0x00, (byte)0xa0, (byte)0x28, (byte)0x5e, (byte)0x53, (byte)0x01, + (byte)0x93, (byte)0x0e, (byte)0x0c, (byte)0x70, (byte)0xfb, (byte)0x68, (byte)0x76, (byte)0x93, + (byte)0x9c, (byte)0xe6, (byte)0x16, (byte)0xce, (byte)0x62, (byte)0x4a, (byte)0x11, (byte)0xe0, + (byte)0x08, (byte)0x6d, (byte)0x34, (byte)0x1e, (byte)0xbc, (byte)0xac, (byte)0xa0, (byte)0xa1, + (byte)0xf5, (byte)0x02, (byte)0x01, (byte)0x11 + }; + + static byte[] privKeyEnc1 = + { + (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x52, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x30, + (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, + (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x04, (byte)0x82, + (byte)0x01, (byte)0x3c, (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x38, (byte)0x02, (byte)0x01, + (byte)0x00, (byte)0x02, (byte)0x41, (byte)0x00, (byte)0xaa, (byte)0x36, (byte)0xab, (byte)0xce, + (byte)0x88, (byte)0xac, (byte)0xfd, (byte)0xff, (byte)0x55, (byte)0x52, (byte)0x3c, (byte)0x7f, + (byte)0xc4, (byte)0x52, (byte)0x3f, (byte)0x90, (byte)0xef, (byte)0xa0, (byte)0x0d, (byte)0xf3, + (byte)0x77, (byte)0x4a, (byte)0x25, (byte)0x9f, (byte)0x2e, (byte)0x62, (byte)0xb4, (byte)0xc5, + (byte)0xd9, (byte)0x9c, (byte)0xb5, (byte)0xad, (byte)0xb3, (byte)0x00, (byte)0xa0, (byte)0x28, + (byte)0x5e, (byte)0x53, (byte)0x01, (byte)0x93, (byte)0x0e, (byte)0x0c, (byte)0x70, (byte)0xfb, + (byte)0x68, (byte)0x76, (byte)0x93, (byte)0x9c, (byte)0xe6, (byte)0x16, (byte)0xce, (byte)0x62, + (byte)0x4a, (byte)0x11, (byte)0xe0, (byte)0x08, (byte)0x6d, (byte)0x34, (byte)0x1e, (byte)0xbc, + (byte)0xac, (byte)0xa0, (byte)0xa1, (byte)0xf5, (byte)0x02, (byte)0x01, (byte)0x11, (byte)0x02, + (byte)0x40, (byte)0x0a, (byte)0x03, (byte)0x37, (byte)0x48, (byte)0x62, (byte)0x64, (byte)0x87, + (byte)0x69, (byte)0x5f, (byte)0x5f, (byte)0x30, (byte)0xbc, (byte)0x38, (byte)0xb9, (byte)0x8b, + (byte)0x44, (byte)0xc2, (byte)0xcd, (byte)0x2d, (byte)0xff, (byte)0x43, (byte)0x40, (byte)0x98, + (byte)0xcd, (byte)0x20, (byte)0xd8, (byte)0xa1, (byte)0x38, (byte)0xd0, (byte)0x90, (byte)0xbf, + (byte)0x64, (byte)0x79, (byte)0x7c, (byte)0x3f, (byte)0xa7, (byte)0xa2, (byte)0xcd, (byte)0xcb, + (byte)0x3c, (byte)0xd1, (byte)0xe0, (byte)0xbd, (byte)0xba, (byte)0x26, (byte)0x54, (byte)0xb4, + (byte)0xf9, (byte)0xdf, (byte)0x8e, (byte)0x8a, (byte)0xe5, (byte)0x9d, (byte)0x73, (byte)0x3d, + (byte)0x9f, (byte)0x33, (byte)0xb3, (byte)0x01, (byte)0x62, (byte)0x4a, (byte)0xfd, (byte)0x1d, + (byte)0x51, (byte)0x02, (byte)0x21, (byte)0x00, (byte)0xd8, (byte)0x40, (byte)0xb4, (byte)0x16, + (byte)0x66, (byte)0xb4, (byte)0x2e, (byte)0x92, (byte)0xea, (byte)0x0d, (byte)0xa3, (byte)0xb4, + (byte)0x32, (byte)0x04, (byte)0xb5, (byte)0xcf, (byte)0xce, (byte)0x33, (byte)0x52, (byte)0x52, + (byte)0x4d, (byte)0x04, (byte)0x16, (byte)0xa5, (byte)0xa4, (byte)0x41, (byte)0xe7, (byte)0x00, + (byte)0xaf, (byte)0x46, (byte)0x12, (byte)0x0d, (byte)0x02, (byte)0x21, (byte)0x00, (byte)0xc9, + (byte)0x7f, (byte)0xb1, (byte)0xf0, (byte)0x27, (byte)0xf4, (byte)0x53, (byte)0xf6, (byte)0x34, + (byte)0x12, (byte)0x33, (byte)0xea, (byte)0xaa, (byte)0xd1, (byte)0xd9, (byte)0x35, (byte)0x3f, + (byte)0x6c, (byte)0x42, (byte)0xd0, (byte)0x88, (byte)0x66, (byte)0xb1, (byte)0xd0, (byte)0x5a, + (byte)0x0f, (byte)0x20, (byte)0x35, (byte)0x02, (byte)0x8b, (byte)0x9d, (byte)0x89, (byte)0x02, + (byte)0x20, (byte)0x59, (byte)0x0b, (byte)0x95, (byte)0x72, (byte)0xa2, (byte)0xc2, (byte)0xa9, + (byte)0xc4, (byte)0x06, (byte)0x05, (byte)0x9d, (byte)0xc2, (byte)0xab, (byte)0x2f, (byte)0x1d, + (byte)0xaf, (byte)0xeb, (byte)0x7e, (byte)0x8b, (byte)0x4f, (byte)0x10, (byte)0xa7, (byte)0x54, + (byte)0x9e, (byte)0x8e, (byte)0xed, (byte)0xf5, (byte)0xb4, (byte)0xfc, (byte)0xe0, (byte)0x9e, + (byte)0x05, (byte)0x02, (byte)0x21, (byte)0x00, (byte)0x8e, (byte)0x3c, (byte)0x05, (byte)0x21, + (byte)0xfe, (byte)0x15, (byte)0xe0, (byte)0xea, (byte)0x06, (byte)0xa3, (byte)0x6f, (byte)0xf0, + (byte)0xf1, (byte)0x0c, (byte)0x99, (byte)0x52, (byte)0xc3, (byte)0x5b, (byte)0x7a, (byte)0x75, + (byte)0x14, (byte)0xfd, (byte)0x32, (byte)0x38, (byte)0xb8, (byte)0x0a, (byte)0xad, (byte)0x52, + (byte)0x98, (byte)0x62, (byte)0x8d, (byte)0x51, (byte)0x02, (byte)0x20, (byte)0x36, (byte)0x3f, + (byte)0xf7, (byte)0x18, (byte)0x9d, (byte)0xa8, (byte)0xe9, (byte)0x0b, (byte)0x1d, (byte)0x34, + (byte)0x1f, (byte)0x71, (byte)0xd0, (byte)0x9b, (byte)0x76, (byte)0xa8, (byte)0xa9, (byte)0x43, + (byte)0xe1, (byte)0x1d, (byte)0x10, (byte)0xb2, (byte)0x4d, (byte)0x24, (byte)0x9f, (byte)0x2d, + (byte)0xea, (byte)0xfe, (byte)0xf8, (byte)0x0c, (byte)0x18, (byte)0x26 + }; + + static byte[] output1 = + { + (byte)0x1b, (byte)0x8f, (byte)0x05, (byte)0xf9, (byte)0xca, (byte)0x1a, (byte)0x79, (byte)0x52, + (byte)0x6e, (byte)0x53, (byte)0xf3, (byte)0xcc, (byte)0x51, (byte)0x4f, (byte)0xdb, (byte)0x89, + (byte)0x2b, (byte)0xfb, (byte)0x91, (byte)0x93, (byte)0x23, (byte)0x1e, (byte)0x78, (byte)0xb9, + (byte)0x92, (byte)0xe6, (byte)0x8d, (byte)0x50, (byte)0xa4, (byte)0x80, (byte)0xcb, (byte)0x52, + (byte)0x33, (byte)0x89, (byte)0x5c, (byte)0x74, (byte)0x95, (byte)0x8d, (byte)0x5d, (byte)0x02, + (byte)0xab, (byte)0x8c, (byte)0x0f, (byte)0xd0, (byte)0x40, (byte)0xeb, (byte)0x58, (byte)0x44, + (byte)0xb0, (byte)0x05, (byte)0xc3, (byte)0x9e, (byte)0xd8, (byte)0x27, (byte)0x4a, (byte)0x9d, + (byte)0xbf, (byte)0xa8, (byte)0x06, (byte)0x71, (byte)0x40, (byte)0x94, (byte)0x39, (byte)0xd2 + }; + + static byte[] pubKeyEnc2 = + { + (byte)0x30, (byte)0x4c, (byte)0x30, (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, + (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, + (byte)0x00, (byte)0x03, (byte)0x3b, (byte)0x00, (byte)0x30, (byte)0x38, (byte)0x02, (byte)0x33, + (byte)0x00, (byte)0xa3, (byte)0x07, (byte)0x9a, (byte)0x90, (byte)0xdf, (byte)0x0d, (byte)0xfd, + (byte)0x72, (byte)0xac, (byte)0x09, (byte)0x0c, (byte)0xcc, (byte)0x2a, (byte)0x78, (byte)0xb8, + (byte)0x74, (byte)0x13, (byte)0x13, (byte)0x3e, (byte)0x40, (byte)0x75, (byte)0x9c, (byte)0x98, + (byte)0xfa, (byte)0xf8, (byte)0x20, (byte)0x4f, (byte)0x35, (byte)0x8a, (byte)0x0b, (byte)0x26, + (byte)0x3c, (byte)0x67, (byte)0x70, (byte)0xe7, (byte)0x83, (byte)0xa9, (byte)0x3b, (byte)0x69, + (byte)0x71, (byte)0xb7, (byte)0x37, (byte)0x79, (byte)0xd2, (byte)0x71, (byte)0x7b, (byte)0xe8, + (byte)0x34, (byte)0x77, (byte)0xcf, (byte)0x02, (byte)0x01, (byte)0x03 + }; + + static byte[] privKeyEnc2 = + { + (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x13, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x30, + (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, + (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x04, (byte)0x81, + (byte)0xfe, (byte)0x30, (byte)0x81, (byte)0xfb, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x02, + (byte)0x33, (byte)0x00, (byte)0xa3, (byte)0x07, (byte)0x9a, (byte)0x90, (byte)0xdf, (byte)0x0d, + (byte)0xfd, (byte)0x72, (byte)0xac, (byte)0x09, (byte)0x0c, (byte)0xcc, (byte)0x2a, (byte)0x78, + (byte)0xb8, (byte)0x74, (byte)0x13, (byte)0x13, (byte)0x3e, (byte)0x40, (byte)0x75, (byte)0x9c, + (byte)0x98, (byte)0xfa, (byte)0xf8, (byte)0x20, (byte)0x4f, (byte)0x35, (byte)0x8a, (byte)0x0b, + (byte)0x26, (byte)0x3c, (byte)0x67, (byte)0x70, (byte)0xe7, (byte)0x83, (byte)0xa9, (byte)0x3b, + (byte)0x69, (byte)0x71, (byte)0xb7, (byte)0x37, (byte)0x79, (byte)0xd2, (byte)0x71, (byte)0x7b, + (byte)0xe8, (byte)0x34, (byte)0x77, (byte)0xcf, (byte)0x02, (byte)0x01, (byte)0x03, (byte)0x02, + (byte)0x32, (byte)0x6c, (byte)0xaf, (byte)0xbc, (byte)0x60, (byte)0x94, (byte)0xb3, (byte)0xfe, + (byte)0x4c, (byte)0x72, (byte)0xb0, (byte)0xb3, (byte)0x32, (byte)0xc6, (byte)0xfb, (byte)0x25, + (byte)0xa2, (byte)0xb7, (byte)0x62, (byte)0x29, (byte)0x80, (byte)0x4e, (byte)0x68, (byte)0x65, + (byte)0xfc, (byte)0xa4, (byte)0x5a, (byte)0x74, (byte)0xdf, (byte)0x0f, (byte)0x8f, (byte)0xb8, + (byte)0x41, (byte)0x3b, (byte)0x52, (byte)0xc0, (byte)0xd0, (byte)0xe5, (byte)0x3d, (byte)0x9b, + (byte)0x59, (byte)0x0f, (byte)0xf1, (byte)0x9b, (byte)0xe7, (byte)0x9f, (byte)0x49, (byte)0xdd, + (byte)0x21, (byte)0xe5, (byte)0xeb, (byte)0x02, (byte)0x1a, (byte)0x00, (byte)0xcf, (byte)0x20, + (byte)0x35, (byte)0x02, (byte)0x8b, (byte)0x9d, (byte)0x86, (byte)0x98, (byte)0x40, (byte)0xb4, + (byte)0x16, (byte)0x66, (byte)0xb4, (byte)0x2e, (byte)0x92, (byte)0xea, (byte)0x0d, (byte)0xa3, + (byte)0xb4, (byte)0x32, (byte)0x04, (byte)0xb5, (byte)0xcf, (byte)0xce, (byte)0x91, (byte)0x02, + (byte)0x1a, (byte)0x00, (byte)0xc9, (byte)0x7f, (byte)0xb1, (byte)0xf0, (byte)0x27, (byte)0xf4, + (byte)0x53, (byte)0xf6, (byte)0x34, (byte)0x12, (byte)0x33, (byte)0xea, (byte)0xaa, (byte)0xd1, + (byte)0xd9, (byte)0x35, (byte)0x3f, (byte)0x6c, (byte)0x42, (byte)0xd0, (byte)0x88, (byte)0x66, + (byte)0xb1, (byte)0xd0, (byte)0x5f, (byte)0x02, (byte)0x1a, (byte)0x00, (byte)0x8a, (byte)0x15, + (byte)0x78, (byte)0xac, (byte)0x5d, (byte)0x13, (byte)0xaf, (byte)0x10, (byte)0x2b, (byte)0x22, + (byte)0xb9, (byte)0x99, (byte)0xcd, (byte)0x74, (byte)0x61, (byte)0xf1, (byte)0x5e, (byte)0x6d, + (byte)0x22, (byte)0xcc, (byte)0x03, (byte)0x23, (byte)0xdf, (byte)0xdf, (byte)0x0b, (byte)0x02, + (byte)0x1a, (byte)0x00, (byte)0x86, (byte)0x55, (byte)0x21, (byte)0x4a, (byte)0xc5, (byte)0x4d, + (byte)0x8d, (byte)0x4e, (byte)0xcd, (byte)0x61, (byte)0x77, (byte)0xf1, (byte)0xc7, (byte)0x36, + (byte)0x90, (byte)0xce, (byte)0x2a, (byte)0x48, (byte)0x2c, (byte)0x8b, (byte)0x05, (byte)0x99, + (byte)0xcb, (byte)0xe0, (byte)0x3f, (byte)0x02, (byte)0x1a, (byte)0x00, (byte)0x83, (byte)0xef, + (byte)0xef, (byte)0xb8, (byte)0xa9, (byte)0xa4, (byte)0x0d, (byte)0x1d, (byte)0xb6, (byte)0xed, + (byte)0x98, (byte)0xad, (byte)0x84, (byte)0xed, (byte)0x13, (byte)0x35, (byte)0xdc, (byte)0xc1, + (byte)0x08, (byte)0xf3, (byte)0x22, (byte)0xd0, (byte)0x57, (byte)0xcf, (byte)0x8d + }; + + static byte[] output2 = + { + (byte)0x14, (byte)0xbd, (byte)0xdd, (byte)0x28, (byte)0xc9, (byte)0x83, (byte)0x35, (byte)0x19, + (byte)0x23, (byte)0x80, (byte)0xe8, (byte)0xe5, (byte)0x49, (byte)0xb1, (byte)0x58, (byte)0x2a, + (byte)0x8b, (byte)0x40, (byte)0xb4, (byte)0x48, (byte)0x6d, (byte)0x03, (byte)0xa6, (byte)0xa5, + (byte)0x31, (byte)0x1f, (byte)0x1f, (byte)0xd5, (byte)0xf0, (byte)0xa1, (byte)0x80, (byte)0xe4, + (byte)0x17, (byte)0x53, (byte)0x03, (byte)0x29, (byte)0xa9, (byte)0x34, (byte)0x90, (byte)0x74, + (byte)0xb1, (byte)0x52, (byte)0x13, (byte)0x54, (byte)0x29, (byte)0x08, (byte)0x24, (byte)0x52, + (byte)0x62, (byte)0x51 + }; + + static byte[] pubKeyEnc3 = + { + (byte)0x30, (byte)0x81, (byte)0x9d, (byte)0x30, (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, + (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, + (byte)0x05, (byte)0x00, (byte)0x03, (byte)0x81, (byte)0x8b, (byte)0x00, (byte)0x30, (byte)0x81, + (byte)0x87, (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xbb, (byte)0xf8, (byte)0x2f, + (byte)0x09, (byte)0x06, (byte)0x82, (byte)0xce, (byte)0x9c, (byte)0x23, (byte)0x38, (byte)0xac, + (byte)0x2b, (byte)0x9d, (byte)0xa8, (byte)0x71, (byte)0xf7, (byte)0x36, (byte)0x8d, (byte)0x07, + (byte)0xee, (byte)0xd4, (byte)0x10, (byte)0x43, (byte)0xa4, (byte)0x40, (byte)0xd6, (byte)0xb6, + (byte)0xf0, (byte)0x74, (byte)0x54, (byte)0xf5, (byte)0x1f, (byte)0xb8, (byte)0xdf, (byte)0xba, + (byte)0xaf, (byte)0x03, (byte)0x5c, (byte)0x02, (byte)0xab, (byte)0x61, (byte)0xea, (byte)0x48, + (byte)0xce, (byte)0xeb, (byte)0x6f, (byte)0xcd, (byte)0x48, (byte)0x76, (byte)0xed, (byte)0x52, + (byte)0x0d, (byte)0x60, (byte)0xe1, (byte)0xec, (byte)0x46, (byte)0x19, (byte)0x71, (byte)0x9d, + (byte)0x8a, (byte)0x5b, (byte)0x8b, (byte)0x80, (byte)0x7f, (byte)0xaf, (byte)0xb8, (byte)0xe0, + (byte)0xa3, (byte)0xdf, (byte)0xc7, (byte)0x37, (byte)0x72, (byte)0x3e, (byte)0xe6, (byte)0xb4, + (byte)0xb7, (byte)0xd9, (byte)0x3a, (byte)0x25, (byte)0x84, (byte)0xee, (byte)0x6a, (byte)0x64, + (byte)0x9d, (byte)0x06, (byte)0x09, (byte)0x53, (byte)0x74, (byte)0x88, (byte)0x34, (byte)0xb2, + (byte)0x45, (byte)0x45, (byte)0x98, (byte)0x39, (byte)0x4e, (byte)0xe0, (byte)0xaa, (byte)0xb1, + (byte)0x2d, (byte)0x7b, (byte)0x61, (byte)0xa5, (byte)0x1f, (byte)0x52, (byte)0x7a, (byte)0x9a, + (byte)0x41, (byte)0xf6, (byte)0xc1, (byte)0x68, (byte)0x7f, (byte)0xe2, (byte)0x53, (byte)0x72, + (byte)0x98, (byte)0xca, (byte)0x2a, (byte)0x8f, (byte)0x59, (byte)0x46, (byte)0xf8, (byte)0xe5, + (byte)0xfd, (byte)0x09, (byte)0x1d, (byte)0xbd, (byte)0xcb, (byte)0x02, (byte)0x01, (byte)0x11 + }; + + static byte[] privKeyEnc3 = + { + (byte)0x30, (byte)0x82, (byte)0x02, (byte)0x75, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x30, + (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, + (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x04, (byte)0x82, + (byte)0x02, (byte)0x5f, (byte)0x30, (byte)0x82, (byte)0x02, (byte)0x5b, (byte)0x02, (byte)0x01, + (byte)0x00, (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xbb, (byte)0xf8, (byte)0x2f, + (byte)0x09, (byte)0x06, (byte)0x82, (byte)0xce, (byte)0x9c, (byte)0x23, (byte)0x38, (byte)0xac, + (byte)0x2b, (byte)0x9d, (byte)0xa8, (byte)0x71, (byte)0xf7, (byte)0x36, (byte)0x8d, (byte)0x07, + (byte)0xee, (byte)0xd4, (byte)0x10, (byte)0x43, (byte)0xa4, (byte)0x40, (byte)0xd6, (byte)0xb6, + (byte)0xf0, (byte)0x74, (byte)0x54, (byte)0xf5, (byte)0x1f, (byte)0xb8, (byte)0xdf, (byte)0xba, + (byte)0xaf, (byte)0x03, (byte)0x5c, (byte)0x02, (byte)0xab, (byte)0x61, (byte)0xea, (byte)0x48, + (byte)0xce, (byte)0xeb, (byte)0x6f, (byte)0xcd, (byte)0x48, (byte)0x76, (byte)0xed, (byte)0x52, + (byte)0x0d, (byte)0x60, (byte)0xe1, (byte)0xec, (byte)0x46, (byte)0x19, (byte)0x71, (byte)0x9d, + (byte)0x8a, (byte)0x5b, (byte)0x8b, (byte)0x80, (byte)0x7f, (byte)0xaf, (byte)0xb8, (byte)0xe0, + (byte)0xa3, (byte)0xdf, (byte)0xc7, (byte)0x37, (byte)0x72, (byte)0x3e, (byte)0xe6, (byte)0xb4, + (byte)0xb7, (byte)0xd9, (byte)0x3a, (byte)0x25, (byte)0x84, (byte)0xee, (byte)0x6a, (byte)0x64, + (byte)0x9d, (byte)0x06, (byte)0x09, (byte)0x53, (byte)0x74, (byte)0x88, (byte)0x34, (byte)0xb2, + (byte)0x45, (byte)0x45, (byte)0x98, (byte)0x39, (byte)0x4e, (byte)0xe0, (byte)0xaa, (byte)0xb1, + (byte)0x2d, (byte)0x7b, (byte)0x61, (byte)0xa5, (byte)0x1f, (byte)0x52, (byte)0x7a, (byte)0x9a, + (byte)0x41, (byte)0xf6, (byte)0xc1, (byte)0x68, (byte)0x7f, (byte)0xe2, (byte)0x53, (byte)0x72, + (byte)0x98, (byte)0xca, (byte)0x2a, (byte)0x8f, (byte)0x59, (byte)0x46, (byte)0xf8, (byte)0xe5, + (byte)0xfd, (byte)0x09, (byte)0x1d, (byte)0xbd, (byte)0xcb, (byte)0x02, (byte)0x01, (byte)0x11, + (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xa5, (byte)0xda, (byte)0xfc, (byte)0x53, + (byte)0x41, (byte)0xfa, (byte)0xf2, (byte)0x89, (byte)0xc4, (byte)0xb9, (byte)0x88, (byte)0xdb, + (byte)0x30, (byte)0xc1, (byte)0xcd, (byte)0xf8, (byte)0x3f, (byte)0x31, (byte)0x25, (byte)0x1e, + (byte)0x06, (byte)0x68, (byte)0xb4, (byte)0x27, (byte)0x84, (byte)0x81, (byte)0x38, (byte)0x01, + (byte)0x57, (byte)0x96, (byte)0x41, (byte)0xb2, (byte)0x94, (byte)0x10, (byte)0xb3, (byte)0xc7, + (byte)0x99, (byte)0x8d, (byte)0x6b, (byte)0xc4, (byte)0x65, (byte)0x74, (byte)0x5e, (byte)0x5c, + (byte)0x39, (byte)0x26, (byte)0x69, (byte)0xd6, (byte)0x87, (byte)0x0d, (byte)0xa2, (byte)0xc0, + (byte)0x82, (byte)0xa9, (byte)0x39, (byte)0xe3, (byte)0x7f, (byte)0xdc, (byte)0xb8, (byte)0x2e, + (byte)0xc9, (byte)0x3e, (byte)0xda, (byte)0xc9, (byte)0x7f, (byte)0xf3, (byte)0xad, (byte)0x59, + (byte)0x50, (byte)0xac, (byte)0xcf, (byte)0xbc, (byte)0x11, (byte)0x1c, (byte)0x76, (byte)0xf1, + (byte)0xa9, (byte)0x52, (byte)0x94, (byte)0x44, (byte)0xe5, (byte)0x6a, (byte)0xaf, (byte)0x68, + (byte)0xc5, (byte)0x6c, (byte)0x09, (byte)0x2c, (byte)0xd3, (byte)0x8d, (byte)0xc3, (byte)0xbe, + (byte)0xf5, (byte)0xd2, (byte)0x0a, (byte)0x93, (byte)0x99, (byte)0x26, (byte)0xed, (byte)0x4f, + (byte)0x74, (byte)0xa1, (byte)0x3e, (byte)0xdd, (byte)0xfb, (byte)0xe1, (byte)0xa1, (byte)0xce, + (byte)0xcc, (byte)0x48, (byte)0x94, (byte)0xaf, (byte)0x94, (byte)0x28, (byte)0xc2, (byte)0xb7, + (byte)0xb8, (byte)0x88, (byte)0x3f, (byte)0xe4, (byte)0x46, (byte)0x3a, (byte)0x4b, (byte)0xc8, + (byte)0x5b, (byte)0x1c, (byte)0xb3, (byte)0xc1, (byte)0x02, (byte)0x41, (byte)0x00, (byte)0xee, + (byte)0xcf, (byte)0xae, (byte)0x81, (byte)0xb1, (byte)0xb9, (byte)0xb3, (byte)0xc9, (byte)0x08, + (byte)0x81, (byte)0x0b, (byte)0x10, (byte)0xa1, (byte)0xb5, (byte)0x60, (byte)0x01, (byte)0x99, + (byte)0xeb, (byte)0x9f, (byte)0x44, (byte)0xae, (byte)0xf4, (byte)0xfd, (byte)0xa4, (byte)0x93, + (byte)0xb8, (byte)0x1a, (byte)0x9e, (byte)0x3d, (byte)0x84, (byte)0xf6, (byte)0x32, (byte)0x12, + (byte)0x4e, (byte)0xf0, (byte)0x23, (byte)0x6e, (byte)0x5d, (byte)0x1e, (byte)0x3b, (byte)0x7e, + (byte)0x28, (byte)0xfa, (byte)0xe7, (byte)0xaa, (byte)0x04, (byte)0x0a, (byte)0x2d, (byte)0x5b, + (byte)0x25, (byte)0x21, (byte)0x76, (byte)0x45, (byte)0x9d, (byte)0x1f, (byte)0x39, (byte)0x75, + (byte)0x41, (byte)0xba, (byte)0x2a, (byte)0x58, (byte)0xfb, (byte)0x65, (byte)0x99, (byte)0x02, + (byte)0x41, (byte)0x00, (byte)0xc9, (byte)0x7f, (byte)0xb1, (byte)0xf0, (byte)0x27, (byte)0xf4, + (byte)0x53, (byte)0xf6, (byte)0x34, (byte)0x12, (byte)0x33, (byte)0xea, (byte)0xaa, (byte)0xd1, + (byte)0xd9, (byte)0x35, (byte)0x3f, (byte)0x6c, (byte)0x42, (byte)0xd0, (byte)0x88, (byte)0x66, + (byte)0xb1, (byte)0xd0, (byte)0x5a, (byte)0x0f, (byte)0x20, (byte)0x35, (byte)0x02, (byte)0x8b, + (byte)0x9d, (byte)0x86, (byte)0x98, (byte)0x40, (byte)0xb4, (byte)0x16, (byte)0x66, (byte)0xb4, + (byte)0x2e, (byte)0x92, (byte)0xea, (byte)0x0d, (byte)0xa3, (byte)0xb4, (byte)0x32, (byte)0x04, + (byte)0xb5, (byte)0xcf, (byte)0xce, (byte)0x33, (byte)0x52, (byte)0x52, (byte)0x4d, (byte)0x04, + (byte)0x16, (byte)0xa5, (byte)0xa4, (byte)0x41, (byte)0xe7, (byte)0x00, (byte)0xaf, (byte)0x46, + (byte)0x15, (byte)0x03, (byte)0x02, (byte)0x40, (byte)0x54, (byte)0x49, (byte)0x4c, (byte)0xa6, + (byte)0x3e, (byte)0xba, (byte)0x03, (byte)0x37, (byte)0xe4, (byte)0xe2, (byte)0x40, (byte)0x23, + (byte)0xfc, (byte)0xd6, (byte)0x9a, (byte)0x5a, (byte)0xeb, (byte)0x07, (byte)0xdd, (byte)0xdc, + (byte)0x01, (byte)0x83, (byte)0xa4, (byte)0xd0, (byte)0xac, (byte)0x9b, (byte)0x54, (byte)0xb0, + (byte)0x51, (byte)0xf2, (byte)0xb1, (byte)0x3e, (byte)0xd9, (byte)0x49, (byte)0x09, (byte)0x75, + (byte)0xea, (byte)0xb7, (byte)0x74, (byte)0x14, (byte)0xff, (byte)0x59, (byte)0xc1, (byte)0xf7, + (byte)0x69, (byte)0x2e, (byte)0x9a, (byte)0x2e, (byte)0x20, (byte)0x2b, (byte)0x38, (byte)0xfc, + (byte)0x91, (byte)0x0a, (byte)0x47, (byte)0x41, (byte)0x74, (byte)0xad, (byte)0xc9, (byte)0x3c, + (byte)0x1f, (byte)0x67, (byte)0xc9, (byte)0x81, (byte)0x02, (byte)0x40, (byte)0x47, (byte)0x1e, + (byte)0x02, (byte)0x90, (byte)0xff, (byte)0x0a, (byte)0xf0, (byte)0x75, (byte)0x03, (byte)0x51, + (byte)0xb7, (byte)0xf8, (byte)0x78, (byte)0x86, (byte)0x4c, (byte)0xa9, (byte)0x61, (byte)0xad, + (byte)0xbd, (byte)0x3a, (byte)0x8a, (byte)0x7e, (byte)0x99, (byte)0x1c, (byte)0x5c, (byte)0x05, + (byte)0x56, (byte)0xa9, (byte)0x4c, (byte)0x31, (byte)0x46, (byte)0xa7, (byte)0xf9, (byte)0x80, + (byte)0x3f, (byte)0x8f, (byte)0x6f, (byte)0x8a, (byte)0xe3, (byte)0x42, (byte)0xe9, (byte)0x31, + (byte)0xfd, (byte)0x8a, (byte)0xe4, (byte)0x7a, (byte)0x22, (byte)0x0d, (byte)0x1b, (byte)0x99, + (byte)0xa4, (byte)0x95, (byte)0x84, (byte)0x98, (byte)0x07, (byte)0xfe, (byte)0x39, (byte)0xf9, + (byte)0x24, (byte)0x5a, (byte)0x98, (byte)0x36, (byte)0xda, (byte)0x3d, (byte)0x02, (byte)0x41, + (byte)0x00, (byte)0xb0, (byte)0x6c, (byte)0x4f, (byte)0xda, (byte)0xbb, (byte)0x63, (byte)0x01, + (byte)0x19, (byte)0x8d, (byte)0x26, (byte)0x5b, (byte)0xdb, (byte)0xae, (byte)0x94, (byte)0x23, + (byte)0xb3, (byte)0x80, (byte)0xf2, (byte)0x71, (byte)0xf7, (byte)0x34, (byte)0x53, (byte)0x88, + (byte)0x50, (byte)0x93, (byte)0x07, (byte)0x7f, (byte)0xcd, (byte)0x39, (byte)0xe2, (byte)0x11, + (byte)0x9f, (byte)0xc9, (byte)0x86, (byte)0x32, (byte)0x15, (byte)0x4f, (byte)0x58, (byte)0x83, + (byte)0xb1, (byte)0x67, (byte)0xa9, (byte)0x67, (byte)0xbf, (byte)0x40, (byte)0x2b, (byte)0x4e, + (byte)0x9e, (byte)0x2e, (byte)0x0f, (byte)0x96, (byte)0x56, (byte)0xe6, (byte)0x98, (byte)0xea, + (byte)0x36, (byte)0x66, (byte)0xed, (byte)0xfb, (byte)0x25, (byte)0x79, (byte)0x80, (byte)0x39, + (byte)0xf7 + }; + + static byte[] output3 = Hex.decode( + "b8246b56a6ed5881aeb585d9a25b2ad790c417e080681bf1ac2bc3deb69d8bce" + + "f0c4366fec400af052a72e9b0effb5b3f2f192dbeaca03c12740057113bf1f06" + + "69ac22e9f3a7852e3c15d913cab0b8863a95c99294ce8674214954610346f4d4" + + "74b26f7c48b42ee68e1f572a1fc4026ac456b4f59f7b621ea1b9d88f64202fb1"); + + byte[] seed = { + (byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59, + (byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4, + (byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde, + (byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f + }; + + private class VecRand extends SecureRandom + { + byte[] seed; + + VecRand(byte[] seed) + { + this.seed = seed; + } + + public void nextBytes( + byte[] bytes) + { + System.arraycopy(seed, 0, bytes, 0, bytes.length); + } + } + + private void baseOaepTest( + int id, + byte[] pubKeyEnc, + byte[] privKeyEnc, + byte[] output) + throws Exception + { + ByteArrayInputStream bIn = new ByteArrayInputStream(pubKeyEnc); + ASN1InputStream dIn = new ASN1InputStream(bIn); + + // + // extract the public key info. + // + RSAPublicKey pubStruct; + + pubStruct = RSAPublicKey.getInstance(new SubjectPublicKeyInfo((ASN1Sequence)dIn.readObject()).parsePublicKey()); + + + bIn = new ByteArrayInputStream(privKeyEnc); + dIn = new ASN1InputStream(bIn); + + // + // extract the private key info. + // + RSAPrivateKey privStruct; + + privStruct = RSAPrivateKey.getInstance(new PrivateKeyInfo((ASN1Sequence)dIn.readObject()).parsePrivateKey()); + + RSAKeyParameters pubParameters = new RSAKeyParameters( + false, + pubStruct.getModulus(), + pubStruct.getPublicExponent()); + + RSAKeyParameters privParameters = new RSAPrivateCrtKeyParameters( + privStruct.getModulus(), + privStruct.getPublicExponent(), + privStruct.getPrivateExponent(), + privStruct.getPrime1(), + privStruct.getPrime2(), + privStruct.getExponent1(), + privStruct.getExponent2(), + privStruct.getCoefficient()); + + byte[] input = new byte[] + { (byte)0x54, (byte)0x85, (byte)0x9b, (byte)0x34, (byte)0x2c, (byte)0x49, (byte)0xea, (byte)0x2a }; + + encDec("id(" + id + ")", pubParameters, privParameters, seed, input, output); + + } + + private void encDec( + String label, + RSAKeyParameters pubParameters, + RSAKeyParameters privParameters, + byte[] seed, + byte[] input, + byte[] output) + throws InvalidCipherTextException + { + AsymmetricBlockCipher cipher = new OAEPEncoding(new RSAEngine()); + + cipher.init(true, new ParametersWithRandom(pubParameters, new VecRand(seed))); + + byte[] out; + + out = cipher.processBlock(input, 0, input.length); + + for (int i = 0; i != output.length; i++) + { + if (out[i] != output[i]) + { + fail(label + " failed encryption"); + } + } + + cipher.init(false, privParameters); + + out = cipher.processBlock(output, 0, output.length); + + for (int i = 0; i != input.length; i++) + { + if (out[i] != input[i]) + { + fail(label + " failed decoding"); + } + } + } + + /* + * RSA vector tests from PKCS#1 page + */ + byte[] modulus_1024 = Hex.decode( + "a8b3b284af8eb50b387034a860f146c4" + + "919f318763cd6c5598c8ae4811a1e0ab" + + "c4c7e0b082d693a5e7fced675cf46685" + + "12772c0cbc64a742c6c630f533c8cc72" + + "f62ae833c40bf25842e984bb78bdbf97" + + "c0107d55bdb662f5c4e0fab9845cb514" + + "8ef7392dd3aaff93ae1e6b667bb3d424" + + "7616d4f5ba10d4cfd226de88d39f16fb"); + + byte[] pubExp_1024 = Hex.decode( + "010001"); + + byte[] privExp_1024 = Hex.decode( + "53339cfdb79fc8466a655c7316aca85c" + + "55fd8f6dd898fdaf119517ef4f52e8fd" + + "8e258df93fee180fa0e4ab29693cd83b" + + "152a553d4ac4d1812b8b9fa5af0e7f55" + + "fe7304df41570926f3311f15c4d65a73" + + "2c483116ee3d3d2d0af3549ad9bf7cbf" + + "b78ad884f84d5beb04724dc7369b31de" + + "f37d0cf539e9cfcdd3de653729ead5d1"); + + byte[] prime1_1024 = Hex.decode( + "d32737e7267ffe1341b2d5c0d150a81b" + + "586fb3132bed2f8d5262864a9cb9f30a" + + "f38be448598d413a172efb802c21acf1" + + "c11c520c2f26a471dcad212eac7ca39d"); + + byte[] prime2_1024 = Hex.decode( + "cc8853d1d54da630fac004f471f281c7" + + "b8982d8224a490edbeb33d3e3d5cc93c" + + "4765703d1dd791642f1f116a0dd852be" + + "2419b2af72bfe9a030e860b0288b5d77"); + + byte[] primeExp1_1024 = Hex.decode( + "0e12bf1718e9cef5599ba1c3882fe804" + + "6a90874eefce8f2ccc20e4f2741fb0a3" + + "3a3848aec9c9305fbecbd2d76819967d" + + "4671acc6431e4037968db37878e695c1"); + + byte[] primeExp2_1024 = Hex.decode( + "95297b0f95a2fa67d00707d609dfd4fc" + + "05c89dafc2ef6d6ea55bec771ea33373" + + "4d9251e79082ecda866efef13c459e1a" + + "631386b7e354c899f5f112ca85d71583"); + + byte[] crtCoef_1024 = Hex.decode( + "4f456c502493bdc0ed2ab756a3a6ed4d" + + "67352a697d4216e93212b127a63d5411" + + "ce6fa98d5dbefd73263e372814274381" + + "8166ed7dd63687dd2a8ca1d2f4fbd8e1"); + + byte[] input_1024_1 = Hex.decode( + "6628194e12073db03ba94cda9ef95323" + + "97d50dba79b987004afefe34"); + + byte[] seed_1024_1 = Hex.decode( + "18b776ea21069d69776a33e96bad48e1" + + "dda0a5ef"); + + byte[] output_1024_1 = Hex.decode( + "354fe67b4a126d5d35fe36c777791a3f" + + "7ba13def484e2d3908aff722fad468fb" + + "21696de95d0be911c2d3174f8afcc201" + + "035f7b6d8e69402de5451618c21a535f" + + "a9d7bfc5b8dd9fc243f8cf927db31322" + + "d6e881eaa91a996170e657a05a266426" + + "d98c88003f8477c1227094a0d9fa1e8c" + + "4024309ce1ecccb5210035d47ac72e8a"); + + byte[] input_1024_2 = Hex.decode( + "750c4047f547e8e41411856523298ac9" + + "bae245efaf1397fbe56f9dd5"); + + byte[] seed_1024_2 = Hex.decode( + "0cc742ce4a9b7f32f951bcb251efd925" + + "fe4fe35f"); + + byte[] output_1024_2 = Hex.decode( + "640db1acc58e0568fe5407e5f9b701df" + + "f8c3c91e716c536fc7fcec6cb5b71c11" + + "65988d4a279e1577d730fc7a29932e3f" + + "00c81515236d8d8e31017a7a09df4352" + + "d904cdeb79aa583adcc31ea698a4c052" + + "83daba9089be5491f67c1a4ee48dc74b" + + "bbe6643aef846679b4cb395a352d5ed1" + + "15912df696ffe0702932946d71492b44"); + + byte[] input_1024_3 = Hex.decode( + "d94ae0832e6445ce42331cb06d531a82" + + "b1db4baad30f746dc916df24d4e3c245" + + "1fff59a6423eb0e1d02d4fe646cf699d" + + "fd818c6e97b051"); + + byte[] seed_1024_3 = Hex.decode( + "2514df4695755a67b288eaf4905c36ee" + + "c66fd2fd"); + + byte[] output_1024_3 = Hex.decode( + "423736ed035f6026af276c35c0b3741b" + + "365e5f76ca091b4e8c29e2f0befee603" + + "595aa8322d602d2e625e95eb81b2f1c9" + + "724e822eca76db8618cf09c5343503a4" + + "360835b5903bc637e3879fb05e0ef326" + + "85d5aec5067cd7cc96fe4b2670b6eac3" + + "066b1fcf5686b68589aafb7d629b02d8" + + "f8625ca3833624d4800fb081b1cf94eb"); + + byte[] input_1024_4 = Hex.decode( + "52e650d98e7f2a048b4f86852153b97e" + + "01dd316f346a19f67a85"); + + byte[] seed_1024_4 = Hex.decode( + "c4435a3e1a18a68b6820436290a37cef" + + "b85db3fb"); + + byte[] output_1024_4 = Hex.decode( + "45ead4ca551e662c9800f1aca8283b05" + + "25e6abae30be4b4aba762fa40fd3d38e" + + "22abefc69794f6ebbbc05ddbb1121624" + + "7d2f412fd0fba87c6e3acd888813646f" + + "d0e48e785204f9c3f73d6d8239562722" + + "dddd8771fec48b83a31ee6f592c4cfd4" + + "bc88174f3b13a112aae3b9f7b80e0fc6" + + "f7255ba880dc7d8021e22ad6a85f0755"); + + byte[] input_1024_5 = Hex.decode( + "8da89fd9e5f974a29feffb462b49180f" + + "6cf9e802"); + + byte[] seed_1024_5 = Hex.decode( + "b318c42df3be0f83fea823f5a7b47ed5" + + "e425a3b5"); + + byte[] output_1024_5 = Hex.decode( + "36f6e34d94a8d34daacba33a2139d00a" + + "d85a9345a86051e73071620056b920e2" + + "19005855a213a0f23897cdcd731b4525" + + "7c777fe908202befdd0b58386b1244ea" + + "0cf539a05d5d10329da44e13030fd760" + + "dcd644cfef2094d1910d3f433e1c7c6d" + + "d18bc1f2df7f643d662fb9dd37ead905" + + "9190f4fa66ca39e869c4eb449cbdc439"); + + byte[] input_1024_6 = Hex.decode( + "26521050844271"); + + byte[] seed_1024_6 = Hex.decode( + "e4ec0982c2336f3a677f6a356174eb0c" + + "e887abc2"); + + byte[] output_1024_6 = Hex.decode( + "42cee2617b1ecea4db3f4829386fbd61" + + "dafbf038e180d837c96366df24c097b4" + + "ab0fac6bdf590d821c9f10642e681ad0" + + "5b8d78b378c0f46ce2fad63f74e0ad3d" + + "f06b075d7eb5f5636f8d403b9059ca76" + + "1b5c62bb52aa45002ea70baace08ded2" + + "43b9d8cbd62a68ade265832b56564e43" + + "a6fa42ed199a099769742df1539e8255"); + + byte[] modulus_1027 = Hex.decode( + "051240b6cc0004fa48d0134671c078c7" + + "c8dec3b3e2f25bc2564467339db38853" + + "d06b85eea5b2de353bff42ac2e46bc97" + + "fae6ac9618da9537a5c8f553c1e35762" + + "5991d6108dcd7885fb3a25413f53efca" + + "d948cb35cd9b9ae9c1c67626d113d57d" + + "de4c5bea76bb5bb7de96c00d07372e96" + + "85a6d75cf9d239fa148d70931b5f3fb0" + + "39"); + + byte[] pubExp_1027 = Hex.decode( + "010001"); + + byte[] privExp_1027 = Hex.decode( + "0411ffca3b7ca5e9e9be7fe38a85105e" + + "353896db05c5796aecd2a725161eb365" + + "1c8629a9b862b904d7b0c7b37f8cb5a1" + + "c2b54001018a00a1eb2cafe4ee4e9492" + + "c348bc2bedab4b9ebbf064e8eff322b9" + + "009f8eec653905f40df88a3cdc49d456" + + "7f75627d41aca624129b46a0b7c698e5" + + "e65f2b7ba102c749a10135b6540d0401"); + + byte[] prime1_1027 = Hex.decode( + "027458c19ec1636919e736c9af25d609" + + "a51b8f561d19c6bf6943dd1ee1ab8a4a" + + "3f232100bd40b88decc6ba235548b6ef" + + "792a11c9de823d0a7922c7095b6eba57" + + "01"); + + byte[] prime2_1027 = Hex.decode( + "0210ee9b33ab61716e27d251bd465f4b" + + "35a1a232e2da00901c294bf22350ce49" + + "0d099f642b5375612db63ba1f2038649" + + "2bf04d34b3c22bceb909d13441b53b51" + + "39"); + + byte[] primeExp1_1027 = Hex.decode( + "39fa028b826e88c1121b750a8b242fa9" + + "a35c5b66bdfd1fa637d3cc48a84a4f45" + + "7a194e7727e49f7bcc6e5a5a412657fc" + + "470c7322ebc37416ef458c307a8c0901"); + + byte[] primeExp2_1027 = Hex.decode( + "015d99a84195943979fa9e1be2c3c1b6" + + "9f432f46fd03e47d5befbbbfd6b1d137" + + "1d83efb330a3e020942b2fed115e5d02" + + "be24fd92c9019d1cecd6dd4cf1e54cc8" + + "99"); + + byte[] crtCoef_1027 = Hex.decode( + "01f0b7015170b3f5e42223ba30301c41" + + "a6d87cbb70e30cb7d3c67d25473db1f6" + + "cbf03e3f9126e3e97968279a865b2c2b" + + "426524cfc52a683d31ed30eb984be412" + + "ba"); + + byte[] input_1027_1 = Hex.decode( + "4a86609534ee434a6cbca3f7e962e76d" + + "455e3264c19f605f6e5ff6137c65c56d" + + "7fb344cd52bc93374f3d166c9f0c6f9c" + + "506bad19330972d2"); + + byte[] seed_1027_1 = Hex.decode( + "1cac19ce993def55f98203f6852896c9" + + "5ccca1f3"); + + byte[] output_1027_1 = Hex.decode( + "04cce19614845e094152a3fe18e54e33" + + "30c44e5efbc64ae16886cb1869014cc5" + + "781b1f8f9e045384d0112a135ca0d12e" + + "9c88a8e4063416deaae3844f60d6e96f" + + "e155145f4525b9a34431ca3766180f70" + + "e15a5e5d8e8b1a516ff870609f13f896" + + "935ced188279a58ed13d07114277d75c" + + "6568607e0ab092fd803a223e4a8ee0b1" + + "a8"); + + byte[] input_1027_2 = Hex.decode( + "b0adc4f3fe11da59ce992773d9059943" + + "c03046497ee9d9f9a06df1166db46d98" + + "f58d27ec074c02eee6cbe2449c8b9fc5" + + "080c5c3f4433092512ec46aa793743c8"); + + byte[] seed_1027_2 = Hex.decode( + "f545d5897585e3db71aa0cb8da76c51d" + + "032ae963"); + + byte[] output_1027_2 = Hex.decode( + "0097b698c6165645b303486fbf5a2a44" + + "79c0ee85889b541a6f0b858d6b6597b1" + + "3b854eb4f839af03399a80d79bda6578" + + "c841f90d645715b280d37143992dd186" + + "c80b949b775cae97370e4ec97443136c" + + "6da484e970ffdb1323a20847821d3b18" + + "381de13bb49aaea66530c4a4b8271f3e" + + "ae172cd366e07e6636f1019d2a28aed1" + + "5e"); + + byte[] input_1027_3 = Hex.decode( + "bf6d42e701707b1d0206b0c8b45a1c72" + + "641ff12889219a82bdea965b5e79a96b" + + "0d0163ed9d578ec9ada20f2fbcf1ea3c" + + "4089d83419ba81b0c60f3606da99"); + + byte[] seed_1027_3 = Hex.decode( + "ad997feef730d6ea7be60d0dc52e72ea" + + "cbfdd275"); + + byte[] output_1027_3 = Hex.decode( + "0301f935e9c47abcb48acbbe09895d9f" + + "5971af14839da4ff95417ee453d1fd77" + + "319072bb7297e1b55d7561cd9d1bb24c" + + "1a9a37c619864308242804879d86ebd0" + + "01dce5183975e1506989b70e5a834341" + + "54d5cbfd6a24787e60eb0c658d2ac193" + + "302d1192c6e622d4a12ad4b53923bca2" + + "46df31c6395e37702c6a78ae081fb9d0" + + "65"); + + byte[] input_1027_4 = Hex.decode( + "fb2ef112f5e766eb94019297934794f7" + + "be2f6fc1c58e"); + + byte[] seed_1027_4 = Hex.decode( + "136454df5730f73c807a7e40d8c1a312" + + "ac5b9dd3"); + + byte[] output_1027_4 = Hex.decode( + "02d110ad30afb727beb691dd0cf17d0a" + + "f1a1e7fa0cc040ec1a4ba26a42c59d0a" + + "796a2e22c8f357ccc98b6519aceb682e" + + "945e62cb734614a529407cd452bee3e4" + + "4fece8423cc19e55548b8b994b849c7e" + + "cde4933e76037e1d0ce44275b08710c6" + + "8e430130b929730ed77e09b015642c55" + + "93f04e4ffb9410798102a8e96ffdfe11" + + "e4"); + + byte[] input_1027_5 = Hex.decode( + "28ccd447bb9e85166dabb9e5b7d1adad" + + "c4b9d39f204e96d5e440ce9ad928bc1c" + + "2284"); + + byte[] seed_1027_5 = Hex.decode( + "bca8057f824b2ea257f2861407eef63d" + + "33208681"); + + byte[] output_1027_5 = Hex.decode( + "00dbb8a7439d90efd919a377c54fae8f" + + "e11ec58c3b858362e23ad1b8a4431079" + + "9066b99347aa525691d2adc58d9b06e3" + + "4f288c170390c5f0e11c0aa3645959f1" + + "8ee79e8f2be8d7ac5c23d061f18dd74b" + + "8c5f2a58fcb5eb0c54f99f01a8324756" + + "8292536583340948d7a8c97c4acd1e98" + + "d1e29dc320e97a260532a8aa7a758a1e" + + "c2"); + + byte[] input_1027_6 = Hex.decode( + "f22242751ec6b1"); + + byte[] seed_1027_6 = Hex.decode( + "2e7e1e17f647b5ddd033e15472f90f68" + + "12f3ac4e"); + + byte[] output_1027_6 = Hex.decode( + "00a5ffa4768c8bbecaee2db77e8f2eec" + + "99595933545520835e5ba7db9493d3e1" + + "7cddefe6a5f567624471908db4e2d83a" + + "0fbee60608fc84049503b2234a07dc83" + + "b27b22847ad8920ff42f674ef79b7628" + + "0b00233d2b51b8cb2703a9d42bfbc825" + + "0c96ec32c051e57f1b4ba528db89c37e" + + "4c54e27e6e64ac69635ae887d9541619" + + "a9"); + + private void oaepVecTest( + int keySize, + int no, + RSAKeyParameters pubParam, + RSAKeyParameters privParam, + byte[] seed, + byte[] input, + byte[] output) + throws Exception + { + encDec(keySize + " " + no, pubParam, privParam, seed, input, output); + } + + public OAEPTest() + { + } + + public String getName() + { + return "OAEP"; + } + + public void performTest() throws Exception + { + baseOaepTest(1, pubKeyEnc1, privKeyEnc1, output1); + baseOaepTest(2, pubKeyEnc2, privKeyEnc2, output2); + baseOaepTest(3, pubKeyEnc3, privKeyEnc3, output3); + + RSAKeyParameters pubParam = new RSAKeyParameters(false, new BigInteger(1, modulus_1024), new BigInteger(1, pubExp_1024)); + RSAKeyParameters privParam = new RSAPrivateCrtKeyParameters(pubParam.getModulus(), pubParam.getExponent(), new BigInteger(1, privExp_1024), new BigInteger(1, prime1_1024), new BigInteger(1, prime2_1024), new BigInteger(1, primeExp1_1024), new BigInteger(1, primeExp2_1024), new BigInteger(1, crtCoef_1024)); + + oaepVecTest(1024, 1, pubParam, privParam, seed_1024_1, input_1024_1, output_1024_1); + oaepVecTest(1024, 2, pubParam, privParam, seed_1024_2, input_1024_2, output_1024_2); + oaepVecTest(1024, 3, pubParam, privParam, seed_1024_3, input_1024_3, output_1024_3); + oaepVecTest(1024, 4, pubParam, privParam, seed_1024_4, input_1024_4, output_1024_4); + oaepVecTest(1024, 5, pubParam, privParam, seed_1024_5, input_1024_5, output_1024_5); + oaepVecTest(1024, 6, pubParam, privParam, seed_1024_6, input_1024_6, output_1024_6); + + pubParam = new RSAKeyParameters(false, new BigInteger(1, modulus_1027), new BigInteger(1, pubExp_1027)); + privParam = new RSAPrivateCrtKeyParameters(pubParam.getModulus(), pubParam.getExponent(), new BigInteger(1, privExp_1027), new BigInteger(1, prime1_1027), new BigInteger(1, prime2_1027), new BigInteger(1, primeExp1_1027), new BigInteger(1, primeExp2_1027), new BigInteger(1, crtCoef_1027)); + + oaepVecTest(1027, 1, pubParam, privParam, seed_1027_1, input_1027_1, output_1027_1); + oaepVecTest(1027, 2, pubParam, privParam, seed_1027_2, input_1027_2, output_1027_2); + oaepVecTest(1027, 3, pubParam, privParam, seed_1027_3, input_1027_3, output_1027_3); + oaepVecTest(1027, 4, pubParam, privParam, seed_1027_4, input_1027_4, output_1027_4); + oaepVecTest(1027, 5, pubParam, privParam, seed_1027_5, input_1027_5, output_1027_5); + oaepVecTest(1027, 6, pubParam, privParam, seed_1027_6, input_1027_6, output_1027_6); + + // + // OAEP - public encrypt, private decrypt differring hashes + // + AsymmetricBlockCipher cipher = new OAEPEncoding(new RSAEngine(), new SHA256Digest(), new SHA1Digest(), new byte[10]); + + cipher.init(true, new ParametersWithRandom(pubParam, new SecureRandom())); + + byte[] input = new byte[10]; + + byte[] out = cipher.processBlock(input, 0, input.length); + + cipher.init(false, privParam); + + out = cipher.processBlock(out, 0, out.length); + + for (int i = 0; i != input.length; i++) + { + if (out[i] != input[i]) + { + fail("mixed digest failed decoding"); + } + } + + cipher = new OAEPEncoding(new RSAEngine(), new SHA1Digest(), new SHA256Digest(), new byte[10]); + + cipher.init(true, new ParametersWithRandom(pubParam, new SecureRandom())); + + out = cipher.processBlock(input, 0, input.length); + + cipher.init(false, privParam); + + out = cipher.processBlock(out, 0, out.length); + + for (int i = 0; i != input.length; i++) + { + if (out[i] != input[i]) + { + fail("mixed digest failed decoding"); + } + } + } + + public static void main( + String[] args) + { + runTest(new OAEPTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/OCBTest.java b/core/src/test/java/org/spongycastle/crypto/test/OCBTest.java new file mode 100644 index 00000000..8596e304 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/OCBTest.java @@ -0,0 +1,520 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.AESEngine; +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.Times; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Test vectors from <a href="http://tools.ietf.org/html/rfc7253">RFC 7253 on The OCB + * Authenticated-Encryption Algorithm</a> + */ +public class OCBTest + extends SimpleTest +{ + private static final String KEY_128 = "000102030405060708090A0B0C0D0E0F"; + private static final String KEY_96 = "0F0E0D0C0B0A09080706050403020100"; + + /* + * Test vectors from Appendix A of the specification, containing the strings N, A, P, C in order + */ + + private static final String[][] TEST_VECTORS_128 = new String[][]{ + { "BBAA99887766554433221100", + "", + "", + "785407BFFFC8AD9EDCC5520AC9111EE6" }, + { "BBAA99887766554433221101", + "0001020304050607", + "0001020304050607", + "6820B3657B6F615A5725BDA0D3B4EB3A257C9AF1F8F03009" }, + { "BBAA99887766554433221102", + "0001020304050607", + "", + "81017F8203F081277152FADE694A0A00" }, + { "BBAA99887766554433221103", + "", + "0001020304050607", + "45DD69F8F5AAE72414054CD1F35D82760B2CD00D2F99BFA9" }, + { "BBAA99887766554433221104", + "000102030405060708090A0B0C0D0E0F", + "000102030405060708090A0B0C0D0E0F", + "571D535B60B277188BE5147170A9A22C3AD7A4FF3835B8C5701C1CCEC8FC3358" }, + { "BBAA99887766554433221105", + "000102030405060708090A0B0C0D0E0F", + "", + "8CF761B6902EF764462AD86498CA6B97" }, + { "BBAA99887766554433221106", + "", + "000102030405060708090A0B0C0D0E0F", + "5CE88EC2E0692706A915C00AEB8B2396F40E1C743F52436BDF06D8FA1ECA343D" }, + { "BBAA99887766554433221107", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "1CA2207308C87C010756104D8840CE1952F09673A448A122C92C62241051F57356D7F3C90BB0E07F" }, + { "BBAA99887766554433221108", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "", + "6DC225A071FC1B9F7C69F93B0F1E10DE" }, + { "BBAA99887766554433221109", + "", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3CE725F32494B9F914D85C0B1EB38357FF" }, + { "BBAA9988776655443322110A", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "BD6F6C496201C69296C11EFD138A467ABD3C707924B964DEAFFC40319AF5A48540FBBA186C5553C68AD9F592A79A4240" }, + { "BBAA9988776655443322110B", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "", + "FE80690BEE8A485D11F32965BC9D2A32" }, + { "BBAA9988776655443322110C", + "", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF46040C53F1432BCDFB5E1DDE3BC18A5F840B52E653444D5DF" }, + { "BBAA9988776655443322110D", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "D5CA91748410C1751FF8A2F618255B68A0A12E093FF454606E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483A7035490C5769E60" }, + { "BBAA9988776655443322110E", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "", + "C5CD9D1850C141E358649994EE701B68" }, + { "BBAA9988776655443322110F", + "", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15A5DDBFC5787E50B5CC55EE507BCB084E479AD363AC366B95A98CA5F3000B1479" }, + }; + + private static final String[][] TEST_VECTORS_96 = new String[][]{ + { "BBAA9988776655443322110D", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FDAC4F02AA" }, + }; + + public String getName() + { + return "OCB"; + } + + public void performTest() + throws Exception + { + byte[] K128 = Hex.decode(KEY_128); + for (int i = 0; i < TEST_VECTORS_128.length; ++i) + { + runTestCase("Test Case " + i, TEST_VECTORS_128[i], 128, K128); + } + + byte[] K96 = Hex.decode(KEY_96); + for (int i = 0; i < TEST_VECTORS_96.length; ++i) + { + runTestCase("Test Case " + i, TEST_VECTORS_96[i], 96, K96); + } + + 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(); + testExceptions(); + } + + private void testExceptions() throws InvalidCipherTextException + { + AEADBlockCipher ocb = createOCBCipher(); + + 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, createOCBCipher(), createOCBCipher(), 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])); + AEADTestUtil.testOutputSizes(this, createOCBCipher(), new AEADParameters(new KeyParameter(new byte[16]), 128, + new byte[15])); + AEADTestUtil.testBufferSizeChecks(this, createOCBCipher(), new AEADParameters(new KeyParameter(new byte[16]), + 128, new byte[15])); + } + + private void runTestCase(String testName, String[] testVector, int macLengthBits, byte[] K) + throws InvalidCipherTextException + { + int pos = 0; + byte[] N = Hex.decode(testVector[pos++]); + byte[] A = Hex.decode(testVector[pos++]); + byte[] P = Hex.decode(testVector[pos++]); + byte[] C = Hex.decode(testVector[pos++]); + + int macLengthBytes = macLengthBits / 8; + + KeyParameter keyParameter = new KeyParameter(K); + AEADParameters parameters = new AEADParameters(keyParameter, macLengthBits, N, A); + + AEADBlockCipher encCipher = initOCBCipher(true, parameters); + AEADBlockCipher decCipher = initOCBCipher(false, parameters); + + checkTestCase(encCipher, decCipher, testName, macLengthBytes, P, C); + checkTestCase(encCipher, decCipher, testName + " (reused)", macLengthBytes, P, C); + + // Key reuse + AEADParameters keyReuseParams = AEADTestUtil.reuseKey(parameters); + encCipher.init(true, keyReuseParams); + decCipher.init(false, keyReuseParams); + checkTestCase(encCipher, decCipher, testName + " (key reuse)", macLengthBytes, P, C); + } + + private BlockCipher createUnderlyingCipher() + { + return new AESEngine(); + } + + private AEADBlockCipher createOCBCipher() + { + return new OCBBlockCipher(createUnderlyingCipher(), createUnderlyingCipher()); + } + + private AEADBlockCipher initOCBCipher(boolean forEncryption, AEADParameters parameters) + { + AEADBlockCipher c = createOCBCipher(); + c.init(forEncryption, parameters); + return c; + } + + private void checkTestCase(AEADBlockCipher encCipher, AEADBlockCipher 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 keyLen, int tagLen, String expectedOutputHex) + throws InvalidCipherTextException + { + byte[] expectedOutput = Hex.decode(expectedOutputHex); + byte[] keyBytes = new byte[keyLen / 8]; + keyBytes[keyBytes.length - 1] = (byte)tagLen; + KeyParameter key = new KeyParameter(keyBytes); + + AEADBlockCipher c1 = initOCBCipher(true, new AEADParameters(key, tagLen, createNonce(385))); + AEADBlockCipher c2 = createOCBCipher(); + + long total = 0; + + byte[] S = new byte[128]; + + int n = 0; + for (int i = 0; i < 128; ++i) + { + c2.init(true, new AEADParameters(key, tagLen, createNonce(++n))); + total += updateCiphers(c1, c2, S, i, true, true); + c2.init(true, new AEADParameters(key, tagLen, createNonce(++n))); + total += updateCiphers(c1, c2, S, i, false, true); + c2.init(true, new AEADParameters(key, tagLen, createNonce(++n))); + 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 byte[] createNonce(int n) + { + return new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)(n >>> 8), (byte)n }; + } + + 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; + } + + private void randomTests() + throws InvalidCipherTextException + { + SecureRandom srng = new SecureRandom(); + srng.setSeed(Times.nanoTime()); + for (int i = 0; i < 10; ++i) + { + randomTest(srng); + } + } + + private void randomTest(SecureRandom srng) + throws InvalidCipherTextException + { + int kLength = 16 + 8 * (Math.abs(srng.nextInt()) % 3); + byte[] K = new byte[kLength]; + srng.nextBytes(K); + + int pLength = srng.nextInt() >>> 16; + byte[] P = new byte[pLength]; + srng.nextBytes(P); + + int aLength = srng.nextInt() >>> 24; + byte[] A = new byte[aLength]; + srng.nextBytes(A); + + int saLength = 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); + AEADBlockCipher 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]; + System.arraycopy(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, AEADTestUtil.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); + AEADBlockCipher 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)((n * (long)(rand.nextInt() >>> 1)) >> 31); + } + + int bits, value; + do + { + bits = rand.nextInt() >>> 1; + value = bits % n; + } + while (bits - value + (n - 1) < 0); + + return value; + } + + public static void main(String[] args) + { + runTest(new OCBTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/PKCS12Test.java b/core/src/test/java/org/spongycastle/crypto/test/PKCS12Test.java new file mode 100644 index 00000000..5374116a --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/PKCS12Test.java @@ -0,0 +1,206 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.PBEParametersGenerator; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.generators.PKCS12ParametersGenerator; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * test for PKCS12 key generation - vectors from + * <a href=http://www.drh-consultancy.demon.co.uk/test.txt> + * http://www.drh-consultancy.demon.co.uk/test.txt</a> + */ +public class PKCS12Test + implements Test +{ + char[] password1 = { 's', 'm', 'e', 'g' }; + char[] password2 = { 'q', 'u', 'e', 'e', 'g' }; + + private boolean isEqual( + byte[] a, + byte[] b) + { + if (a.length != b.length) + { + return false; + } + + for (int i = 0; i != a.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + private TestResult run1( + int id, + char[] password, + byte[] salt, + int iCount, + byte[] result) + { + PBEParametersGenerator generator = new PKCS12ParametersGenerator( + new SHA1Digest()); + + generator.init( + PBEParametersGenerator.PKCS12PasswordToBytes(password), + salt, + iCount); + + CipherParameters key = generator.generateDerivedParameters(24 * 8); + + if (isEqual(result, ((KeyParameter)key).getKey())) + { + return new SimpleTestResult(true, "PKCS12Test: Okay"); + } + else + { + return new SimpleTestResult(false, "PKCS12Test: id " + + id + " Failed"); + } + } + + private TestResult run2( + int id, + char[] password, + byte[] salt, + int iCount, + byte[] result) + { + PBEParametersGenerator generator = new PKCS12ParametersGenerator( + new SHA1Digest()); + + generator.init( + PBEParametersGenerator.PKCS12PasswordToBytes(password), + salt, + iCount); + + ParametersWithIV params = (ParametersWithIV)generator.generateDerivedParameters(64, 64); + + if (isEqual(result, params.getIV())) + { + return new SimpleTestResult(true, "PKCS12Test: Okay"); + } + else + { + return new SimpleTestResult(false, "PKCS12Test: id " + + id + " Failed"); + } + } + + private TestResult run3( + int id, + char[] password, + byte[] salt, + int iCount, + byte[] result) + { + PBEParametersGenerator generator = new PKCS12ParametersGenerator( + new SHA1Digest()); + + generator.init( + PBEParametersGenerator.PKCS12PasswordToBytes(password), + salt, + iCount); + + CipherParameters key = generator.generateDerivedMacParameters(160); + + if (isEqual(result, ((KeyParameter)key).getKey())) + { + return new SimpleTestResult(true, "PKCS12Test: Okay"); + } + else + { + return new SimpleTestResult(false, "PKCS12Test: id " + + id + " Failed"); + } + } + + public String getName() + { + return "PKCS12Test"; + } + + public TestResult perform() + { + TestResult result; + + result = run1(1, password1, Hex.decode("0A58CF64530D823F"), 1, + Hex.decode("8AAAE6297B6CB04642AB5B077851284EB7128F1A2A7FBCA3")); + + if (result.isSuccessful()) + { + result = run2(2, password1, Hex.decode("0A58CF64530D823F"), 1, + Hex.decode("79993DFE048D3B76")); + } + + if (result.isSuccessful()) + { + result = run1(3, password1, Hex.decode("642B99AB44FB4B1F"), 1, + Hex.decode("F3A95FEC48D7711E985CFE67908C5AB79FA3D7C5CAA5D966")); + } + + if (result.isSuccessful()) + { + result = run2(4, password1, Hex.decode("642B99AB44FB4B1F"), 1, + Hex.decode("C0A38D64A79BEA1D")); + } + + if (result.isSuccessful()) + { + result = run3(5, password1, Hex.decode("3D83C0E4546AC140"), 1, + Hex.decode("8D967D88F6CAA9D714800AB3D48051D63F73A312")); + } + + if (result.isSuccessful()) + { + result = run1(6, password2, Hex.decode("05DEC959ACFF72F7"), 1000, + Hex.decode("ED2034E36328830FF09DF1E1A07DD357185DAC0D4F9EB3D4")); + } + + if (result.isSuccessful()) + { + result = run2(7, password2, Hex.decode("05DEC959ACFF72F7"), 1000, + Hex.decode("11DEDAD7758D4860")); + } + + if (result.isSuccessful()) + { + result = run1(8, password2, Hex.decode("1682C0FC5B3F7EC5"), 1000, + Hex.decode("483DD6E919D7DE2E8E648BA8F862F3FBFBDC2BCB2C02957F")); + } + + if (result.isSuccessful()) + { + result = run2(9, password2, Hex.decode("1682C0FC5B3F7EC5"), 1000, + Hex.decode("9D461D1B00355C50")); + } + + if (result.isSuccessful()) + { + result = run3(10, password2, Hex.decode("263216FCC2FAB31C"), 1000, + Hex.decode("5EC4C7A80DF652294C3925B6489A7AB857C83476")); + } + + return result; + } + + public static void main( + String[] args) + { + PKCS12Test test = new PKCS12Test(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/PKCS5Test.java b/core/src/test/java/org/spongycastle/crypto/test/PKCS5Test.java new file mode 100644 index 00000000..66aef5eb --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/PKCS5Test.java @@ -0,0 +1,265 @@ +package org.spongycastle.crypto.test; + +import java.io.ByteArrayInputStream; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import org.spongycastle.asn1.pkcs.EncryptionScheme; +import org.spongycastle.asn1.pkcs.KeyDerivationFunc; +import org.spongycastle.asn1.pkcs.PBES2Parameters; +import org.spongycastle.asn1.pkcs.PBKDF2Params; +import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.spongycastle.asn1.pkcs.RC2CBCParameter; +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.PBEParametersGenerator; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.engines.DESedeEngine; +import org.spongycastle.crypto.engines.RC2Engine; +import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * A test class for PKCS5 PBES2 with PBKDF2 (PKCS5 v2.0) using + * test vectors provider at + * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html> + * RSA's PKCS5 Page</a> + * <br> + * The vectors are Base 64 encoded and encrypted using the password "password" + * (without quotes). They should all yield the same PrivateKeyInfo object. + */ +public class PKCS5Test + extends SimpleTest +{ + /** + * encrypted using des-cbc. + */ + static byte[] sample1 = Base64.decode( + "MIIBozA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIfWBDXwLp4K4CAggA" + + "MBEGBSsOAwIHBAiaCF/AvOgQ6QSCAWDWX4BdAzCRNSQSANSuNsT5X8mWYO27mr3Y" + + "9c9LoBVXGNmYWKA77MI4967f7SmjNcgXj3xNE/jmnVz6hhsjS8E5VPT3kfyVkpdZ" + + "0lr5e9Yk2m3JWpPU7++v5zBkZmC4V/MwV/XuIs6U+vykgzMgpxQg0oZKS9zgmiZo" + + "f/4dOCL0UtCDnyOSvqT7mCVIcMDIEKu8QbVlgZYBop08l60EuEU3gARUo8WsYQmO" + + "Dz/ldx0Z+znIT0SXVuOwc+RVItC5T/Qx+aijmmpt+9l14nmaGBrEkmuhmtdvU/4v" + + "aptewGRgmjOfD6cqK+zs0O5NrrJ3P/6ZSxXj91CQgrThGfOv72bUncXEMNtc8pks" + + "2jpHFjGMdKufnadAD7XuMgzkkaklEXZ4f5tU6heIIwr51g0GBEGF96gYPFnjnSQM" + + "75JE02Clo+DfcfXpcybPTwwFg2jd6JTTOfkdf6OdSlA/1XNK43FA"); + + /** + * encrypted using des-ede3-cbc. + */ + static byte[] sample2 = Base64.decode( + "MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeFeOWl1jywYCAggA" + + "MBQGCCqGSIb3DQMHBAjUJ5eGBhQGtQSCAWBrHrRgqO8UUMLcWzZEtpk1l3mjxiF/" + + "koCMkHsFwowgyWhEbgIkTgbSViK54LVK8PskekcGNLph+rB6bGZ7pPbL5pbXASJ8" + + "+MkQcG3FZdlS4Ek9tTJDApj3O1UubZGFG4uvTlJJFbF1BOJ3MkY3XQ9Gl1qwv7j5" + + "6e103Da7Cq9+oIDKmznza78XXQYrUsPo8mJGjUxPskEYlzwvHjKubRnYm/K6RKhi" + + "5f4zX4BQ/Dt3H812ZjRXrsjAJP0KrD/jyD/jCT7zNBVPH1izBds+RwizyQAHwfNJ" + + "BFR78TH4cgzB619X47FDVOnT0LqQNVd0O3cSwnPrXE9XR3tPayE+iOB15llFSmi8" + + "z0ByOXldEpkezCn92Umk++suzIVj1qfsK+bv2phZWJPbLEIWPDRHUbYf76q5ArAr" + + "u4xtxT/hoK3krEs/IN3d70qjlUJ36SEw1UaZ82PWhakQbdtu39ZraMJB"); + + /** + * encrypted using rc2-cbc. + */ + static byte[] sample3 = Base64.decode( + "MIIBrjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIrHyQPBZqWLUCAggA" + + "AgEQMBkGCCqGSIb3DQMCMA0CAToECEhbh7YZKiPSBIIBYCT1zp6o5jpFlIkgwPop" + + "7bW1+8ACr4exqzkeb3WflQ8cWJ4cURxzVdvxUnXeW1VJdaQZtjS/QHs5GhPTG/0f" + + "wtvnaPfwrIJ3FeGaZfcg2CrYhalOFmEb4xrE4KyoEQmUN8tb/Cg94uzd16BOPw21" + + "RDnE8bnPdIGY7TyL95kbkqH23mK53pi7h+xWIgduW+atIqDyyt55f7WMZcvDvlj6" + + "VpN/V0h+qxBHL274WA4dj6GYgeyUFpi60HdGCK7By2TBy8h1ZvKGjmB9h8jZvkx1" + + "MkbRumXxyFsowTZawyYvO8Um6lbfEDP9zIEUq0IV8RqH2MRyblsPNSikyYhxX/cz" + + "tdDxRKhilySbSBg5Kr8OfcwKp9bpinN96nmG4xr3Tch1bnVvqJzOQ5+Vva2WwVvH" + + "2JkWvYm5WaANg4Q6bRxu9vz7DuhbJjQdZbxFezIAgrJdSe92B00jO/0Kny1WjiVO" + + "6DA="); + + static byte[] result = Hex.decode( + "30820155020100300d06092a864886f70d01010105000482013f3082013b020100024100" + + "debbfc2c09d61bada2a9462f24224e54cc6b3cc0755f15ce318ef57e79df17026b6a85cc" + + "a12428027245045df2052a329a2f9ad3d17b78a10572ad9b22bf343b020301000102402d" + + "90a96adcec472743527bc023153d8f0d6e96b40c8ed228276d467d843306429f8670559b" + + "f376dd41857f6397c2fc8d95e0e53ed62de420b855430ee4a1b8a1022100ffcaf0838239" + + "31e073ff534f06a5d415b3d414bc614a4544a3dff7ed271817eb022100deea30242117db" + + "2d3b8837f58f1da530ff83cf9283680da33683ec4e583610f1022100e6026381adb0a683" + + "f16a8f4c096b462979b9e4277cc89f3ed8a905b46fa9ff9f02210097c146d4d1d2b3dbaf" + + "53a504ff51674c5c271800de84d003f4f10ac6ab36e38102202bfa141f10bda874e1017d" + + "845e82767c1c38e82745daf421f0c8cd09d7652387"); + + private class PBETest + extends SimpleTest + { + int id; + BufferedBlockCipher cipher; + byte[] sample; + int keySize; + + PBETest( + int id, + BufferedBlockCipher cipher, + byte[] sample, + int keySize) + { + this.id = id; + this.cipher = cipher; + this.sample = sample; + this.keySize = keySize; + } + + public String getName() + { + return cipher.getUnderlyingCipher().getAlgorithmName() + " PKCS5S2 Test " + id; + } + + public void performTest() + { + char[] password = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' }; + PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(); + ByteArrayInputStream bIn = new ByteArrayInputStream(sample); + ASN1InputStream dIn = new ASN1InputStream(bIn); + EncryptedPrivateKeyInfo info = null; + + try + { + info = EncryptedPrivateKeyInfo.getInstance(dIn.readObject()); + } + catch (Exception e) + { + fail("failed construction - exception " + e.toString(), e); + } + + PBES2Parameters alg = PBES2Parameters.getInstance(info.getEncryptionAlgorithm().getParameters()); + PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters()); + EncryptionScheme scheme = alg.getEncryptionScheme(); + + if (func.getKeyLength() != null) + { + keySize = func.getKeyLength().intValue() * 8; + } + + int iterationCount = func.getIterationCount().intValue(); + byte[] salt = func.getSalt(); + + generator.init( + PBEParametersGenerator.PKCS5PasswordToBytes(password), + salt, + iterationCount); + + CipherParameters param; + + if (scheme.getAlgorithm().equals(PKCSObjectIdentifiers.RC2_CBC)) + { + RC2CBCParameter rc2Params = RC2CBCParameter.getInstance(scheme.getParameters()); + byte[] iv = rc2Params.getIV(); + + param = new ParametersWithIV(generator.generateDerivedParameters(keySize), iv); + } + else + { + byte[] iv = ASN1OctetString.getInstance(scheme.getParameters()).getOctets(); + + param = new ParametersWithIV(generator.generateDerivedParameters(keySize), iv); + } + + cipher.init(false, param); + + byte[] data = info.getEncryptedData(); + byte[] out = new byte[cipher.getOutputSize(data.length)]; + int len = cipher.processBytes(data, 0, data.length, out, 0); + + try + { + len += cipher.doFinal(out, len); + } + catch (Exception e) + { + fail("failed doFinal - exception " + e.toString()); + } + + if (result.length != len) + { + fail("failed length"); + } + + for (int i = 0; i != len; i++) + { + if (out[i] != result[i]) + { + fail("failed comparison"); + } + } + } + } + + public String getName() + { + return "PKCS5S2"; + } + + public void performTest() + throws Exception + { + BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESEngine())); + SimpleTest test = new PBETest(0, cipher, sample1, 64); + + test.performTest(); + + cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESedeEngine())); + test = new PBETest(1, cipher, sample2, 192); + + test.performTest(); + + cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new RC2Engine())); + test = new PBETest(2, cipher, sample3, 0); + test.performTest(); + + // + // RFC 3211 tests + // + char[] password = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' }; + PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(); + + byte[] salt = Hex.decode("1234567878563412"); + + generator.init( + PBEParametersGenerator.PKCS5PasswordToBytes(password), + salt, + 5); + + if (!areEqual(((KeyParameter)generator.generateDerivedParameters(64)).getKey(), Hex.decode("d1daa78615f287e6"))) + { + fail("64 test failed"); + } + + password = "All n-entities must communicate with other n-entities via n-1 entiteeheehees".toCharArray(); + + generator.init( + PBEParametersGenerator.PKCS5PasswordToBytes(password), + salt, + 500); + + if (!areEqual(((KeyParameter)generator.generateDerivedParameters(192)).getKey(), Hex.decode("6a8970bf68c92caea84a8df28510858607126380cc47ab2d"))) + { + fail("192 test failed"); + } + + generator.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt, 60000); + if (!areEqual(((KeyParameter)generator.generateDerivedParameters(192)).getKey(), Hex.decode("29aaef810c12ecd2236bbcfb55407f9852b5573dc1c095bb"))) + { + fail("192 (60000) test failed"); + } + } + + public static void main( + String[] args) + { + runTest(new PKCS5Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/PSSBlindTest.java b/core/src/test/java/org/spongycastle/crypto/test/PSSBlindTest.java new file mode 100644 index 00000000..36362bca --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/PSSBlindTest.java @@ -0,0 +1,398 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.engines.RSABlindingEngine; +import org.spongycastle.crypto.engines.RSAEngine; +import org.spongycastle.crypto.generators.RSABlindingFactorGenerator; +import org.spongycastle.crypto.generators.RSAKeyPairGenerator; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.crypto.params.RSABlindingParameters; +import org.spongycastle.crypto.params.RSAKeyGenerationParameters; +import org.spongycastle.crypto.params.RSAKeyParameters; +import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters; +import org.spongycastle.crypto.signers.PSSSigner; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/* + * RSA PSS test vectors for PKCS#1 V2.1 with blinding + */ +public class PSSBlindTest + extends SimpleTest +{ + private final int DATA_LENGTH = 1000; + private final int NUM_TESTS = 50; + private final int NUM_TESTS_WITH_KEY_GENERATION = 10; + + private class FixedRandom + extends SecureRandom + { + byte[] vals; + + FixedRandom( + byte[] vals) + { + this.vals = vals; + } + + public void nextBytes( + byte[] bytes) + { + System.arraycopy(vals, 0, bytes, 0, vals.length); + } + } + + // + // Example 1: A 1024-bit RSA keypair + // + private RSAKeyParameters pub1 = new RSAKeyParameters(false, + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16)); + + private RSAKeyParameters prv1 = new RSAPrivateCrtKeyParameters( + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16), + new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16), + new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16), + new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16), + new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16), + new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16), + new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16)); + + // PSSExample1.1 + + private byte[] msg1a = Hex.decode("cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d45ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba958fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73318b750a0167d0"); + + private byte[] slt1a = Hex.decode("dee959c7e06411361420ff80185ed57f3e6776af"); + + private byte[] sig1a = Hex.decode("9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f9579aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c"); + + // PSSExample1.2 + + private byte[] msg1b = Hex.decode("851384cdfe819c22ed6c4ccb30daeb5cf059bc8e1166b7e3530c4c233e2b5f8f71a1cca582d43ecc72b1bca16dfc7013226b9e"); + + private byte[] slt1b = Hex.decode("ef2869fa40c346cb183dab3d7bffc98fd56df42d"); + + private byte[] sig1b = Hex.decode("3ef7f46e831bf92b32274142a585ffcefbdca7b32ae90d10fb0f0c729984f04ef29a9df0780775ce43739b97838390db0a5505e63de927028d9d29b219ca2c4517832558a55d694a6d25b9dab66003c4cccd907802193be5170d26147d37b93590241be51c25055f47ef62752cfbe21418fafe98c22c4d4d47724fdb5669e843"); + + // + // Example 2: A 1025-bit RSA keypair + // + + private RSAKeyParameters pub2 = new RSAKeyParameters(false, + new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv2 = new RSAPrivateCrtKeyParameters( + new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16), + new BigInteger("010001", 16), + new BigInteger("027d147e4673057377fd1ea201565772176a7dc38358d376045685a2e787c23c15576bc16b9f444402d6bfc5d98a3e88ea13ef67c353eca0c0ddba9255bd7b8bb50a644afdfd1dd51695b252d22e7318d1b6687a1c10ff75545f3db0fe602d5f2b7f294e3601eab7b9d1cecd767f64692e3e536ca2846cb0c2dd486a39fa75b1", 16), + new BigInteger("016601e926a0f8c9e26ecab769ea65a5e7c52cc9e080ef519457c644da6891c5a104d3ea7955929a22e7c68a7af9fcad777c3ccc2b9e3d3650bce404399b7e59d1", 16), + new BigInteger("014eafa1d4d0184da7e31f877d1281ddda625664869e8379e67ad3b75eae74a580e9827abd6eb7a002cb5411f5266797768fb8e95ae40e3e8a01f35ff89e56c079", 16), + new BigInteger("e247cce504939b8f0a36090de200938755e2444b29539a7da7a902f6056835c0db7b52559497cfe2c61a8086d0213c472c78851800b171f6401de2e9c2756f31", 16), + new BigInteger("b12fba757855e586e46f64c38a70c68b3f548d93d787b399999d4c8f0bbd2581c21e19ed0018a6d5d3df86424b3abcad40199d31495b61309f27c1bf55d487c1", 16), + new BigInteger("564b1e1fa003bda91e89090425aac05b91da9ee25061e7628d5f51304a84992fdc33762bd378a59f030a334d532bd0dae8f298ea9ed844636ad5fb8cbdc03cad", 16)); + + // PSS Example 2.1 + + private byte[] msg2a = Hex.decode("daba032066263faedb659848115278a52c44faa3a76f37515ed336321072c40a9d9b53bc05014078adf520875146aae70ff060226dcb7b1f1fc27e9360"); + private byte[] slt2a = Hex.decode("57bf160bcb02bb1dc7280cf0458530b7d2832ff7"); + private byte[] sig2a = Hex.decode("014c5ba5338328ccc6e7a90bf1c0ab3fd606ff4796d3c12e4b639ed9136a5fec6c16d8884bdd99cfdc521456b0742b736868cf90de099adb8d5ffd1deff39ba4007ab746cefdb22d7df0e225f54627dc65466131721b90af445363a8358b9f607642f78fab0ab0f43b7168d64bae70d8827848d8ef1e421c5754ddf42c2589b5b3"); + + // PSS Example 2.2 + + private byte[] msg2b = Hex.decode("e4f8601a8a6da1be34447c0959c058570c3668cfd51dd5f9ccd6ad4411fe8213486d78a6c49f93efc2ca2288cebc2b9b60bd04b1e220d86e3d4848d709d032d1e8c6a070c6af9a499fcf95354b14ba6127c739de1bb0fd16431e46938aec0cf8ad9eb72e832a7035de9b7807bdc0ed8b68eb0f5ac2216be40ce920c0db0eddd3860ed788efaccaca502d8f2bd6d1a7c1f41ff46f1681c8f1f818e9c4f6d91a0c7803ccc63d76a6544d843e084e363b8acc55aa531733edb5dee5b5196e9f03e8b731b3776428d9e457fe3fbcb3db7274442d785890e9cb0854b6444dace791d7273de1889719338a77fe"); + private byte[] slt2b = Hex.decode("7f6dd359e604e60870e898e47b19bf2e5a7b2a90"); + private byte[] sig2b = Hex.decode("010991656cca182b7f29d2dbc007e7ae0fec158eb6759cb9c45c5ff87c7635dd46d150882f4de1e9ae65e7f7d9018f6836954a47c0a81a8a6b6f83f2944d6081b1aa7c759b254b2c34b691da67cc0226e20b2f18b42212761dcd4b908a62b371b5918c5742af4b537e296917674fb914194761621cc19a41f6fb953fbcbb649dea"); + + // + // Example 4: A 1027-bit RSA key pair + // + + private RSAKeyParameters pub4 = new RSAKeyParameters(false, + new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv4 = new RSAPrivateCrtKeyParameters( + new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16), + new BigInteger("010001", 16), + new BigInteger("fa041f8cd9697ceed38ec8caa275523b4dd72b09a301d3541d72f5d31c05cbce2d6983b36183af10690bd46c46131e35789431a556771dd0049b57461bf060c1f68472e8a67c25f357e5b6b4738fa541a730346b4a07649a2dfa806a69c975b6aba64678acc7f5913e89c622f2d8abb1e3e32554e39df94ba60c002e387d9011", 16), + new BigInteger("029232336d2838945dba9dd7723f4e624a05f7375b927a87abe6a893a1658fd49f47f6c7b0fa596c65fa68a23f0ab432962d18d4343bd6fd671a5ea8d148413995", 16), + new BigInteger("020ef5efe7c5394aed2272f7e81a74f4c02d145894cb1b3cab23a9a0710a2afc7e3329acbb743d01f680c4d02afb4c8fde7e20930811bb2b995788b5e872c20bb1", 16), + new BigInteger("026e7e28010ecf2412d9523ad704647fb4fe9b66b1a681581b0e15553a89b1542828898f27243ebab45ff5e1acb9d4df1b051fbc62824dbc6f6c93261a78b9a759", 16), + new BigInteger("012ddcc86ef655998c39ddae11718669e5e46cf1495b07e13b1014cd69b3af68304ad2a6b64321e78bf3bbca9bb494e91d451717e2d97564c6549465d0205cf421", 16), + new BigInteger("010600c4c21847459fe576703e2ebecae8a5094ee63f536bf4ac68d3c13e5e4f12ac5cc10ab6a2d05a199214d1824747d551909636b774c22cac0b837599abcc75", 16)); + + // PSS Example 4.1 + + private byte[] msg4a = Hex.decode("9fb03b827c8217d9"); + + private byte[] slt4a = Hex.decode("ed7c98c95f30974fbe4fbddcf0f28d6021c0e91d"); + + private byte[] sig4a = Hex.decode("0323d5b7bf20ba4539289ae452ae4297080feff4518423ff4811a817837e7d82f1836cdfab54514ff0887bddeebf40bf99b047abc3ecfa6a37a3ef00f4a0c4a88aae0904b745c846c4107e8797723e8ac810d9e3d95dfa30ff4966f4d75d13768d20857f2b1406f264cfe75e27d7652f4b5ed3575f28a702f8c4ed9cf9b2d44948"); + + // PSS Example 4.2 + + private byte[] msg4b = Hex.decode("0ca2ad77797ece86de5bf768750ddb5ed6a3116ad99bbd17edf7f782f0db1cd05b0f677468c5ea420dc116b10e80d110de2b0461ea14a38be68620392e7e893cb4ea9393fb886c20ff790642305bf302003892e54df9f667509dc53920df583f50a3dd61abb6fab75d600377e383e6aca6710eeea27156e06752c94ce25ae99fcbf8592dbe2d7e27453cb44de07100ebb1a2a19811a478adbeab270f94e8fe369d90b3ca612f9f"); + + private byte[] slt4b = Hex.decode("22d71d54363a4217aa55113f059b3384e3e57e44"); + + private byte[] sig4b = Hex.decode("049d0185845a264d28feb1e69edaec090609e8e46d93abb38371ce51f4aa65a599bdaaa81d24fba66a08a116cb644f3f1e653d95c89db8bbd5daac2709c8984000178410a7c6aa8667ddc38c741f710ec8665aa9052be929d4e3b16782c1662114c5414bb0353455c392fc28f3db59054b5f365c49e1d156f876ee10cb4fd70598"); + + + // + // Example 8: A 1031-bit RSA key pair + // + + private RSAKeyParameters pub8 = new RSAKeyParameters(false, + new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv8 = new RSAPrivateCrtKeyParameters( + new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16), + new BigInteger("010001", 16), + new BigInteger("6c66ffe98980c38fcdeab5159898836165f4b4b817c4f6a8d486ee4ea9130fe9b9092bd136d184f95f504a607eac565846d2fdd6597a8967c7396ef95a6eeebb4578a643966dca4d8ee3de842de63279c618159c1ab54a89437b6a6120e4930afb52a4ba6ced8a4947ac64b30a3497cbe701c2d6266d517219ad0ec6d347dbe9", 16), + new BigInteger("08dad7f11363faa623d5d6d5e8a319328d82190d7127d2846c439b0ab72619b0a43a95320e4ec34fc3a9cea876422305bd76c5ba7be9e2f410c8060645a1d29edb", 16), + new BigInteger("0847e732376fc7900f898ea82eb2b0fc418565fdae62f7d9ec4ce2217b97990dd272db157f99f63c0dcbb9fbacdbd4c4dadb6df67756358ca4174825b48f49706d", 16), + new BigInteger("05c2a83c124b3621a2aa57ea2c3efe035eff4560f33ddebb7adab81fce69a0c8c2edc16520dda83d59a23be867963ac65f2cc710bbcfb96ee103deb771d105fd85", 16), + new BigInteger("04cae8aa0d9faa165c87b682ec140b8ed3b50b24594b7a3b2c220b3669bb819f984f55310a1ae7823651d4a02e99447972595139363434e5e30a7e7d241551e1b9", 16), + new BigInteger("07d3e47bf686600b11ac283ce88dbb3f6051e8efd04680e44c171ef531b80b2b7c39fc766320e2cf15d8d99820e96ff30dc69691839c4b40d7b06e45307dc91f3f", 16)); + + // PSS Example 8.1 + + private byte[] msg8a = Hex.decode("81332f4be62948415ea1d899792eeacf6c6e1db1da8be13b5cea41db2fed467092e1ff398914c714259775f595f8547f735692a575e6923af78f22c6997ddb90fb6f72d7bb0dd5744a31decd3dc3685849836ed34aec596304ad11843c4f88489f209735f5fb7fdaf7cec8addc5818168f880acbf490d51005b7a8e84e43e54287977571dd99eea4b161eb2df1f5108f12a4142a83322edb05a75487a3435c9a78ce53ed93bc550857d7a9fb"); + + private byte[] slt8a = Hex.decode("1d65491d79c864b373009be6f6f2467bac4c78fa"); + + private byte[] sig8a = Hex.decode("0262ac254bfa77f3c1aca22c5179f8f040422b3c5bafd40a8f21cf0fa5a667ccd5993d42dbafb409c520e25fce2b1ee1e716577f1efa17f3da28052f40f0419b23106d7845aaf01125b698e7a4dfe92d3967bb00c4d0d35ba3552ab9a8b3eef07c7fecdbc5424ac4db1e20cb37d0b2744769940ea907e17fbbca673b20522380c5"); + + // PSS Example 8.2 + + private byte[] msg8b = Hex.decode("e2f96eaf0e05e7ba326ecca0ba7fd2f7c02356f3cede9d0faabf4fcc8e60a973e5595fd9ea08"); + + private byte[] slt8b = Hex.decode("435c098aa9909eb2377f1248b091b68987ff1838"); + + private byte[] sig8b = Hex.decode("2707b9ad5115c58c94e932e8ec0a280f56339e44a1b58d4ddcff2f312e5f34dcfe39e89c6a94dcee86dbbdae5b79ba4e0819a9e7bfd9d982e7ee6c86ee68396e8b3a14c9c8f34b178eb741f9d3f121109bf5c8172fada2e768f9ea1433032c004a8aa07eb990000a48dc94c8bac8aabe2b09b1aa46c0a2aa0e12f63fbba775ba7e"); + + // + // Example 9: A 1536-bit RSA key pair + // + + private RSAKeyParameters pub9 = new RSAKeyParameters(false, + new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv9 = new RSAPrivateCrtKeyParameters( + new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16), + new BigInteger("010001", 16), + new BigInteger("6a7fd84fb85fad073b34406db74f8d61a6abc12196a961dd79565e9da6e5187bce2d980250f7359575359270d91590bb0e427c71460b55d51410b191bcf309fea131a92c8e702738fa719f1e0041f52e40e91f229f4d96a1e6f172e15596b4510a6daec26105f2bebc53316b87bdf21311666070e8dfee69d52c71a976caae79c72b68d28580dc686d9f5129d225f82b3d615513a882b3db91416b48ce08888213e37eeb9af800d81cab328ce420689903c00c7b5fd31b75503a6d419684d629", 16), + new BigInteger("f8eb97e98df12664eefdb761596a69ddcd0e76daece6ed4bf5a1b50ac086f7928a4d2f8726a77e515b74da41988f220b1cc87aa1fc810ce99a82f2d1ce821edced794c6941f42c7a1a0b8c4d28c75ec60b652279f6154a762aed165d47dee367", 16), + new BigInteger("ed4d71d0a6e24b93c2e5f6b4bbe05f5fb0afa042d204fe3378d365c2f288b6a8dad7efe45d153eef40cacc7b81ff934002d108994b94a5e4728cd9c963375ae49965bda55cbf0efed8d6553b4027f2d86208a6e6b489c176128092d629e49d3d", 16), + new BigInteger("2bb68bddfb0c4f56c8558bffaf892d8043037841e7fa81cfa61a38c5e39b901c8ee71122a5da2227bd6cdeeb481452c12ad3d61d5e4f776a0ab556591befe3e59e5a7fddb8345e1f2f35b9f4cee57c32414c086aec993e9353e480d9eec6289f", 16), + new BigInteger("4ff897709fad079746494578e70fd8546130eeab5627c49b080f05ee4ad9f3e4b7cba9d6a5dff113a41c3409336833f190816d8a6bc42e9bec56b7567d0f3c9c696db619b245d901dd856db7c8092e77e9a1cccd56ee4dba42c5fdb61aec2669", 16), + new BigInteger("77b9d1137b50404a982729316efafc7dfe66d34e5a182600d5f30a0a8512051c560d081d4d0a1835ec3d25a60f4e4d6aa948b2bf3dbb5b124cbbc3489255a3a948372f6978496745f943e1db4f18382ceaa505dfc65757bb3f857a58dce52156", 16)); + + // PSS Example 9.1 + + private byte[] msg9a = Hex.decode("a88e265855e9d7ca36c68795f0b31b591cd6587c71d060a0b3f7f3eaef43795922028bc2b6ad467cfc2d7f659c5385aa70ba3672cdde4cfe4970cc7904601b278872bf51321c4a972f3c95570f3445d4f57980e0f20df54846e6a52c668f1288c03f95006ea32f562d40d52af9feb32f0fa06db65b588a237b34e592d55cf979f903a642ef64d2ed542aa8c77dc1dd762f45a59303ed75e541ca271e2b60ca709e44fa0661131e8d5d4163fd8d398566ce26de8730e72f9cca737641c244159420637028df0a18079d6208ea8b4711a2c750f5"); + + private byte[] slt9a = Hex.decode("c0a425313df8d7564bd2434d311523d5257eed80"); + + private byte[] sig9a = Hex.decode("586107226c3ce013a7c8f04d1a6a2959bb4b8e205ba43a27b50f124111bc35ef589b039f5932187cb696d7d9a32c0c38300a5cdda4834b62d2eb240af33f79d13dfbf095bf599e0d9686948c1964747b67e89c9aba5cd85016236f566cc5802cb13ead51bc7ca6bef3b94dcbdbb1d570469771df0e00b1a8a06777472d2316279edae86474668d4e1efff95f1de61c6020da32ae92bbf16520fef3cf4d88f61121f24bbd9fe91b59caf1235b2a93ff81fc403addf4ebdea84934a9cdaf8e1a9e"); + + // PSS Example 9.2 + + private byte[] msg9b = Hex.decode("c8c9c6af04acda414d227ef23e0820c3732c500dc87275e95b0d095413993c2658bc1d988581ba879c2d201f14cb88ced153a01969a7bf0a7be79c84c1486bc12b3fa6c59871b6827c8ce253ca5fefa8a8c690bf326e8e37cdb96d90a82ebab69f86350e1822e8bd536a2e"); + + private byte[] slt9b = Hex.decode("b307c43b4850a8dac2f15f32e37839ef8c5c0e91"); + + private byte[] sig9b = Hex.decode("80b6d643255209f0a456763897ac9ed259d459b49c2887e5882ecb4434cfd66dd7e1699375381e51cd7f554f2c271704b399d42b4be2540a0eca61951f55267f7c2878c122842dadb28b01bd5f8c025f7e228418a673c03d6bc0c736d0a29546bd67f786d9d692ccea778d71d98c2063b7a71092187a4d35af108111d83e83eae46c46aa34277e06044589903788f1d5e7cee25fb485e92949118814d6f2c3ee361489016f327fb5bc517eb50470bffa1afa5f4ce9aa0ce5b8ee19bf5501b958"); + + + public String getName() + { + return "PSSBlindTest"; + } + + private void testSig( + int id, + RSAKeyParameters pub, + RSAKeyParameters prv, + byte[] slt, + byte[] msg, + byte[] sig) + throws Exception + { + RSABlindingFactorGenerator blindFactorGen = new RSABlindingFactorGenerator(); + RSABlindingEngine blindingEngine = new RSABlindingEngine(); + PSSSigner blindSigner = new PSSSigner(blindingEngine, new SHA1Digest(), 20); + PSSSigner signer = new PSSSigner(new RSAEngine(), new SHA1Digest(), 20); + + blindFactorGen.init(pub); + + BigInteger blindFactor = blindFactorGen.generateBlindingFactor(); + RSABlindingParameters params = new RSABlindingParameters(pub, blindFactor); + + // generate a blind signature + blindSigner.init(true, new ParametersWithRandom(params, new FixedRandom(slt))); + + blindSigner.update(msg, 0, msg.length); + + byte[] blindedData = blindSigner.generateSignature(); + + RSAEngine signerEngine = new RSAEngine(); + + signerEngine.init(true, prv); + + byte[] blindedSig = signerEngine.processBlock(blindedData, 0, blindedData.length); + + // unblind the signature + blindingEngine.init(false, params); + + byte[] s = blindingEngine.processBlock(blindedSig, 0, blindedSig.length); + + //signature verification + if (!areEqual(s, sig)) + { + fail("test " + id + " failed generation"); + } + + //verify signature with PSSSigner + signer.init(false, pub); + signer.update(msg, 0, msg.length); + + if (!signer.verifySignature(s)) + { + fail("test " + id + " failed PSSSigner verification"); + } + } + + private boolean isProcessingOkay( + RSAKeyParameters pub, + RSAKeyParameters prv, + byte[] data, + SecureRandom random) + throws Exception + { + RSABlindingFactorGenerator blindFactorGen = new RSABlindingFactorGenerator(); + RSABlindingEngine blindingEngine = new RSABlindingEngine(); + PSSSigner blindSigner = new PSSSigner(blindingEngine, new SHA1Digest(), 20); + PSSSigner pssEng = new PSSSigner(new RSAEngine(), new SHA1Digest(), 20); + + random.nextBytes(data); + + blindFactorGen.init(pub); + + BigInteger blindFactor = blindFactorGen.generateBlindingFactor(); + RSABlindingParameters params = new RSABlindingParameters(pub, blindFactor); + + // generate a blind signature + blindSigner.init(true, new ParametersWithRandom(params, random)); + + blindSigner.update(data, 0, data.length); + + byte[] blindedData = blindSigner.generateSignature(); + + RSAEngine signerEngine = new RSAEngine(); + + signerEngine.init(true, prv); + + byte[] blindedSig = signerEngine.processBlock(blindedData, 0, blindedData.length); + + // unblind the signature + blindingEngine.init(false, params); + + byte[] s = blindingEngine.processBlock(blindedSig, 0, blindedSig.length); + + //verify signature with PSSSigner + pssEng.init(false, pub); + pssEng.update(data, 0, data.length); + + return pssEng.verifySignature(s); + } + + public void performTest() + throws Exception + { + testSig(1, pub1, prv1, slt1a, msg1a, sig1a); + testSig(2, pub1, prv1, slt1b, msg1b, sig1b); + testSig(3, pub2, prv2, slt2a, msg2a, sig2a); + testSig(4, pub2, prv2, slt2b, msg2b, sig2b); + testSig(5, pub4, prv4, slt4a, msg4a, sig4a); + testSig(6, pub4, prv4, slt4b, msg4b, sig4b); + testSig(7, pub8, prv8, slt8a, msg8a, sig8a); + testSig(8, pub8, prv8, slt8b, msg8b, sig8b); + testSig(9, pub9, prv9, slt9a, msg9a, sig9a); + testSig(10, pub9, prv9, slt9b, msg9b, sig9b); + + // + // loop test + // + int failed = 0; + byte[] data = new byte[DATA_LENGTH]; + + SecureRandom random = new SecureRandom(); + + + RSAKeyParameters[] kprv ={prv1, prv2, prv4, prv8, prv9}; + RSAKeyParameters[] kpub ={pub1, pub2, pub4, pub8, pub9}; + + int i = 0; + for (int j = 0; j < NUM_TESTS; j++, i++) + { + if (i == kprv.length) + { + i = 0; + } + + if (!isProcessingOkay(kpub[i], kprv[i], data, random)) + { + failed++; + } + } + + if (failed != 0) + { + fail("loop test failed - failures: " + failed); + } + + // + // key generation test + // + RSAKeyPairGenerator pGen = new RSAKeyPairGenerator(); + RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters( + BigInteger.valueOf(0x11), new SecureRandom(), 1024, 25); + + pGen.init(genParam); + failed = 0; + + for (int k = 0; k < NUM_TESTS_WITH_KEY_GENERATION; k++) + { + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + for (int j = 0; j < NUM_TESTS; j++) + { + if (!isProcessingOkay((RSAKeyParameters)pair.getPublic(), (RSAKeyParameters)pair.getPrivate(), data, random)) + { + failed++; + } + } + + } + + if (failed != 0) + { + fail("loop test with key generation failed - failures: " + failed); + } + } + + public static void main( + String[] args) + { + runTest(new PSSBlindTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/PSSTest.java b/core/src/test/java/org/spongycastle/crypto/test/PSSTest.java new file mode 100644 index 00000000..517433a6 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/PSSTest.java @@ -0,0 +1,332 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.engines.RSAEngine; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.crypto.params.RSAKeyParameters; +import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters; +import org.spongycastle.crypto.signers.PSSSigner; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/* + * RSA PSS test vectors for PKCS#1 V2.1 + */ +public class PSSTest + extends SimpleTest +{ + private final int DATA_LENGTH = 1000; + private final int NUM_TESTS = 500; + + private class FixedRandom + extends SecureRandom + { + byte[] vals; + + FixedRandom( + byte[] vals) + { + this.vals = vals; + } + + public void nextBytes( + byte[] bytes) + { + System.arraycopy(vals, 0, bytes, 0, vals.length); + } + } + + // + // Example 1: A 1024-bit RSA keypair + // + private RSAKeyParameters pub1 = new RSAKeyParameters(false, + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16)); + + private RSAKeyParameters prv1 = new RSAPrivateCrtKeyParameters( + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16), + new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16), + new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16), + new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16), + new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16), + new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16), + new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16)); + + // PSSExample1.1 + + private byte[] msg1a = Hex.decode("cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d45ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba958fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73318b750a0167d0"); + + private byte[] slt1a = Hex.decode("dee959c7e06411361420ff80185ed57f3e6776af"); + + private byte[] sig1a = Hex.decode("9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f9579aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c"); + + // PSSExample1.2 + + private byte[] msg1b = Hex.decode("851384cdfe819c22ed6c4ccb30daeb5cf059bc8e1166b7e3530c4c233e2b5f8f71a1cca582d43ecc72b1bca16dfc7013226b9e"); + + private byte[] slt1b = Hex.decode("ef2869fa40c346cb183dab3d7bffc98fd56df42d"); + + private byte[] sig1b = Hex.decode("3ef7f46e831bf92b32274142a585ffcefbdca7b32ae90d10fb0f0c729984f04ef29a9df0780775ce43739b97838390db0a5505e63de927028d9d29b219ca2c4517832558a55d694a6d25b9dab66003c4cccd907802193be5170d26147d37b93590241be51c25055f47ef62752cfbe21418fafe98c22c4d4d47724fdb5669e843"); + + // + // Example 2: A 1025-bit RSA keypair + // + + private RSAKeyParameters pub2 = new RSAKeyParameters(false, + new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv2 = new RSAPrivateCrtKeyParameters( + new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16), + new BigInteger("010001", 16), + new BigInteger("027d147e4673057377fd1ea201565772176a7dc38358d376045685a2e787c23c15576bc16b9f444402d6bfc5d98a3e88ea13ef67c353eca0c0ddba9255bd7b8bb50a644afdfd1dd51695b252d22e7318d1b6687a1c10ff75545f3db0fe602d5f2b7f294e3601eab7b9d1cecd767f64692e3e536ca2846cb0c2dd486a39fa75b1", 16), + new BigInteger("016601e926a0f8c9e26ecab769ea65a5e7c52cc9e080ef519457c644da6891c5a104d3ea7955929a22e7c68a7af9fcad777c3ccc2b9e3d3650bce404399b7e59d1", 16), + new BigInteger("014eafa1d4d0184da7e31f877d1281ddda625664869e8379e67ad3b75eae74a580e9827abd6eb7a002cb5411f5266797768fb8e95ae40e3e8a01f35ff89e56c079", 16), + new BigInteger("e247cce504939b8f0a36090de200938755e2444b29539a7da7a902f6056835c0db7b52559497cfe2c61a8086d0213c472c78851800b171f6401de2e9c2756f31", 16), + new BigInteger("b12fba757855e586e46f64c38a70c68b3f548d93d787b399999d4c8f0bbd2581c21e19ed0018a6d5d3df86424b3abcad40199d31495b61309f27c1bf55d487c1", 16), + new BigInteger("564b1e1fa003bda91e89090425aac05b91da9ee25061e7628d5f51304a84992fdc33762bd378a59f030a334d532bd0dae8f298ea9ed844636ad5fb8cbdc03cad", 16)); + + // PSS Example 2.1 + + private byte[] msg2a = Hex.decode("daba032066263faedb659848115278a52c44faa3a76f37515ed336321072c40a9d9b53bc05014078adf520875146aae70ff060226dcb7b1f1fc27e9360"); + private byte[] slt2a = Hex.decode("57bf160bcb02bb1dc7280cf0458530b7d2832ff7"); + private byte[] sig2a = Hex.decode("014c5ba5338328ccc6e7a90bf1c0ab3fd606ff4796d3c12e4b639ed9136a5fec6c16d8884bdd99cfdc521456b0742b736868cf90de099adb8d5ffd1deff39ba4007ab746cefdb22d7df0e225f54627dc65466131721b90af445363a8358b9f607642f78fab0ab0f43b7168d64bae70d8827848d8ef1e421c5754ddf42c2589b5b3"); + + // PSS Example 2.2 + + private byte[] msg2b = Hex.decode("e4f8601a8a6da1be34447c0959c058570c3668cfd51dd5f9ccd6ad4411fe8213486d78a6c49f93efc2ca2288cebc2b9b60bd04b1e220d86e3d4848d709d032d1e8c6a070c6af9a499fcf95354b14ba6127c739de1bb0fd16431e46938aec0cf8ad9eb72e832a7035de9b7807bdc0ed8b68eb0f5ac2216be40ce920c0db0eddd3860ed788efaccaca502d8f2bd6d1a7c1f41ff46f1681c8f1f818e9c4f6d91a0c7803ccc63d76a6544d843e084e363b8acc55aa531733edb5dee5b5196e9f03e8b731b3776428d9e457fe3fbcb3db7274442d785890e9cb0854b6444dace791d7273de1889719338a77fe"); + private byte[] slt2b = Hex.decode("7f6dd359e604e60870e898e47b19bf2e5a7b2a90"); + private byte[] sig2b = Hex.decode("010991656cca182b7f29d2dbc007e7ae0fec158eb6759cb9c45c5ff87c7635dd46d150882f4de1e9ae65e7f7d9018f6836954a47c0a81a8a6b6f83f2944d6081b1aa7c759b254b2c34b691da67cc0226e20b2f18b42212761dcd4b908a62b371b5918c5742af4b537e296917674fb914194761621cc19a41f6fb953fbcbb649dea"); + + // + // Example 4: A 1027-bit RSA key pair + // + + private RSAKeyParameters pub4 = new RSAKeyParameters(false, + new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv4 = new RSAPrivateCrtKeyParameters( + new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16), + new BigInteger("010001", 16), + new BigInteger("fa041f8cd9697ceed38ec8caa275523b4dd72b09a301d3541d72f5d31c05cbce2d6983b36183af10690bd46c46131e35789431a556771dd0049b57461bf060c1f68472e8a67c25f357e5b6b4738fa541a730346b4a07649a2dfa806a69c975b6aba64678acc7f5913e89c622f2d8abb1e3e32554e39df94ba60c002e387d9011", 16), + new BigInteger("029232336d2838945dba9dd7723f4e624a05f7375b927a87abe6a893a1658fd49f47f6c7b0fa596c65fa68a23f0ab432962d18d4343bd6fd671a5ea8d148413995", 16), + new BigInteger("020ef5efe7c5394aed2272f7e81a74f4c02d145894cb1b3cab23a9a0710a2afc7e3329acbb743d01f680c4d02afb4c8fde7e20930811bb2b995788b5e872c20bb1", 16), + new BigInteger("026e7e28010ecf2412d9523ad704647fb4fe9b66b1a681581b0e15553a89b1542828898f27243ebab45ff5e1acb9d4df1b051fbc62824dbc6f6c93261a78b9a759", 16), + new BigInteger("012ddcc86ef655998c39ddae11718669e5e46cf1495b07e13b1014cd69b3af68304ad2a6b64321e78bf3bbca9bb494e91d451717e2d97564c6549465d0205cf421", 16), + new BigInteger("010600c4c21847459fe576703e2ebecae8a5094ee63f536bf4ac68d3c13e5e4f12ac5cc10ab6a2d05a199214d1824747d551909636b774c22cac0b837599abcc75", 16)); + + // PSS Example 4.1 + + private byte[] msg4a = Hex.decode("9fb03b827c8217d9"); + + private byte[] slt4a = Hex.decode("ed7c98c95f30974fbe4fbddcf0f28d6021c0e91d"); + + private byte[] sig4a = Hex.decode("0323d5b7bf20ba4539289ae452ae4297080feff4518423ff4811a817837e7d82f1836cdfab54514ff0887bddeebf40bf99b047abc3ecfa6a37a3ef00f4a0c4a88aae0904b745c846c4107e8797723e8ac810d9e3d95dfa30ff4966f4d75d13768d20857f2b1406f264cfe75e27d7652f4b5ed3575f28a702f8c4ed9cf9b2d44948"); + + // PSS Example 4.2 + + private byte[] msg4b = Hex.decode("0ca2ad77797ece86de5bf768750ddb5ed6a3116ad99bbd17edf7f782f0db1cd05b0f677468c5ea420dc116b10e80d110de2b0461ea14a38be68620392e7e893cb4ea9393fb886c20ff790642305bf302003892e54df9f667509dc53920df583f50a3dd61abb6fab75d600377e383e6aca6710eeea27156e06752c94ce25ae99fcbf8592dbe2d7e27453cb44de07100ebb1a2a19811a478adbeab270f94e8fe369d90b3ca612f9f"); + + private byte[] slt4b = Hex.decode("22d71d54363a4217aa55113f059b3384e3e57e44"); + + private byte[] sig4b = Hex.decode("049d0185845a264d28feb1e69edaec090609e8e46d93abb38371ce51f4aa65a599bdaaa81d24fba66a08a116cb644f3f1e653d95c89db8bbd5daac2709c8984000178410a7c6aa8667ddc38c741f710ec8665aa9052be929d4e3b16782c1662114c5414bb0353455c392fc28f3db59054b5f365c49e1d156f876ee10cb4fd70598"); + + + // + // Example 8: A 1031-bit RSA key pair + // + + private RSAKeyParameters pub8 = new RSAKeyParameters(false, + new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv8 = new RSAPrivateCrtKeyParameters( + new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16), + new BigInteger("010001", 16), + new BigInteger("6c66ffe98980c38fcdeab5159898836165f4b4b817c4f6a8d486ee4ea9130fe9b9092bd136d184f95f504a607eac565846d2fdd6597a8967c7396ef95a6eeebb4578a643966dca4d8ee3de842de63279c618159c1ab54a89437b6a6120e4930afb52a4ba6ced8a4947ac64b30a3497cbe701c2d6266d517219ad0ec6d347dbe9", 16), + new BigInteger("08dad7f11363faa623d5d6d5e8a319328d82190d7127d2846c439b0ab72619b0a43a95320e4ec34fc3a9cea876422305bd76c5ba7be9e2f410c8060645a1d29edb", 16), + new BigInteger("0847e732376fc7900f898ea82eb2b0fc418565fdae62f7d9ec4ce2217b97990dd272db157f99f63c0dcbb9fbacdbd4c4dadb6df67756358ca4174825b48f49706d", 16), + new BigInteger("05c2a83c124b3621a2aa57ea2c3efe035eff4560f33ddebb7adab81fce69a0c8c2edc16520dda83d59a23be867963ac65f2cc710bbcfb96ee103deb771d105fd85", 16), + new BigInteger("04cae8aa0d9faa165c87b682ec140b8ed3b50b24594b7a3b2c220b3669bb819f984f55310a1ae7823651d4a02e99447972595139363434e5e30a7e7d241551e1b9", 16), + new BigInteger("07d3e47bf686600b11ac283ce88dbb3f6051e8efd04680e44c171ef531b80b2b7c39fc766320e2cf15d8d99820e96ff30dc69691839c4b40d7b06e45307dc91f3f", 16)); + + // PSS Example 8.1 + + private byte[] msg8a = Hex.decode("81332f4be62948415ea1d899792eeacf6c6e1db1da8be13b5cea41db2fed467092e1ff398914c714259775f595f8547f735692a575e6923af78f22c6997ddb90fb6f72d7bb0dd5744a31decd3dc3685849836ed34aec596304ad11843c4f88489f209735f5fb7fdaf7cec8addc5818168f880acbf490d51005b7a8e84e43e54287977571dd99eea4b161eb2df1f5108f12a4142a83322edb05a75487a3435c9a78ce53ed93bc550857d7a9fb"); + + private byte[] slt8a = Hex.decode("1d65491d79c864b373009be6f6f2467bac4c78fa"); + + private byte[] sig8a = Hex.decode("0262ac254bfa77f3c1aca22c5179f8f040422b3c5bafd40a8f21cf0fa5a667ccd5993d42dbafb409c520e25fce2b1ee1e716577f1efa17f3da28052f40f0419b23106d7845aaf01125b698e7a4dfe92d3967bb00c4d0d35ba3552ab9a8b3eef07c7fecdbc5424ac4db1e20cb37d0b2744769940ea907e17fbbca673b20522380c5"); + + // PSS Example 8.2 + + private byte[] msg8b = Hex.decode("e2f96eaf0e05e7ba326ecca0ba7fd2f7c02356f3cede9d0faabf4fcc8e60a973e5595fd9ea08"); + + private byte[] slt8b = Hex.decode("435c098aa9909eb2377f1248b091b68987ff1838"); + + private byte[] sig8b = Hex.decode("2707b9ad5115c58c94e932e8ec0a280f56339e44a1b58d4ddcff2f312e5f34dcfe39e89c6a94dcee86dbbdae5b79ba4e0819a9e7bfd9d982e7ee6c86ee68396e8b3a14c9c8f34b178eb741f9d3f121109bf5c8172fada2e768f9ea1433032c004a8aa07eb990000a48dc94c8bac8aabe2b09b1aa46c0a2aa0e12f63fbba775ba7e"); + + // + // Example 9: A 1536-bit RSA key pair + // + + private RSAKeyParameters pub9 = new RSAKeyParameters(false, + new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv9 = new RSAPrivateCrtKeyParameters( + new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16), + new BigInteger("010001", 16), + new BigInteger("6a7fd84fb85fad073b34406db74f8d61a6abc12196a961dd79565e9da6e5187bce2d980250f7359575359270d91590bb0e427c71460b55d51410b191bcf309fea131a92c8e702738fa719f1e0041f52e40e91f229f4d96a1e6f172e15596b4510a6daec26105f2bebc53316b87bdf21311666070e8dfee69d52c71a976caae79c72b68d28580dc686d9f5129d225f82b3d615513a882b3db91416b48ce08888213e37eeb9af800d81cab328ce420689903c00c7b5fd31b75503a6d419684d629", 16), + new BigInteger("f8eb97e98df12664eefdb761596a69ddcd0e76daece6ed4bf5a1b50ac086f7928a4d2f8726a77e515b74da41988f220b1cc87aa1fc810ce99a82f2d1ce821edced794c6941f42c7a1a0b8c4d28c75ec60b652279f6154a762aed165d47dee367", 16), + new BigInteger("ed4d71d0a6e24b93c2e5f6b4bbe05f5fb0afa042d204fe3378d365c2f288b6a8dad7efe45d153eef40cacc7b81ff934002d108994b94a5e4728cd9c963375ae49965bda55cbf0efed8d6553b4027f2d86208a6e6b489c176128092d629e49d3d", 16), + new BigInteger("2bb68bddfb0c4f56c8558bffaf892d8043037841e7fa81cfa61a38c5e39b901c8ee71122a5da2227bd6cdeeb481452c12ad3d61d5e4f776a0ab556591befe3e59e5a7fddb8345e1f2f35b9f4cee57c32414c086aec993e9353e480d9eec6289f", 16), + new BigInteger("4ff897709fad079746494578e70fd8546130eeab5627c49b080f05ee4ad9f3e4b7cba9d6a5dff113a41c3409336833f190816d8a6bc42e9bec56b7567d0f3c9c696db619b245d901dd856db7c8092e77e9a1cccd56ee4dba42c5fdb61aec2669", 16), + new BigInteger("77b9d1137b50404a982729316efafc7dfe66d34e5a182600d5f30a0a8512051c560d081d4d0a1835ec3d25a60f4e4d6aa948b2bf3dbb5b124cbbc3489255a3a948372f6978496745f943e1db4f18382ceaa505dfc65757bb3f857a58dce52156", 16)); + + // PSS Example 9.1 + + private byte[] msg9a = Hex.decode("a88e265855e9d7ca36c68795f0b31b591cd6587c71d060a0b3f7f3eaef43795922028bc2b6ad467cfc2d7f659c5385aa70ba3672cdde4cfe4970cc7904601b278872bf51321c4a972f3c95570f3445d4f57980e0f20df54846e6a52c668f1288c03f95006ea32f562d40d52af9feb32f0fa06db65b588a237b34e592d55cf979f903a642ef64d2ed542aa8c77dc1dd762f45a59303ed75e541ca271e2b60ca709e44fa0661131e8d5d4163fd8d398566ce26de8730e72f9cca737641c244159420637028df0a18079d6208ea8b4711a2c750f5"); + + private byte[] slt9a = Hex.decode("c0a425313df8d7564bd2434d311523d5257eed80"); + + private byte[] sig9a = Hex.decode("586107226c3ce013a7c8f04d1a6a2959bb4b8e205ba43a27b50f124111bc35ef589b039f5932187cb696d7d9a32c0c38300a5cdda4834b62d2eb240af33f79d13dfbf095bf599e0d9686948c1964747b67e89c9aba5cd85016236f566cc5802cb13ead51bc7ca6bef3b94dcbdbb1d570469771df0e00b1a8a06777472d2316279edae86474668d4e1efff95f1de61c6020da32ae92bbf16520fef3cf4d88f61121f24bbd9fe91b59caf1235b2a93ff81fc403addf4ebdea84934a9cdaf8e1a9e"); + + // PSS Example 9.2 + + private byte[] msg9b = Hex.decode("c8c9c6af04acda414d227ef23e0820c3732c500dc87275e95b0d095413993c2658bc1d988581ba879c2d201f14cb88ced153a01969a7bf0a7be79c84c1486bc12b3fa6c59871b6827c8ce253ca5fefa8a8c690bf326e8e37cdb96d90a82ebab69f86350e1822e8bd536a2e"); + + private byte[] slt9b = Hex.decode("b307c43b4850a8dac2f15f32e37839ef8c5c0e91"); + + private byte[] sig9b = Hex.decode("80b6d643255209f0a456763897ac9ed259d459b49c2887e5882ecb4434cfd66dd7e1699375381e51cd7f554f2c271704b399d42b4be2540a0eca61951f55267f7c2878c122842dadb28b01bd5f8c025f7e228418a673c03d6bc0c736d0a29546bd67f786d9d692ccea778d71d98c2063b7a71092187a4d35af108111d83e83eae46c46aa34277e06044589903788f1d5e7cee25fb485e92949118814d6f2c3ee361489016f327fb5bc517eb50470bffa1afa5f4ce9aa0ce5b8ee19bf5501b958"); + + + public String getName() + { + return "PSSTest"; + } + + private void testSig( + int id, + RSAKeyParameters pub, + RSAKeyParameters prv, + byte[] slt, + byte[] msg, + byte[] sig) + throws Exception + { + PSSSigner eng = new PSSSigner(new RSAEngine(), new SHA1Digest(), 20); + + eng.init(true, new ParametersWithRandom(prv, new FixedRandom(slt))); + + eng.update(msg, 0, msg.length); + + byte[] s = eng.generateSignature(); + + if (!areEqual(s, sig)) + { + fail("test " + id + " failed generation"); + } + + eng.init(false, pub); + + eng.update(msg, 0, msg.length); + + if (!eng.verifySignature(s)) + { + fail("test " + id + " failed verification"); + } + } + + public void performTest() + throws Exception + { + testSig(1, pub1, prv1, slt1a, msg1a, sig1a); + testSig(2, pub1, prv1, slt1b, msg1b, sig1b); + testSig(3, pub2, prv2, slt2a, msg2a, sig2a); + testSig(4, pub2, prv2, slt2b, msg2b, sig2b); + testSig(5, pub4, prv4, slt4a, msg4a, sig4a); + testSig(6, pub4, prv4, slt4b, msg4b, sig4b); + testSig(7, pub8, prv8, slt8a, msg8a, sig8a); + testSig(8, pub8, prv8, slt8b, msg8b, sig8b); + testSig(9, pub9, prv9, slt9a, msg9a, sig9a); + testSig(10, pub9, prv9, slt9b, msg9b, sig9b); + + // + // loop test - sha-1 only + // + PSSSigner eng = new PSSSigner(new RSAEngine(), new SHA1Digest(), 20); + int failed = 0; + byte[] data = new byte[DATA_LENGTH]; + + SecureRandom random = new SecureRandom(); + random.nextBytes(data); + + for (int j = 0; j < NUM_TESTS; j++) + { + eng.init(true, new ParametersWithRandom(prv8, random)); + + eng.update(data, 0, data.length); + + byte[] s = eng.generateSignature(); + + eng.init(false, pub8); + + eng.update(data, 0, data.length); + + if (!eng.verifySignature(s)) + { + failed++; + } + } + + if (failed != 0) + { + fail("loop test failed - failures: " + failed); + } + + // + // loop test - sha-256 and sha-1 + // + eng = new PSSSigner(new RSAEngine(), new SHA256Digest(), new SHA1Digest(), 20); + failed = 0; + data = new byte[DATA_LENGTH]; + + random.nextBytes(data); + + for (int j = 0; j < NUM_TESTS; j++) + { + eng.init(true, new ParametersWithRandom(prv8, random)); + + eng.update(data, 0, data.length); + + byte[] s = eng.generateSignature(); + + eng.init(false, pub8); + + eng.update(data, 0, data.length); + + if (!eng.verifySignature(s)) + { + failed++; + } + } + + if (failed != 0) + { + fail("loop test failed - failures: " + failed); + } + } + + public static void main( + String[] args) + { + runTest(new PSSTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/PaddingTest.java b/core/src/test/java/org/spongycastle/crypto/test/PaddingTest.java new file mode 100644 index 00000000..2e905377 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/PaddingTest.java @@ -0,0 +1,200 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.paddings.BlockCipherPadding; +import org.spongycastle.crypto.paddings.ISO10126d2Padding; +import org.spongycastle.crypto.paddings.ISO7816d4Padding; +import org.spongycastle.crypto.paddings.PKCS7Padding; +import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.spongycastle.crypto.paddings.TBCPadding; +import org.spongycastle.crypto.paddings.X923Padding; +import org.spongycastle.crypto.paddings.ZeroBytePadding; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * General Padding tests. + */ +public class PaddingTest + extends SimpleTest +{ + public PaddingTest() + { + } + + private void blockCheck( + PaddedBufferedBlockCipher cipher, + BlockCipherPadding padding, + KeyParameter key, + byte[] data) + { + byte[] out = new byte[data.length + 8]; + byte[] dec = new byte[data.length]; + + try + { + cipher.init(true, key); + + int len = cipher.processBytes(data, 0, data.length, out, 0); + + len += cipher.doFinal(out, len); + + cipher.init(false, key); + + int decLen = cipher.processBytes(out, 0, len, dec, 0); + + decLen += cipher.doFinal(dec, decLen); + + if (!areEqual(data, dec)) + { + fail("failed to decrypt - i = " + data.length + ", padding = " + padding.getPaddingName()); + } + } + catch (Exception e) + { + fail("Exception - " + e.toString(), e); + } + } + + public void testPadding( + BlockCipherPadding padding, + SecureRandom rand, + byte[] ffVector, + byte[] ZeroVector) + { + PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new DESEngine(), padding); + KeyParameter key = new KeyParameter(Hex.decode("0011223344556677")); + + // + // ff test + // + byte[] data = { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0 }; + + if (ffVector != null) + { + padding.addPadding(data, 3); + + if (!areEqual(data, ffVector)) + { + fail("failed ff test for " + padding.getPaddingName()); + } + } + + // + // zero test + // + if (ZeroVector != null) + { + data = new byte[8]; + padding.addPadding(data, 4); + + if (!areEqual(data, ZeroVector)) + { + fail("failed zero test for " + padding.getPaddingName()); + } + } + + for (int i = 1; i != 200; i++) + { + data = new byte[i]; + + rand.nextBytes(data); + + blockCheck(cipher, padding, key, data); + } + } + + private void testOutputSizes() + { + PaddedBufferedBlockCipher bc = new PaddedBufferedBlockCipher(new DESEngine(), new PKCS7Padding()); + KeyParameter key = new KeyParameter(Hex.decode("0011223344556677")); + + for (int i = 0; i < bc.getBlockSize() * 2; i++) + { + bc.init(true, key); + if (bc.getUpdateOutputSize(i) < 0) + { + fail("Padded cipher encrypt negative update output size for input size " + i); + } + if (bc.getOutputSize(i) < 0) + { + fail("Padded cipher encrypt negative output size for input size " + i); + } + + bc.init(false, key); + if (bc.getUpdateOutputSize(i) < 0) + { + fail("Padded cipher decrypt negative update output size for input size " + i); + } + if (bc.getOutputSize(i) < 0) + { + fail("Padded cipher decrypt negative output size for input size " + i); + } + + } + } + + public void performTest() + { + SecureRandom rand = new SecureRandom(new byte[20]); + + rand.setSeed(System.currentTimeMillis()); + + testPadding(new PKCS7Padding(), rand, + Hex.decode("ffffff0505050505"), + Hex.decode("0000000004040404")); + + PKCS7Padding padder = new PKCS7Padding(); + try + { + padder.padCount(new byte[8]); + + fail("invalid padding not detected"); + } + catch (InvalidCipherTextException e) + { + if (!"pad block corrupted".equals(e.getMessage())) + { + fail("wrong exception for corrupt padding: " + e); + } + } + + testPadding(new ISO10126d2Padding(), rand, + null, + null); + + testPadding(new X923Padding(), rand, + null, + null); + + testPadding(new TBCPadding(), rand, + Hex.decode("ffffff0000000000"), + Hex.decode("00000000ffffffff")); + + testPadding(new ZeroBytePadding(), rand, + Hex.decode("ffffff0000000000"), + null); + + testPadding(new ISO7816d4Padding(), rand, + Hex.decode("ffffff8000000000"), + Hex.decode("0000000080000000")); + + testOutputSizes(); + + } + + public String getName() + { + return "PaddingTest"; + } + + public static void main( + String[] args) + { + runTest(new PaddingTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/Poly1305Test.java b/core/src/test/java/org/spongycastle/crypto/test/Poly1305Test.java new file mode 100644 index 00000000..2410f249 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/Poly1305Test.java @@ -0,0 +1,388 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.CipherKeyGenerator; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.KeyGenerationParameters; +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.generators.Poly1305KeyGenerator; +import org.spongycastle.crypto.macs.Poly1305; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/* + */ +public class Poly1305Test + extends SimpleTest +{ + private static final int MAXLEN = 1000; + + private static class KeyEngine + implements BlockCipher + { + + private byte[] key; + private final int blockSize; + + public KeyEngine(int blockSize) + { + this.blockSize = blockSize; + } + + public void init(boolean forEncryption, CipherParameters params) + throws IllegalArgumentException + { + if (params instanceof KeyParameter) + { + this.key = ((KeyParameter)params).getKey(); + } + } + + public String getAlgorithmName() + { + return "Key"; + } + + public int getBlockSize() + { + return blockSize; + } + + public int processBlock(byte[] in, int inOff, byte[] out, int outOff) + throws DataLengthException, + IllegalStateException + { + System.arraycopy(key, 0, out, outOff, key.length); + return key.length; + } + + public void reset() + { + } + + } + + private static class TestCase + { + private final byte[] key; + private final byte[] nonce; + private final byte[] message; + private final byte[] expectedMac; + + public TestCase(String key, String nonce, String message, String expectedMac) + { + this.key = Hex.decode(key); + // nacl test case keys are not pre-clamped + Poly1305KeyGenerator.clamp(this.key); + this.nonce = (nonce == null) ? null : Hex.decode(nonce); + this.message = Hex.decode(message); + this.expectedMac = Hex.decode(expectedMac); + } + } + + private static TestCase[] CASES = { + // Raw Poly1305 + // onetimeauth.c from nacl-20110221 + new TestCase("2539121d8e234e652d651fa4c8cff880eea6a7251c1e72916d11c2cb214d3c25", null, + "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a" + + "c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738" + + "b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da" + + "99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5", + "f3ffc7703f9400e52a7dfb4b3d3305d9"), + + // Poly1305-AES + // Loop 1 of test-poly1305aes from poly1305aes-20050218 + new TestCase("0000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000", "", "66e94bd4ef8a2c3b884cfa59ca342b2e"), + new TestCase("f795bd4a52e29ed713d313fa20e98dbcf795bd0a50e29e0710d3130a20e98d0c", + "917cf69ebd68b2ec9b9fe9a3eadda692", "66f7", "5ca585c75e8f8f025e710cabc9a1508b"), + new TestCase("e69dae0aab9f91c03a325dcc9436fa903ef49901c8e11c000430d90ad45e7603", + "166450152e2394835606a9d1dd2cdc8b", "66f75c0e0c7a406586", "2924f51b9c2eff5df09db61dd03a9ca1"), + new TestCase("85a4ea91a7de0b0d96eed0d4bf6ecf1cda4afc035087d90e503f8f0ea08c3e0d", + "0b6ef7a0b8f8c738b0f8d5995415271f", + "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea", + "3c5a13adb18d31c64cc29972030c917d"), + new TestCase( + "25eb69bac5cdf7d6bfcee4d9d5507b82ca3c6a0da0a864024ca3090628c28e0d", + "046772a4f0a8de92e4f0d628cdb04484", + "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de", + "fc5fb58dc65daf19b14d1d05da1064e8"), + + // Specific test cases generated from test-poly1305aes from poly1305aes-20050218 that + // expose Java unsigned integer problems + new TestCase( + "95cc0e44d0b79a8856afcae1bec4fe3c" + "01bcb20bfc8b6e03609ddd09f44b060f", + null, + "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de" + + "fc3e0677d956b4c62664bac15962ab15d93ccbbc03aafdbde779162ed93b55361f0f8acaa41d50ef5175927fe79ea316186516eef15001cd04d3524a55" + + "e4fa3c5ca479d3aaa8a897c21807f721b6270ffc68b6889d81a116799f6aaa35d8e04c7a7dd5e6da2519e8759f54e906696f5772fee093283bcef7b930" + + "aed50323bcbc8c820c67422c1e16bdc022a9c0277c9d95fef0ea4ee11e2b27276da811523c5acb80154989f8a67ee9e3fa30b73b0c1c34bf46e3464d97" + + "7cd7fcd0ac3b82721080bb0d9b982ee2c77feee983d7ba35da88ce86955002940652ab63bc56fb16f994da2b01d74356509d7d1b6d7956b0e5a557757b" + + "d1ced2eef8650bc5b6d426108c1518abcbd0befb6a0d5fd57a3e2dbf31458eab63df66613653d4beae73f5c40eb438fbcfdcf4a4ba46320184b9ca0da4" + + "dfae77de7ccc910356caea3243f33a3c81b064b3b7cedc7435c223f664227215715980e6e0bb570d459ba80d7512dbe458c8f0f3f52d659b6e8eef19ee" + + "71aea2ced85c7a42ffca6522a62db49a2a46eff72bd7f7e0883acd087183f0627f3537a4d558754ed63358e8182bee196735b361dc9bd64d5e34e1074a" + + "855655d2974cc6fa1653754cf40f561d8c7dc526aab2908ec2d2b977cde1a1fb1071e32f40e049ea20f30368ba1592b4fe57fb51595d23acbdace324cd" + + "d78060a17187c662368854e915402d9b52fb21e984663e41c26a109437e162cfaf071b53f77e50000a5388ff183b82ce7a1af476c416d7d204157b3633" + + "b2f4ec077b699b032816997e37bceded8d4a04976fd7d0c0b029f290794c3be504c5242287ea2f831f11ed5690d92775cd6e863d7731fd4da687ebfb13" + + "df4c41dc0fb8", "ae345d555eb04d6947bb95c0965237e2"), + new TestCase( + "76fb3635a2dc92a1f768163ab12f2187" + "cd07fd0ef8c0be0afcbdb30af4af0009", + null, + "f05204a74f0f88a7fa1a95b84ec3d8ffb36fcdc7723ea65dfe7cd464e86e0abf6b9d51db3220cfd8496ad6e6d36ebee8d990f9ce0d3bb7f72b7ab5b3ab0a73240d11efe772c857021ae859db4933cdde4387b471d2ce700fef4b81087f8f47c307881fd83017afcd15b8d21edf9b704677f46df97b07e5b83f87c8abd90af9b1d0f9e2710e8ebd0d4d1c6a055abea861f42368bed94d9373e909c1d3715b221c16bc524c55c31ec3eab204850bb2474a84f9917038eff9d921130951391b5c54f09b5e1de833ea2cd7d3b306740abb7096d1e173da83427da2adddd3631eda30b54dbf487f2b082e8646f07d6e0a87e97522ca38d4ace4954bf3db6dd3a93b06fa18eb56856627ed6cffcd7ae26374554ca18ab8905f26331d323fe10e6e70624c7bc07a70f06ecd804b48f8f7e75e910165e1beb554f1f0ec7949c9c8d429a206b4d5c0653102249b6098e6b45fac2a07ff0220b0b8ae8f4c6bcc0c813a7cd141fa8b398b42575fc395747c5a0257ac41d6c1f434cfbf5dfe8349f5347ef6b60e611f5d6c3cbc20ca2555274d1934325824cef4809da293ea13f181929e2af025bbd1c9abdc3af93afd4c50a2854ade3887f4d2c8c225168052c16e74d76d2dd3e9467a2c5b8e15c06ffbffa42b8536384139f07e195a8c9f70f514f31dca4eb2cf262c0dcbde53654b6250a29efe21d54e83c80e005a1cad36d5934ff01c32e4bc5fe06d03064ff4a268517df4a94c759289f323734318cfa5d859d4ce9c16e63d02dff0896976f521607638535d2ee8dd3312e1ddc80a55d34fe829ab954c1ebd54d929954770f1be9d32b4c05003c5c9e97943b6431e2afe820b1e967b19843e5985a131b1100517cdc363799104af91e2cf3f53cb8fd003653a6dd8a31a3f9d566a7124b0ffe9695bcb87c482eb60106f88198f766a40bc0f4873c23653c5f9e7a8e446f770beb8034cf01d21028ba15ccee21a8db918c4829d61c88bfa927bc5def831501796c5b401a60a6b1b433c9fb905c8cd40412fffee81ab", + "045be28cc52009f506bdbfabedacf0b4"), + + }; + + public String getName() + { + return "Poly1305"; + } + + public void performTest() + throws Exception + { + testKeyGenerator(); + testInit(); + for (int i = 0; i < CASES.length; i++) + { + testCase(i); + } + testSequential(); + testReset(); + } + + private void testCase(int i) + { + byte[] out = new byte[16]; + TestCase tc = CASES[i]; + + final Mac mac; + if (tc.nonce == null) + { + // Raw Poly1305 test - don't do any transform on AES key part + mac = new Poly1305(new KeyEngine(16)); + mac.init(new ParametersWithIV(new KeyParameter(tc.key), new byte[16])); + } + else + { + mac = new Poly1305(new AESFastEngine()); + mac.init(new ParametersWithIV(new KeyParameter(tc.key), tc.nonce)); + } + mac.update(tc.message, 0, tc.message.length); + mac.doFinal(out, 0); + + if (!Arrays.areEqual(out, tc.expectedMac)) + { + fail("Mismatched output " + i, new String(Hex.encode(tc.expectedMac)), new String(Hex.encode(out))); + } + } + + private void testSequential() + { + // Sequential test, adapted from test-poly1305aes + int len; + byte[] kr = new byte[32]; + byte[] m = new byte[MAXLEN]; + byte[] n = new byte[16]; + byte[] out = new byte[16]; + + int c = 0; + final Mac mac = new Poly1305(new AESFastEngine()); + for (int loop = 0; loop < 13; loop++) + { + len = 0; + for (;;) + { + c++; + mac.init(new ParametersWithIV(new KeyParameter(kr), n)); + mac.update(m, 0, len); + mac.doFinal(out, 0); + + // if (c == 678) + // { + // TestCase tc = CASES[0]; + // + // if (!Arrays.areEqual(tc.key, kr)) + // { + // System.err.println("Key bad"); + // System.err.println(new String(Hex.encode(tc.key))); + // System.err.println(new String(Hex.encode(kr))); + // System.exit(1); + // } + // if (!Arrays.areEqual(tc.nonce, n)) + // { + // System.err.println("Nonce bad"); + // System.exit(1); + // } + // System.out.printf("[%d] m: %s\n", c, new String(Hex.encode(m, 0, len))); + // System.out.printf("[%d] K: %s\n", c, new String(Hex.encodje(kr))); + // System.out.printf("[%d] N: %s\n", c, new String(Hex.encode(n))); + // System.out.printf("[%d] M: ", c); + // } + // System.out.printf("%d/%s\n", c, new String(Hex.encode(out))); + + if (len >= MAXLEN) + break; + n[0] ^= loop; + for (int i = 0; i < 16; ++i) + n[i] ^= out[i]; + if (len % 2 != 0) + for (int i = 0; i < 16; ++i) + kr[i] ^= out[i]; + if (len % 3 != 0) + for (int i = 0; i < 16; ++i) + kr[i + 16] ^= out[i]; + Poly1305KeyGenerator.clamp(kr); + m[len++] ^= out[0]; + } + } + // Output after 13 loops as generated by poly1305 ref + if (c != 13013 || !Arrays.areEqual(out, Hex.decode("c96f60a23701a5b0fd2016f58cbe4f7e"))) + { + fail("Sequential Poly1305 " + c, "c96f60a23701a5b0fd2016f58cbe4f7e", new String(Hex.encode(out))); + } + } + + private void testReset() + { + CipherKeyGenerator gen = new Poly1305KeyGenerator(); + gen.init(new KeyGenerationParameters(new SecureRandom(), 256)); + byte[] k = gen.generateKey(); + + byte[] m = new byte[10000]; + byte[] check = new byte[16]; + byte[] out = new byte[16]; + + // Generate baseline + Mac poly = new Poly1305(new AESFastEngine()); + poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); + + poly.update(m, 0, m.length); + poly.doFinal(check, 0); + + // Check reset after doFinal + poly.update(m, 0, m.length); + poly.doFinal(out, 0); + + if (!Arrays.areEqual(check, out)) + { + fail("Mac not reset after doFinal"); + } + + // Check reset + poly.update((byte)1); + poly.update((byte)2); + poly.reset(); + poly.update(m, 0, m.length); + poly.doFinal(out, 0); + + if (!Arrays.areEqual(check, out)) + { + fail("Mac not reset after doFinal"); + } + + // Check init resets + poly.update((byte)1); + poly.update((byte)2); + poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); + poly.update(m, 0, m.length); + poly.doFinal(out, 0); + + if (!Arrays.areEqual(check, out)) + { + fail("Mac not reset after doFinal"); + } + } + + private void testInit() + { + CipherKeyGenerator gen = new Poly1305KeyGenerator(); + gen.init(new KeyGenerationParameters(new SecureRandom(), 256)); + byte[] k = gen.generateKey(); + + Mac poly = new Poly1305(new AESFastEngine()); + poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); + + try + { + poly.init(new ParametersWithIV(new KeyParameter(k), new byte[15])); + fail("16 byte nonce required"); + } catch (IllegalArgumentException e) + { + // Expected + } + + try + { + byte[] k2 = new byte[k.length - 1]; + System.arraycopy(k, 0, k2, 0, k2.length); + poly.init(new ParametersWithIV(new KeyParameter(k2), new byte[16])); + fail("32 byte key required"); + } catch (IllegalArgumentException e) + { + // Expected + } + + try + { + k[19] = (byte)0xFF; + poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); + fail("Unclamped key should not be accepted."); + } catch (IllegalArgumentException e) + { + // Expected + } + + } + + private void testKeyGenerator() + { + CipherKeyGenerator gen = new Poly1305KeyGenerator(); + gen.init(new KeyGenerationParameters(new SecureRandom(), 256)); + byte[] k = gen.generateKey(); + + if (k.length != 32) + { + fail("Poly1305 key should be 256 bits."); + } + + try + { + Poly1305KeyGenerator.checkKey(k); + } catch (IllegalArgumentException e) + { + fail("Poly1305 key should be clamped on generation."); + } + + byte[] k2 = new byte[k.length]; + System.arraycopy(k, 0, k2, 0, k2.length); + Poly1305KeyGenerator.clamp(k); + if (!Arrays.areEqual(k, k2)) + { + fail("Poly1305 key should be clamped on generation."); + } + + try + { + k2[19] = (byte)0xff; + Poly1305KeyGenerator.checkKey(k2); + fail("Unclamped key should fail check."); + } catch (IllegalArgumentException e) + { + // Expected + } + } + + public static void main(String[] args) + throws Exception + { + runTest(new Poly1305Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RC2Test.java b/core/src/test/java/org/spongycastle/crypto/test/RC2Test.java new file mode 100644 index 00000000..fde13347 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RC2Test.java @@ -0,0 +1,66 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.RC2Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.RC2Parameters; +import org.spongycastle.util.encoders.Hex; + +/** + * RC2 tester - vectors from ftp://ftp.isi.edu/in-notes/rfc2268.txt + * + * RFC 2268 "A Description of the RC2(r) Encryption Algorithm" + */ +public class RC2Test + extends CipherTest +{ + static BlockCipherVectorTest[] tests = + { + new BlockCipherVectorTest(0, new RC2Engine(), + new RC2Parameters(Hex.decode("0000000000000000"), 63), + "0000000000000000", "ebb773f993278eff"), + + new BlockCipherVectorTest(1, new RC2Engine(), + new RC2Parameters(Hex.decode("ffffffffffffffff"), 64), + "ffffffffffffffff", "278b27e42e2f0d49"), + + new BlockCipherVectorTest(2, new RC2Engine(), + new RC2Parameters(Hex.decode("3000000000000000"), 64), + "1000000000000001", "30649edf9be7d2c2"), + + new BlockCipherVectorTest(3, new RC2Engine(), + new RC2Parameters(Hex.decode("88"), 64), + "0000000000000000", "61a8a244adacccf0"), + + new BlockCipherVectorTest(4, new RC2Engine(), + new RC2Parameters(Hex.decode("88bca90e90875a"), 64), + "0000000000000000", "6ccf4308974c267f"), + + new BlockCipherVectorTest(5, new RC2Engine(), + new RC2Parameters(Hex.decode("88bca90e90875a7f0f79c384627bafb2"), 64), + "0000000000000000", "1a807d272bbe5db1"), + + new BlockCipherVectorTest(6, new RC2Engine(), + new RC2Parameters(Hex.decode("88bca90e90875a7f0f79c384627bafb2"), 128), + "0000000000000000", "2269552ab0f85ca6"), + + new BlockCipherVectorTest(7, new RC2Engine(), + new RC2Parameters(Hex.decode("88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e"), 129), + "0000000000000000", "5b78d3a43dfff1f1") + }; + + RC2Test() + { + super(tests, new RC2Engine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "RC2"; + } + + public static void main( + String[] args) + { + runTest(new RC2Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RC2WrapTest.java b/core/src/test/java/org/spongycastle/crypto/test/RC2WrapTest.java new file mode 100644 index 00000000..27cca204 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RC2WrapTest.java @@ -0,0 +1,111 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.Wrapper; +import org.spongycastle.crypto.engines.RC2WrapEngine; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.crypto.params.RC2Parameters; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * RC2 wrap tester + */ +public class RC2WrapTest + implements Test +{ + private class RFCRandom + extends SecureRandom + { + public void nextBytes( + byte[] nextBytes) + { + System.arraycopy(Hex.decode("4845cce7fd1250"), 0, nextBytes, 0, nextBytes.length); + } + } + + private TestResult wrapTest( + int id, + CipherParameters paramsWrap, + CipherParameters paramsUnwrap, + byte[] in, + byte[] out) + { + Wrapper wrapper = new RC2WrapEngine(); + + wrapper.init(true, paramsWrap); + + try + { + byte[] cText = wrapper.wrap(in, 0, in.length); + if (!Arrays.areEqual(cText, out)) + { + return new SimpleTestResult(false, getName() + ": failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": failed wrap test exception " + e.toString(), e); + } + + wrapper.init(false, paramsUnwrap); + + try + { + byte[] pText = wrapper.unwrap(out, 0, out.length); + if (!Arrays.areEqual(pText, in)) + { + return new SimpleTestResult(false, getName() + ": failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText))); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": failed unwrap test exception " + e.toString(), e); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public TestResult perform() + { + byte[] kek1 = Hex.decode("fd04fd08060707fb0003fefffd02fe05"); + byte[] iv1 = Hex.decode("c7d90059b29e97f7"); + byte[] in1 = Hex.decode("b70a25fbc9d86a86050ce0d711ead4d9"); + byte[] out1 = Hex.decode("70e699fb5701f7833330fb71e87c85a420bdc99af05d22af5a0e48d35f3138986cbaafb4b28d4f35"); + // + // note the RFC 3217 test specifies a key to be used with an effective key size of + // 40 bits which is why it is done here - in practice nothing less than 128 bits should be used. + // + CipherParameters paramWrap = new ParametersWithRandom(new ParametersWithIV(new RC2Parameters(kek1, 40), iv1), new RFCRandom()); + CipherParameters paramUnwrap = new RC2Parameters(kek1, 40); + + TestResult result = wrapTest(1, paramWrap, paramUnwrap, in1, out1); + + if (!result.isSuccessful()) + { + return result; + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public String getName() + { + return "RC2Wrap"; + } + + public static void main( + String[] args) + { + RC2WrapTest test = new RC2WrapTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RC4Test.java b/core/src/test/java/org/spongycastle/crypto/test/RC4Test.java new file mode 100644 index 00000000..c03b4e51 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RC4Test.java @@ -0,0 +1,45 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.RC4Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * RC4 Test + */ +public class RC4Test + extends SimpleTest +{ + StreamCipherVectorTest[] tests = + { + new StreamCipherVectorTest(0, new RC4Engine(), + new KeyParameter(Hex.decode("0123456789ABCDEF")), + "4e6f772069732074", "3afbb5c77938280d"), + new StreamCipherVectorTest(0, new RC4Engine(), + new KeyParameter(Hex.decode("0123456789ABCDEF")), + "68652074696d6520", "1cf1e29379266d59"), + new StreamCipherVectorTest(0, new RC4Engine(), + new KeyParameter(Hex.decode("0123456789ABCDEF")), + "666f7220616c6c20", "12fbb0c771276459") + }; + + public String getName() + { + return "RC4"; + } + + public void performTest() + { + for (int i = 0; i != tests.length; i++) + { + tests[i].performTest(); + } + } + + public static void main( + String[] args) + { + runTest(new RC4Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RC5Test.java b/core/src/test/java/org/spongycastle/crypto/test/RC5Test.java new file mode 100644 index 00000000..29686ee0 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RC5Test.java @@ -0,0 +1,188 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.RC532Engine; +import org.spongycastle.crypto.engines.RC564Engine; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.crypto.params.RC5Parameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * RC5 tester - vectors from ftp://ftp.nordu.net/rfc/rfc2040.txt + * + * RFC 2040 "The RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS Algorithms" + */ +public class RC5Test + implements Test +{ + BlockCipherVectorTest[] tests = + { + new BlockCipherVectorTest(0, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("0000000000000000")), + "0000000000000000", "7a7bba4d79111d1e"), + new BlockCipherVectorTest(1, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "797bba4d78111d1e"), + new BlockCipherVectorTest(2, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("0000000000000001")), + "0000000000000000", "7a7bba4d79111d1f"), + new BlockCipherVectorTest(3, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("0000000000000000")), + "0000000000000001", "7a7bba4d79111d1f"), + new BlockCipherVectorTest(4, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("0102030405060708")), + "1020304050607080", "8b9ded91ce7794a6"), + new BlockCipherVectorTest(5, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("11"), 1), + Hex.decode("0000000000000000")), + "0000000000000000", "2f759fe7ad86a378"), + new BlockCipherVectorTest(6, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 2), + Hex.decode("0000000000000000")), + "0000000000000000", "dca2694bf40e0788"), + new BlockCipherVectorTest(7, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00000000"), 2), + Hex.decode("0000000000000000")), + "0000000000000000", "dca2694bf40e0788"), + new BlockCipherVectorTest(8, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00000000"), 8), + Hex.decode("0000000000000000")), + "0000000000000000", "dcfe098577eca5ff"), + new BlockCipherVectorTest(9, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 8), + Hex.decode("0102030405060708")), + "1020304050607080", "9646fb77638f9ca8"), + new BlockCipherVectorTest(10, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 12), + Hex.decode("0102030405060708")), + "1020304050607080", "b2b3209db6594da4"), + new BlockCipherVectorTest(11, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 16), + Hex.decode("0102030405060708")), + "1020304050607080", "545f7f32a5fc3836"), + new BlockCipherVectorTest(12, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304"), 8), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "8285e7c1b5bc7402"), + new BlockCipherVectorTest(13, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304"), 12), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "fc586f92f7080934"), + new BlockCipherVectorTest(14, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304"), 16), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "cf270ef9717ff7c4"), + new BlockCipherVectorTest(15, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405060708"), 12), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "e493f1c1bb4d6e8c"), + new BlockCipherVectorTest(16, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405060708"), 8), + Hex.decode("0102030405060708")), + "1020304050607080", "5c4c041e0f217ac3"), + new BlockCipherVectorTest(17, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405060708"), 12), + Hex.decode("0102030405060708")), + "1020304050607080", "921f12485373b4f7"), + new BlockCipherVectorTest(18, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405060708"), 16), + Hex.decode("0102030405060708")), + "1020304050607080", "5ba0ca6bbe7f5fad"), + new BlockCipherVectorTest(19, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304050607081020304050607080"), 8), + Hex.decode("0102030405060708")), + "1020304050607080", "c533771cd0110e63"), + new BlockCipherVectorTest(20, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304050607081020304050607080"), 12), + Hex.decode("0102030405060708")), + "1020304050607080", "294ddb46b3278d60"), + new BlockCipherVectorTest(21, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304050607081020304050607080"), 16), + Hex.decode("0102030405060708")), + "1020304050607080", "dad6bda9dfe8f7e8"), + new BlockCipherVectorTest(22, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405"), 12), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "97e0787837ed317f"), + new BlockCipherVectorTest(23, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405"), 8), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "7875dbf6738c6478"), + new BlockCipherVectorTest(23, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405"), 8), + Hex.decode("7875dbf6738c6478")), + "0808080808080808", "8f34c3c681c99695"), + new BlockCipherVectorTest(640, new CBCBlockCipher(new RC564Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "9f09b98d3f6062d9d4d59973d00e0e63"), + new BlockCipherVectorTest(641, new CBCBlockCipher(new RC564Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("00000000000000000000000000000000")), + "ffffffffffffffffffffffffffffffff", "9e09b98d3f6062d9d3d59973d00e0e63") + }; + + public String getName() + { + return "RC5"; + } + + public TestResult perform() + { + for (int i = 0; i != tests.length; i++) + { + TestResult res = tests[i].perform(); + + if (!res.isSuccessful()) + { + return res; + } + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + RC5Test test = new RC5Test(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RC6Test.java b/core/src/test/java/org/spongycastle/crypto/test/RC6Test.java new file mode 100644 index 00000000..9d91547b --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RC6Test.java @@ -0,0 +1,64 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.RC6Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * RC6 Test - test vectors from AES Submitted RSA Reference implementation. + * ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/aes/rc6-unix-refc.tar + */ +public class RC6Test + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new RC6Engine(), + new KeyParameter( + Hex.decode("00000000000000000000000000000000")), + "80000000000000000000000000000000", + "f71f65e7b80c0c6966fee607984b5cdf"), + new BlockCipherVectorTest(1, new RC6Engine(), + new KeyParameter( + Hex.decode("000000000000000000000000000000008000000000000000")), + "00000000000000000000000000000000", + "dd04c176440bbc6686c90aee775bd368"), + new BlockCipherVectorTest(2, new RC6Engine(), + new KeyParameter( + Hex.decode("000000000000000000000000000000000000001000000000")), + "00000000000000000000000000000000", + "937fe02d20fcb72f0f57201012b88ba4"), + new BlockCipherVectorTest(3, new RC6Engine(), + new KeyParameter( + Hex.decode("00000001000000000000000000000000")), + "00000000000000000000000000000000", + "8a380594d7396453771a1dfbe2914c8e"), + new BlockCipherVectorTest(4, new RC6Engine(), + new KeyParameter( + Hex.decode("1000000000000000000000000000000000000000000000000000000000000000")), + "00000000000000000000000000000000", + "11395d4bfe4c8258979ee2bf2d24dff4"), + new BlockCipherVectorTest(5, new RC6Engine(), + new KeyParameter( + Hex.decode("0000000000000000000000000000000000080000000000000000000000000000")), + "00000000000000000000000000000000", + "3d6f7e99f6512553bb983e8f75672b97") + }; + + RC6Test() + { + super(tests, new RC6Engine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "RC6"; + } + + public static void main( + String[] args) + { + runTest(new RC6Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RFC3211WrapTest.java b/core/src/test/java/org/spongycastle/crypto/test/RFC3211WrapTest.java new file mode 100644 index 00000000..8568e590 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RFC3211WrapTest.java @@ -0,0 +1,220 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.Wrapper; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.engines.DESedeEngine; +import org.spongycastle.crypto.engines.RFC3211WrapEngine; +import org.spongycastle.crypto.modes.CBCBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +import java.security.SecureRandom; + +/** + * Wrap Test based on RFC3211 test vectors + */ +public class RFC3211WrapTest + extends SimpleTest +{ + SecureRandom r1 = new SecureRandom() + { + int[] ints = { 0xC4, 0x36, 0xF5, 0x41 }; + int count = 0; + + public int nextInt() + { + return ints[count++]; + } + }; + + SecureRandom r2 = new SecureRandom() + { + int[] ints = { 0xFA, 0x06, 0x0A, 0x45 }; + int count = 0; + + public int nextInt() + { + return ints[count++]; + } + }; + + public String getName() + { + return "RFC3211Wrap"; + } + + private void wrapTest( + int id, + BlockCipher engine, + byte[] kek, + byte[] iv, + SecureRandom rand, + byte[] in, + byte[] out) + throws Exception + { + Wrapper wrapper = new RFC3211WrapEngine(engine); + + wrapper.init(true, new ParametersWithRandom(new ParametersWithIV(new KeyParameter(kek), iv), rand)); + + byte[] cText = wrapper.wrap(in, 0, in.length); + if (!Arrays.areEqual(cText, out)) + { + fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + + wrapper.init(false, new ParametersWithIV(new KeyParameter(kek), iv)); + + byte[] pText = wrapper.unwrap(out, 0, out.length); + if (!Arrays.areEqual(pText, in)) + { + fail("rfailed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText))); + } + } + + private void testCorruption() + throws InvalidCipherTextException + { + byte[] kek = Hex.decode("D1DAA78615F287E6"); + byte[] iv = Hex.decode("EFE598EF21B33D6D"); + + Wrapper wrapper = new RFC3211WrapEngine(new DESEngine()); + + wrapper.init(false, new ParametersWithIV(new KeyParameter(kek), iv)); + + byte[] block = Hex.decode("ff739D838C627C897323A2F8C436F541"); + encryptBlock(kek, iv, block); + + try + { + wrapper.unwrap(block, 0, block.length); + + fail("bad length not detected"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals("wrapped key corrupted")) + { + fail("wrong exception on length"); + } + } + + block = Hex.decode("08639D838C627C897323A2F8C436F541"); + testChecksum(kek, iv, block, wrapper); + + block = Hex.decode("08736D838C627C897323A2F8C436F541"); + testChecksum(kek, iv, block, wrapper); + + block = Hex.decode("08739D638C627C897323A2F8C436F541"); + testChecksum(kek, iv, block, wrapper); + } + + private void testChecksum(byte[] kek, byte[] iv, byte[] block, Wrapper wrapper) + { + encryptBlock(kek, iv, block); + + try + { + wrapper.unwrap(block, 0, block.length); + + fail("bad checksum not detected"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals("wrapped key fails checksum")) + { + fail("wrong exception"); + } + } + } + + private void encryptBlock(byte[] key, byte[] iv, byte[] cekBlock) + { + BlockCipher engine = new CBCBlockCipher(new DESEngine()); + + engine.init(true, new ParametersWithIV(new KeyParameter(key), iv)); + + for (int i = 0; i < cekBlock.length; i += 8) + { + engine.processBlock(cekBlock, i, cekBlock, i); + } + + for (int i = 0; i < cekBlock.length; i += 8) + { + engine.processBlock(cekBlock, i, cekBlock, i); + } + } + + public void performTest() + throws Exception + { + wrapTest(1, new DESEngine(), Hex.decode("D1DAA78615F287E6"), Hex.decode("EFE598EF21B33D6D"), r1, Hex.decode("8C627C897323A2F8"), Hex.decode("B81B2565EE373CA6DEDCA26A178B0C10")); + wrapTest(2, new DESedeEngine(), Hex.decode("6A8970BF68C92CAEA84A8DF28510858607126380CC47AB2D"), Hex.decode("BAF1CA7931213C4E"), r2, + Hex.decode("8C637D887223A2F965B566EB014B0FA5D52300A3F7EA40FFFC577203C71BAF3B"), + Hex.decode("C03C514ABDB9E2C5AAC038572B5E24553876B377AAFB82ECA5A9D73F8AB143D9EC74E6CAD7DB260C")); + + testCorruption(); + + Wrapper wrapper = new RFC3211WrapEngine(new DESEngine()); + ParametersWithIV params = new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16]); + byte[] buf = new byte[16]; + + try + { + wrapper.init(true, params); + + wrapper.unwrap(buf, 0, buf.length); + + fail("failed unwrap state test."); + } + catch (IllegalStateException e) + { + // expected + } + catch (InvalidCipherTextException e) + { + fail("unexpected exception: " + e, e); + } + + try + { + wrapper.init(false, params); + + wrapper.wrap(buf, 0, buf.length); + + fail("failed unwrap state test."); + } + catch (IllegalStateException e) + { + // expected + } + + // + // short test + // + try + { + wrapper.init(false, params); + + wrapper.unwrap(buf, 0, buf.length / 2); + + fail("failed unwrap short test."); + } + catch (InvalidCipherTextException e) + { + // expected + } + } + + public static void main( + String[] args) + { + runTest(new RFC3211WrapTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RIPEMD128DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD128DigestTest.java new file mode 100644 index 00000000..04c1c2b2 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD128DigestTest.java @@ -0,0 +1,58 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.RIPEMD128Digest; + +/** + * RIPEMD128 Digest Test + */ +public class RIPEMD128DigestTest + extends DigestTest +{ + final static String[] messages = { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + final static String[] digests = { + "cdf26213a150dc3ecb610f18f6b38b46", + "86be7afa339d0fc7cfc785e72f578d33", + "c14a12199c66e4ba84636b0f69144c77", + "9e327b3d6e523062afc1132d7df9d1b8", + "fd2aa607f71dc8f510714922b371834e", + "a1aa0689d0fafa2ddc22e88b49133a06", + "d1e959eb179c911faea4624c60c5c702", + "3f45ef194732c2dbb2c4a2c769795fa3" + }; + + final static String million_a_digest = "4a7f5723f954eba1216c9d8f6320431f"; + + RIPEMD128DigestTest() + { + super(new RIPEMD128Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new RIPEMD128Digest((RIPEMD128Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new RIPEMD128DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RIPEMD128HMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD128HMacTest.java new file mode 100644 index 00000000..8a0a07c2 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD128HMacTest.java @@ -0,0 +1,86 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.digests.RIPEMD128Digest; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * RIPEMD128 HMac Test, test vectors from RFC 2286 + */ +public class RIPEMD128HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "fbf61f9492aa4bbf81c172e84e0734db", + "875f828862b6b334b427c55f9f7ff09b", + "09f0b2846d2f543da363cbec8d62a38d", + "bdbbd7cf03e44b5aa60af815be4d2294", + "e79808f24b25fd031c155f0d551d9a3a", + "dc732928de98104a1f59d373c150acbb", + "5c6bec96793e16d40690c237635f30c5" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" + }; + + public String getName() + { + return "RIPEMD128HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new RIPEMD128Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed"); + } + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + RIPEMD128HMacTest test = new RIPEMD128HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RIPEMD160DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD160DigestTest.java new file mode 100644 index 00000000..9af98c92 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD160DigestTest.java @@ -0,0 +1,58 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.RIPEMD160Digest; + +/** + * RIPEMD160 Digest Test + */ +public class RIPEMD160DigestTest + extends DigestTest +{ + final static String[] messages = { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + final static String[] digests = { + "9c1185a5c5e9fc54612808977ee8f548b2258d31", + "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", + "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", + "5d0689ef49d2fae572b881b123a85ffa21595f36", + "f71c27109c692c1b56bbdceb5b9d2865b3708dbc", + "12a053384a9c0c88e405a06c27dcf49ada62eb2b", + "b0e20b6e3116640286ed3a87a5713079b21f5189", + "9b752e45573d4b39f4dbd3323cab82bf63326bfb" + }; + + final static String million_a_digest = "52783243c1697bdbe16d37f97f68f08325dc1528"; + + RIPEMD160DigestTest() + { + super(new RIPEMD160Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new RIPEMD160Digest((RIPEMD160Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new RIPEMD160DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RIPEMD160HMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD160HMacTest.java new file mode 100644 index 00000000..1676fef3 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD160HMacTest.java @@ -0,0 +1,86 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.digests.RIPEMD160Digest; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * RIPEMD160 HMac Test, test vectors from RFC 2286 + */ +public class RIPEMD160HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668", + "dda6c0213a485a9e24f4742064a7f033b43c4069", + "b0b105360de759960ab4f35298e116e295d8e7c1", + "d5ca862f4d21d5e610e18b4cf1beb97a4365ecf4", + "7619693978f91d90539ae786500ff3d8e0518e39", + "6466ca07ac5eac29e1bd523e5ada7605b791fd8b", + "69ea60798d71616cce5fd0871e23754cd75d5a0a" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" + }; + + public String getName() + { + return "RIPEMD160HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new RIPEMD160Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed"); + } + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + RIPEMD160HMacTest test = new RIPEMD160HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RIPEMD256DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD256DigestTest.java new file mode 100644 index 00000000..dd8a1b9c --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD256DigestTest.java @@ -0,0 +1,58 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.RIPEMD256Digest; + +/** + * RIPEMD128 Digest Test + */ +public class RIPEMD256DigestTest + extends DigestTest +{ + final static String[] messages = { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + final static String[] digests = { + "02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d", + "f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925", + "afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65", + "87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e", + "649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133", + "3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f", + "5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8", + "06fdcc7a409548aaf91368c06a6275b553e3f099bf0ea4edfd6778df89a890dd" + }; + + final static String million_a_digest = "ac953744e10e31514c150d4d8d7b677342e33399788296e43ae4850ce4f97978"; + + RIPEMD256DigestTest() + { + super(new RIPEMD256Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new RIPEMD256Digest((RIPEMD256Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new RIPEMD256DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RIPEMD320DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD320DigestTest.java new file mode 100644 index 00000000..c64616ba --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RIPEMD320DigestTest.java @@ -0,0 +1,58 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.RIPEMD320Digest; + +/** + * RIPEMD320 Digest Test + */ +public class RIPEMD320DigestTest + extends DigestTest +{ + final static String[] messages = { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + final static String[] digests = { + "22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8", + "ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d", + "de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d", + "3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197", + "cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009", + "d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac", + "ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4", + "557888af5f6d8ed62ab66945c6d2a0a47ecd5341e915eb8fea1d0524955f825dc717e4a008ab2d42" + }; + + final static String million_a_digest = "bdee37f4371e20646b8b0d862dda16292ae36f40965e8c8509e63d1dbddecc503e2b63eb9245bb66"; + + RIPEMD320DigestTest() + { + super(new RIPEMD320Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new RIPEMD320Digest((RIPEMD320Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new RIPEMD320DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RSABlindedTest.java b/core/src/test/java/org/spongycastle/crypto/test/RSABlindedTest.java new file mode 100644 index 00000000..749e6ba1 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RSABlindedTest.java @@ -0,0 +1,437 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.AsymmetricBlockCipher; +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.encodings.OAEPEncoding; +import org.spongycastle.crypto.encodings.PKCS1Encoding; +import org.spongycastle.crypto.engines.RSABlindedEngine; +import org.spongycastle.crypto.generators.RSAKeyPairGenerator; +import org.spongycastle.crypto.params.RSAKeyGenerationParameters; +import org.spongycastle.crypto.params.RSAKeyParameters; +import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +import java.math.BigInteger; +import java.security.SecureRandom; + +public class RSABlindedTest + extends SimpleTest +{ + static BigInteger mod = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16); + static BigInteger pubExp = new BigInteger("11", 16); + static BigInteger privExp = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16); + static BigInteger p = new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16); + static BigInteger q = new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16); + static BigInteger pExp = new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16); + static BigInteger qExp = new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16); + static BigInteger crtCoef = new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16); + + static String input = "4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + // + // to check that we handling byte extension by big number correctly. + // + static String edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + static byte[] oversizedSig = Hex.decode("01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] dudBlock = Hex.decode("000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] truncatedDataBlock = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] incorrectPadding = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] missingDataBlock = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + + public String getName() + { + return "RSABlinded"; + } + + private void testStrictPKCS1Length(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + AsymmetricBlockCipher eng = new RSABlindedEngine(); + + eng.init(true, privParameters); + + byte[] data = null; + + try + { + data = eng.processBlock(oversizedSig, 0, oversizedSig.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng = new PKCS1Encoding(eng); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + + fail("oversized signature block not recognised"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals("block incorrect size")) + { + fail("RSA: failed - exception " + e.toString(), e); + } + } + + //System.setProperty(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY, "false"); + + System.getProperties().put(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY, "false"); + eng = new PKCS1Encoding(new RSABlindedEngine()); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (InvalidCipherTextException e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + System.getProperties().remove(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY); + } + + private void testTruncatedPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block truncated"); + } + + private void testDudPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "unknown block type"); + } + + private void testWrongPaddingPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block padding incorrect"); + } + + private void testMissingDataPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "no data in block"); + } + + private void checkForPKCS1Exception(RSAKeyParameters pubParameters, RSAKeyParameters privParameters, byte[] inputData, String expectedMessage) + { + AsymmetricBlockCipher eng = new RSABlindedEngine(); + + eng.init(true, privParameters); + + byte[] data = null; + + try + { + data = eng.processBlock(inputData, 0, inputData.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng = new PKCS1Encoding(eng); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + + fail("missing data block not recognised"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals(expectedMessage)) + { + fail("RSA: failed - exception " + e.toString(), e); + } + } + } + + private void testOAEP(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + // + // OAEP - public encrypt, private decrypt + // + AsymmetricBlockCipher eng = new OAEPEncoding(new RSABlindedEngine()); + byte[] data = Hex.decode(input); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed OAEP Test"); + } + } + + public void performTest() + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); + RSAKeyParameters privParameters = new RSAPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef); + byte[] data = Hex.decode(edgeInput); + + // + // RAW + // + AsymmetricBlockCipher eng = new RSABlindedEngine(); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!edgeInput.equals(new String(Hex.encode(data)))) + { + fail("failed RAW edge Test"); + } + + data = Hex.decode(input); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed RAW Test"); + } + + // + // PKCS1 - public encrypt, private decrypt + // + eng = new PKCS1Encoding(eng); + + eng.init(true, pubParameters); + + if (eng.getOutputBlockSize() != ((PKCS1Encoding)eng).getUnderlyingCipher().getOutputBlockSize()) + { + fail("PKCS1 output block size incorrect"); + } + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed PKCS1 public/private Test"); + } + + // + // PKCS1 - private encrypt, public decrypt + // + eng = new PKCS1Encoding(((PKCS1Encoding)eng).getUnderlyingCipher()); + + eng.init(true, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed PKCS1 private/public Test"); + } + + // + // key generation test + // + RSAKeyPairGenerator pGen = new RSAKeyPairGenerator(); + RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters( + BigInteger.valueOf(0x11), new SecureRandom(), 768, 25); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + eng = new RSABlindedEngine(); + + if (((RSAKeyParameters)pair.getPublic()).getModulus().bitLength() < 768) + { + fail("failed key generation (768) length test"); + } + + eng.init(true, pair.getPublic()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pair.getPrivate()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed key generation (768) Test"); + } + + genParam = new RSAKeyGenerationParameters(BigInteger.valueOf(0x11), new SecureRandom(), 1024, 25); + + pGen.init(genParam); + pair = pGen.generateKeyPair(); + + eng.init(true, pair.getPublic()); + + if (((RSAKeyParameters)pair.getPublic()).getModulus().bitLength() < 1024) + { + fail("failed key generation (1024) length test"); + } + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pair.getPrivate()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed key generation (1024) test"); + } + + testOAEP(pubParameters, privParameters); + testStrictPKCS1Length(pubParameters, privParameters); + testDudPKCS1Block(pubParameters, privParameters); + testMissingDataPKCS1Block(pubParameters, privParameters); + testTruncatedPKCS1Block(pubParameters, privParameters); + testWrongPaddingPKCS1Block(pubParameters, privParameters); + + try + { + new RSABlindedEngine().processBlock(new byte[]{ 1 }, 0, 1); + fail("failed initialisation check"); + } + catch (IllegalStateException e) + { + // expected + } + } + + + public static void main( + String[] args) + { + runTest(new RSABlindedTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RSADigestSignerTest.java b/core/src/test/java/org/spongycastle/crypto/test/RSADigestSignerTest.java new file mode 100644 index 00000000..5587dcf8 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RSADigestSignerTest.java @@ -0,0 +1,55 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.asn1.x509.X509ObjectIdentifiers; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.params.RSAKeyParameters; +import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters; +import org.spongycastle.crypto.signers.RSADigestSigner; +import org.spongycastle.util.encoders.Base64; +import org.spongycastle.util.test.SimpleTest; + +import java.math.BigInteger; + +public class RSADigestSignerTest + extends SimpleTest +{ + public String getName() + { + return "RSADigestSigner"; + } + + public void performTest() throws Exception + { + BigInteger rsaPubMod = new BigInteger(Base64.decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt")); + BigInteger rsaPubExp = new BigInteger(Base64.decode("EQ==")); + BigInteger rsaPrivMod = new BigInteger(Base64.decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt")); + BigInteger rsaPrivDP = new BigInteger(Base64.decode("JXzfzG5v+HtLJIZqYMUefJfFLu8DPuJGaLD6lI3cZ0babWZ/oPGoJa5iHpX4Ul/7l3s1PFsuy1GhzCdOdlfRcQ==")); + BigInteger rsaPrivDQ = new BigInteger(Base64.decode("YNdJhw3cn0gBoVmMIFRZzflPDNthBiWy/dUMSRfJCxoZjSnr1gysZHK01HteV1YYNGcwPdr3j4FbOfri5c6DUQ==")); + BigInteger rsaPrivExp = new BigInteger(Base64.decode("DxFAOhDajr00rBjqX+7nyZ/9sHWRCCp9WEN5wCsFiWVRPtdB+NeLcou7mWXwf1Y+8xNgmmh//fPV45G2dsyBeZbXeJwB7bzx9NMEAfedchyOwjR8PYdjK3NpTLKtZlEJ6Jkh4QihrXpZMO4fKZWUm9bid3+lmiq43FwW+Hof8/E=")); + BigInteger rsaPrivP = new BigInteger(Base64.decode("AJ9StyTVW+AL/1s7RBtFwZGFBgd3zctBqzzwKPda6LbtIFDznmwDCqAlIQH9X14X7UPLokCDhuAa76OnDXb1OiE=")); + BigInteger rsaPrivQ = new BigInteger(Base64.decode("AM3JfD79dNJ5A3beScSzPtWxx/tSLi0QHFtkuhtSizeXdkv5FSba7lVzwEOGKHmW829bRoNxThDy4ds1IihW1w0=")); + BigInteger rsaPrivQinv = new BigInteger(Base64.decode("Lt0g7wrsNsQxuDdB8q/rH8fSFeBXMGLtCIqfOec1j7FEIuYA/ACiRDgXkHa0WgN7nLXSjHoy630wC5Toq8vvUg==")); + RSAKeyParameters rsaPublic = new RSAKeyParameters(false, rsaPubMod, rsaPubExp); + RSAPrivateCrtKeyParameters rsaPrivate = new RSAPrivateCrtKeyParameters(rsaPrivMod, rsaPubExp, rsaPrivExp, rsaPrivP, rsaPrivQ, rsaPrivDP, rsaPrivDQ, rsaPrivQinv); + + byte[] msg = new byte[] { 1, 6, 3, 32, 7, 43, 2, 5, 7, 78, 4, 23 }; + + RSADigestSigner signer = new RSADigestSigner(new SHA1Digest()); + signer.init(true, rsaPrivate); + signer.update(msg, 0, msg.length); + byte[] sig = signer.generateSignature(); + + signer = new RSADigestSigner(new SHA1Digest(), X509ObjectIdentifiers.id_SHA1); + signer.init(false, rsaPublic); + signer.update(msg, 0, msg.length); + if (!signer.verifySignature(sig)) + { + fail("RSA Digest Signer failed."); + } + } + + public static void main(String[] args) + { + runTest(new RSADigestSignerTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RSAKeyEncapsulationTest.java b/core/src/test/java/org/spongycastle/crypto/test/RSAKeyEncapsulationTest.java new file mode 100755 index 00000000..b2f0f8fd --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RSAKeyEncapsulationTest.java @@ -0,0 +1,61 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.generators.KDF2BytesGenerator; +import org.spongycastle.crypto.generators.RSAKeyPairGenerator; +import org.spongycastle.crypto.kems.RSAKeyEncapsulation; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.RSAKeyGenerationParameters; +import org.spongycastle.util.test.SimpleTest; + +/** + * Tests for the RSA Key Encapsulation Mechanism + */ +public class RSAKeyEncapsulationTest + extends SimpleTest +{ + public String getName() + { + return "RSAKeyEncapsulation"; + } + + public void performTest() + throws Exception + { + // Generate RSA key pair + RSAKeyPairGenerator rsaGen = new RSAKeyPairGenerator(); + rsaGen.init(new RSAKeyGenerationParameters(BigInteger.valueOf(65537), new SecureRandom(), 1024, 5)); + AsymmetricCipherKeyPair keys = rsaGen.generateKeyPair(); + + // Set RSA-KEM parameters + RSAKeyEncapsulation kem; + KDF2BytesGenerator kdf = new KDF2BytesGenerator(new SHA1Digest()); + SecureRandom rnd = new SecureRandom(); + byte[] out = new byte[128]; + KeyParameter key1, key2; + + // Test RSA-KEM + kem = new RSAKeyEncapsulation(kdf, rnd); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed test"); + } + } + + public static void main( + String[] args) + { + runTest(new RSAKeyEncapsulationTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RSATest.java b/core/src/test/java/org/spongycastle/crypto/test/RSATest.java new file mode 100644 index 00000000..bf115003 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RSATest.java @@ -0,0 +1,498 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.AsymmetricBlockCipher; +import org.spongycastle.crypto.AsymmetricCipherKeyPair; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.encodings.OAEPEncoding; +import org.spongycastle.crypto.encodings.PKCS1Encoding; +import org.spongycastle.crypto.engines.RSAEngine; +import org.spongycastle.crypto.generators.RSAKeyPairGenerator; +import org.spongycastle.crypto.params.RSAKeyGenerationParameters; +import org.spongycastle.crypto.params.RSAKeyParameters; +import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class RSATest + extends SimpleTest +{ + static BigInteger mod = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16); + static BigInteger pubExp = new BigInteger("11", 16); + static BigInteger privExp = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16); + static BigInteger p = new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16); + static BigInteger q = new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16); + static BigInteger pExp = new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16); + static BigInteger qExp = new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16); + static BigInteger crtCoef = new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16); + + static String input = "4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + // + // to check that we handling byte extension by big number correctly. + // + static String edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + static byte[] oversizedSig = Hex.decode("01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] dudBlock = Hex.decode("000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] truncatedDataBlock = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] incorrectPadding = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] missingDataBlock = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + + public String getName() + { + return "RSA"; + } + + private void testStrictPKCS1Length(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + AsymmetricBlockCipher eng = new RSAEngine(); + + eng.init(true, privParameters); + + byte[] data = null; + + try + { + data = eng.processBlock(oversizedSig, 0, oversizedSig.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng = new PKCS1Encoding(eng); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + + fail("oversized signature block not recognised"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals("block incorrect size")) + { + fail("RSA: failed - exception " + e.toString(), e); + } + } + + //System.setProperty(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY, "false"); + + System.getProperties().put(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY, "false"); + eng = new PKCS1Encoding(new RSAEngine()); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (InvalidCipherTextException e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + System.getProperties().remove(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY); + } + + private void testTruncatedPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block truncated"); + } + + private void testDudPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "unknown block type"); + } + + private void testWrongPaddingPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block padding incorrect"); + } + + private void testMissingDataPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "no data in block"); + } + + private void checkForPKCS1Exception(RSAKeyParameters pubParameters, RSAKeyParameters privParameters, byte[] inputData, String expectedMessage) + { + AsymmetricBlockCipher eng = new RSAEngine(); + + eng.init(true, privParameters); + + byte[] data = null; + + try + { + data = eng.processBlock(inputData, 0, inputData.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng = new PKCS1Encoding(eng); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + + fail("missing data block not recognised"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals(expectedMessage)) + { + fail("RSA: failed - exception " + e.toString(), e); + } + } + } + + private void testOAEP(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + // + // OAEP - public encrypt, private decrypt + // + AsymmetricBlockCipher eng = new OAEPEncoding(new RSAEngine()); + byte[] data = Hex.decode(input); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed OAEP Test"); + } + } + + private void zeroBlockTest(CipherParameters encParameters, CipherParameters decParameters) + { + AsymmetricBlockCipher eng = new PKCS1Encoding(new RSAEngine()); + + eng.init(true, encParameters); + + if (eng.getOutputBlockSize() != ((PKCS1Encoding)eng).getUnderlyingCipher().getOutputBlockSize()) + { + fail("PKCS1 output block size incorrect"); + } + + byte[] zero = new byte[0]; + byte[] data = null; + + try + { + data = eng.processBlock(zero, 0, zero.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, decParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!Arrays.areEqual(zero, data)) + { + fail("failed PKCS1 zero Test"); + } + } + + public void performTest() + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); + RSAKeyParameters privParameters = new RSAPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef); + byte[] data = Hex.decode(edgeInput); + + // + // RAW + // + AsymmetricBlockCipher eng = new RSAEngine(); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!edgeInput.equals(new String(Hex.encode(data)))) + { + fail("failed RAW edge Test"); + } + + data = Hex.decode(input); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed RAW Test"); + } + + // + // PKCS1 - public encrypt, private decrypt + // + eng = new PKCS1Encoding(eng); + + eng.init(true, pubParameters); + + if (eng.getOutputBlockSize() != ((PKCS1Encoding)eng).getUnderlyingCipher().getOutputBlockSize()) + { + fail("PKCS1 output block size incorrect"); + } + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed PKCS1 public/private Test"); + } + + // + // PKCS1 - private encrypt, public decrypt + // + eng = new PKCS1Encoding(((PKCS1Encoding)eng).getUnderlyingCipher()); + + eng.init(true, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed PKCS1 private/public Test"); + } + + zeroBlockTest(pubParameters, privParameters); + zeroBlockTest(privParameters, pubParameters); + + // + // key generation test + // + RSAKeyPairGenerator pGen = new RSAKeyPairGenerator(); + RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters( + BigInteger.valueOf(0x11), new SecureRandom(), 768, 25); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + eng = new RSAEngine(); + + if (((RSAKeyParameters)pair.getPublic()).getModulus().bitLength() < 768) + { + fail("failed key generation (768) length test"); + } + + eng.init(true, pair.getPublic()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pair.getPrivate()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed key generation (768) Test"); + } + + genParam = new RSAKeyGenerationParameters(BigInteger.valueOf(0x11), new SecureRandom(), 1024, 25); + + pGen.init(genParam); + pair = pGen.generateKeyPair(); + + eng.init(true, pair.getPublic()); + + if (((RSAKeyParameters)pair.getPublic()).getModulus().bitLength() < 1024) + { + fail("failed key generation (1024) length test"); + } + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pair.getPrivate()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed key generation (1024) test"); + } + + genParam = new RSAKeyGenerationParameters( + BigInteger.valueOf(0x11), new SecureRandom(), 16, 25); + pGen.init(genParam); + + for (int i = 0; i < 100; ++i) + { + pair = pGen.generateKeyPair(); + RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters) pair.getPrivate(); + BigInteger pqDiff = privKey.getP().subtract(privKey.getQ()).abs(); + + if (pqDiff.bitLength() < 5) + { + fail("P and Q too close in RSA key pair"); + } + } + + testOAEP(pubParameters, privParameters); + testStrictPKCS1Length(pubParameters, privParameters); + testDudPKCS1Block(pubParameters, privParameters); + testMissingDataPKCS1Block(pubParameters, privParameters); + testTruncatedPKCS1Block(pubParameters, privParameters); + testWrongPaddingPKCS1Block(pubParameters, privParameters); + + try + { + new RSAEngine().processBlock(new byte[]{ 1 }, 0, 1); + fail("failed initialisation check"); + } + catch (IllegalStateException e) + { + // expected + } + } + + + public static void main( + String[] args) + { + runTest(new RSATest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RegressionTest.java b/core/src/test/java/org/spongycastle/crypto/test/RegressionTest.java new file mode 100644 index 00000000..0c89e979 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RegressionTest.java @@ -0,0 +1,157 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +public class RegressionTest +{ + public static Test[] tests = + { + new AESTest(), + new AESLightTest(), + new AESFastTest(), + new AESWrapTest(), + new AESWrapPadTest(), + new DESTest(), + new DESedeTest(), + new ModeTest(), + new PaddingTest(), + new DHTest(), + new ElGamalTest(), + new DSATest(), + new ECTest(), + new DeterministicDSATest(), + new GOST3410Test(), + new ECGOST3410Test(), + new ECIESTest(), + new ECNRTest(), + new MacTest(), + new GOST28147MacTest(), + new RC2Test(), + new RC2WrapTest(), + new RC4Test(), + new RC5Test(), + new RC6Test(), + new RijndaelTest(), + new SerpentTest(), + new CamelliaTest(), + new CamelliaLightTest(), + new DigestRandomNumberTest(), + new SkipjackTest(), + new BlowfishTest(), + new TwofishTest(), + new Threefish256Test(), + new Threefish512Test(), + new Threefish1024Test(), + new SkeinDigestTest(), + new SkeinMacTest(), + new CAST5Test(), + new CAST6Test(), + new GOST28147Test(), + new IDEATest(), + new RSATest(), + new RSABlindedTest(), + new RSADigestSignerTest(), + new PSSBlindTest(), + new ISO9796Test(), + new ISO9797Alg3MacTest(), + new MD2DigestTest(), + new MD4DigestTest(), + new MD5DigestTest(), + new SHA1DigestTest(), + new SHA224DigestTest(), + new SHA256DigestTest(), + new SHA384DigestTest(), + new SHA512DigestTest(), + new SHA512t224DigestTest(), + new SHA512t256DigestTest(), + new SHA3DigestTest(), + new RIPEMD128DigestTest(), + new RIPEMD160DigestTest(), + new RIPEMD256DigestTest(), + new RIPEMD320DigestTest(), + new TigerDigestTest(), + new GOST3411DigestTest(), + new WhirlpoolDigestTest(), + new MD5HMacTest(), + new SHA1HMacTest(), + new SHA224HMacTest(), + new SHA256HMacTest(), + new SHA384HMacTest(), + new SHA512HMacTest(), + new RIPEMD128HMacTest(), + new RIPEMD160HMacTest(), + new OAEPTest(), + new PSSTest(), + new CTSTest(), + new CCMTest(), + new PKCS5Test(), + new PKCS12Test(), + new KDF1GeneratorTest(), + new KDF2GeneratorTest(), + new MGF1GeneratorTest(), + new HKDFGeneratorTest(), + new DHKEKGeneratorTest(), + new ECDHKEKGeneratorTest(), + new ShortenedDigestTest(), + new EqualsHashCodeTest(), + new TEATest(), + new XTEATest(), + new RFC3211WrapTest(), + new SEEDTest(), + new Salsa20Test(), + new XSalsa20Test(), + new ChaChaTest(), + new CMacTest(), + new EAXTest(), + new GCMTest(), + new GMacTest(), + new HCFamilyTest(), + new HCFamilyVecTest(), + new ISAACTest(), + new NoekeonTest(), + new VMPCKSA3Test(), + new VMPCMacTest(), + new VMPCTest(), + new Grainv1Test(), + new Grain128Test(), + //new NaccacheSternTest(), + new SRP6Test(), + new SCryptTest(), + new ResetTest(), + new NullTest(), + new DSTU4145Test(), + new SipHashTest(), + new Poly1305Test(), + new OCBTest(), + new NonMemoableDigestTest(), + new RSAKeyEncapsulationTest(), + new ECIESKeyEncapsulationTest(), + new HashCommitmentTest(), + new CipherStreamTest(), + new BlockCipherResetTest(), + new StreamCipherResetTest(), + new SM3DigestTest(), + new Shacal2Test(), + new KDFCounterGeneratorTest(), + new KDFDoublePipelineIteratorGeneratorTest(), + new KDFFeedbackGeneratorTest(), + new CramerShoupTest() + }; + + public static void main( + String[] args) + { + for (int i = 0; i != tests.length; i++) + { + TestResult result = tests[i].perform(); + + if (result.getException() != null) + { + result.getException().printStackTrace(); + } + + System.out.println(result); + } + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ResetTest.java b/core/src/test/java/org/spongycastle/crypto/test/ResetTest.java new file mode 100644 index 00000000..dd323d7d --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ResetTest.java @@ -0,0 +1,99 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BufferedBlockCipher; +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.engines.DESEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class ResetTest + extends SimpleTest +{ + private static final byte[] input = Hex.decode("4e6f77206973207468652074696d6520666f7220616c6c20"); + private static final byte[] output = Hex.decode("3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"); + public String getName() + { + return "Reset"; + } + + public void performTest() + throws Exception + { + BufferedBlockCipher cipher = new BufferedBlockCipher(new DESEngine()); + + KeyParameter param = new KeyParameter(Hex.decode("0123456789abcdef")); + + basicTrial(cipher, param); + + cipher.init(false, param); + + byte[] out = new byte[input.length]; + + int len2 = cipher.processBytes(output, 0, output.length - 1, out, 0); + + try + { + cipher.doFinal(out, len2); + fail("no DataLengthException - short input"); + } + catch (DataLengthException e) + { + // ignore + } + + len2 = cipher.processBytes(output, 0, output.length, out, 0); + + cipher.doFinal(out, len2); + + if (!areEqual(input, out)) + { + fail("failed reversal one got " + new String(Hex.encode(out))); + } + + len2 = cipher.processBytes(output, 0, output.length - 1, out, 0); + + try + { + cipher.doFinal(out, len2); + fail("no DataLengthException - short output"); + } + catch (DataLengthException e) + { + // ignore + } + + len2 = cipher.processBytes(output, 0, output.length, out, 0); + + cipher.doFinal(out, len2); + + if (!areEqual(input, out)) + { + fail("failed reversal two got " + new String(Hex.encode(out))); + } + } + + private void basicTrial(BufferedBlockCipher cipher, KeyParameter param) + throws InvalidCipherTextException + { + cipher.init(true, param); + + byte[] out = new byte[input.length]; + + int len1 = cipher.processBytes(input, 0, input.length, out, 0); + + cipher.doFinal(out, len1); + + if (!areEqual(out, output)) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + public static void main( + String[] args) + { + runTest(new ResetTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/RijndaelTest.java b/core/src/test/java/org/spongycastle/crypto/test/RijndaelTest.java new file mode 100644 index 00000000..6c5d742b --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/RijndaelTest.java @@ -0,0 +1,116 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.RijndaelEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Test vectors from the NIST standard tests and Brian Gladman's vector set + * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/"> + * http://fp.gladman.plus.com/cryptography_technology/rijndael/</a> + */ +public class RijndaelTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new RijndaelEngine(128), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(1, new RijndaelEngine(128), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(2, 10000, new RijndaelEngine(128), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(3, 10000, new RijndaelEngine(128), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(4, new RijndaelEngine(128), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(5, 10000, new RijndaelEngine(128), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(6, new RijndaelEngine(128), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(7, 10000, new RijndaelEngine(128), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(8, new RijndaelEngine(160), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c")), + "3243f6a8885a308d313198a2e03707344a409382", "16e73aec921314c29df905432bc8968ab64b1f51"), + new BlockCipherVectorTest(8, new RijndaelEngine(160), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160")), + "3243f6a8885a308d313198a2e03707344a409382", "0553eb691670dd8a5a5b5addf1aa7450f7a0e587"), + new BlockCipherVectorTest(8, new RijndaelEngine(160), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")), + "3243f6a8885a308d313198a2e03707344a409382", "73cd6f3423036790463aa9e19cfcde894ea16623"), + new BlockCipherVectorTest(8, new RijndaelEngine(160), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")), + "3243f6a8885a308d313198a2e03707344a409382", "601b5dcd1cf4ece954c740445340bf0afdc048df"), + new BlockCipherVectorTest(8, new RijndaelEngine(160), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")), + "3243f6a8885a308d313198a2e03707344a409382", "579e930b36c1529aa3e86628bacfe146942882cf"), + new BlockCipherVectorTest(8, new RijndaelEngine(192), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d", "b24d275489e82bb8f7375e0d5fcdb1f481757c538b65148a"), + new BlockCipherVectorTest(9, new RijndaelEngine(192), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d", "725ae43b5f3161de806a7c93e0bca93c967ec1ae1b71e1cf"), + new BlockCipherVectorTest(10, new RijndaelEngine(192), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d", "bbfc14180afbf6a36382a061843f0b63e769acdc98769130"), + new BlockCipherVectorTest(11, new RijndaelEngine(192), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d", "0ebacf199e3315c2e34b24fcc7c46ef4388aa475d66c194c"), + new BlockCipherVectorTest(12, new RijndaelEngine(224), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "b0a8f78f6b3c66213f792ffd2a61631f79331407a5e5c8d3793aceb1"), + new BlockCipherVectorTest(13, new RijndaelEngine(224), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "08b99944edfce33a2acb131183ab0168446b2d15e958480010f545e3"), + new BlockCipherVectorTest(14, new RijndaelEngine(224), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "be4c597d8f7efe22a2f7e5b1938e2564d452a5bfe72399c7af1101e2"), + new BlockCipherVectorTest(15, new RijndaelEngine(224), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "ef529598ecbce297811b49bbed2c33bbe1241d6e1a833dbe119569e8"), + new BlockCipherVectorTest(16, new RijndaelEngine(224), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "02fafc200176ed05deb8edb82a3555b0b10d47a388dfd59cab2f6c11"), + new BlockCipherVectorTest(17, new RijndaelEngine(256), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "7d15479076b69a46ffb3b3beae97ad8313f622f67fedb487de9f06b9ed9c8f19"), + new BlockCipherVectorTest(18, new RijndaelEngine(256), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "514f93fb296b5ad16aa7df8b577abcbd484decacccc7fb1f18dc567309ceeffd"), + new BlockCipherVectorTest(19, new RijndaelEngine(256), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "5d7101727bb25781bf6715b0e6955282b9610e23a43c2eb062699f0ebf5887b2"), + new BlockCipherVectorTest(20, new RijndaelEngine(256), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "d56c5a63627432579e1dd308b2c8f157b40a4bfb56fea1377b25d3ed3d6dbf80"), + new BlockCipherVectorTest(21, new RijndaelEngine(256), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "a49406115dfb30a40418aafa4869b7c6a886ff31602a7dd19c889dc64f7e4e7a") + }; + + RijndaelTest() + { + super(tests, new RijndaelEngine(128), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "Rijndael"; + } + + public static void main( + String[] args) + { + runTest(new RijndaelTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SCryptTest.java b/core/src/test/java/org/spongycastle/crypto/test/SCryptTest.java new file mode 100644 index 00000000..f64a6a76 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SCryptTest.java @@ -0,0 +1,144 @@ +package org.spongycastle.crypto.test; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import org.spongycastle.crypto.generators.SCrypt; +import org.spongycastle.util.Strings; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/* + * scrypt test vectors from "Stronger Key Derivation Via Sequential Memory-hard Functions" Appendix B. + * (http://www.tarsnap.com/scrypt/scrypt.pdf) + */ +public class SCryptTest extends SimpleTest +{ + public String getName() + { + return "SCrypt"; + } + + public void performTest() throws Exception + { + testParameters(); + testVectors(); + } + + public void testParameters() + { + checkOK("Minimal values", new byte[0], new byte[0], 2, 1, 1, 1); + checkIllegal("Cost parameter must be > 1", new byte[0], new byte[0], 1, 1, 1, 1); + checkOK("Cost parameter 65536 OK for r == 1", new byte[0], new byte[0], 65536, 1, 1, 1); + checkIllegal("Cost parameter must <= 65536 for r == 1", new byte[0], new byte[0], 65537, 1, 1, 1); + checkIllegal("Block size must be >= 1", new byte[0], new byte[0], 2, 0, 2, 1); + checkIllegal("Parallelisation parameter must be >= 1", new byte[0], new byte[0], 2, 1, 0, 1); + // checkOK("Parallelisation parameter 65535 OK for r = 4", new byte[0], new byte[0], 2, 32, + // 65535, 1); + checkIllegal("Parallelisation parameter must be < 65535 for r = 4", new byte[0], new byte[0], 2, 32, 65536, 1); + + checkIllegal("Len parameter must be > 1", new byte[0], new byte[0], 2, 1, 1, 0); + } + + private void checkOK(String msg, byte[] pass, byte[] salt, int N, int r, int p, int len) + { + try + { + SCrypt.generate(pass, salt, N, r, p, len); + } + catch (IllegalArgumentException e) + { + e.printStackTrace(); + fail(msg); + } + } + + private void checkIllegal(String msg, byte[] pass, byte[] salt, int N, int r, int p, int len) + { + try + { + SCrypt.generate(pass, salt, N, r, p, len); + fail(msg); + } + catch (IllegalArgumentException e) + { + // e.printStackTrace(); + } + } + + public void testVectors() + throws Exception + { + BufferedReader br = new BufferedReader(new InputStreamReader( + getClass().getResourceAsStream("SCryptTestVectors.txt"))); + + int count = 0; + String line = br.readLine(); + + while (line != null) + { + ++count; + String header = line; + StringBuffer data = new StringBuffer(); + + while (!isEndData(line = br.readLine())) + { + for (int i = 0; i != line.length(); i++) + { + if (line.charAt(i) != ' ') + { + data.append(line.charAt(i)); + } + } + } + + int start = header.indexOf('(') + 1; + int limit = header.lastIndexOf(')'); + String argStr = header.substring(start, limit); + String[] args = Strings.split(argStr, ','); + + byte[] P = extractQuotedString(args[0]); + byte[] S = extractQuotedString(args[1]); + int N = extractInteger(args[2]); + int r = extractInteger(args[3]); + int p = extractInteger(args[4]); + int dkLen = extractInteger(args[5]); + byte[] expected = Hex.decode(data.toString()); + + // This skips very expensive test case(s), remove check to re-enable + if (N <= 16384) + { + byte[] result = SCrypt.generate(P, S, N, r, p, dkLen); + + if (!areEqual(expected, result)) + { + fail("Result does not match expected value in test case " + count); + } + } + } + + br.close(); + } + + private static boolean isEndData(String line) + { + return line == null || line.startsWith("scrypt"); + } + + private static byte[] extractQuotedString(String arg) + { + arg = arg.trim(); + arg = arg.substring(1, arg.length() - 1); + return Strings.toByteArray(arg); + } + + private static int extractInteger(String arg) + { + return Integer.parseInt(arg.trim()); + } + + public static void main(String[] args) + { + runTest(new SCryptTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SEEDTest.java b/core/src/test/java/org/spongycastle/crypto/test/SEEDTest.java new file mode 100644 index 00000000..a38c59c1 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SEEDTest.java @@ -0,0 +1,53 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.SEEDEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * SEED tester - vectors http://www.ietf.org/rfc/rfc4009.txt + */ +public class SEEDTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new SEEDEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "000102030405060708090a0b0c0d0e0f", + "5EBAC6E0054E166819AFF1CC6D346CDB"), + new BlockCipherVectorTest(0, new SEEDEngine(), + new KeyParameter(Hex.decode("000102030405060708090a0b0c0d0e0f")), + "00000000000000000000000000000000", + "c11f22f20140505084483597e4370f43"), + new BlockCipherVectorTest(0, new SEEDEngine(), + new KeyParameter(Hex.decode("4706480851E61BE85D74BFB3FD956185")), + "83A2F8A288641FB9A4E9A5CC2F131C7D", + "EE54D13EBCAE706D226BC3142CD40D4A"), + new BlockCipherVectorTest(0, new SEEDEngine(), + new KeyParameter(Hex.decode("28DBC3BC49FFD87DCFA509B11D422BE7")), + "B41E6BE2EBA84A148E2EED84593C5EC7", + "9B9B7BFCD1813CB95D0B3618F40F5122"), + new BlockCipherVectorTest(0, new SEEDEngine(), + new KeyParameter(Hex.decode("0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E")), + "0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E", + "8296F2F1B007AB9D533FDEE35A9AD850"), + }; + + SEEDTest() + { + super(tests, new SEEDEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "SEED"; + } + + public static void main( + String[] args) + { + runTest(new SEEDTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA1DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA1DigestTest.java new file mode 100644 index 00000000..ab0adae2 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA1DigestTest.java @@ -0,0 +1,48 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA1Digest; + +/** + * standard vector test for SHA-1 from "Handbook of Applied Cryptography", page 345. + */ +public class SHA1DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdefghijklmnopqrstuvwxyz" + }; + + private static String[] digests = + { + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", + "a9993e364706816aba3e25717850c26c9cd0d89d", + "32d10c7b8cf96570ca04ce37f2a19d84240d3a89" + }; + + SHA1DigestTest() + { + super(new SHA1Digest(), messages, digests); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA1Digest((SHA1Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA1Digest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA1DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA1HMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA1HMacTest.java new file mode 100644 index 00000000..4740988c --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA1HMacTest.java @@ -0,0 +1,111 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * SHA1 HMac Test, test vectors from RFC 2202 + */ +public class SHA1HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F" + }; + + final static String[] digests = { + "b617318655057264e28bc0b6fb378c8ef146be00", + "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", + "125d7342b9ac11cd91a39af48aa17b4f63f175d3", + "4c9007f4026250c6bc8414f9bf50c86c2d7235da", + "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", + "aa4ae5e15272d00e95705637ce8a3b55ed402112", + "e8e99d0f45237d786d6bbaa7965c7808bbff1a91", + "5FD596EE78D5553C8FF4E72D266DFD192366DA29" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", + "Sample message for keylen=blocklen" + }; + + public String getName() + { + return "SHA1HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new SHA1Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed"); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + "Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + SHA1HMacTest test = new SHA1HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA224DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA224DigestTest.java new file mode 100644 index 00000000..abe5b316 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA224DigestTest.java @@ -0,0 +1,59 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA224Digest; + +/** + * standard vector test for SHA-224 from RFC 3874 - only the last three are in + * the RFC. + */ +public class SHA224DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + }; + + private static String[] digests = + { + "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", + "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", + "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", + "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" + }; + + // 1 million 'a' + static private String million_a_digest = "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67"; + + SHA224DigestTest() + { + super(new SHA224Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA224Digest((SHA224Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA224Digest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA224DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA224HMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA224HMacTest.java new file mode 100644 index 00000000..5f4c73ed --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA224HMacTest.java @@ -0,0 +1,108 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.digests.SHA224Digest; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * SHA224 HMac Test + */ +public class SHA224HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22", + "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44", + "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea", + "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a", + "0e2aea68a90c8d37c988bcdb9fca6fa8099cd857c7ec4a1815cac54c", + "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e", + "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." + }; + + public String getName() + { + return "SHA224HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new SHA224Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed got -" + new String(Hex.encode(resBuf))); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + "Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + SHA224HMacTest test = new SHA224HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA256DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA256DigestTest.java new file mode 100644 index 00000000..548ca1fb --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA256DigestTest.java @@ -0,0 +1,60 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA256Digest; + +/** + * standard vector test for SHA-256 from FIPS Draft 180-2. + * + * Note, the first two vectors are _not_ from the draft, the last three are. + */ +public class SHA256DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + }; + + private static String[] digests = + { + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" + }; + + // 1 million 'a' + static private String million_a_digest = "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"; + + SHA256DigestTest() + { + super(new SHA256Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA256Digest((SHA256Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA256Digest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA256DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA256HMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA256HMacTest.java new file mode 100644 index 00000000..f29a81d1 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA256HMacTest.java @@ -0,0 +1,108 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * SHA256 HMac Test + */ +public class SHA256HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", + "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", + "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", + "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b", + "a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5", + "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54", + "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." + }; + + public String getName() + { + return "SHA256HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new SHA256Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed got -" + new String(Hex.encode(resBuf))); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + "Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + SHA256HMacTest test = new SHA256HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA384DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA384DigestTest.java new file mode 100644 index 00000000..7e1afbf3 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA384DigestTest.java @@ -0,0 +1,59 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA384Digest; + +/** + * standard vector test for SHA-384 from FIPS Draft 180-2. + * + * Note, the first two vectors are _not_ from the draft, the last three are. + */ +public class SHA384DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + }; + + private static String[] digests = + { + "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", + "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", + "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039" + }; + + static private String million_a_digest = "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985"; + + SHA384DigestTest() + { + super(new SHA384Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA384Digest((SHA384Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA384Digest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA384DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA384HMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA384HMacTest.java new file mode 100644 index 00000000..77152471 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA384HMacTest.java @@ -0,0 +1,108 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.digests.SHA384Digest; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * SHA384 HMac Test + */ +public class SHA384HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6", + "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649", + "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27", + "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb", + "3abf34c3503b2a23a46efc619baef897f4c8e42c934ce55ccbae9740fcbc1af4ca62269e2a37cd88ba926341efe4aeea", + "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952", + "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." + }; + + public String getName() + { + return "SHA384HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new SHA384Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed got -" + new String(Hex.encode(resBuf))); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + "Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + SHA384HMacTest test = new SHA384HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA3DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA3DigestTest.java new file mode 100644 index 00000000..eb636e2a --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA3DigestTest.java @@ -0,0 +1,363 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.digests.SHA3Digest; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * SHA3 Digest Test + */ +public class SHA3DigestTest + extends SimpleTest +{ + final static String[] messages = { + "", + "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67", + "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f672e" + }; + + final static String[] digests288 = { // the default settings + "6753e3380c09e385d0339eb6b050a68f66cfd60a73476e6fd6adeb72f5edd7c6f04a5d01", // message[0] + "0bbe6afae0d7e89054085c1cc47b1689772c89a41796891e197d1ca1b76f288154933ded", // message[1] + "82558a209b960ddeb531e6dcb281885b2400ca160472462486e79f071e88a3330a8a303d", // message[2] + "94049e1ad7ef5d5b0df2b880489e7ab09ec937c3bfc1b04470e503e1ac7b1133c18f86da", // 64k a-test + "a9cb5a75b5b81b7528301e72553ed6770214fa963956e790528afe420de33c074e6f4220", // random alphabet test + "eadaf5ba2ad6a2f6f338fce0e1efdad2a61bb38f6be6068b01093977acf99e97a5d5827c" // extremely long data test + }; + + final static String[] digests224 = { + "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd", + "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe", + "c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab", + "f621e11c142fbf35fa8c22841c3a812ba1e0151be4f38d80b9f1ff53", + "68b5fc8c87193155bba68a2485377e809ee4f81a85ef023b9e64add0", + "c42e4aee858e1a8ad2976896b9d23dd187f64436ee15969afdbc68c5" + }; + + final static String[] digests256 = { + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15", + "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d", + "0047a916daa1f92130d870b542e22d3108444f5a7e4429f05762fb647e6ed9ed", + "db368762253ede6d4f1db87e0b799b96e554eae005747a2ea687456ca8bcbd03", + "5f313c39963dcf792b5470d4ade9f3a356a3e4021748690a958372e2b06f82a4" + }; + + final static String[] digests384 = { + "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff", + "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3", + "9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b", + "c704cfe7a1a53208ca9526cd24251e0acdc252ecd978eee05acd16425cfb404ea81f5a9e2e5e97784d63ee6a0618a398", + "d4fe8586fd8f858dd2e4dee0bafc19b4c12b4e2a856054abc4b14927354931675cdcaf942267f204ea706c19f7beefc4", + "9b7168b4494a80a86408e6b9dc4e5a1837c85dd8ff452ed410f2832959c08c8c0d040a892eb9a755776372d4a8732315" + }; + + final static String[] digests512 = { + "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", + "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609", + "ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760", + "34341ead153aa1d1fdcf6cf624c2b4f6894b6fd16dc38bd4ec971ac0385ad54fafcb2e0ed86a1e509456f4246fdcb02c3172824cd649d9ad54c51f7fb49ea67c", + "dc44d4f4d36b07ab5fc04016cbe53548e5a7778671c58a43cb379fd00c06719b8073141fc22191ffc3db5f8b8983ae8341fa37f18c1c969664393aa5ceade64e", + "3e122edaf37398231cfaca4c7c216c9d66d5b899ec1d7ac617c40c7261906a45fc01617a021e5da3bd8d4182695b5cb785a28237cbb167590e34718e56d8aab8" + }; + + // test vectors from http://www.di-mgt.com.au/hmac_sha3_testvectors.html + final static byte[][] macKeys = + { + Hex.decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + Hex.decode("4a656665"), + Hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + Hex.decode("0102030405060708090a0b0c0d0e0f10111213141516171819"), + Hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaa"), + Hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaa"), + Hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + }; + + final static String[] macData = + { + "4869205468657265", + "7768617420646f2079612077616e7420666f72206e6f7468696e673f", + "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + + "dddddddddddddddddddddddddddddddddddd", + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a" + + "65204b6579202d2048617368204b6579204669727374", + "5468697320697320612074657374207573696e672061206c6172676572207468" + + "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" + + "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" + + "647320746f20626520686173686564206265666f7265206265696e6720757365" + + "642062792074686520484d414320616c676f726974686d2e", + "5468697320697320612074657374207573696e672061206c6172676572207468" + + "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" + + "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" + + "647320746f20626520686173686564206265666f7265206265696e6720757365\n" + + "642062792074686520484d414320616c676f726974686d2e" + }; + + final static String[] mac224 = + { + "b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc", + "e824fec96c074f22f99235bb942da1982664ab692ca8501053cbd414", + "770df38c99d6e2bacd68056dcfe07d4c89ae20b2686a6185e1faa449", + "305a8f2dfb94bad28861a03cbc4d590febe775c58cb4961c28428a0b", + "e7a52dfa45f95a217c100066b239aa8ad519be9b35d667268b1b57ff", + "ba13009405a929f398b348885caa5419191bb948ada32194afc84104", + "92649468be236c3c72c189909c063b13f994be05749dc91310db639e" + }; + + final static String[] mac256 = + { + "9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821", + "aa9aed448c7abc8b5e326ffa6a01cdedf7b4b831881468c044ba8dd4566369a1", + "95f43e50f8df80a21977d51a8db3ba572dcd71db24687e6f86f47c1139b26260", + "6331ba9b4af5804a68725b3663eb74814494b63c6093e35fb320a85d507936fd", + "b4d0cdee7ec2ba81a88b86918958312300a15622377929a054a9ce3ae1fac2b6", + "1fdc8cb4e27d07c10d897dec39c217792a6e64fa9c63a77ce42ad106ef284e02", + "fdaa10a0299aecff9bb411cf2d7748a4022e4a26be3fb5b11b33d8c2b7ef5484" + }; + + final static String[] mac384 = + { + "892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048", + "5af5c9a77a23a6a93d80649e562ab77f4f3552e3c5caffd93bdf8b3cfc6920e3023fc26775d9df1f3c94613146ad2c9d", + "4243c29f2201992ff96441e3b91ff81d8c601d706fbc83252684a4bc51101ca9b2c06ddd03677303c502ac5331752a3c", + "b730724d3d4090cda1be799f63acbbe389fef7792fc18676fa5453aab398664650ed029c3498bbe8056f06c658e1e693", + "d62482ef601d7847439b55236e9679388ffcd53c62cd126f39be6ea63de762e26cd5974cb9a8de401b786b5555040f6f", + "4860ea191ac34994cf88957afe5a836ef36e4cc1a66d75bf77defb7576122d75f60660e4cf731c6effac06402787e2b9", + "fe9357e3cfa538eb0373a2ce8f1e26ad6590afdaf266f1300522e8896d27e73f654d0631c8fa598d4bb82af6b744f4f5" + }; + + final static String[] mac512 = + { + "8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755", + "c2962e5bbe1238007852f79d814dbbecd4682e6f097d37a363587c03bfa2eb0859d8d9c701e04cececfd3dd7bfd438f20b8b648e01bf8c11d26824b96cebbdcb", + "eb0ed9580e0ec11fc66cbb646b1be904eaff6da4556d9334f65ee4b2c85739157bae9027c51505e49d1bb81cfa55e6822db55262d5a252c088a29a5e95b84a66", + "b46193bb59f4f696bf702597616da91e2a4558a593f4b015e69141ba81e1e50ea580834c2b87f87baa25a3a03bfc9bb389847f2dc820beae69d30c4bb75369cb", + "d05888a6ebf8460423ea7bc85ea4ffda847b32df32291d2ce115fd187707325c7ce4f71880d91008084ce24a38795d20e6a28328a0f0712dc38253370da3ebb5", + "2c6b9748d35c4c8db0b4407dd2ed2381f133bdbd1dfaa69e30051eb6badfcca64299b88ae05fdbd3dd3dd7fe627e42e39e48b0fe8c7f1e85f2dbd52c2d753572", + "6adc502f14e27812402fc81a807b28bf8a53c87bea7a1df6256bf66f5de1a4cb741407ad15ab8abc136846057f881969fbb159c321c904bfb557b77afb7778c8" + }; + + final static KeyParameter truncKey = new KeyParameter(Hex.decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c")); + final static byte[] truncData = Hex.decode("546573742057697468205472756e636174696f6e"); + + final static byte[] trunc224 = Hex.decode("f52bbcfd654264e7133085c5e69b72c3"); + final static byte[] trunc256 = Hex.decode("745e7e687f8335280d54202ef13cecc6"); + final static byte[] trunc384 = Hex.decode("fa9aea2bc1e181e47cbb8c3df243814d"); + final static byte[] trunc512 = Hex.decode("04c929fead434bba190dacfa554ce3f5"); + + final static byte[] xtremeData = Hex.decode("61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f"); + + SHA3DigestTest() + { + } + + public String getName() + { + return "SHA3"; + } + + private void testDigest(Digest digest, String[] expected) + { + byte[] hash = new byte[digest.getDigestSize()]; + + for (int i = 0; i != messages.length; i++) + { + if (messages.length != 0) + { + byte[] data = Hex.decode(messages[i]); + + digest.update(data, 0, data.length); + } + + digest.doFinal(hash, 0); + + if (!Arrays.areEqual(Hex.decode(expected[i]), hash)) + { + fail("sha3 mismatch on " + digest.getAlgorithmName() + " index " + i); + } + } + + byte[] k64 = new byte[1024 * 64]; + + for (int i = 0; i != k64.length; i++) + { + k64[i] = (byte)'a'; + } + + digest.update(k64, 0, k64.length); + + digest.doFinal(hash, 0); + + if (!Arrays.areEqual(Hex.decode(expected[messages.length]), hash)) + { + fail("sha3 mismatch on " + digest.getAlgorithmName() + " 64k a"); + } + + for (int i = 0; i != k64.length; i++) + { + digest.update((byte)'a'); + } + + digest.doFinal(hash, 0); + + if (!Arrays.areEqual(Hex.decode(expected[messages.length]), hash)) + { + fail("sha3 mismatch on " + digest.getAlgorithmName() + " 64k a single"); + } + + + for (int i = 0; i != k64.length; i++) + { + k64[i] = (byte)('a' + (i % 26)); + } + + digest.update(k64, 0, k64.length); + + digest.doFinal(hash, 0); + + if (!Arrays.areEqual(Hex.decode(expected[messages.length + 1]), hash)) + { + fail("sha3 mismatch on " + digest.getAlgorithmName() + " 64k alpha"); + } + + for (int i = 0; i != 64; i++) + { + digest.update(k64[i * 1024]); + digest.update(k64, i * 1024 + 1, 1023); + } + + digest.doFinal(hash, 0); + + if (!Arrays.areEqual(Hex.decode(expected[messages.length + 1]), hash)) + { + fail("sha3 mismatch on " + digest.getAlgorithmName() + " 64k chunked alpha"); + } + + testDigestDoFinal(digest); + + // + // extremely long data test + // +// System.out.println("Starting very long"); +// for (int i = 0; i != 16384; i++) +// { +// for (int j = 0; j != 1024; j++) +// { +// digest.update(xtremeData, 0, xtremeData.length); +// } +// } +// +// digest.doFinal(hash, 0); +// +// if (!Arrays.areEqual(Hex.decode(expected[messages.length + 2]), hash)) +// { +// fail("sha3 mismatch on " + digest.getAlgorithmName() + " extreme data test"); +// } +// System.out.println("Done"); + } + + private void testDigestDoFinal(Digest digest) + { + byte[] hash = new byte[digest.getDigestSize()]; + digest.doFinal(hash, 0); + + for (int i = 0; i <= digest.getDigestSize(); ++i) + { + byte[] cmp = new byte[2 * digest.getDigestSize()]; + System.arraycopy(hash, 0, cmp, i, hash.length); + + byte[] buf = new byte[2 * digest.getDigestSize()]; + digest.doFinal(buf, i); + + if (!Arrays.areEqual(cmp, buf)) + { + fail("sha3 offset doFinal on " + digest.getAlgorithmName()); + } + } + } + + private void testMac(Digest digest, byte[][] keys, String[] data, String[] expected, byte[] truncExpected) + { + Mac mac = new HMac(digest); + + for (int i = 0; i != keys.length; i++) + { + mac.init(new KeyParameter(keys[i])); + + byte[] mData = Hex.decode(data[i]); + + mac.update(mData, 0, mData.length); + + byte[] macV = new byte[mac.getMacSize()]; + + mac.doFinal(macV, 0); + + if (!Arrays.areEqual(Hex.decode(expected[i]), macV)) + { + fail("sha3 HMAC mismatch on " + digest.getAlgorithmName()); + } + } + + mac = new HMac(digest); + + mac.init(truncKey); + + mac.update(truncData, 0, truncData.length); + + byte[] macV = new byte[mac.getMacSize()]; + + mac.doFinal(macV, 0); + + for (int i = 0; i != truncExpected.length; i++) + { + if (macV[i] != truncExpected[i]) + { + fail("mismatch on truncated HMAC for " + digest.getAlgorithmName()); + } + } + } + + public void performTest() + { + testDigest(new SHA3Digest(), digests288); + testDigest(new SHA3Digest(224), digests224); + testDigest(new SHA3Digest(256), digests256); + testDigest(new SHA3Digest(384), digests384); + testDigest(new SHA3Digest(512), digests512); + + testMac(new SHA3Digest(224), macKeys, macData, mac224, trunc224); + testMac(new SHA3Digest(256), macKeys, macData, mac256, trunc256); + testMac(new SHA3Digest(384), macKeys, macData, mac384, trunc384); + testMac(new SHA3Digest(512), macKeys, macData, mac512, trunc512); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA3Digest((SHA3Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new SHA3DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA512DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA512DigestTest.java new file mode 100644 index 00000000..e1ccc9e2 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA512DigestTest.java @@ -0,0 +1,60 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA512Digest; + +/** + * standard vector test for SHA-512 from FIPS Draft 180-2. + * + * Note, the first two vectors are _not_ from the draft, the last three are. + */ +public class SHA512DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + }; + + private static String[] digests = + { + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", + "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", + "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" + }; + + // 1 million 'a' + static private String million_a_digest = "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"; + + SHA512DigestTest() + { + super(new SHA512Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA512Digest((SHA512Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA512Digest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA512DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA512HMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA512HMacTest.java new file mode 100644 index 00000000..c4b4d66a --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA512HMacTest.java @@ -0,0 +1,108 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.digests.SHA512Digest; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.Test; +import org.spongycastle.util.test.TestResult; + +/** + * SHA512 HMac Test + */ +public class SHA512HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854", + "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737", + "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb", + "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd", + "415fad6271580a531d4179bc891d87a650188707922a4fbb36663a1eb16da008711c5b50ddd0fc235084eb9d3364a1454fb2ef67cd1d29fe6773068ea266e96b", + "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598", + "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." + }; + + public String getName() + { + return "SHA512HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new SHA512Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed got -" + new String(Hex.encode(resBuf))); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + "Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + SHA512HMacTest test = new SHA512HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA512t224DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA512t224DigestTest.java new file mode 100644 index 00000000..443aa0b9 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA512t224DigestTest.java @@ -0,0 +1,60 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA512tDigest; + +/** + * standard vector test for SHA-512/224 from FIPS 180-4. + * + * Note, only the last 2 message entries are FIPS originated.. + */ +public class SHA512t224DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + }; + + private static String[] digests = + { + "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4", + "d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327", + "4634270F707B6A54DAAE7530460842E20E37ED265CEEE9A43E8924AA", + "23FEC5BB94D60B23308192640B0C453335D664734FE40E7268674AF9" + }; + + // 1 million 'a' + static private String million_a_digest = "37ab331d76f0d36de422bd0edeb22a28accd487b7a8453ae965dd287"; + + SHA512t224DigestTest() + { + super(new SHA512tDigest(224), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA512tDigest((SHA512tDigest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA512tDigest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA512t224DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SHA512t256DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/SHA512t256DigestTest.java new file mode 100644 index 00000000..3e44cf5f --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SHA512t256DigestTest.java @@ -0,0 +1,60 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA512tDigest; + +/** + * standard vector test for SHA-512/256 from FIPS 180-4. + * + * Note, only the last 2 message entries are FIPS originated.. + */ +public class SHA512t256DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + }; + + private static String[] digests = + { + "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a", + "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8", + "53048E2681941EF99B2E29B76B4C7DABE4C2D0C634FC6D46E0E2F13107E7AF23", + "3928E184FB8690F840DA3988121D31BE65CB9D3EF83EE6146FEAC861E19B563A" + }; + + // 1 million 'a' + static private String million_a_digest = "9a59a052930187a97038cae692f30708aa6491923ef5194394dc68d56c74fb21"; + + SHA512t256DigestTest() + { + super(new SHA512tDigest(256), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA512tDigest((SHA512tDigest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA512tDigest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA512t256DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SM3DigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/SM3DigestTest.java new file mode 100644 index 00000000..df0bec32 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SM3DigestTest.java @@ -0,0 +1,57 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SM3Digest; + +/** + * standard vector test for SM3 digest from chinese specification + */ +public class SM3DigestTest + extends DigestTest +{ + private static String[] messages = { + // Standard test vectors + "abc", + "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd", + // Non-standard test vectors + "", + "a", + "abcdefghijklmnopqrstuvwxyz", + }; + + private static String[] digests = { + // Standard test vectors + "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", + "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", + // Non-standard test vectors + "1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b", + "623476ac18f65a2909e43c7fec61b49c7e764a91a18ccb82f1917a29c86c5e88", + "b80fe97a4da24afc277564f66a359ef440462ad28dcc6d63adb24d5c20a61595", + }; + + final static String sixtyFourKdigest = "97049bdc8f0736bc7300eafa9980aeb9cf00f24f7ec3a8f1f8884954d7655c1d"; + final static String million_a_digest = "c8aaf89429554029e231941a2acc0ad61ff2a5acd8fadd25847a3a732b3b02c3"; + + SM3DigestTest() + { + super(new SM3Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + sixtyFourKTest(sixtyFourKdigest); + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SM3Digest((SM3Digest)digest); + } + + public static void main(String[] args) + { + runTest(new SM3DigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SRP6Test.java b/core/src/test/java/org/spongycastle/crypto/test/SRP6Test.java new file mode 100644 index 00000000..c2ab0ad8 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SRP6Test.java @@ -0,0 +1,276 @@ +package org.spongycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.CryptoException; +import org.spongycastle.crypto.agreement.srp.SRP6Client; +import org.spongycastle.crypto.agreement.srp.SRP6Server; +import org.spongycastle.crypto.agreement.srp.SRP6Util; +import org.spongycastle.crypto.agreement.srp.SRP6VerifierGenerator; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.generators.DHParametersGenerator; +import org.spongycastle.crypto.params.DHParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class SRP6Test extends SimpleTest +{ + private static final BigInteger ZERO = BigInteger.valueOf(0); + + private static BigInteger fromHex(String hex) + { + return new BigInteger(1, Hex.decode(hex)); + } + + // 1024 bit example prime from RFC5054 and corresponding generator + private static final BigInteger N_1024 = fromHex("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" + + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" + + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" + + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" + + "FD5138FE8376435B9FC61D2FC0EB06E3"); + private static final BigInteger g_1024 = BigInteger.valueOf(2); + + private final SecureRandom random = new SecureRandom(); + + public String getName() + { + return "SRP6"; + } + + public void performTest() throws Exception + { + rfc5054AppendixBTestVectors(); + + testMutualVerification(N_1024, g_1024); + testClientCatchesBadB(N_1024, g_1024); + testServerCatchesBadA(N_1024, g_1024); + + testWithRandomParams(256); + testWithRandomParams(384); + testWithRandomParams(512); + } + + private void rfc5054AppendixBTestVectors() throws Exception + { + byte[] I = "alice".getBytes("UTF8"); + byte[] P = "password123".getBytes("UTF8"); + byte[] s = Hex.decode("BEB25379D1A8581EB5A727673A2441EE"); + BigInteger N = N_1024; + BigInteger g = g_1024; + BigInteger a = fromHex("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DDDA2D4393"); + BigInteger b = fromHex("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D105284D20"); + + BigInteger expect_k = fromHex("7556AA045AEF2CDD07ABAF0F665C3E818913186F"); + BigInteger expect_x = fromHex("94B7555AABE9127CC58CCF4993DB6CF84D16C124"); + BigInteger expect_v = fromHex("7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D812" + + "9BADA1F1822223CA1A605B530E379BA4729FDC59F105B4787E5186F5" + + "C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5" + + "EA53D15C1AFF87B2B9DA6E04E058AD51CC72BFC9033B564E26480D78" + + "E955A5E29E7AB245DB2BE315E2099AFB"); + BigInteger expect_A = fromHex("61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC4" + + "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC" + + "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44" + + "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA" + + "B349EF5D76988A3672FAC47B0769447B"); + BigInteger expect_B = fromHex("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011" + + "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99" + + "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA" + + "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE" + + "EB4012B7D7665238A8E3FB004B117B58"); + BigInteger expect_u = fromHex("CE38B9593487DA98554ED47D70A7AE5F462EF019"); + BigInteger expect_S = fromHex("B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D" + + "233861E359B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C" + + "41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F" + + "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D" + + "C346D7E474B29EDE8A469FFECA686E5A"); + + BigInteger k = SRP6Util.calculateK(new SHA1Digest(), N, g); + if (!k.equals(expect_k)) + { + fail("wrong value of 'k'"); + } + + BigInteger x = SRP6Util.calculateX(new SHA1Digest(), N, s, I, P); + if (!x.equals(expect_x)) + { + fail("wrong value of 'x'"); + } + + SRP6VerifierGenerator gen = new SRP6VerifierGenerator(); + gen.init(N, g, new SHA1Digest()); + BigInteger v = gen.generateVerifier(s, I, P); + if (!v.equals(expect_v)) + { + fail("wrong value of 'v'"); + } + + final BigInteger aVal = a; + SRP6Client client = new SRP6Client() + { + protected BigInteger selectPrivateValue() + { + return aVal; + } + }; + client.init(N, g, new SHA1Digest(), random); + + BigInteger A = client.generateClientCredentials(s, I, P); + if (!A.equals(expect_A)) + { + fail("wrong value of 'A'"); + } + + final BigInteger bVal = b; + SRP6Server server = new SRP6Server() + { + protected BigInteger selectPrivateValue() + { + return bVal; + } + }; + server.init(N, g, v, new SHA1Digest(), random); + + BigInteger B = server.generateServerCredentials(); + if (!B.equals(expect_B)) + { + fail("wrong value of 'B'"); + } + + BigInteger u = SRP6Util.calculateU(new SHA1Digest(), N, A, B); + if (!u.equals(expect_u)) + { + fail("wrong value of 'u'"); + } + + BigInteger clientS = client.calculateSecret(B); + if (!clientS.equals(expect_S)) + { + fail("wrong value of 'S' (client)"); + } + + BigInteger serverS = server.calculateSecret(A); + if (!serverS.equals(expect_S)) + { + fail("wrong value of 'S' (server)"); + } + } + + private void testWithRandomParams(int bits) throws CryptoException + { + DHParametersGenerator paramGen = new DHParametersGenerator(); + paramGen.init(bits, 25, random); + DHParameters parameters = paramGen.generateParameters(); + + BigInteger g = parameters.getG(); + BigInteger p = parameters.getP(); + + testMutualVerification(p, g); + } + + private void testMutualVerification(BigInteger N, BigInteger g) throws CryptoException + { + byte[] I = "username".getBytes(); + byte[] P = "password".getBytes(); + byte[] s = new byte[16]; + random.nextBytes(s); + + SRP6VerifierGenerator gen = new SRP6VerifierGenerator(); + gen.init(N, g, new SHA256Digest()); + BigInteger v = gen.generateVerifier(s, I, P); + + SRP6Client client = new SRP6Client(); + client.init(N, g, new SHA256Digest(), random); + + SRP6Server server = new SRP6Server(); + server.init(N, g, v, new SHA256Digest(), random); + + BigInteger A = client.generateClientCredentials(s, I, P); + BigInteger B = server.generateServerCredentials(); + + BigInteger clientS = client.calculateSecret(B); + BigInteger serverS = server.calculateSecret(A); + + if (!clientS.equals(serverS)) + { + fail("SRP agreement failed - client/server calculated different secrets"); + } + } + + private void testClientCatchesBadB(BigInteger N, BigInteger g) + { + byte[] I = "username".getBytes(); + byte[] P = "password".getBytes(); + byte[] s = new byte[16]; + random.nextBytes(s); + + SRP6Client client = new SRP6Client(); + client.init(N, g, new SHA256Digest(), random); + + client.generateClientCredentials(s, I, P); + + try + { + client.calculateSecret(ZERO); + fail("Client failed to detect invalid value for 'B'"); + } + catch (CryptoException e) + { + // Expected + } + + try + { + client.calculateSecret(N); + fail("Client failed to detect invalid value for 'B'"); + } + catch (CryptoException e) + { + // Expected + } + } + + private void testServerCatchesBadA(BigInteger N, BigInteger g) + { + byte[] I = "username".getBytes(); + byte[] P = "password".getBytes(); + byte[] s = new byte[16]; + random.nextBytes(s); + + SRP6VerifierGenerator gen = new SRP6VerifierGenerator(); + gen.init(N, g, new SHA256Digest()); + BigInteger v = gen.generateVerifier(s, I, P); + + SRP6Server server = new SRP6Server(); + server.init(N, g, v, new SHA256Digest(), random); + + server.generateServerCredentials(); + + try + { + server.calculateSecret(ZERO); + fail("Client failed to detect invalid value for 'A'"); + } + catch (CryptoException e) + { + // Expected + } + + try + { + server.calculateSecret(N); + fail("Client failed to detect invalid value for 'A'"); + } + catch (CryptoException e) + { + // Expected + } + } + + public static void main(String[] args) + { + runTest(new SRP6Test()); + } +} + diff --git a/core/src/test/java/org/spongycastle/crypto/test/Salsa20Test.java b/core/src/test/java/org/spongycastle/crypto/test/Salsa20Test.java new file mode 100644 index 00000000..1cdf10cf --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/Salsa20Test.java @@ -0,0 +1,400 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.engines.Salsa20Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Salsa20 Test + */ +public class Salsa20Test + extends SimpleTest +{ + byte[] zeroes = Hex.decode( + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"); + + String set1v0_0 = "4DFA5E481DA23EA09A31022050859936" + + "DA52FCEE218005164F267CB65F5CFD7F" + + "2B4F97E0FF16924A52DF269515110A07" + + "F9E460BC65EF95DA58F740B7D1DBB0AA"; + + String set1v0_192 = "DA9C1581F429E0A00F7D67E23B730676" + + "783B262E8EB43A25F55FB90B3E753AEF" + + "8C6713EC66C51881111593CCB3E8CB8F" + + "8DE124080501EEEB389C4BCB6977CF95"; + + String set1v0_256 = "7D5789631EB4554400E1E025935DFA7B" + + "3E9039D61BDC58A8697D36815BF1985C" + + "EFDF7AE112E5BB81E37ECF0616CE7147" + + "FC08A93A367E08631F23C03B00A8DA2F"; + + String set1v0_448 = "B375703739DACED4DD4059FD71C3C47F" + + "C2F9939670FAD4A46066ADCC6A564578" + + "3308B90FFB72BE04A6B147CBE38CC0C3" + + "B9267C296A92A7C69873F9F263BE9703"; + + String set1v9_0 = "0471076057830FB99202291177FBFE5D" + + "38C888944DF8917CAB82788B91B53D1C" + + "FB06D07A304B18BB763F888A61BB6B75" + + "5CD58BEC9C4CFB7569CB91862E79C459"; + + String set1v9_192 = "D1D7E97556426E6CFC21312AE3811425" + + "9E5A6FB10DACBD88E4354B0472556935" + + "2B6DA5ACAFACD5E266F9575C2ED8E6F2" + + "EFE4B4D36114C3A623DD49F4794F865B"; + + String set1v9_256 = "AF06FAA82C73291231E1BD916A773DE1" + + "52FD2126C40A10C3A6EB40F22834B8CC" + + "68BD5C6DBD7FC1EC8F34165C517C0B63" + + "9DB0C60506D3606906B8463AA0D0EC2F"; + + String set1v9_448 = "AB3216F1216379EFD5EC589510B8FD35" + + "014D0AA0B613040BAE63ECAB90A9AF79" + + "661F8DA2F853A5204B0F8E72E9D9EB4D" + + "BA5A4690E73A4D25F61EE7295215140C"; + + String set6v0_0 = "F5FAD53F79F9DF58C4AEA0D0ED9A9601" + + "F278112CA7180D565B420A48019670EA" + + "F24CE493A86263F677B46ACE1924773D" + + "2BB25571E1AA8593758FC382B1280B71"; + + String set6v0_65472 = "B70C50139C63332EF6E77AC54338A407" + + "9B82BEC9F9A403DFEA821B83F7860791" + + "650EF1B2489D0590B1DE772EEDA4E3BC" + + "D60FA7CE9CD623D9D2FD5758B8653E70"; + + String set6v0_65536 = "81582C65D7562B80AEC2F1A673A9D01C" + + "9F892A23D4919F6AB47B9154E08E699B" + + "4117D7C666477B60F8391481682F5D95" + + "D96623DBC489D88DAA6956B9F0646B6E"; + + String set6v1_0 = "3944F6DC9F85B128083879FDF190F7DE" + + "E4053A07BC09896D51D0690BD4DA4AC1" + + "062F1E47D3D0716F80A9B4D85E6D6085" + + "EE06947601C85F1A27A2F76E45A6AA87"; + + String set6v1_65472 = "36E03B4B54B0B2E04D069E690082C8C5" + + "92DF56E633F5D8C7682A02A65ECD1371" + + "8CA4352AACCB0DA20ED6BBBA62E177F2" + + "10E3560E63BB822C4158CAA806A88C82"; + + String set6v1_65536 = "1B779E7A917C8C26039FFB23CF0EF8E0" + + "8A1A13B43ACDD9402CF5DF38501098DF" + + "C945A6CC69A6A17367BC03431A86B3ED" + + "04B0245B56379BF997E25800AD837D7D"; + + // Salsa20/12 + String salsa12_set1v0_0 = "FC207DBFC76C5E1774961E7A5AAD0906" + + "9B2225AC1CE0FE7A0CE77003E7E5BDF8" + + "B31AF821000813E6C56B8C1771D6EE70" + + "39B2FBD0A68E8AD70A3944B677937897"; + + String salsa12_set1v0_192 = "4B62A4881FA1AF9560586510D5527ED4" + + "8A51ECAFA4DECEEBBDDC10E9918D44AB" + + "26B10C0A31ED242F146C72940C6E9C37" + + "53F641DA84E9F68B4F9E76B6C48CA5AC"; + + String salsa12_set1v0_256 = "F52383D9DEFB20810325F7AEC9EADE34" + + "D9D883FEE37E05F74BF40875B2D0BE79" + + "ED8886E5BFF556CEA8D1D9E86B1F68A9" + + "64598C34F177F8163E271B8D2FEB5996"; + + String salsa12_set1v0_448 = "A52ED8C37014B10EC0AA8E05B5CEEE12" + + "3A1017557FB3B15C53E6C5EA8300BF74" + + "264A73B5315DC821AD2CAB0F3BB2F152" + + "BDAEA3AEE97BA04B8E72A7B40DCC6BA4"; + + // Salsa20/8 + String salsa8_set1v0_0 = "A9C9F888AB552A2D1BBFF9F36BEBEB33" + + "7A8B4B107C75B63BAE26CB9A235BBA9D" + + "784F38BEFC3ADF4CD3E266687EA7B9F0" + + "9BA650AE81EAC6063AE31FF12218DDC5"; + + String salsa8_set1v0_192 = "BB5B6BB2CC8B8A0222DCCC1753ED4AEB" + + "23377ACCBD5D4C0B69A8A03BB115EF71" + + "871BC10559080ACA7C68F0DEF32A80DD" + + "BAF497259BB76A3853A7183B51CC4B9F"; + + String salsa8_set1v0_256 = "4436CDC0BE39559F5E5A6B79FBDB2CAE" + + "4782910F27FFC2391E05CFC78D601AD8" + + "CD7D87B074169361D997D1BED9729C0D" + + "EB23418E0646B7997C06AA84E7640CE3"; + + String salsa8_set1v0_448 = "BEE85903BEA506B05FC04795836FAAAC" + + "7F93F785D473EB762576D96B4A65FFE4" + + "63B34AAE696777FC6351B67C3753B89B" + + "A6B197BD655D1D9CA86E067F4D770220"; + + + public String getName() + { + return "Salsa20"; + } + + public void performTest() + { + salsa20Test1(20, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + set1v0_0, set1v0_192, set1v0_256, set1v0_448); + salsa20Test1(20, new ParametersWithIV(new KeyParameter(Hex.decode("00400000000000000000000000000000")), Hex.decode("0000000000000000")), + set1v9_0, set1v9_192, set1v9_256, set1v9_448); + salsa20Test1(12, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + salsa12_set1v0_0, salsa12_set1v0_192, salsa12_set1v0_256, salsa12_set1v0_448); + salsa20Test1(8, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + salsa8_set1v0_0, salsa8_set1v0_192, salsa8_set1v0_256, salsa8_set1v0_448); + salsa20Test2(new ParametersWithIV(new KeyParameter(Hex.decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.decode("0D74DB42A91077DE")), + set6v0_0, set6v0_65472, set6v0_65536); + salsa20Test2(new ParametersWithIV(new KeyParameter(Hex.decode("0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12")), Hex.decode("167DE44BB21980E7")), + set6v1_0, set6v1_65472, set6v1_65536); + reinitBug(); + skipTest(); + } + + private void salsa20Test1(int rounds, CipherParameters params, String v0, String v192, String v256, String v448) + { + StreamCipher salsa = new Salsa20Engine(rounds); + byte[] buf = new byte[64]; + + salsa.init(true, params); + + for (int i = 0; i != 7; i++) + { + salsa.processBytes(zeroes, 0, 64, buf, 0); + switch (i) + { + case 0: + if (!areEqual(buf, Hex.decode(v0))) + { + mismatch("v0/" + rounds, v0, buf); + } + break; + case 3: + if (!areEqual(buf, Hex.decode(v192))) + { + mismatch("v192/" + rounds, v192, buf); + } + break; + case 4: + if (!areEqual(buf, Hex.decode(v256))) + { + mismatch("v256/" + rounds, v256, buf); + } + break; + default: + // ignore + } + } + + for (int i = 0; i != 64; i++) + { + buf[i] = salsa.returnByte(zeroes[i]); + } + + if (!areEqual(buf, Hex.decode(v448))) + { + mismatch("v448", v448, buf); + } + } + + private void salsa20Test2(CipherParameters params, String v0, String v65472, String v65536) + { + StreamCipher salsa = new Salsa20Engine(); + byte[] buf = new byte[64]; + + salsa.init(true, params); + + for (int i = 0; i != 1025; i++) + { + salsa.processBytes(zeroes, 0, 64, buf, 0); + switch (i) + { + case 0: + if (!areEqual(buf, Hex.decode(v0))) + { + mismatch("v0", v0, buf); + } + break; + case 1023: + if (!areEqual(buf, Hex.decode(v65472))) + { + mismatch("v65472", v65472, buf); + } + break; + case 1024: + if (!areEqual(buf, Hex.decode(v65536))) + { + mismatch("v65536", v65536, buf); + } + break; + default: + // ignore + } + } + } + + private void mismatch(String name, String expected, byte[] found) + { + fail("mismatch on " + name, expected, new String(Hex.encode(found))); + } + + + private void reinitBug() + { + KeyParameter key = new KeyParameter(Hex.decode("80000000000000000000000000000000")); + ParametersWithIV parameters = new ParametersWithIV(key, Hex.decode("0000000000000000")); + + StreamCipher salsa = new Salsa20Engine(); + + salsa.init(true, parameters); + + try + { + salsa.init(true, key); + fail("Salsa20 should throw exception if no IV in Init"); + } + catch (IllegalArgumentException e) + { + } + } + + private boolean areEqual(byte[] a, int aOff, byte[] b, int bOff) + { + for (int i = bOff; i != b.length; i++) + { + if (a[aOff + i - bOff] != b[i]) + { + return false; + } + } + + return true; + } + + private void skipTest() + { + SecureRandom rand = new SecureRandom(); + byte[] plain = new byte[5000]; + byte[] cipher = new byte[5000]; + + rand.nextBytes(plain); + + CipherParameters params = new ParametersWithIV(new KeyParameter(Hex.decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.decode("0D74DB42A91077DE")); + Salsa20Engine engine = new Salsa20Engine(); + + engine.init(true, params); + + engine.processBytes(plain, 0, plain.length, cipher, 0); + + byte[] fragment = new byte[20]; + + engine.init(true, params); + + engine.skip(10); + + engine.processBytes(plain, 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 10, fragment, 0)) + { + fail("skip forward 10 failed"); + } + + engine.skip(1000); + + engine.processBytes(plain, 1010 + fragment.length, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + fragment.length, fragment, 0)) + { + fail("skip forward 1000 failed"); + } + + engine.skip(-10); + + engine.processBytes(plain, 1010 + 2 * fragment.length - 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + 2 * fragment.length - 10, fragment, 0)) + { + fail("skip back 10 failed"); + } + + engine.skip(-1000); + + if (engine.getPosition() != 60) + { + fail("skip position incorrect - " + 60 + " got " + engine.getPosition()); + } + + engine.processBytes(plain, 60, fragment.length, fragment, 0); + + if (!areEqual(cipher, 60, fragment, 0)) + { + fail("skip back 1000 failed"); + } + + long pos = engine.seekTo(1010); + if (pos != 1010) + { + fail("position wrong"); + } + + engine.processBytes(plain, 1010, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010, fragment, 0)) + { + fail("seek to 1010 failed"); + } + + engine.reset(); + + for (int i = 0; i != 1000; i++) + { + engine.skip(i); + + if (engine.getPosition() != i) + { + fail("skip forward at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip forward i failed: " + i); + } + + if (engine.getPosition() != i + fragment.length) + { + fail("cipher at wrong position: " + engine.getPosition() + " [" + i + "]"); + } + + engine.skip(-fragment.length); + + if (engine.getPosition() != i) + { + fail("skip back at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip back i failed: " + i); + } + + engine.reset(); + } + } + + public static void main( + String[] args) + { + runTest(new Salsa20Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SerpentTest.java b/core/src/test/java/org/spongycastle/crypto/test/SerpentTest.java new file mode 100644 index 00000000..bf687980 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SerpentTest.java @@ -0,0 +1,103 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.SerpentEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + */ +public class SerpentTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new SerpentEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "00000000000000000000000000000000", "8910494504181950f98dd998a82b6749"), + new BlockCipherVectorTest(1, new SerpentEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "80000000000000000000000000000000", "10b5ffb720b8cb9002a1142b0ba2e94a"), + new BlockCipherVectorTest(2, new SerpentEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000008000000000000000000000", "4f057a42d8d5bd9746e434680ddcd5e5"), + new BlockCipherVectorTest(3, new SerpentEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000400000000000", "99407bf8582ef12550886ef5b6f169b9"), + new BlockCipherVectorTest(4, new SerpentEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "40000000000000000000000000000000", "d522a3b8d6d89d4d2a124fdd88f36896"), + new BlockCipherVectorTest(5, new SerpentEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "00000000000200000000000000000000", "189b8ec3470085b3da97e82ca8964e32"), + new BlockCipherVectorTest(6, new SerpentEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "00000000000000000000008000000000", "f77d868cf760b9143a89809510ccb099"), + new BlockCipherVectorTest(7, new SerpentEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "08000000000000000000000000000000", "d43b7b981b829342fce0e3ec6f5f4c82"), + new BlockCipherVectorTest(8, new SerpentEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "00000000000000000100000000000000", "0bf30e1a0c33ccf6d5293177886912a7"), + new BlockCipherVectorTest(9, new SerpentEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "00000000000000000000000000000001", "6a7f3b805d2ddcba49b89770ade5e507"), + new BlockCipherVectorTest(10, new SerpentEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "49afbfad9d5a34052cd8ffa5986bd2dd"), + new BlockCipherVectorTest(11, new SerpentEngine(), + new KeyParameter(Hex.decode("000000000000000000000000004000000000000000000000")), + "00000000000000000000000000000000", "ba8829b1de058c4b48615d851fc74f17"), + new BlockCipherVectorTest(12, new SerpentEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000100000000")), + "00000000000000000000000000000000", "89f64377bf1e8a46c8247044e8056a98"), +/* + new BlockCipherMonteCarloTest(13, 10000, new SerpentEngine(), + new KeyParameter(Hex.decode("47f5f881daab9b67b43bd1342e339c19")), + "7a4f7db38c52a8b711b778a38d203b6b", "003380e19f10065740394f48e2fe80b7"), +*/ + new BlockCipherMonteCarloTest(13, 100, new SerpentEngine(), + new KeyParameter(Hex.decode("47f5f881daab9b67b43bd1342e339c19")), + "7a4f7db38c52a8b711b778a38d203b6b", "4db75303d815c2f7cc6ca935d1c5a046"), +/* + new BlockCipherMonteCarloTest(14, 10000, new SerpentEngine(), + new KeyParameter(Hex.decode("31fba879ebc5e80df35e6fa33eaf92d6")), + "70a05e12f74589009692a337f53ff614", "afb5425426906db26b70bdf842ac5400"), +*/ + new BlockCipherMonteCarloTest(14, 100, new SerpentEngine(), + new KeyParameter(Hex.decode("31fba879ebc5e80df35e6fa33eaf92d6")), + "70a05e12f74589009692a337f53ff614", "fc53a50f4d3bc9836001893d2f41742d"), +/* + new BlockCipherMonteCarloTest(15, 10000, new SerpentEngine(), + new KeyParameter(Hex.decode("bde6dd392307984695aee80e574f9977caae9aa78eda53e8")), + "9cc523d034a93740a0aa4e2054bb34d8", "1949d506ada7de1f1344986e8ea049b2"), +*/ + new BlockCipherMonteCarloTest(15, 100, new SerpentEngine(), + new KeyParameter(Hex.decode("bde6dd392307984695aee80e574f9977caae9aa78eda53e8")), + "9cc523d034a93740a0aa4e2054bb34d8", "77117e6a9e80f40b2a36b7d755573c2d"), +/* + new BlockCipherMonteCarloTest(16, 10000, new SerpentEngine(), + new KeyParameter(Hex.decode("60f6f8ad4290699dc50921a1bbcca92da914e7d9cf01a9317c79c0af8f2487a1")), + "ee1a61106fae2d381d686cbf854bab65", "e57f45559027cb1f2ed9603d814e1c34"), +*/ + new BlockCipherMonteCarloTest(16, 100, new SerpentEngine(), + new KeyParameter(Hex.decode("60f6f8ad4290699dc50921a1bbcca92da914e7d9cf01a9317c79c0af8f2487a1")), + "ee1a61106fae2d381d686cbf854bab65", "dcd7f13ea0dcdfd0139d1a42e2ffb84b") + }; + + SerpentTest() + { + super(tests, new SerpentEngine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "Serpent"; + } + + public static void main( + String[] args) + { + runTest(new SerpentTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/Shacal2Test.java b/core/src/test/java/org/spongycastle/crypto/test/Shacal2Test.java new file mode 100644 index 00000000..5ffd9473 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/Shacal2Test.java @@ -0,0 +1,200 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.engines.Shacal2Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Shacal2 tester - vectors from https://www.cosic.esat.kuleuven.be/nessie/testvectors/ + */ +public class Shacal2Test + extends CipherTest +{ + static SimpleTest[] tests = + { + // set 8.0 + new BlockCipherVectorTest(0, new Shacal2Engine(), + new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F" + + "101112131415161718191A1B1C1D1E1F" + + "202122232425262728292A2B2C2D2E2F" + + "303132333435363738393A3B3C3D3E3F")), + "98BCC10405AB0BFC686BECECAAD01AC1" + + "9B452511BCEB9CB094F905C51CA45430", + "00112233445566778899AABBCCDDEEFF" + + "102132435465768798A9BACBDCEDFE0F"), + // set 8.1 + new BlockCipherVectorTest(1, new Shacal2Engine(), + new KeyParameter(Hex.decode("2BD6459F82C5B300952C49104881FF48" + + "2BD6459F82C5B300952C49104881FF48" + + "2BD6459F82C5B300952C49104881FF48" + + "2BD6459F82C5B300952C49104881FF48")), + "481F122A75F2C4C3395140B5A951EBBA" + + "06D96BDFD9D8FF4FB59CBD1287808D5A", + "EA024714AD5C4D84EA024714AD5C4D84" + + "EA024714AD5C4D84EA024714AD5C4D84"), + // 7.255 + new BlockCipherVectorTest(2, new Shacal2Engine(), + new KeyParameter(Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")), + "94FEDFF2A0CFE3C983D340C88D73F8CF" + + "4B79FC581797EC10B27D4DA1B51E1BC7", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), + // 7.100 + new BlockCipherVectorTest(3, new Shacal2Engine(), + new KeyParameter(Hex.decode("64646464646464646464646464646464" + + "64646464646464646464646464646464" + + "64646464646464646464646464646464" + + "64646464646464646464646464646464")), + "6643CB84B3B3F126F5E50959EF4CE73D" + + "B8500918ABE1056368DB06CA8C1C0D45", + "64646464646464646464646464646464" + + "64646464646464646464646464646464"), + // 7.50 + new BlockCipherVectorTest(4, new Shacal2Engine(), + new KeyParameter(Hex.decode("32323232323232323232323232323232" + + "32323232323232323232323232323232" + + "32323232323232323232323232323232" + + "32323232323232323232323232323232")), + "92E937285AB11FE3561542C43C918966" + + "971DE722E9B9D38BD69EAC77899DCF81", + "32323232323232323232323232323232" + + "32323232323232323232323232323232"), + // 7.0 + new BlockCipherVectorTest(5, new Shacal2Engine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000")), + "F8C9259FA4F5D787B570AFA9219166A6" + + "3636FC5C30AC289155D0CC4FFCB4B03D", + "00000000000000000000000000000000" + + "00000000000000000000000000000000"), + // 6.255 + new BlockCipherVectorTest(6, new Shacal2Engine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000")), + "F4E976DF0172CD961D4C8D466A12F676" + + "5B9089046E747CD2A41BF43C18A8328E", + "00000000000000000000000000000000" + + "00000000000000000000000000000001"), + // 6.100 + new BlockCipherVectorTest(7, new Shacal2Engine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000")), + "3B929F0597E21D0076EC399D21B67713" + + "B40E3AD559704219A26A3380212D5AD6", + "00000000000000000000000008000000" + + "00000000000000000000000000000000"), + + // 6.0 + new BlockCipherVectorTest(8, new Shacal2Engine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000")), + "43A0DAD8307F19FBBCF166FE20BAC075" + + "C56FF14042550E472094B042BE5963EE", + "80000000000000000000000000000000" + + "00000000000000000000000000000000"), + }; + + Shacal2Test() + { + super(tests, new Shacal2Engine(), new KeyParameter(new byte[16])); + } + + public void performTest() + throws Exception + { + super.performTest(); + + // 1.0 + iteratedTest(0, + Hex.decode("80000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"), + Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000"), + Hex.decode("361AB6322FA9E7A7BB23818D839E01BD" + + "DAFDF47305426EDD297AEDB9F6202BAE"), + Hex.decode("226A582DE04383D0F3E7DE655DD848AC" + + "3E14CCFB4E76F7B7069879F67C4D5420"), + Hex.decode("B05D5A18C0712082CFF5BA9DBBCD7269" + + "114FC3DF83B42DAC306D95BBC473D839")); + + // 1.100 + iteratedTest(1, + Hex.decode("00000000000000000000000008000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"), + Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000"), + Hex.decode("F703282E54592A5617E10618027BB67F" + + "639E43A90767150D8B7F5E83054B3CBD"), + Hex.decode("3B442692B579485B8BA2F92CE3B90DE7" + + "D2EA03D8B3C8E7BE7BF6415F798EED90"), + Hex.decode("331B9B65F06230380BBEECFBFBA94BCF" + + "92AF6341F815D7651F996144A5377263")); + } + + private void iteratedTest(int index, byte[] key, byte[] plain, byte[] cipher, byte[] cipher100, byte[] cipher1000) + { + BlockCipher engine = new Shacal2Engine(); + + engine.init(true, new KeyParameter(key)); + + byte[] buf = new byte[plain.length]; + + System.arraycopy(plain, 0, buf, 0, plain.length); + + engine.processBlock(buf, 0, buf, 0); + + if (!Arrays.areEqual(cipher, buf)) + { + fail(index + " single count failed"); + } + + for (int i = 1; i != 100; i++) + { + engine.processBlock(buf, 0, buf, 0); + } + + if (!Arrays.areEqual(cipher100, buf)) + { + fail(index + " 100 count failed"); + } + + for (int i = 100; i != 1000; i++) + { + engine.processBlock(buf, 0, buf, 0); + } + + if (!Arrays.areEqual(cipher1000, buf)) + { + fail(index + " 1000 count failed"); + } + } + + public String getName() + { + return "Shacal2"; + } + + public static void main( + String[] args) + { + runTest(new Shacal2Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/ShortenedDigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/ShortenedDigestTest.java new file mode 100644 index 00000000..58b70149 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/ShortenedDigestTest.java @@ -0,0 +1,89 @@ +/* + * Created on 6/05/2006 + * + * To change the template for this generated file go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.ExtendedDigest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA512Digest; +import org.spongycastle.crypto.digests.ShortenedDigest; +import org.spongycastle.util.test.SimpleTest; + +public class ShortenedDigestTest + extends SimpleTest +{ + public void performTest() + { + ExtendedDigest d = new SHA1Digest(); + ShortenedDigest sd = new ShortenedDigest(new SHA1Digest(), 10); + + if (sd.getDigestSize() != 10) + { + fail("size check wrong for SHA-1"); + } + + if (sd.getByteLength() != d.getByteLength()) + { + fail("byte length check wrong for SHA-1"); + } + + // + // check output fits + // + sd.doFinal(new byte[10], 0); + + d = new SHA512Digest(); + sd = new ShortenedDigest(new SHA512Digest(), 20); + + if (sd.getDigestSize() != 20) + { + fail("size check wrong for SHA-512"); + } + + if (sd.getByteLength() != d.getByteLength()) + { + fail("byte length check wrong for SHA-512"); + } + + // + // check output fits + // + sd.doFinal(new byte[20], 0); + + try + { + new ShortenedDigest(null, 20); + + fail("null parameter not caught"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + new ShortenedDigest(new SHA1Digest(), 50); + + fail("short digest not caught"); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + public String getName() + { + return "ShortenedDigest"; + } + + public static void main( + String[] args) + { + runTest(new ShortenedDigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SipHashTest.java b/core/src/test/java/org/spongycastle/crypto/test/SipHashTest.java new file mode 100644 index 00000000..6c6b28e2 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SipHashTest.java @@ -0,0 +1,143 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.macs.SipHash; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Pack; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/* + * SipHash test values from "SipHash: a fast short-input PRF", by Jean-Philippe + * Aumasson and Daniel J. Bernstein (https://131002.net/siphash/siphash.pdf), Appendix A. + */ +public class SipHashTest + extends SimpleTest +{ + private static final int UPDATE_BYTES = 0; + private static final int UPDATE_FULL = 1; + private static final int UPDATE_MIX = 2; + + public String getName() + { + return "SipHash"; + } + + public void performTest() + throws Exception + { + byte[] key = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] input = Hex.decode("000102030405060708090a0b0c0d0e"); + + runMAC(key, input, UPDATE_BYTES); + runMAC(key, input, UPDATE_FULL); + runMAC(key, input, UPDATE_MIX); + + SecureRandom random = new SecureRandom(); + for (int i = 0; i < 100; ++i) + { + randomTest(random); + } + } + + private void runMAC(byte[] key, byte[] input, int updateType) + throws Exception + { + long expected = 0xa129ca6149be45e5L; + + SipHash mac = new SipHash(); + mac.init(new KeyParameter(key)); + + updateMAC(mac, input, updateType); + + long result = mac.doFinal(); + if (expected != result) + { + fail("Result does not match expected value for doFinal()"); + } + + byte[] expectedBytes = new byte[8]; + Pack.longToLittleEndian(expected, expectedBytes, 0); + + updateMAC(mac, input, updateType); + + byte[] output = new byte[mac.getMacSize()]; + int len = mac.doFinal(output, 0); + if (len != output.length) + { + fail("Result length does not equal getMacSize() for doFinal(byte[],int)"); + } + if (!areEqual(expectedBytes, output)) + { + fail("Result does not match expected value for doFinal(byte[],int)"); + } + } + + private void randomTest(SecureRandom random) + { + byte[] key = new byte[16]; + random.nextBytes(key); + + int length = 1 + random.nextInt(1024); + byte[] input = new byte[length]; + random.nextBytes(input); + + SipHash mac = new SipHash(); + mac.init(new KeyParameter(key)); + + updateMAC(mac, input, UPDATE_BYTES); + long result1 = mac.doFinal(); + + updateMAC(mac, input, UPDATE_FULL); + long result2 = mac.doFinal(); + + updateMAC(mac, input, UPDATE_MIX); + long result3 = mac.doFinal(); + + if (result1 != result2 || result1 != result3) + { + fail("Inconsistent results in random test"); + } + } + + private void updateMAC(SipHash mac, byte[] input, int updateType) + { + switch (updateType) + { + case UPDATE_BYTES: + { + for (int i = 0; i < input.length; ++i) + { + mac.update(input[i]); + } + break; + } + case UPDATE_FULL: + { + mac.update(input, 0, input.length); + break; + } + case UPDATE_MIX: + { + int step = Math.max(1, input.length / 3); + int pos = 0; + while (pos < input.length) + { + mac.update(input[pos++]); + int len = Math.min(input.length - pos, step); + mac.update(input, pos, len); + pos += len; + } + break; + } + default: + throw new IllegalStateException(); + } + } + + public static void main(String[] args) + { + runTest(new SipHashTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SkeinDigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/SkeinDigestTest.java new file mode 100644 index 00000000..cb5c8648 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SkeinDigestTest.java @@ -0,0 +1,294 @@ +package org.spongycastle.crypto.test; + +import java.io.IOException; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SkeinDigest; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.Memoable; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class SkeinDigestTest + extends SimpleTest +{ + private static class Case + { + private byte[] message; + private byte[] digest; + private int blockSize; + private int outputSize; + + public Case(int blockSize, int outputSize, String message, String digest) + { + this.blockSize = blockSize; + this.outputSize = outputSize; + this.message = Hex.decode(message); + this.digest = Hex.decode(digest); + } + + public int getOutputSize() + { + return outputSize; + } + + public int getBlockSize() + { + return blockSize; + } + + public byte[] getMessage() + { + return message; + } + + public byte[] getDigest() + { + return digest; + } + + } + + // Test cases from skein_golden_kat.txt and skein_golden_kat_short.txt in Skein 1.3 NIST CD + private static final Case[] TEST_CASES = { + new Case(256, 256, "", "c8877087da56e072870daa843f176e9453115929094c3a40c463a196c29bf7ba"), + new Case(256, 256, "fb", "088eb23cc2bccfb8171aa64e966d4af937325167dfcd170700ffd21f8a4cbdac"), + new Case(256, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8", + "5c3002ff57a627089ea2f97a5000d5678416389019e80e45a3bbcab118315d26"), + new Case(256, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a129233", + "640c894a4bba6574c83e920ddf7dd2982fc634881bbbcb9d774eae0a285e89ce"), + new Case(256, 160, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "0cd491b7715704c3a15a45a1ca8d93f8f646d3a1"), + new Case(256, 224, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "afd1e2d0f5b6cd4e1f8b3935fa2497d27ee97e72060adac099543487"), + new Case(256, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "4de6fe2bfdaa3717a4261030ef0e044ced9225d066354610842a24a3eafd1dcf"), + new Case(256, 384, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "954620fb31e8b782a2794c6542827026fe069d715df04261629fcbe81d7d529b" + + "95ba021fa4239fb00afaa75f5fd8e78b"), + new Case(256, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "51347e27c7eabba514959f899a6715ef6ad5cf01c23170590e6a8af399470bf9" + + "0ea7409960a708c1dbaa90e86389df254abc763639bb8cdf7fb663b29d9557c3"), + new Case(256, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "6c9b6facbaf116b538aa655e0be0168084aa9f1be445f7e06714585e5999a6c9" + + "84fffa9d41a316028692d4aad18f573fbf27cf78e84de26da1928382b023987d" + + "cfe002b6201ea33713c54a8a5d9eb346f0365e04330d2faaf7bc8aba92a5d7fb" + + "6345c6fb26750bce65ab2045c233627679ac6e9acb33602e26fe3526063ecc8b"), + + new Case(512, 512, "", "bc5b4c50925519c290cc634277ae3d6257212395cba733bbad37a4af0fa06af4" + + "1fca7903d06564fea7a2d3730dbdb80c1f85562dfcc070334ea4d1d9e72cba7a"), + new Case(512, 512, "fb", "c49e03d50b4b2cc46bd3b7ef7014c8a45b016399fd1714467b7596c86de98240" + + "e35bf7f9772b7d65465cd4cffab14e6bc154c54fc67b8bc340abf08eff572b9e"), + new Case(512, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8", + "abefb179d52f68f86941acbbe014cc67ec66ad78b7ba9508eb1400ee2cbdb06f" + + "9fe7c2a260a0272d0d80e8ef5e8737c0c6a5f1c02ceb00fb2746f664b85fcef5"), + new Case(512, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a129233", + "5c5b7956f9d973c0989aa40a71aa9c48a65af2757590e9a758343c7e23ea2df4" + + "057ce0b49f9514987feff97f648e1dd065926e2c371a0211ca977c213f14149f"), + new Case(512, 160, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "ef03079d61b57c6047e15fa2b35b46fa24279539"), + new Case(512, 224, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "d9e3219b214e15246a2038f76a573e018ef69b385b3bd0576b558231"), + new Case(512, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "809dd3f763a11af90912bbb92bc0d94361cbadab10142992000c88b4ceb88648"), + new Case(512, 384, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "825f5cbd5da8807a7b4d3e7bd9cd089ca3a256bcc064cd73a9355bf3ae67f2bf" + + "93ac7074b3b19907a0665ba3a878b262"), + new Case(512, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "1a0d5abf4432e7c612d658f8dcfa35b0d1ab68b8d6bd4dd115c23cc57b5c5bcd" + + "de9bff0ece4208596e499f211bc07594d0cb6f3c12b0e110174b2a9b4b2cb6a9"), + + new Case(1024, 1024, "", "0fff9563bb3279289227ac77d319b6fff8d7e9f09da1247b72a0a265cd6d2a62" + + "645ad547ed8193db48cff847c06494a03f55666d3b47eb4c20456c9373c86297" + + "d630d5578ebd34cb40991578f9f52b18003efa35d3da6553ff35db91b81ab890" + + "bec1b189b7f52cb2a783ebb7d823d725b0b4a71f6824e88f68f982eefc6d19c6"), + new Case(1024, 1024, "fb", "6426bdc57b2771a6ef1b0dd39f8096a9a07554565743ac3de851d28258fcff22" + + "9993e11c4e6bebc8b6ecb0ad1b140276081aa390ec3875960336119427827473" + + "4770671b79f076771e2cfdaaf5adc9b10cbae43d8e6cd2b1c1f5d6c82dc96618" + + "00ddc476f25865b8748253173187d81da971c027d91d32fb390301c2110d2db2"), + new Case(1024, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8", + "140e93726ab0b0467c0b8a834ad8cda4d1769d273661902b70db0dcb5ee692ac" + + "b3f852d03b11f857850f2428432811309c1dcbe5724f00267ea3667e89fadb4e" + + "4911da6b0ba8a7eddf87c1c67152ef0f07b7fead3557318478bdef5ad1e5926d" + + "7071fdd4bfa5076d4b3253f8de479ebdf5357676f1641b2f097e9b785e9e528e"), + new Case(1024, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a129233", + "31105e1ef042c30b95b16e0f6e6a1a19172bb7d54a0597dd0c711194888efe1d" + + "bce82d47416df9577ca387219f06e45cd10964ff36f6711edbbea0e9595b0f66" + + "f72b755d70a46857e0aec98561a743d49370d8e572e212811273125f66cc30bf" + + "117d3221894c48012bf6e2219de91e064b01523517420a1e00f71c4cc04bab62"), + new Case(1024, 160, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "2e6a4cbf2ef05ea9c24b93e8d1de732ddf2739eb"), + new Case(1024, 224, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "1d6de19f37f7a3c265440eecb4b9fbd3300bb5ac60895cfc0d4d3c72"), + new Case(1024, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "986a4d472b123e8148731a8eac9db23325f0058c4ccbc44a5bb6fe3a8db672d7"), + new Case(1024, 384, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "9c3d0648c11f31c18395d5e6c8ebd73f43d189843fc45235e2c35e345e12d62b" + + "c21a41f65896ddc6a04969654c2e2ce9"), + new Case(1024, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "5d0416f49c2d08dfd40a1446169dc6a1d516e23b8b853be4933513051de8d5c2" + + "6baccffb08d3b16516ba3c6ccf3e9a6c78fff6ef955f2dbc56e1459a7cdba9a5"), + new Case(1024, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "96ca81f586c825d0360aef5acaec49ad55289e1797072eee198b64f349ce65b6" + + "e6ed804fe38f05135fe769cc56240ddda5098f620865ce4a4278c77fa2ec6bc3" + + "1c0f354ca78c7ca81665bfcc5dc54258c3b8310ed421d9157f36c093814d9b25" + + "103d83e0ddd89c52d0050e13a64c6140e6388431961685734b1f138fe2243086"), + + }; + + public String getName() + { + return "SkeinDigest"; + } + + public void performTest() + throws Exception + { + runTest(TEST_CASES[7]); + for (int i = 0; i < TEST_CASES.length; i++) + { + Case test = TEST_CASES[i]; + runTest(test); + } + } + + private void runTest(Case dc) + { + SkeinDigest digest = new SkeinDigest(dc.getBlockSize(), dc.getOutputSize()); + + byte[] message = dc.getMessage(); + digest.update(message, 0, message.length); + + byte[] output = new byte[digest.getDigestSize()]; + digest.doFinal(output, 0); + + if (!Arrays.areEqual(output, dc.getDigest())) + { + fail(digest.getAlgorithmName() + " message mismatch.\n Message " + new String(Hex.encode(dc.getMessage())), + new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + + // Clone test + digest.update(message, 0, message.length / 2); + + // clone the Digest + Digest d = new SkeinDigest(digest); + + digest.update(message, message.length / 2, message.length - message.length / 2); + digest.doFinal(output, 0); + + if (!areEqual(dc.getDigest(), output)) + { + fail("failing clone vector test", new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + + d.update(message, message.length / 2, message.length - message.length / 2); + d.doFinal(output, 0); + + if (!areEqual(dc.getDigest(), output)) + { + fail("failing second clone vector test", new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + + // + // memo test + // + Memoable m = (Memoable)digest; + + digest.update(message, 0, message.length / 2); + + // copy the Digest + Memoable copy1 = m.copy(); + Memoable copy2 = copy1.copy(); + + digest.update(message, message.length / 2, message.length - message.length / 2); + digest.doFinal(output, 0); + + if (!areEqual(dc.getDigest(), output)) + { + fail("failing memo vector test", new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + + m.reset(copy1); + + digest.update(message, message.length / 2, message.length - message.length / 2); + digest.doFinal(output, 0); + + if (!areEqual(dc.getDigest(), output)) + { + fail("failing memo reset vector test", new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + + Digest md = (Digest)copy2; + + md.update(message, message.length / 2, message.length - message.length / 2); + md.doFinal(output, 0); + + if (!areEqual(dc.getDigest(), output)) + { + fail("failing memo copy vector test", new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + } + + public static void main(String[] args) + throws IOException + { + // generateTests(); + runTest(new SkeinDigestTest()); + } + +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SkeinMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/SkeinMacTest.java new file mode 100644 index 00000000..3f1c616f --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SkeinMacTest.java @@ -0,0 +1,162 @@ +package org.spongycastle.crypto.test; + +import java.io.IOException; + +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.macs.SkeinMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class SkeinMacTest + extends SimpleTest +{ + private static class Case + { + private byte[] message; + private byte[] digest; + private byte[] key; + private int blockSize; + private int outputSize; + + public Case(int blockSize, int outputSize, String message, String key, String digest) + { + this.blockSize = blockSize; + this.outputSize = outputSize; + this.message = Hex.decode(message); + this.key = Hex.decode(key); + this.digest = Hex.decode(digest); + } + + public int getOutputSize() + { + return outputSize; + } + + public int getBlockSize() + { + return blockSize; + } + + public byte[] getMessage() + { + return message; + } + + public byte[] getKey() + { + return key; + } + + public byte[] getDigest() + { + return digest; + } + + public String toString() + { + return "new Case(" + blockSize + ", " + outputSize + ", \"" + new String(Hex.encode(message)) + "\", \"" + + new String(Hex.encode(key)) + "\", \"" + new String(Hex.encode(digest)) + "\""; + } + + } + + // Test cases from skein_golden_kat.txt in Skein 1.3 NIST CD + // Excludes empty '(none)' key 'random+MAC' tests, which are in effect digest + private static final Case[] TEST_CASES = { + new Case(256, 256, "", "cb41f1706cde09651203c2d0efbaddf8", "886e4efefc15f06aa298963971d7a25398fffe5681c84db39bd00851f64ae29d"), + new Case(256, 256, "d3", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "979422a94e3afaa46664124d4e5e8b9422b1d8baf11c6ae6725992ac72a112ca"), + new Case(256, 256, "d3090c72", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "1d658372cbea2f9928493cc47599d6f4ad8ce33536bedfa20b739f07516519d5"), + new Case(256, 256, "d3090c72167517f7", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "41ef6b0f0fad81c040284f3b1a91e9c44e4c26a6d7207f3aac4362856ef12aca"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "ca8208119b9e4e4057631ab31015cfd256f6763a0a34381633d97f640899b84f"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "9e9980fcc16ee082cf164a5147d0e0692aeffe3dcb8d620e2bb542091162e2e9"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc235", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "c353a316558ec34f8245dd2f9c2c4961fbc7decc3b69053c103e4b8aaaf20394"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdf", "cb41f1706cde09651203c2d0efbaddf8", "b1b8c18188e69a6ecae0b6018e6b638c6a91e6de6881e32a60858468c17b520d"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "1dfd2515a412e78852cd81a7f2167711b4ca19b2891c2ea36ba94f8451944793"), + new Case(256, 224, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf8", "a097340709b443ed2c0a921f5dcefef3ead65c4f0bcd5f13da54d7ed"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "ac1b4fab6561c92d0c487e082daec53e0db4f505e08bf51cae4fd5375e37fc04"), + new Case(256, 384, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "96e6cebb23573d0a70ce36a67aa05d2403148093f25c695e1254887cc97f9771d2518413af4286bf2a06b61a53f7fcec"), + new Case(256, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "0e95e597e71d6350f20b99c4179f54f43a4722705c06ba765a82cb0a314fe2fe87ef8090063b757e53182706ed18737dadc0da1e1c66518f08334052702c5ed7"), + new Case(256, 264, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf8", "064abd4896f460b1953f5a357e7f7c5256e29cdb62b8740d0b52295cfa2ef4c7a2"), + new Case(256, 520, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "edf220e43e048603bd16197d59b673b9974de5b8bcf7cb1558a4799f6fd3743eb5fb400cd6129afc0c60e7b741b7e5806f0e0b93eb8429fbc7efa222175a9c80fd"), + new Case(256, 1032, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "f3f59fb07399c7b73aae02a8590883cb2fdfde75c55654e71846522301bde48d267169adcc559e038e8c2f28faa552b550d51874055384adea93c036c71a1f0af0c7bcc3bc923738d5307b9da7cb423d4e615c629c4aba71f70d4c9d1fa008176825e51bfa0203445a4083947ec19f6a0fbd082b5b970f2396fb67420639410447"), + new Case(256, 2056, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "80eb80d9b8836b32fa576fc84ba08edfbdfd6979123d61914e610a70a372b37f560a10909484f9f4a377c93e29ba681dfe522c41dc83b5ee0567e5370007c7bbe4df0b2b4a25e088f80d72fc30734cdcd76d817b42fbd44dca881019afb25306f19d4e91848778af306517d2072cef72caa327e877c5b6554f83cec3d00877131b47c4d3b557f5a13541c4d5080ee3ce7a658993d083efd0db3496a8752060c3c8552f44b290cabdcc867f691ad605836c08dbd59c9528d885b600b85fdfc8a9d0e636ac3ad8b4295bcb0169e78dc358e77eacc8c4b61bddfa9e5f32d2268a006cfe05c57150fe8e68cabd21cf6cf6035aa1fe4db36c922b765aad0b64e82a2c37"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed696e6c9db1e6abea026288954a9c2d5758d7c5db7c9e48aa3d21cae3d977a7c3926066aa393dbd538dd0c30da8916c8757f24c18488014668a2627163a37b261833dc2f8c3c56b1b2e0be21fd3fbdb507b2950b77a6cc02efb393e57419383a920767bca2c972107aa61384542d47cbfb82cfe5c415389d1b0a2d74e2c5da851", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "8f88de68f03cd2f396ccdd49c3a0f4ff15bcda7eb357da9753f6116b124de91d"), + new Case(512, 512, "", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "9bd43d2a2fcfa92becb9f69faab3936978f1b865b7e44338fc9c8f16aba949ba340291082834a1fc5aa81649e13d50cd98641a1d0883062bfe2c16d1faa7e3aa"), + new Case(512, 512, "d3", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "f0c0a10f031c8fc69cfabcd54154c318b5d6cd95d06b12cf20264402492211ee010d5cecc2dc37fd772afac0596b2bf71e6020ef2dee7c860628b6e643ed9ff6"), + new Case(512, 512, "d3090c72167517f7", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "0c1f1921253dd8e5c2d4c5f4099f851042d91147892705829161f5fc64d89785226eb6e187068493ee4c78a4b7c0f55a8cbbb1a5982c2daf638fc6a74b16b0d7"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "478d7b6c0cc6e35d9ebbdedf39128e5a36585db6222891692d1747d401de34ce3db6fcbab6c968b7f2620f4a844a2903b547775579993736d2493a75ff6752a1"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e59", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "13c170bac1de35e5fb843f65fabecf214a54a6e0458a4ff6ea5df91915468f4efcd371effa8965a9e82c5388d84730490dcf3976af157b8baf550655a5a6ab78"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc235", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "a947812529a72fd3b8967ec391b298bee891babc8487a1ec4ea3d88f6b2b5be09ac6a780f30f8e8c3bbb4f18bc302a28f3e87d170ba0f858a8fefe3487478cca"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdf", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "7690ba61f10e0bba312980b0212e6a9a51b0e9aadfde7ca535754a706e042335b29172aae29d8bad18efaf92d43e6406f3098e253f41f2931eda5911dc740352"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "d10e3ba81855ac087fbf5a3bc1f99b27d05f98ba22441138026225d34a418b93fd9e8dfaf5120757451adabe050d0eb59d271b0fe1bbf04badbcf9ba25a8791b"), + new Case(512, 160, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "5670b226156570dff3efe16661ab86eb24982cdf"), + new Case(512, 224, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "c41b9ff9753e6c0f8ed88866e320535e927fe4da552c289841a920db"), + new Case(512, 384, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "dfbf5c1319a1d9d70efb2f1600fbcf694f935907f31d24a16d6cd2fb2d7855a769681766c0a29da778eed346cd1d740f"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "04d8cddb0ad931d54d195899a094684344e902286037272890bce98a41813edc37a3cee190a693fcca613ee30049ce7ec2bdff9613f56778a13f8c28a21d167a"), + new Case(512, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "08fca368b3b14ac406676adf37ac9be2dbb8704e694055a0c6331184d4f0070098f23f0963ee29002495771bf56fb4d3d9ff3506abcd80be927379f7880d5d7703919fbf92184f498ac44f47f015ce676eded9165d47d53733f5a27abbc05f45acd98b97cc15ffdced641defd1a5119ef841b452a1b8f94ee69004466ccdc143"), + new Case(512, 264, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "669e770ebe7eacc2b64caaf049923ad297a5b37cfa61c283392d81ccfcb9bbbc09"), + new Case(512, 1032, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "acc2e03f07f33e9820a6038421089429adcd6a7a83f733beec048c05bf37531a170a5537fcb565c348a70a83217f8be768ff6f95fd2b3d89cb7d8a3dc849505e3710eb4e65a8e7134bbf580d92fe18c9aa987563669b1f014aa5e092519089355534eaa9f0bdc99f6839f54080ffe74623254c906ecb8896b4346c3178a0bc2898"), + new Case(512, 2056, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "9f3e082223c43090a4a3ffbdcd469cbabfe0c1399d1edf45a5dfc18f4db5428928a76e979b8d0d5dffec0e6a59ada448c1ffbc06cc80a2006f002adc0c6dbf458563762228dce4381944e460ebebfe06f1237093634625107469a22a189a47f8b025899265d8890a1b39df64552394377e88ba2ad44a8c8d174f884ac8c3ae24ddb0affca5fceb6aa76e09706881e8371774b9b050a69b96ef5e97e81043f8b7e9479e287ab441bacd62caf768a82c8c3e3107be70eb8799a39856fe29842a04e25de0ef9de1b7e65bd0f1f7306835287fc957388e2035b7d22d3aa9c06a9fefbca16f3f60e1c4def89038d918942152a069aa2e0be8ae7475d859031adec84583"), + new Case(1024, 1024, "", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "bcf37b3459c88959d6b6b58b2bfe142cef60c6f4ec56b0702480d7893a2b0595aa354e87102a788b61996b9cbc1eade7dafbf6581135572c09666d844c90f066b800fc4f5fd1737644894ef7d588afc5c38f5d920bdbd3b738aea3a3267d161ed65284d1f57da73b68817e17e381ca169115152b869c66b812bb9a84275303f0"), + new Case(1024, 1024, "d3090c72", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "df0596e5808835a3e304aa27923db05f61dac57c0696a1d19abf188e70aa9dbcc659e9510f7c9a37fbc025bd4e5ea293e78ed7838dd0b08864e8ad40ddb3a88031ebefc21572a89960d1916107a7da7ac0c067e34ec46a86a29ca63fa250bd398eb32ec1ed0f8ac8329f26da018b029e41e2e58d1dfc44de81615e6c987ed9c9"), + new Case(1024, 1024, "d3090c72167517f7", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "3cfbb79cd88af8ee09c7670bcbab6907a31f80fa31d9d7c9d50826c9568f307a78bd254961398c76b6e338fd9ca5f351059350d30963c3320659b223b991fc46d1307686fe2b4763d9f593c57ad5adbc45caf2ea3dc6090f5a74fa5fa6d9e9838964ea0a2aa216831ab069b00629a1a9b037083403bdb25d3d06a21c430c87dd"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e59", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "0a1b960099fc9d653b0fd1f5b6b972fb366907b772cbce5a59b6171d7935506f70c212bd169d68c5cfd8618343611b7eb2e686ff1dc7c03a57e1a55ed10726848161eea903d53b58459be42d95df989c66c2eea4e51cde272c2d8be67bf3bca2aee633777eb8486781eaa060d0f538abd6c93dbd2d1bf66e6f50bfdcac3725a4"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "3e0cd7938d71c39ffbb08a6ba7995ade3ad140e2c0c45cdbafb099247e08e4c20b61c1f885ced5ed2f816680925034918236e5807f0eecf3f27e9cfca36675eb75873efa1fb41f17541dc2f7c2469eaecb35cc7ca58e489804caf56f09fb97c9f689c64ad49c6888f86c483e901bd3d25798b394ef93faf9154900f92f31f433"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdf", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "7266752f7e9aa04bd7d8a1b16030677de6021301f6a62473c76bae2b98bbf8aad73bd00a4b5035f741caf2317ab80e4e97f5c5bbe8acc0e8b424bcb13c7c6740a985801fba54addde8d4f13f69d2bfc98ae104d46a211145217e51d510ea846cec9581d14fda079f775c8b18d66cb31bf7060996ee8a69eee7f107909ce59a97"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "71f40bf2aa635125ef83c8df0d4e9ea18b73b56be4f45e89b910a7c68d396b65b09d18abc7d1b6de3f53fd5de583e6f22e612dd17b292068af6027daaf8b4cd60acf5bc85044741e9f7a1f423f5827f5e360930a2e71912239af9fc6343604fdcf3f3569854f2bb8d25a81e3b3f5261a02fe8292aaaa50c324101ab2c7a2f349"), + new Case(1024, 160, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "17c3c533b27d666da556ae586e641b7a3a0bcc45"), + new Case(1024, 224, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "6625df9801581009125ea4e5c94ad6f1a2d692c278822ccb6eb67235"), + new Case(1024, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "6c5b671c1766f6eecea6d24b641d4a6bf84bba13a1976f8f80b3f30ee2f93de6"), + new Case(1024, 384, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "98af454d7fa3706dfaafbf58c3f9944868b57f68f493987347a69fce19865febba0407a16b4e82065035651f0b1e0327"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "211ac479e9961141da3aac19d320a1dbbbfad55d2dce87e6a345fcd58e36827597378432b482d89bad44dddb13e6ad86e0ee1e0882b4eb0cd6a181e9685e18dd302ebb3aa74502c06254dcadfb2bd45d288f82366b7afc3bc0f6b1a3c2e8f84d37fbedd07a3f8fcff84faf24c53c11da600aaa118e76cfdcb366d0b3f7729dce"), + new Case(1024, 264, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "dc1d253b7cadbdaef18503b1809a7f1d4f8c323b7f6f8ca50b76d3864649ce1c7d"), + new Case(1024, 520, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "decd79578d12bf6806530c382230a2c7836429c70cac941179e1dd982938bab91fb6f3638df1cc1ef615ecfc4249e5aca8a73c4c1eebef662a836d0be903b00146"), + new Case(1024, 1032, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "440fe691e04f1fed8c253d6c4670646156f33fffaea702de9445df5739eb960cecf85d56e2e6860a610211a5c909932ab774b978aa0b0d5bbce82775172ab12dceddd51d1eb030057ce61bea6c18f6bb368d26ae76a9e44a962eb132e6c42c25d9fecc4f13348300ca55c78e0990de96c1ae24eb3ee3324782c93dd628260a2c8d"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed696e6c9db1e6abea026288954a9c2d5758d7c5db7c9e48aa3d21cae3d977a7c3926066aa393dbd538dd0c30da8916c8757f24c18488014668a2627163a37b261833dc2f8c3c56b1b2e0be21fd3fbdb507b2950b77a6cc02efb393e57419383a920767bca2c972107aa61384542d47cbfb82cfe5c415389d1b0a2d74e2c5da851", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "46a42b0d7b8679f8fcea156c072cf9833c468a7d59ac5e5d326957d60dfe1cdfb27eb54c760b9e049fda47f0b847ac68d6b340c02c39d4a18c1bdfece3f405fae8aa848bdbefe3a4c277a095e921228618d3be8bd1999a071682810de748440ad416a97742cc9e8a9b85455b1d76472cf562f525116698d5cd0a35ddf86e7f8a"), + + }; + + public String getName() + { + return "SkeinMac"; + } + + public void performTest() + throws Exception + { + for (int i = 0; i < TEST_CASES.length; i++) + { + Case test = TEST_CASES[i]; + runTest(test); + } + } + + private void runTest(Case dc) + { + Mac digest = new SkeinMac(dc.getBlockSize(), dc.getOutputSize()); + digest.init(new KeyParameter(dc.getKey())); + + byte[] message = dc.getMessage(); + digest.update(message, 0, message.length); + + byte[] output = new byte[digest.getMacSize()]; + digest.doFinal(output, 0); + + if (!Arrays.areEqual(output, dc.getDigest())) + { + fail(digest.getAlgorithmName() + " message " + (dc.getMessage().length * 8) + " mismatch.\n Message " + new String(Hex.encode(dc.getMessage())) + + "\n Key " + new String(Hex.encode(dc.getKey())) + "\n Expected " + + new String(Hex.encode(dc.getDigest())) + "\n Actual " + new String(Hex.encode(output))); + } + + } + + public static void main(String[] args) + throws IOException + { + runTest(new SkeinMacTest()); + } + +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/SkipjackTest.java b/core/src/test/java/org/spongycastle/crypto/test/SkipjackTest.java new file mode 100644 index 00000000..e7b2d867 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/SkipjackTest.java @@ -0,0 +1,35 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.SkipjackEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + */ +public class SkipjackTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new SkipjackEngine(), + new KeyParameter(Hex.decode("00998877665544332211")), + "33221100ddccbbaa", "2587cae27a12d300") + }; + + SkipjackTest() + { + super(tests, new SkipjackEngine(), new KeyParameter(Hex.decode("00998877665544332211"))); + } + + public String getName() + { + return "SKIPJACK"; + } + + public static void main( + String[] args) + { + runTest(new SkipjackTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/StreamCipherResetTest.java b/core/src/test/java/org/spongycastle/crypto/test/StreamCipherResetTest.java new file mode 100644 index 00000000..7c166ada --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/StreamCipherResetTest.java @@ -0,0 +1,133 @@ +package org.spongycastle.crypto.test; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.crypto.engines.ChaChaEngine; +import org.spongycastle.crypto.engines.Grain128Engine; +import org.spongycastle.crypto.engines.Grainv1Engine; +import org.spongycastle.crypto.engines.HC128Engine; +import org.spongycastle.crypto.engines.HC256Engine; +import org.spongycastle.crypto.engines.ISAACEngine; +import org.spongycastle.crypto.engines.RC4Engine; +import org.spongycastle.crypto.engines.Salsa20Engine; +import org.spongycastle.crypto.engines.XSalsa20Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * Test whether block ciphers implement reset contract on init, encrypt/decrypt and reset. + */ +public class StreamCipherResetTest + extends SimpleTest +{ + public String getName() + { + return "Stream Cipher Reset"; + } + + public void performTest() + throws Exception + { + testReset(new Salsa20Engine(), new Salsa20Engine(), new ParametersWithIV(new KeyParameter(random(32)), + random(8))); + testReset(new Salsa20Engine(), new Salsa20Engine(), new ParametersWithIV(new KeyParameter(random(16)), + random(8))); + testReset(new XSalsa20Engine(), new XSalsa20Engine(), new ParametersWithIV(new KeyParameter(random(32)), + random(24))); + testReset(new ChaChaEngine(), new ChaChaEngine(), new ParametersWithIV(new KeyParameter(random(32)), random(8))); + testReset(new ChaChaEngine(), new ChaChaEngine(), new ParametersWithIV(new KeyParameter(random(16)), random(8))); + testReset(new RC4Engine(), new RC4Engine(), new KeyParameter(random(16))); + testReset(new ISAACEngine(), new ISAACEngine(), new KeyParameter(random(16))); + testReset(new HC128Engine(), new HC128Engine(), new ParametersWithIV(new KeyParameter(random(16)), random(16))); + testReset(new HC256Engine(), new HC256Engine(), new ParametersWithIV(new KeyParameter(random(16)), random(16))); + testReset(new Grainv1Engine(), new Grainv1Engine(), new ParametersWithIV(new KeyParameter(random(16)), + random(8))); + testReset(new Grain128Engine(), new Grain128Engine(), new ParametersWithIV(new KeyParameter(random(16)), + random(12))); + } + + private static final SecureRandom RAND = new SecureRandom(); + + private byte[] random(int size) + { + final byte[] data = new byte[size]; + RAND.nextBytes(data); + return data; + } + + private void testReset(StreamCipher cipher1, StreamCipher cipher2, CipherParameters params) + throws InvalidCipherTextException + { + cipher1.init(true, params); + + byte[] plaintext = new byte[1023]; + byte[] ciphertext = new byte[plaintext.length]; + + // Establish baseline answer + cipher1.processBytes(plaintext, 0, plaintext.length, ciphertext, 0); + + // Test encryption resets + checkReset(cipher1, params, true, plaintext, ciphertext); + + // Test decryption resets with fresh instance + cipher2.init(false, params); + checkReset(cipher2, params, false, ciphertext, plaintext); + } + + private void checkReset(StreamCipher cipher, + CipherParameters params, + boolean encrypt, + byte[] pretext, + byte[] posttext) + throws InvalidCipherTextException + { + // Do initial run + byte[] output = new byte[posttext.length]; + cipher.processBytes(pretext, 0, pretext.length, output, 0); + + // Check encrypt resets cipher + cipher.init(encrypt, params); + + try + { + cipher.processBytes(pretext, 0, pretext.length, output, 0); + } + catch (Exception e) + { + fail(cipher.getAlgorithmName() + " init did not reset: " + e.getMessage()); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(cipher.getAlgorithmName() + " init did not reset.", new String(Hex.encode(posttext)), + new String(Hex.encode(output))); + } + + // Check reset resets data + cipher.reset(); + + try + { + cipher.processBytes(pretext, 0, pretext.length, output, 0); + } + catch (Exception e) + { + fail(cipher.getAlgorithmName() + " reset did not reset: " + e.getMessage()); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(cipher.getAlgorithmName() + " reset did not reset."); + } + } + + public static void main(String[] args) + { + runTest(new StreamCipherResetTest()); + } + +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/StreamCipherVectorTest.java b/core/src/test/java/org/spongycastle/crypto/test/StreamCipherVectorTest.java new file mode 100644 index 00000000..2d3b197d --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/StreamCipherVectorTest.java @@ -0,0 +1,62 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.StreamCipher; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * a basic test that takes a stream cipher, key parameter, and an input + * and output string. + */ +public class StreamCipherVectorTest + extends SimpleTest +{ + int id; + StreamCipher cipher; + CipherParameters param; + byte[] input; + byte[] output; + + public StreamCipherVectorTest( + int id, + StreamCipher cipher, + CipherParameters param, + String input, + String output) + { + this.id = id; + this.cipher = cipher; + this.param = param; + this.input = Hex.decode(input); + this.output = Hex.decode(output); + } + + public String getName() + { + return cipher.getAlgorithmName() + " Vector Test " + id; + } + + public void performTest() + { + cipher.init(true, param); + + byte[] out = new byte[input.length]; + + cipher.processBytes(input, 0, input.length, out, 0); + + if (!areEqual(out, output)) + { + fail("failed.", new String(Hex.encode(output)) , new String(Hex.encode(out))); + } + + cipher.init(false, param); + + cipher.processBytes(output, 0, output.length, out, 0); + + if (!areEqual(input, out)) + { + fail("failed reversal"); + } + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/TEATest.java b/core/src/test/java/org/spongycastle/crypto/test/TEATest.java new file mode 100644 index 00000000..a2740600 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/TEATest.java @@ -0,0 +1,48 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.TEAEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * TEA tester - based on C implementation results from http://www.simonshepherd.supanet.com/tea.htm + */ +public class TEATest + extends CipherTest +{ + static SimpleTest[] tests = { + new BlockCipherVectorTest(0, new TEAEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "0000000000000000", + "41ea3a0a94baa940"), + new BlockCipherVectorTest(1, new TEAEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "0102030405060708", + "6a2f9cf3fccf3c55"), + new BlockCipherVectorTest(2, new TEAEngine(), + new KeyParameter(Hex.decode("0123456712345678234567893456789A")), + "0000000000000000", + "34e943b0900f5dcb"), + new BlockCipherVectorTest(3, new TEAEngine(), + new KeyParameter(Hex.decode("0123456712345678234567893456789A")), + "0102030405060708", + "773dc179878a81c0"), + }; + + TEATest() + { + super(tests, new TEAEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "TEA"; + } + + public static void main( + String[] args) + { + runTest(new TEATest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/Threefish1024Test.java b/core/src/test/java/org/spongycastle/crypto/test/Threefish1024Test.java new file mode 100644 index 00000000..9e087187 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/Threefish1024Test.java @@ -0,0 +1,60 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.ThreefishEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.TweakableBlockCipherParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class Threefish1024Test + extends CipherTest +{ + // Test cases from skein_golden_kat_internals.txt in Skein 1.3 NIST CD + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024), + new TweakableBlockCipherParameters( + new KeyParameter(new byte[128]), + new byte[16]), + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000", + "f05c3d0a3d05b304f785ddc7d1e036015c8aa76e2f217b06c6e1544c0bc1a90d" + + "f0accb9473c24e0fd54fea68057f43329cb454761d6df5cf7b2e9b3614fbd5a2" + + "0b2e4760b40603540d82eabc5482c171c832afbe68406bc39500367a592943fa" + + "9a5b4a43286ca3c4cf46104b443143d560a4b230488311df4feef7e1dfe8391e"), + new BlockCipherVectorTest(1, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024), + new TweakableBlockCipherParameters( + new KeyParameter(Hex.decode( + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + + "505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f" + + "707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f")), + Hex.decode("000102030405060708090a0b0c0d0e0f")), + "fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0" + + "dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0" + + "bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a0" + + "9f9e9d9c9b9a999897969594939291908f8e8d8c8b8a89888786858483828180", + "a6654ddbd73cc3b05dd777105aa849bce49372eaaffc5568d254771bab85531c" + + "94f780e7ffaae430d5d8af8c70eebbe1760f3b42b737a89cb363490d670314bd" + + "8aa41ee63c2e1f45fbd477922f8360b388d6125ea6c7af0ad7056d01796e90c8" + + "3313f4150a5716b30ed5f569288ae974ce2b4347926fce57de44512177dd7cde") + }; + + Threefish1024Test() + { + super(tests, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024), new KeyParameter(new byte[128])); + } + + public String getName() + { + return "Threefish-1024"; + } + + public static void main( + String[] args) + { + runTest(new Threefish1024Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/Threefish256Test.java b/core/src/test/java/org/spongycastle/crypto/test/Threefish256Test.java new file mode 100644 index 00000000..6753c245 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/Threefish256Test.java @@ -0,0 +1,45 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.ThreefishEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.TweakableBlockCipherParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class Threefish256Test + extends CipherTest +{ + // Test cases from skein_golden_kat_internals.txt in Skein 1.3 NIST CD + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256), + new TweakableBlockCipherParameters( + new KeyParameter(new byte[32]), + new byte[16]), + "0000000000000000000000000000000000000000000000000000000000000000", + "84da2a1f8beaee947066ae3e3103f1ad536db1f4a1192495116b9f3ce6133fd8"), + new BlockCipherVectorTest(1, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256), + new TweakableBlockCipherParameters( + new KeyParameter(Hex.decode( + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f")), + Hex.decode("000102030405060708090a0b0c0d0e0f")), + "FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0", + "e0d091ff0eea8fdfc98192e62ed80ad59d865d08588df476657056b5955e97df") + }; + + Threefish256Test() + { + super(tests, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "Threefish-256"; + } + + public static void main( + String[] args) + { + runTest(new Threefish256Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/Threefish512Test.java b/core/src/test/java/org/spongycastle/crypto/test/Threefish512Test.java new file mode 100644 index 00000000..ba5447f4 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/Threefish512Test.java @@ -0,0 +1,50 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.ThreefishEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.TweakableBlockCipherParameters; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class Threefish512Test + extends CipherTest +{ + // Test cases from skein_golden_kat_internals.txt in Skein 1.3 NIST CD + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), + new TweakableBlockCipherParameters( + new KeyParameter(new byte[64]), + new byte[16]), + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000", + "b1a2bbc6ef6025bc40eb3822161f36e375d1bb0aee3186fbd19e47c5d479947b" + + "7bc2f8586e35f0cff7e7f03084b0b7b1f1ab3961a580a3e97eb41ea14a6d7bbe"), + new BlockCipherVectorTest(1, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), + new TweakableBlockCipherParameters( + new KeyParameter(Hex.decode( + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f")), + Hex.decode("000102030405060708090a0b0c0d0e0f")), + "fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0" + + "dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0", + "e304439626d45a2cb401cad8d636249a6338330eb06d45dd8b36b90e97254779" + + "272a0a8d99463504784420ea18c9a725af11dffea10162348927673d5c1caf3d") + }; + + Threefish512Test() + { + super(tests, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), new KeyParameter(new byte[64])); + } + + public String getName() + { + return "Threefish-512"; + } + + public static void main( + String[] args) + { + runTest(new Threefish512Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/TigerDigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/TigerDigestTest.java new file mode 100644 index 00000000..b9a40655 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/TigerDigestTest.java @@ -0,0 +1,59 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.TigerDigest; + +/** + * Tiger Digest Test + */ +public class TigerDigestTest + extends DigestTest +{ + final static String[] messages = { + "", + "abc", + "Tiger", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvw", + "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789", + "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-" + }; + + final static String[] digests = { + "3293AC630C13F0245F92BBB1766E16167A4E58492DDE73F3", + "2AAB1484E8C158F2BFB8C5FF41B57A525129131C957B5F93", + "DD00230799F5009FEC6DEBC838BB6A27DF2B9D6F110C7937", + "F71C8583902AFB879EDFE610F82C0D4786A3A534504486B5", + "38F41D9D9A710A10C3727AC0DEEAA270727D9F926EC10139", + "48CEEB6308B87D46E95D656112CDF18D97915F9765658957", + "631ABDD103EB9A3D245B6DFD4D77B257FC7439501D1568DD", + "C54034E5B43EB8005848A7E0AE6AAC76E4FF590AE715FD25", + "C54034E5B43EB8005848A7E0AE6AAC76E4FF590AE715FD25" + }; + + final static String hash64k = "FDF4F5B35139F48E710E421BE5AF411DE1A8AAC333F26204"; + + TigerDigestTest() + { + super(new TigerDigest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + sixtyFourKTest(hash64k); + } + + protected Digest cloneDigest(Digest digest) + { + return new TigerDigest((TigerDigest)digest); + } + + public static void main( + String[] args) + { + runTest(new TigerDigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/TwofishTest.java b/core/src/test/java/org/spongycastle/crypto/test/TwofishTest.java new file mode 100644 index 00000000..84f3e7fc --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/TwofishTest.java @@ -0,0 +1,45 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.TwofishEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class TwofishTest + extends CipherTest +{ + static String key1 = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; + static String key2 = "000102030405060708090a0b0c0d0e0f1011121314151617"; + static String key3 = "000102030405060708090a0b0c0d0e0f"; + + static String input = "000102030405060708090A0B0C0D0E0F"; + + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new TwofishEngine(), + new KeyParameter(Hex.decode(key1)), + input, "8ef0272c42db838bcf7b07af0ec30f38"), + new BlockCipherVectorTest(1, new TwofishEngine(), + new KeyParameter(Hex.decode(key2)), + input, "95accc625366547617f8be4373d10cd7"), + new BlockCipherVectorTest(2, new TwofishEngine(), + new KeyParameter(Hex.decode(key3)), + input, "9fb63337151be9c71306d159ea7afaa4") + }; + + TwofishTest() + { + super(tests, new TwofishEngine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "Twofish"; + } + + public static void main( + String[] args) + { + runTest(new TwofishTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/VMPCKSA3Test.java b/core/src/test/java/org/spongycastle/crypto/test/VMPCKSA3Test.java new file mode 100644 index 00000000..21000db9 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/VMPCKSA3Test.java @@ -0,0 +1,97 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.engines.VMPCKSA3Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * VMPC Test + */ +public class VMPCKSA3Test extends SimpleTest +{ + private static final byte[] input = new byte[1000000]; + + public String getName() + { + return "VMPC-KSA3"; + } + + private void checkByte(byte[] array, int position, byte b) + { + if (array[position] != b) + { + fail("Fail on position " + position, + new String(Hex.encode(new byte[] { b })), + new String(Hex.encode(new byte[] { array[position] }))); + } + } + + public void performTest() + { + byte[] key = Hex.decode("9661410AB797D8A9EB767C21172DF6C7"); + byte[] iv = Hex.decode("4B5C2F003E67F39557A8D26F3DA2B155"); + CipherParameters kp = new KeyParameter(key); + CipherParameters kpwiv = new ParametersWithIV(kp, iv); + + VMPCKSA3Engine engine = new VMPCKSA3Engine(); + + try + { + engine.init(true, kp); + fail("init failed to throw expected exception"); + } + catch (IllegalArgumentException e) + { + // Expected + } + + engine.init(true, kpwiv); + checkEngine(engine); + + engine.reset(); + byte[] output = checkEngine(engine); + + engine.init(false, kpwiv); + byte[] recovered = new byte[output.length]; + engine.processBytes(output, 0, output.length, recovered, 0); + + if (!Arrays.areEqual(input, recovered)) + { + fail("decrypted bytes differ from original bytes"); + } + } + + private byte[] checkEngine(VMPCKSA3Engine engine) + { + byte[] output = new byte[input.length]; + engine.processBytes(input, 0, output.length, output, 0); + + checkByte(output, 0, (byte) 0xB6); + checkByte(output, 1, (byte) 0xEB); + checkByte(output, 2, (byte) 0xAE); + checkByte(output, 3, (byte) 0xFE); + checkByte(output, 252, (byte) 0x48); + checkByte(output, 253, (byte) 0x17); + checkByte(output, 254, (byte) 0x24); + checkByte(output, 255, (byte) 0x73); + checkByte(output, 1020, (byte) 0x1D); + checkByte(output, 1021, (byte) 0xAE); + checkByte(output, 1022, (byte) 0xC3); + checkByte(output, 1023, (byte) 0x5A); + checkByte(output, 102396, (byte) 0x1D); + checkByte(output, 102397, (byte) 0xA7); + checkByte(output, 102398, (byte) 0xE1); + checkByte(output, 102399, (byte) 0xDC); + + return output; + } + + public static void main(String[] args) + { + runTest(new VMPCKSA3Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/VMPCMacTest.java b/core/src/test/java/org/spongycastle/crypto/test/VMPCMacTest.java new file mode 100644 index 00000000..a8d84029 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/VMPCMacTest.java @@ -0,0 +1,51 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.macs.VMPCMac; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class VMPCMacTest extends SimpleTest +{ + public String getName() + { + return "VMPC-MAC"; + } + + public static void main(String[] args) + { + runTest(new VMPCMacTest()); + } + + static byte[] output1 = Hex.decode("9BDA16E2AD0E284774A3ACBC8835A8326C11FAAD"); + + public void performTest() throws Exception + { + CipherParameters kp = new KeyParameter( + Hex.decode("9661410AB797D8A9EB767C21172DF6C7")); + CipherParameters kpwiv = new ParametersWithIV(kp, + Hex.decode("4B5C2F003E67F39557A8D26F3DA2B155")); + + byte[] m = new byte[256]; + for (int i = 0; i < 256; i++) + { + m[i] = (byte) i; + } + + VMPCMac mac = new VMPCMac(); + mac.init(kpwiv); + + mac.update(m, 0, m.length); + + byte[] out = new byte[20]; + mac.doFinal(out, 0); + + if (!Arrays.areEqual(out, output1)) + { + fail("Fail", new String(Hex.encode(output1)), new String(Hex.encode(out))); + } + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/VMPCTest.java b/core/src/test/java/org/spongycastle/crypto/test/VMPCTest.java new file mode 100644 index 00000000..8155ddcc --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/VMPCTest.java @@ -0,0 +1,97 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.engines.VMPCEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * VMPC Test + */ +public class VMPCTest extends SimpleTest +{ + private static final byte[] input = new byte[1000000]; + + public String getName() + { + return "VMPC"; + } + + private void checkByte(byte[] array, int position, byte b) + { + if (array[position] != b) + { + fail("Fail on position " + position, + new String(Hex.encode(new byte[] { b })), + new String(Hex.encode(new byte[] { array[position] }))); + } + } + + public void performTest() + { + byte[] key = Hex.decode("9661410AB797D8A9EB767C21172DF6C7"); + byte[] iv = Hex.decode("4B5C2F003E67F39557A8D26F3DA2B155"); + CipherParameters kp = new KeyParameter(key); + CipherParameters kpwiv = new ParametersWithIV(kp, iv); + + VMPCEngine engine = new VMPCEngine(); + + try + { + engine.init(true, kp); + fail("init failed to throw expected exception"); + } + catch (IllegalArgumentException e) + { + // Expected + } + + engine.init(true, kpwiv); + checkEngine(engine); + + engine.reset(); + byte[] output = checkEngine(engine); + + engine.init(false, kpwiv); + byte[] recovered = new byte[output.length]; + engine.processBytes(output, 0, output.length, recovered, 0); + + if (!Arrays.areEqual(input, recovered)) + { + fail("decrypted bytes differ from original bytes"); + } + } + + private byte[] checkEngine(VMPCEngine engine) + { + byte[] output = new byte[input.length]; + engine.processBytes(input, 0, output.length, output, 0); + + checkByte(output, 0, (byte) 0xA8); + checkByte(output, 1, (byte) 0x24); + checkByte(output, 2, (byte) 0x79); + checkByte(output, 3, (byte) 0xF5); + checkByte(output, 252, (byte) 0xB8); + checkByte(output, 253, (byte) 0xFC); + checkByte(output, 254, (byte) 0x66); + checkByte(output, 255, (byte) 0xA4); + checkByte(output, 1020, (byte) 0xE0); + checkByte(output, 1021, (byte) 0x56); + checkByte(output, 1022, (byte) 0x40); + checkByte(output, 1023, (byte) 0xA5); + checkByte(output, 102396, (byte) 0x81); + checkByte(output, 102397, (byte) 0xCA); + checkByte(output, 102398, (byte) 0x49); + checkByte(output, 102399, (byte) 0x9A); + + return output; + } + + public static void main(String[] args) + { + runTest(new VMPCTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/WhirlpoolDigestTest.java b/core/src/test/java/org/spongycastle/crypto/test/WhirlpoolDigestTest.java new file mode 100644 index 00000000..806f5cc2 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/WhirlpoolDigestTest.java @@ -0,0 +1,105 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.WhirlpoolDigest; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * ISO vector test for Whirlpool + * + */ +public class WhirlpoolDigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890", + "abcdbcdecdefdefgefghfghighijhijk" + }; + + private static String[] digests = + { + "19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A73E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3", + "8ACA2602792AEC6F11A67206531FB7D7F0DFF59413145E6973C45001D0087B42D11BC645413AEFF63A42391A39145A591A92200D560195E53B478584FDAE231A", + "4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5", + "378C84A4126E2DC6E56DCC7458377AAC838D00032230F53CE1F5700C0FFB4D3B8421557659EF55C106B4B52AC5A4AAA692ED920052838F3362E86DBD37A8903E", + "F1D754662636FFE92C82EBB9212A484A8D38631EAD4238F5442EE13B8054E41B08BF2A9251C30B6A0B8AAE86177AB4A6F68F673E7207865D5D9819A3DBA4EB3B", + "DC37E008CF9EE69BF11F00ED9ABA26901DD7C28CDEC066CC6AF42E40F82F3A1E08EBA26629129D8FB7CB57211B9281A65517CC879D7B962142C65F5A7AF01467", + "466EF18BABB0154D25B9D38A6414F5C08784372BCCB204D6549C4AFADB6014294D5BD8DF2A6C44E538CD047B2681A51A2C60481E88C5A20B2C2A80CF3A9A083B", + "2A987EA40F917061F5D6F0A0E4644F488A7A5A52DEEE656207C562F988E95C6916BDC8031BC5BE1B7B947639FE050B56939BAAA0ADFF9AE6745B7B181C3BE3FD" + }; + + WhirlpoolDigestTest() + { + super(new WhirlpoolDigest(), messages, digests); + } + + protected Digest cloneDigest(Digest digest) + { + return new WhirlpoolDigest((WhirlpoolDigest)digest); + } + + private static String _millionAResultVector = "0C99005BEB57EFF50A7CF005560DDF5D29057FD86B20BFD62DECA0F1CCEA4AF51FC15490EDDC47AF32BB2B66C34FF9AD8C6008AD677F77126953B226E4ED8B01"; + + private static String _thirtyOneZeros = "3E3F188F8FEBBEB17A933FEAF7FE53A4858D80C915AD6A1418F0318E68D49B4E459223CD414E0FBC8A57578FD755D86E827ABEF4070FC1503E25D99E382F72BA"; + + public String getName() + { + return "Whirlpool"; + } + + public void performTest() + { + super.performTest(); + + byte[] thirtyOneZeros = new byte[31]; + performStandardVectorTest("31 zeroes test", + thirtyOneZeros, _thirtyOneZeros); + + byte[] millionAInByteArray = new byte[1000000]; + Arrays.fill(millionAInByteArray, (byte)'a'); + + performStandardVectorTest("Million 'a' test", + millionAInByteArray, _millionAResultVector); + } + + private void performStandardVectorTest(String testTitle, byte[] inputBytes, + String resultsAsHex) + { + doPerformTest(testTitle, inputBytes, resultsAsHex); + } + + private void doPerformTest(String testTitle, byte[] inputBytes, String resultsAsHex) + { + String resStr = createHexOutputFromDigest(inputBytes); + if (!resultsAsHex.equals(resStr.toUpperCase())) + { + fail(testTitle, resultsAsHex, resStr); + } + } + + private String createHexOutputFromDigest(byte[] digestBytes) + { + String resStr; + Digest digest = new WhirlpoolDigest(); + byte[] resBuf = new byte[digest.getDigestSize()]; + digest.update(digestBytes, 0, digestBytes.length); + digest.doFinal(resBuf, 0); + resStr = new String(Hex.encode(resBuf)); + return resStr; + } + + public static void main(String[] args) + { + runTest(new WhirlpoolDigestTest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/XSalsa20Test.java b/core/src/test/java/org/spongycastle/crypto/test/XSalsa20Test.java new file mode 100644 index 00000000..6c0ab486 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/XSalsa20Test.java @@ -0,0 +1,166 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.XSalsa20Engine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +public class XSalsa20Test extends SimpleTest +{ + private static class TestCase + { + + private byte[] key; + private byte[] iv; + private byte[] plaintext; + private byte[] ciphertext; + + public TestCase(String key, String iv, String plaintext, String ciphertext) + { + this.key = Hex.decode(key); + this.iv = Hex.decode(iv); + this.plaintext = Hex.decode(plaintext); + this.ciphertext = Hex.decode(ciphertext); + } + + public byte[] getKey() + { + return key; + } + + public byte[] getIv() + { + return iv; + } + + public byte[] getPlaintext() + { + return plaintext; + } + + public byte[] getCiphertext() + { + return ciphertext; + } + } + + // Test cases generated by naclcrypto-20090308, as used by cryptopp + private static final TestCase[] TEST_CASES = new TestCase[] { + new TestCase( + "a6a7251c1e72916d11c2cb214d3c252539121d8e234e652d651fa4c8cff88030", + "9e645a74e9e0a60d8243acd9177ab51a1beb8d5a2f5d700c", + "093c5e5585579625337bd3ab619d615760d8c5b224a85b1d0efe0eb8a7ee163abb0376529fcc09bab506c618e13ce777d82c3ae9d1a6f972d4160287cbfe60bf2130fc0a6ff6049d0a5c8a82f429231f008082e845d7e189d37f9ed2b464e6b919e6523a8c1210bd52a02a4c3fe406d3085f5068d1909eeeca6369abc981a42e87fe665583f0ab85ae71f6f84f528e6b397af86f6917d9754b7320dbdc2fea81496f2732f532ac78c4e9c6cfb18f8e9bdf74622eb126141416776971a84f94d156beaf67aecbf2ad412e76e66e8fad7633f5b6d7f3d64b5c6c69ce29003c6024465ae3b89be78e915d88b4b5621d", + "b2af688e7d8fc4b508c05cc39dd583d6714322c64d7f3e63147aede2d9534934b04ff6f337b031815cd094bdbc6d7a92077dce709412286822ef0737ee47f6b7ffa22f9d53f11dd2b0a3bb9fc01d9a88f9d53c26e9365c2c3c063bc4840bfc812e4b80463e69d179530b25c158f543191cff993106511aa036043bbc75866ab7e34afc57e2cce4934a5faae6eabe4f221770183dd060467827c27a354159a081275a291f69d946d6fe28ed0b9ce08206cf484925a51b9498dbde178ddd3ae91a8581b91682d860f840782f6eea49dbb9bd721501d2c67122dea3b7283848c5f13e0c0de876bd227a856e4de593a3"), + new TestCase( + "9e1da239d155f52ad37f75c7368a536668b051952923ad44f57e75ab588e475a", + "af06f17859dffa799891c4288f6635b5c5a45eee9017fd72", + "feac9d54fc8c115ae247d9a7e919dd76cfcbc72d32cae4944860817cbdfb8c04e6b1df76a16517cd33ccf1acda9206389e9e318f5966c093cfb3ec2d9ee2de856437ed581f552f26ac2907609df8c613b9e33d44bfc21ff79153e9ef81a9d66cc317857f752cc175fd8891fefebb7d041e6517c3162d197e2112837d3bc4104312ad35b75ea686e7c70d4ec04746b52ff09c421451459fb59f", + "2c261a2f4e61a62e1b27689916bf03453fcbc97bb2af6f329391ef063b5a219bf984d07d70f602d85f6db61474e9d9f5a2deecb4fcd90184d16f3b5b5e168ee03ea8c93f3933a22bc3d1a5ae8c2d8b02757c87c073409052a2a8a41e7f487e041f9a49a0997b540e18621cad3a24f0a56d9b19227929057ab3ba950f6274b121f193e32e06e5388781a1cb57317c0ba6305e910961d01002f0"), + new TestCase("d5c7f6797b7e7e9c1d7fd2610b2abf2bc5a7885fb3ff78092fb3abe8986d35e2", + "744e17312b27969d826444640e9c4a378ae334f185369c95", + "7758298c628eb3a4b6963c5445ef66971222be5d1a4ad839715d1188071739b77cc6e05d5410f963a64167629757", + "27b8cfe81416a76301fd1eec6a4d99675069b2da2776c360db1bdfea7c0aa613913e10f7a60fec04d11e65f2d64e"), + new TestCase( + "737d7811ce96472efed12258b78122f11deaec8759ccbd71eac6bbefa627785c", + "6fb2ee3dda6dbd12f1274f126701ec75c35c86607adb3edd", + "501325fb2645264864df11faa17bbd58312b77cad3d94ac8fb8542f0eb653ad73d7fce932bb874cb89ac39fc47f8267cf0f0c209f204b2d8578a3bdf461cb6a271a468bebaccd9685014ccbc9a73618c6a5e778a21cc8416c60ad24ddc417a130d53eda6dfbfe47d09170a7be1a708b7b5f3ad464310be36d9a2a95dc39e83d38667e842eb6411e8a23712297b165f690c2d7ca1b1346e3c1fccf5cafd4f8be0", + "6724c372d2e9074da5e27a6c54b2d703dc1d4c9b1f8d90f00c122e692ace7700eadca942544507f1375b6581d5a8fb39981c1c0e6e1ff2140b082e9ec016fce141d5199647d43b0b68bfd0fea5e00f468962c7384dd6129aea6a3fdfe75abb210ed5607cef8fa0e152833d5ac37d52e557b91098a322e76a45bbbcf4899e790618aa3f4c2e5e0fc3de93269a577d77a5502e8ea02f717b1dd2df1ec69d8b61ca"), + new TestCase( + "760158da09f89bbab2c99e6997f9523a95fcef10239bcca2573b7105f6898d34", + "43636b2cc346fc8b7c85a19bf507bdc3dafe953b88c69dba", + "d30a6d42dff49f0ed039a306bae9dec8d9e88366cc19e8c3642fd58fa0794ebf8029d949730339b0823a51f0f49f0d2c71f1051c1e0e2c86941f172789cdb1b0107413e70f982ff9761877bb526ef1c3eb1106a948d60ef21bd35d32cfd64f89b79ed63ecc5cca56246af736766f285d8e6b0da9cb1cd21020223ffacc5a32", + "c815b6b79b64f9369aec8dce8c753df8a50f2bc97c70ce2f014db33a65ac5816bac9e30ac08bdded308c65cb87e28e2e71b677dc25c5a6499c1553555daf1f55270a56959dffa0c66f24e0af00951ec4bb59ccc3a6c5f52e0981647e53e439313a52c40fa7004c855b6e6eb25b212a138e843a9ba46edb2a039ee82a263abe"), + new TestCase( + "27ba7e81e7edd4e71be53c07ce8e633138f287e155c7fa9e84c4ad804b7fa1b9", + "ea05f4ebcd2fb6b000da0612861ba54ff5c176fb601391aa", + "e09ff5d2cb050d69b2d42494bde5825238c756d6991d99d7a20d1ef0b83c371c89872690b2fc11d5369f4fc4971b6d3d6c078aef9b0f05c0e61ab89c025168054defeb03fef633858700c58b1262ce011300012673e893e44901dc18eee3105699c44c805897bdaf776af1833162a21a", + "a23e7ef93c5d0667c96d9e404dcbe6be62026fa98f7a3ff9ba5d458643a16a1cef7272dc6097a9b52f35983557c77a11b314b4f7d5dc2cca15ee47616f861873cbfed1d32372171a61e38e447f3cf362b3abbb2ed4170d89dcb28187b7bfd206a3e026f084a7e0ed63d319de6bc9afc0"), + new TestCase("6799d76e5ffb5b4920bc2768bafd3f8c16554e65efcf9a16f4683a7a06927c11", + "61ab951921e54ff06d9b77f313a4e49df7a057d5fd627989", "472766", "8fd7df"), + new TestCase( + "f68238c08365bb293d26980a606488d09c2f109edafa0bbae9937b5cc219a49c", + "5190b51e9b708624820b5abdf4e40fad1fb950ad1adc2d26", + "47ec6b1f73c4b7ff5274a0bfd7f45f864812c85a12fbcb3c2cf8a3e90cf66ccf2eacb521e748363c77f52eb426ae57a0c6c78f75af71284569e79d1a92f949a9d69c4efc0b69902f1e36d7562765543e2d3942d9f6ff5948d8a312cff72c1afd9ea3088aff7640bfd265f7a9946e606abc77bcedae6bddc75a0dba0bd917d73e3bd1268f727e0096345da1ed25cf553ea7a98fea6b6f285732de37431561ee1b3064887fbcbd71935e02", + "36160e88d3500529ba4edba17bc24d8cfaca9a0680b3b1fc97cf03f3675b7ac301c883a68c071bc54acdd3b63af4a2d72f985e51f9d60a4c7fd481af10b2fc75e252fdee7ea6b6453190617dcc6e2fe1cd56585fc2f0b0e97c5c3f8ad7eb4f31bc4890c03882aac24cc53acc1982296526690a220271c2f6e326750d3fbda5d5b63512c831f67830f59ac49aae330b3e0e02c9ea0091d19841f1b0e13d69c9fbfe8a12d6f30bb734d9d2"), + new TestCase( + "45b2bd0de4ed9293ec3e26c4840faaf64b7d619d51e9d7a2c7e36c83d584c3df", + "546c8c5d6be8f90952cab3f36d7c1957baaa7a59abe3d7e5", + "5007c8cd5b3c40e17d7fe423a87ae0ced86bec1c39dc07a25772f3e96dabd56cd3fd7319f6c9654925f2d87087a700e1b130da796895d1c9b9acd62b266144067d373ed51e787498b03c52faad16bb3826fa511b0ed2a19a8663f5ba2d6ea7c38e7212e9697d91486c49d8a000b9a1935d6a7ff7ef23e720a45855481440463b4ac8c4f6e7062adc1f1e1e25d3d65a31812f58a71160", + "8eacfba568898b10c0957a7d44100685e8763a71a69a8d16bc7b3f88085bb9a2f09642e4d09a9f0ad09d0aad66b22610c8bd02ff6679bb92c2c026a216bf425c6be35fb8dae7ff0c72b0efd6a18037c70eed0ca90062a49a3c97fdc90a8f9c2ea536bfdc41918a7582c9927fae47efaa3dc87967b7887dee1bf071734c7665901d9105dae2fdf66b4918e51d8f4a48c60d19fbfbbcba"), + new TestCase( + "fe559c9a282beb40814d016d6bfcb2c0c0d8bf077b1110b8703a3ce39d70e0e1", + "b076200cc7011259805e18b304092754002723ebec5d6200", + "6db65b9ec8b114a944137c821fd606be75478d928366d5284096cdef782fcff7e8f59cb8ffcda979757902c5ffa6bc477ceaa4cb5d5ea76f94d91e833f823a6bc78f1055dfa6a97bea8965c1cde67a668e001257334a585727d9e0f7c1a06e88d3d25a4e6d9096c968bf138e116a3ebeffd4bb4808adb1fd698164ba0a35c709a47f16f1f4435a2345a9194a00b95abd51851d505809a6077da9baca5831afff31578c487ee68f2767974a98a7e803aac788da98319c4ea8eaa3d394855651f484cef543f537e35158ee29", + "4dce9c8f97a028051b0727f34e1b9ef21f06f0760f36e71713204027902090ba2bb6b13436ee778d9f50530efbd7a32b0d41443f58ccaee781c7b716d3a96fdec0e3764ed7959f34c3941278591ea033b5cbadc0f1916032e9bebbd1a8395b83fb63b1454bd775bd20b3a2a96f951246ac14daf68166ba62f6cbff8bd121ac9498ff8852fd2be975df52b5daef3829d18eda42e715022dcbf930d0a789ee6a146c2c7088c35773c63c06b4af4559856ac199ced86863e4294707825337c5857970eb7fddeb263781309011"), + new TestCase( + "0ae10012d7e56614b03dcc89b14bae9242ffe630f3d7e35ce8bbb97bbc2c92c3", + "f96b025d6cf46a8a12ac2af1e2aef1fb83590adadaa5c5ea", + "ea0f354e96f12bc72bbaa3d12b4a8ed879b042f0689878f46b651cc4116d6f78409b11430b3aaa30b2076891e8e1fa528f2fd169ed93dc9f84e24409eec2101daf4d057be2492d11de640cbd7b355ad29fb70400fffd7cd6d425abeeb732a0eaa4330af4c656252c4173deab653eb85c58462d7ab0f35fd12b613d29d473d330310dc323d3c66348bbdbb68a326324657cae7b77a9e34358f2cec50c85609e73056856796e3be8d62b6e2fe9f953", + "e8abd48924b54e5b80866be7d4ebe5cf4274cafff08b39cb2d40a8f0b472398aedc776e0793812fbf1f60078635d2ed86b15efcdba60411ee23b07233592a44ec31b1013ce8964236675f8f183aef885e864f2a72edf4215b5338fa2b54653dfa1a8c55ce5d95cc605b9b311527f2e3463ffbec78a9d1d65dabad2f338769c9f43f133a791a11c7eca9af0b771a4ac32963dc8f631a2c11217ac6e1b9430c1aae1ceebe22703f429998a8fb8c641"), + new TestCase( + "082c539bc5b20f97d767cd3f229eda80b2adc4fe49c86329b5cd6250a9877450", + "845543502e8b64912d8f2c8d9fffb3c69365686587c08d0c", + "a96bb7e910281a6dfad7c8a9c370674f0ceec1ad8d4f0de32f9ae4a23ed329e3d6bc708f876640a229153ac0e7281a8188dd77695138f01cda5f41d5215fd5c6bdd46d982cb73b1efe2997970a9fdbdb1e768d7e5db712068d8ba1af6067b5753495e23e6e1963af012f9c7ce450bf2de619d3d59542fb55f3", + "835da74fc6de08cbda277a7966a07c8dcd627e7b17adde6d930b6581e3124b8baad096f693991fedb1572930601fc7709541839b8e3ffd5f033d2060d999c6c6e3048276613e648000acb5212cc632a916afce290e20ebdf612d08a6aa4c79a74b070d3f872a861f8dc6bb07614db515d363349d3a8e3336a3"), + new TestCase("3d02bff3375d403027356b94f514203737ee9a85d2052db3e4e5a217c259d18a", + "74216c95031895f48c1dba651555ebfa3ca326a755237025", + "0d4b0f54fd09ae39baa5fa4baccf2e6682e61b257e01f42b8f", + "16c4006c28365190411eb1593814cf15e74c22238f210afc3d"), + new TestCase( + "ad1a5c47688874e6663a0f3fa16fa7efb7ecadc175c468e5432914bdb480ffc6", + "e489eed440f1aae1fac8fb7a9825635454f8f8f1f52e2fcc", + "aa6c1e53580f03a9abb73bfdadedfecada4c6b0ebe020ef10db745e54ba861caf65f0e40dfc520203bb54d29e0a8f78f16b3f1aa525d6bfa33c54726e59988cfbec78056", + "02fe84ce81e178e7aabdd3ba925a766c3c24756eefae33942af75e8b464556b5997e616f3f2dfc7fce91848afd79912d9fb55201b5813a5a074d2c0d4292c1fd441807c5"), + new TestCase( + "053a02bedd6368c1fb8afc7a1b199f7f7ea2220c9a4b642a6850091c9d20ab9c", + "c713eea5c26dad75ad3f52451e003a9cb0d649f917c89dde", + "8f0a8a164760426567e388840276de3f95cb5e3fadc6ed3f3e4fe8bc169d9388804dcb94b6587dbb66cb0bd5f87b8e98b52af37ba290629b858e0e2aa7378047a26602", + "516710e59843e6fbd4f25d0d8ca0ec0d47d39d125e9dad987e0518d49107014cb0ae405e30c2eb3794750bca142ce95e290cf95abe15e822823e2e7d3ab21bc8fbd445"), + new TestCase( + "5b14ab0fbed4c58952548a6cb1e0000cf4481421f41288ea0aa84add9f7deb96", + "54bf52b911231b952ba1a6af8e45b1c5a29d97e2abad7c83", + "37fb44a675978b560ff9a4a87011d6f3ad2d37a2c3815b45a3c0e6d1b1d8b1784cd468927c2ee39e1dccd4765e1c3d676a335be1ccd6900a45f5d41a317648315d8a8c24adc64eb285f6aeba05b9029586353d303f17a807658b9ff790474e1737bd5fdc604aeff8dfcaf1427dcc3aacbb0256badcd183ed75a2dc52452f87d3c1ed2aa583472b0ab91cda20614e9b6fdbda3b49b098c95823cc72d8e5b717f2314b0324e9ce", + "ae6deb5d6ce43d4b09d0e6b1c0e9f46157bcd8ab50eaa3197ff9fa2bf7af649eb52c68544fd3adfe6b1eb316f1f23538d470c30dbfec7e57b60cbcd096c782e7736b669199c8253e70214cf2a098fda8eac5da79a9496a3aae754d03b17c6d70d1027f42bf7f95ce3d1d9c338854e158fcc803e4d6262fb639521e47116ef78a7a437ca9427ba645cd646832feab822a208278e45e93e118d780b988d65397eddfd7a819526e"), + new TestCase( + "d74636e3413a88d85f322ca80fb0bd650bd0bf0134e2329160b69609cd58a4b0", + "efb606aa1d9d9f0f465eaa7f8165f1ac09f5cb46fecf2a57", + "f85471b75f6ec81abac2799ec09e98e280b2ffd64ca285e5a0109cfb31ffab2d617b2c2952a2a8a788fc0da2af7f530758f74f1ab56391ab5ff2adbcc5be2d6c7f49fbe8118104c6ff9a23c6dfe52f57954e6a69dcee5db06f514f4a0a572a9a8525d961dae72269b987189d465df6107119c7fa790853e063cba0fab7800ca932e258880fd74c33c784675bedad0e7c09e9cc4d63dd5e9713d5d4a0196e6b562226ac31b4f57c04f90a181973737ddc7e80f364112a9fbb435ebdbcabf7d490ce52", + "b2b795fe6c1d4c83c1327e015a67d4465fd8e32813575cbab263e20ef05864d2dc17e0e4eb81436adfe9f638dcc1c8d78f6b0306baf938e5d2ab0b3e05e735cc6fff2d6e02e3d60484bea7c7a8e13e23197fea7b04d47d48f4a4e5944174539492800d3ef51e2ee5e4c8a0bdf050c2dd3dd74fce5e7e5c37364f7547a11480a3063b9a0a157b15b10a5a954de2731ced055aa2e2767f0891d4329c426f3808ee867bed0dc75b5922b7cfb895700fda016105a4c7b7f0bb90f029f6bbcb04ac36ac16") }; + + public String getName() + { + return "XSalsa20"; + } + + public void performTest() throws Exception + { + for (int i = 0; i < TEST_CASES.length; i++) + { + performTest(i, TEST_CASES[i]); + } + } + + private void performTest(int number, TestCase testCase) + { + final byte[] plaintext = testCase.getPlaintext(); + byte[] output = new byte[plaintext.length]; + + XSalsa20Engine engine = new XSalsa20Engine(); + engine.init(false, new ParametersWithIV(new KeyParameter(testCase.getKey()), testCase.getIv())); + + engine.processBytes(testCase.getPlaintext(), 0, testCase.getPlaintext().length, output, 0); + + if (!Arrays.areEqual(testCase.getCiphertext(), output)) + { + fail("mismatch on " + number, new String(Hex.encode(testCase.getCiphertext())), + new String(Hex.encode(output))); + } + } + + public static void main(String[] args) + { + runTest(new XSalsa20Test()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/XTEATest.java b/core/src/test/java/org/spongycastle/crypto/test/XTEATest.java new file mode 100644 index 00000000..74da43be --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/XTEATest.java @@ -0,0 +1,48 @@ +package org.spongycastle.crypto.test; + +import org.spongycastle.crypto.engines.XTEAEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTest; + +/** + * TEA tester - based on C implementation results from http://www.simonshepherd.supanet.com/tea.htm + */ +public class XTEATest + extends CipherTest +{ + static SimpleTest[] tests = { + new BlockCipherVectorTest(0, new XTEAEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "0000000000000000", + "dee9d4d8f7131ed9"), + new BlockCipherVectorTest(1, new XTEAEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "0102030405060708", + "065c1b8975c6a816"), + new BlockCipherVectorTest(2, new XTEAEngine(), + new KeyParameter(Hex.decode("0123456712345678234567893456789A")), + "0000000000000000", + "1ff9a0261ac64264"), + new BlockCipherVectorTest(3, new XTEAEngine(), + new KeyParameter(Hex.decode("0123456712345678234567893456789A")), + "0102030405060708", + "8c67155b2ef91ead"), + }; + + XTEATest() + { + super(tests, new XTEAEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "XTEA"; + } + + public static void main( + String[] args) + { + runTest(new XTEATest()); + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/cavp/CAVPListener.java b/core/src/test/java/org/spongycastle/crypto/test/cavp/CAVPListener.java new file mode 100644 index 00000000..71011614 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/cavp/CAVPListener.java @@ -0,0 +1,18 @@ +package org.spongycastle.crypto.test.cavp; + +import java.util.Properties; + +public interface CAVPListener +{ + public void setup(); + + public void receiveStart(String name); + + public void receiveCAVPVectors(String name, Properties config, Properties vectors); + + public void receiveCommentLine(String commentLine); + + public void receiveEnd(); + + public void tearDown(); +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/cavp/CAVPReader.java b/core/src/test/java/org/spongycastle/crypto/test/cavp/CAVPReader.java new file mode 100644 index 00000000..2cee4559 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/cavp/CAVPReader.java @@ -0,0 +1,152 @@ +package org.spongycastle.crypto.test.cavp; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.Digest; +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.digests.SHA224Digest; +import org.spongycastle.crypto.digests.SHA256Digest; +import org.spongycastle.crypto.digests.SHA384Digest; +import org.spongycastle.crypto.digests.SHA512Digest; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.engines.DESedeEngine; +import org.spongycastle.crypto.macs.CMac; +import org.spongycastle.crypto.macs.HMac; + +public class CAVPReader +{ + + private static final Pattern COMMENT_PATTERN = Pattern.compile("^\\s*\\#\\s*(.*)$"); + private static final Pattern CONFIG_PATTERN = Pattern.compile("^\\s*+\\[\\s*+(.*?)\\s*+=\\s*+(.*?)\\s*+\\]\\s*+$"); + private static final Pattern VECTOR_PATTERN = Pattern.compile("^\\s*+(.*?)\\s*+=\\s*+(.*?)\\s*+$"); + private static final Pattern EMPTY_PATTERN = Pattern.compile("^\\s*+$"); + static final Pattern PATTERN_FOR_R = Pattern.compile("(\\d+)_BITS"); + private final CAVPListener listener; + private String name; + private BufferedReader lineReader; + + + public CAVPReader(CAVPListener listener) + { + this.listener = listener; + } + + public void setInput(String name, Reader reader) + { + this.name = name; + this.lineReader = new BufferedReader(reader); + } + + public void readAll() + throws IOException + { + + listener.setup(); + + Properties config = new Properties(); + + boolean startNewVector = true; + + Properties vectors = new Properties(); + + while (true) + { + final String line = lineReader.readLine(); + if (line == null) + { + listener.receiveEnd(); + break; + } + + final Matcher commentMatcher = COMMENT_PATTERN.matcher(line); + if (commentMatcher.matches()) + { + listener.receiveCommentLine(commentMatcher.group(1)); + continue; + } + + final Matcher configMatcher = CONFIG_PATTERN.matcher(line); + if (configMatcher.matches()) + { + config.put(configMatcher.group(1), configMatcher.group(2)); + continue; + } + + final Matcher vectorMatcher = VECTOR_PATTERN.matcher(line); + if (vectorMatcher.matches()) + { + vectors.put(vectorMatcher.group(1), vectorMatcher.group(2)); + startNewVector = false; + continue; + } + + final Matcher emptyMatcher = EMPTY_PATTERN.matcher(line); + if (emptyMatcher.matches()) + { + if (startNewVector) + { + continue; + } + + listener.receiveCAVPVectors(name, config, vectors); + vectors = new Properties(); + startNewVector = true; + } + } + + listener.tearDown(); + } + + static Mac createPRF(Properties config) + { + final Mac prf; + if (config.getProperty("PRF").matches("CMAC_AES\\d\\d\\d")) + { + BlockCipher blockCipher = new AESFastEngine(); + prf = new CMac(blockCipher); + } + else if (config.getProperty("PRF").matches("CMAC_TDES\\d")) + { + BlockCipher blockCipher = new DESedeEngine(); + prf = new CMac(blockCipher); + } + else if (config.getProperty("PRF").matches("HMAC_SHA1")) + { + Digest digest = new SHA1Digest(); + prf = new HMac(digest); + } + else if (config.getProperty("PRF").matches("HMAC_SHA224")) + { + Digest digest = new SHA224Digest(); + prf = new HMac(digest); + } + else if (config.getProperty("PRF").matches("HMAC_SHA256")) + { + Digest digest = new SHA256Digest(); + prf = new HMac(digest); + } + else if (config.getProperty("PRF").matches("HMAC_SHA384")) + { + Digest digest = new SHA384Digest(); + prf = new HMac(digest); + } + else if (config.getProperty("PRF").matches("HMAC_SHA512")) + { + Digest digest = new SHA512Digest(); + prf = new HMac(digest); + } + else + { + throw new IllegalStateException("Unknown Mac for PRF"); + } + return prf; + } + +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFCounterTests.java b/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFCounterTests.java new file mode 100644 index 00000000..ee53d475 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFCounterTests.java @@ -0,0 +1,119 @@ +package org.spongycastle.crypto.test.cavp; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; +import java.util.regex.Matcher; + +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.generators.KDFCounterBytesGenerator; +import org.spongycastle.crypto.params.KDFCounterParameters; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.TestFailedException; + +public final class KDFCounterTests + implements CAVPListener +{ + private PrintWriter out; + + public void receiveCAVPVectors(String name, Properties config, + Properties vectors) + { + + // create Mac based PRF from PRF property, create the KDF + final Mac prf = CAVPReader.createPRF(config); + final KDFCounterBytesGenerator gen = new KDFCounterBytesGenerator(prf); + + + Matcher matcherForR = CAVPReader.PATTERN_FOR_R.matcher(config.getProperty("RLEN")); + if (!matcherForR.matches()) + { + throw new IllegalStateException("RLEN value should always match"); + } + final int r = Integer.parseInt(matcherForR.group(1)); + + final int count = Integer.parseInt(vectors.getProperty("COUNT")); + final int l = Integer.parseInt(vectors.getProperty("L")); + final byte[] ki = Hex.decode(vectors.getProperty("KI")); + + //Three variants of this KDF are possible, with the counter before the fixed data, after the fixed data, or in the middle of the fixed data. + if (config.getProperty("CTRLOCATION").matches("BEFORE_FIXED")) + { + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFCounterParameters params = new KDFCounterParameters(ki, null, fixedInputData, r); + gen.init(params); + } + else if (config.getProperty("CTRLOCATION").matches("AFTER_FIXED")) + { + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFCounterParameters params = new KDFCounterParameters(ki, fixedInputData, null, r); + gen.init(params); + } + else if (config.getProperty("CTRLOCATION").matches("MIDDLE_FIXED")) + { + final byte[] DataBeforeCtrData = Hex.decode(vectors.getProperty("DataBeforeCtrData")); + final byte[] DataAfterCtrData = Hex.decode(vectors.getProperty("DataAfterCtrData")); + final KDFCounterParameters params = new KDFCounterParameters(ki, DataBeforeCtrData, DataAfterCtrData, r); + gen.init(params); + } + else + { + return; // Unknown CTRLOCATION + } + + + final byte[] koGenerated = new byte[l / 8]; + gen.generateBytes(koGenerated, 0, koGenerated.length); + + final byte[] koVectors = Hex.decode(vectors.getProperty("KO")); + + compareKO(name, config, count, koGenerated, koVectors); + } + + private static void compareKO( + String name, Properties config, int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!Arrays.areEqual(calculatedOKM, testOKM)) + { + throw new TestFailedException(new SimpleTestResult( + false, name + " using " + config + " test " + test + " failed")); + + } + } + + public void receiveCommentLine(String commentLine) + { + // out.println("# " + commentLine); + } + + public void receiveStart(String name) + { + // do nothing + } + + public void receiveEnd() + { + out.println(" *** *** *** "); + } + + public void setup() + { + try + { + out = new PrintWriter(new FileWriter("KDFCTR.gen")); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } + } + + public void tearDown() + { + out.close(); + } +}
\ No newline at end of file diff --git a/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFDoublePipelineCounterTests.java b/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFDoublePipelineCounterTests.java new file mode 100644 index 00000000..8f58be49 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFDoublePipelineCounterTests.java @@ -0,0 +1,107 @@ +package org.spongycastle.crypto.test.cavp; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; +import java.util.regex.Matcher; + +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.generators.KDFDoublePipelineIterationBytesGenerator; +import org.spongycastle.crypto.params.KDFDoublePipelineIterationParameters; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.TestFailedException; + +public final class KDFDoublePipelineCounterTests + implements CAVPListener +{ + private PrintWriter out; + + public void receiveCAVPVectors(String name, Properties config, + Properties vectors) + { + // out.println(" === " + name + " === "); + // out.println(" --- config --- "); + // out.println(config); + // out.println(" --- vectors --- "); + // out.println(vectors); + + // always skip AFTER_FIXED + if (!config.getProperty("CTRLOCATION").matches("AFTER_ITER")) + { + return; + } + + // create Mac based PRF from PRF property, create the KDF + final Mac prf = CAVPReader.createPRF(config); + final KDFDoublePipelineIterationBytesGenerator gen = new KDFDoublePipelineIterationBytesGenerator(prf); + + + Matcher matcherForR = CAVPReader.PATTERN_FOR_R.matcher(config.getProperty("RLEN")); + if (!matcherForR.matches()) + { + throw new IllegalStateException("RLEN value should always match"); + } + final int r = Integer.parseInt(matcherForR.group(1)); + + final int count = Integer.parseInt(vectors.getProperty("COUNT")); + final int l = Integer.parseInt(vectors.getProperty("L")); + final byte[] ki = Hex.decode(vectors.getProperty("KI")); + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFDoublePipelineIterationParameters params = KDFDoublePipelineIterationParameters.createWithCounter(ki, fixedInputData, r); + gen.init(params); + + final byte[] koGenerated = new byte[l / 8]; + gen.generateBytes(koGenerated, 0, koGenerated.length); + + final byte[] koVectors = Hex.decode(vectors.getProperty("KO")); + + compareKO(name, config, count, koGenerated, koVectors); + } + + private static void compareKO( + String name, Properties config, int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!Arrays.areEqual(calculatedOKM, testOKM)) + { + throw new TestFailedException(new SimpleTestResult( + false, name + " using " + config + " test " + test + " failed")); + + } + } + + public void receiveCommentLine(String commentLine) + { + // out.println("# " + commentLine); + } + + public void receiveStart(String name) + { + // do nothing + } + + public void receiveEnd() + { + out.println(" *** *** *** "); + } + + public void setup() + { + try + { + out = new PrintWriter(new FileWriter("KDFDblPipelineCounter.gen")); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } + } + + public void tearDown() + { + out.close(); + } +}
\ No newline at end of file diff --git a/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFDoublePipelineIterationNoCounterTests.java b/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFDoublePipelineIterationNoCounterTests.java new file mode 100644 index 00000000..512568f5 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFDoublePipelineIterationNoCounterTests.java @@ -0,0 +1,88 @@ +package org.spongycastle.crypto.test.cavp; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; + +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.generators.KDFDoublePipelineIterationBytesGenerator; +import org.spongycastle.crypto.params.KDFDoublePipelineIterationParameters; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.TestFailedException; + +public final class KDFDoublePipelineIterationNoCounterTests + implements CAVPListener +{ + private PrintWriter out; + + public void receiveCAVPVectors(String name, Properties config, + Properties vectors) + { + + + // create Mac based PRF from PRF property, create the KDF + final Mac prf = CAVPReader.createPRF(config); + final KDFDoublePipelineIterationBytesGenerator gen = new KDFDoublePipelineIterationBytesGenerator(prf); + + final int count = Integer.parseInt(vectors.getProperty("COUNT")); + final int l = Integer.parseInt(vectors.getProperty("L")); + final byte[] ki = Hex.decode(vectors.getProperty("KI")); + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFDoublePipelineIterationParameters params = KDFDoublePipelineIterationParameters.createWithoutCounter(ki, fixedInputData); + gen.init(params); + + final byte[] koGenerated = new byte[l / 8]; + gen.generateBytes(koGenerated, 0, koGenerated.length); + + final byte[] koVectors = Hex.decode(vectors.getProperty("KO")); + + compareKO(name, config, count, koGenerated, koVectors); + } + + private static void compareKO( + String name, Properties config, int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!Arrays.areEqual(calculatedOKM, testOKM)) + { + throw new TestFailedException(new SimpleTestResult( + false, name + " using " + config + " test " + test + " failed")); + + } + } + + public void receiveCommentLine(String commentLine) + { + // out.println("# " + commentLine); + } + + public void receiveStart(String name) + { + // do nothing + } + + public void receiveEnd() + { + out.println(" *** *** *** "); + } + + public void setup() + { + try + { + out = new PrintWriter(new FileWriter("KDFDblPipelineNoCounter.gen")); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } + } + + public void tearDown() + { + out.close(); + } +}
\ No newline at end of file diff --git a/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFFeedbackCounterTests.java b/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFFeedbackCounterTests.java new file mode 100644 index 00000000..84cd4dd8 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFFeedbackCounterTests.java @@ -0,0 +1,108 @@ +package org.spongycastle.crypto.test.cavp; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; +import java.util.regex.Matcher; + +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.generators.KDFFeedbackBytesGenerator; +import org.spongycastle.crypto.params.KDFFeedbackParameters; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.TestFailedException; + +public final class KDFFeedbackCounterTests + implements CAVPListener +{ + private PrintWriter out; + + public void receiveCAVPVectors(String name, Properties config, + Properties vectors) + { + // out.println(" === " + name + " === "); + // out.println(" --- config --- "); + // out.println(config); + // out.println(" --- vectors --- "); + // out.println(vectors); + + // always skip AFTER_FIXED + if (!config.getProperty("CTRLOCATION").matches("AFTER_ITER")) + { + return; + } + + // create Mac based PRF from PRF property, create the KDF + final Mac prf = CAVPReader.createPRF(config); + final KDFFeedbackBytesGenerator gen = new KDFFeedbackBytesGenerator(prf); + + + Matcher matcherForR = CAVPReader.PATTERN_FOR_R.matcher(config.getProperty("RLEN")); + if (!matcherForR.matches()) + { + throw new IllegalStateException("RLEN value should always match"); + } + final int r = Integer.parseInt(matcherForR.group(1)); + + final int count = Integer.parseInt(vectors.getProperty("COUNT")); + final int l = Integer.parseInt(vectors.getProperty("L")); + final byte[] ki = Hex.decode(vectors.getProperty("KI")); + final byte[] iv = Hex.decode(vectors.getProperty("IV")); + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFFeedbackParameters params = KDFFeedbackParameters.createWithCounter(ki, iv, fixedInputData, r); + gen.init(params); + + final byte[] koGenerated = new byte[l / 8]; + gen.generateBytes(koGenerated, 0, koGenerated.length); + + final byte[] koVectors = Hex.decode(vectors.getProperty("KO")); + + compareKO(name, config, count, koGenerated, koVectors); + } + + private static void compareKO( + String name, Properties config, int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!Arrays.areEqual(calculatedOKM, testOKM)) + { + throw new TestFailedException(new SimpleTestResult( + false, name + " using " + config + " test " + test + " failed")); + + } + } + + public void receiveCommentLine(String commentLine) + { + // out.println("# " + commentLine); + } + + public void receiveStart(String name) + { + // do nothing + } + + public void receiveEnd() + { + out.println(" *** *** *** "); + } + + public void setup() + { + try + { + out = new PrintWriter(new FileWriter("KDFFeedbackCounter.gen")); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } + } + + public void tearDown() + { + out.close(); + } +}
\ No newline at end of file diff --git a/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFFeedbackNoCounterTests.java b/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFFeedbackNoCounterTests.java new file mode 100644 index 00000000..4c6fa942 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/cavp/KDFFeedbackNoCounterTests.java @@ -0,0 +1,89 @@ +package org.spongycastle.crypto.test.cavp; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; + +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.generators.KDFFeedbackBytesGenerator; +import org.spongycastle.crypto.params.KDFFeedbackParameters; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; +import org.spongycastle.util.test.SimpleTestResult; +import org.spongycastle.util.test.TestFailedException; + +public final class KDFFeedbackNoCounterTests + implements CAVPListener +{ + private PrintWriter out; + + public void receiveCAVPVectors(String name, Properties config, + Properties vectors) + { + + + // create Mac based PRF from PRF property, create the KDF + final Mac prf = CAVPReader.createPRF(config); + final KDFFeedbackBytesGenerator gen = new KDFFeedbackBytesGenerator(prf); + + final int count = Integer.parseInt(vectors.getProperty("COUNT")); + final int l = Integer.parseInt(vectors.getProperty("L")); + final byte[] ki = Hex.decode(vectors.getProperty("KI")); + final byte[] iv = Hex.decode(vectors.getProperty("IV")); + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFFeedbackParameters params = KDFFeedbackParameters.createWithoutCounter(ki, iv, fixedInputData); + gen.init(params); + + final byte[] koGenerated = new byte[l / 8]; + gen.generateBytes(koGenerated, 0, koGenerated.length); + + final byte[] koVectors = Hex.decode(vectors.getProperty("KO")); + + compareKO(name, config, count, koGenerated, koVectors); + } + + private static void compareKO( + String name, Properties config, int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!Arrays.areEqual(calculatedOKM, testOKM)) + { + throw new TestFailedException(new SimpleTestResult( + false, name + " using " + config + " test " + test + " failed")); + + } + } + + public void receiveCommentLine(String commentLine) + { +// out.println("# " + commentLine); + } + + public void receiveStart(String name) + { + // do nothing + } + + public void receiveEnd() + { + out.println(" *** *** *** "); + } + + public void setup() + { + try + { + out = new PrintWriter(new FileWriter("KDFFeedbackNoCounter.gen")); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } + } + + public void tearDown() + { + out.close(); + } +}
\ No newline at end of file diff --git a/core/src/test/java/org/spongycastle/crypto/test/speedy/MacThroughputTest.java b/core/src/test/java/org/spongycastle/crypto/test/speedy/MacThroughputTest.java new file mode 100644 index 00000000..ffbc673f --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/speedy/MacThroughputTest.java @@ -0,0 +1,156 @@ +package org.spongycastle.crypto.test.speedy; + +import java.security.SecureRandom; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.KeyGenerationParameters; +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.engines.NullEngine; +import org.spongycastle.crypto.generators.Poly1305KeyGenerator; +import org.spongycastle.crypto.macs.CMac; +import org.spongycastle.crypto.macs.GMac; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.macs.Poly1305; +import org.spongycastle.crypto.macs.SipHash; +import org.spongycastle.crypto.macs.SkeinMac; +import org.spongycastle.crypto.modes.GCMBlockCipher; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; + +/** + * Microbenchmark of MACs on short, medium, long messages, with optional object creation cost. + */ +public class MacThroughputTest +{ + + private static final long CLOCK_SPEED = 2400000000L; + + private static final SecureRandom RANDOM = new SecureRandom(); + private static Poly1305KeyGenerator kg = new Poly1305KeyGenerator();; + + private static final byte[] SHORT_MESSAGE = new byte[16]; + private static final byte[] MEDIUM_MESSAGE = new byte[256]; + private static final byte[] LONG_MESSAGE = new byte[8192]; + static + { + RANDOM.nextBytes(SHORT_MESSAGE); + RANDOM.nextBytes(MEDIUM_MESSAGE); + RANDOM.nextBytes(LONG_MESSAGE); + } + + private static final int SHORT_MESSAGE_COUNT = 20000000; + private static final int MEDIUM_MESSAGE_COUNT = 2200000; + private static final int LONG_MESSAGE_COUNT = 80000; + + static + { + kg.init(new KeyGenerationParameters(RANDOM, 256)); + } + + private static KeyParameter generatePoly1305Key() + { + return new KeyParameter(kg.generateKey()); + } + + public static void main(String[] args) + { + testMac(new HMac(new SHA1Digest()), new KeyParameter(generateNonce(20)), 3); + testMac(new SkeinMac(SkeinMac.SKEIN_512, 128), new KeyParameter(generateNonce(64)), 2); + testMac(new SipHash(), new KeyParameter(generateNonce(16)), 1); + testMac(new CMac(new AESFastEngine()), new KeyParameter(generateNonce(16)), 3); + testMac(new GMac(new GCMBlockCipher(new AESFastEngine())), new ParametersWithIV(new KeyParameter( + generateNonce(16)), generateNonce(16)), 5); + testMac(new Poly1305(new NullEngine(16)), new ParametersWithIV(generatePoly1305Key(), generateNonce(16)), 1); + testMac(new Poly1305(new AESFastEngine()), new ParametersWithIV(generatePoly1305Key(), generateNonce(16)), 1); + testMac(new Poly1305Reference(new NullEngine(16)), new ParametersWithIV(generatePoly1305Key(), + generateNonce(16)), 1); + } + + private static byte[] generateNonce(int sizeBytes) + { + byte[] nonce = new byte[16]; + RANDOM.nextBytes(nonce); + return nonce; + } + + private static void testMac(Mac mac, CipherParameters params, int rateFactor) + { + System.out.println("========================="); + + long total = testRun(mac, params, false, MEDIUM_MESSAGE, adjust(MEDIUM_MESSAGE_COUNT, rateFactor)); + System.out.printf("%s Warmup 1 run time: %,d ms\n", mac.getAlgorithmName(), total / 1000000); + total = testRun(mac, params, false, MEDIUM_MESSAGE, adjust(MEDIUM_MESSAGE_COUNT, rateFactor)); + System.out.printf("%s Warmup 2 run time: %,d ms\n", mac.getAlgorithmName(), total / 1000000); + System.gc(); + try + { + Thread.sleep(1000); + } catch (InterruptedException e) + { + } + + test("Short", mac, params, false, SHORT_MESSAGE, adjust(SHORT_MESSAGE_COUNT, rateFactor)); + // test("Short", mac, params, true, SHORT_MESSAGE, adjust(SHORT_MESSAGE_COUNT, rateFactor)); + test("Medium", mac, params, false, MEDIUM_MESSAGE, adjust(MEDIUM_MESSAGE_COUNT, rateFactor)); + // test("Medium", mac, params, true, MEDIUM_MESSAGE, adjust(MEDIUM_MESSAGE_COUNT, + // rateFactor)); + test("Long", mac, params, false, LONG_MESSAGE, adjust(LONG_MESSAGE_COUNT, rateFactor)); + // test("Long", mac, params, true, LONG_MESSAGE, adjust(LONG_MESSAGE_COUNT, rateFactor)); + } + + private static int adjust(int iterationCount, int rateFactor) + { + return (int)(iterationCount * (1.0f / rateFactor)); + } + + private static void test(String name, + Mac mac, + CipherParameters params, + boolean initPerMessage, + byte[] message, + int adjustedCount) + { + System.out.println("========================="); + long total = testRun(mac, params, initPerMessage, message, adjustedCount); + + long averageRuntime = total / adjustedCount; + System.out.printf("%s %-7s%s Total run time: %,d ms\n", mac.getAlgorithmName(), name, initPerMessage ? "*" + : " ", total / 1000000); + System.out.printf("%s %-7s%s Average run time: %,d ns\n", mac.getAlgorithmName(), name, initPerMessage ? "*" + : " ", averageRuntime); + final long mbPerSecond = (long)((double)message.length / averageRuntime * 1000000000 / (1024 * 1024)); + System.out.printf("%s %-7s%s Average speed: %,d MB/s\n", mac.getAlgorithmName(), name, initPerMessage ? "*" + : " ", mbPerSecond); + System.out.printf("%s %-7s%s Average speed: %,f c/b\n", mac.getAlgorithmName(), name, initPerMessage ? "*" + : " ", CLOCK_SPEED / (double)(mbPerSecond * (1024 * 1024))); + } + + private static long testRun(Mac mac, + CipherParameters params, + boolean initPerMessage, + byte[] message, + int adjustedCount) + { + byte[] out = new byte[mac.getMacSize()]; + + if (!initPerMessage) + { + mac.init(params); + } + long start = System.nanoTime(); + + for (int i = 0; i < adjustedCount; i++) + { + if (initPerMessage) + { + mac.init(params); + } + mac.update(message, 0, message.length); + mac.doFinal(out, 0); + } + long total = System.nanoTime() - start; + return total; + } +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/speedy/Poly1305Reference.java b/core/src/test/java/org/spongycastle/crypto/test/speedy/Poly1305Reference.java new file mode 100644 index 00000000..a30c1116 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/speedy/Poly1305Reference.java @@ -0,0 +1,292 @@ +package org.spongycastle.crypto.test.speedy; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.Mac; +import org.spongycastle.crypto.generators.Poly1305KeyGenerator; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.ParametersWithIV; + +/** + * Poly1305 message authentication code, designed by D. J. Bernstein. + * <p> + * Poly1305 computes a 128-bit (16 bytes) authenticator, using a 128 bit nonce and a 256 bit key + * consisting of a 128 bit key applied to an underlying cipher, and a 128 bit key (with 106 + * effective key bits) used in the authenticator. + * <p> + * This implementation is adapted from the public domain <a href="http://nacl.cr.yp.to/">nacl</a> + * <code>ref</code> implementation, and is probably too slow for real usage. + * + * @see Poly1305KeyGenerator + */ +public class Poly1305Reference + implements Mac +{ + private static final int BLOCK_SIZE = 16; + private static final int STATE_SIZE = BLOCK_SIZE + 1; + private static int[] minusp = {5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252}; + + private final BlockCipher cipher; + + /** Encrypted nonce */ + private final byte[] encryptedNonce = new byte[BLOCK_SIZE]; + + /** Private integer r *, expanded to 17 bytes */ + private final int[] r = new int[STATE_SIZE]; + + /** Accumulated authenticator value */ + private final int[] h = new int[STATE_SIZE]; + + /** Temp buffer for incorporating into authenticator */ + private final int[] c = new int[STATE_SIZE]; + + private final byte[] singleByte = new byte[1]; + + /** Current block of buffered input */ + private final byte[] currentBlock = new byte[BLOCK_SIZE]; + + /** Current offset in input buffer */ + private int currentBlockOffset = 0; + + public Poly1305Reference(BlockCipher cipher) + { + if (cipher.getBlockSize() != BLOCK_SIZE) + { + throw new IllegalArgumentException("Poly1305 requires a 128 bit block cipher."); + } + this.cipher = cipher; + } + + public void init(CipherParameters params) + throws IllegalArgumentException + { + final byte[] nonce; + final byte[] key; + if ((params instanceof ParametersWithIV) && ((ParametersWithIV)params).getParameters() instanceof KeyParameter) + { + nonce = ((ParametersWithIV)params).getIV(); + key = ((KeyParameter)((ParametersWithIV)params).getParameters()).getKey(); + } + else + { + throw new IllegalArgumentException("Poly1305 requires a key and and IV."); + } + + setKey(key, nonce); + reset(); + } + + private void setKey(byte[] key, byte[] nonce) + { + if (nonce.length != BLOCK_SIZE) + { + throw new IllegalArgumentException("Poly1305 requires a 128 bit IV."); + } + Poly1305KeyGenerator.checkKey(key); + + // Expand private integer r + for (int i = 0; i < BLOCK_SIZE; i++) + { + r[i] = key[BLOCK_SIZE + i] & 0xFF; + } + r[BLOCK_SIZE] = 0; + + // Calculate encrypted nonce + final byte[] cipherKey = new byte[BLOCK_SIZE]; + System.arraycopy(key, 0, cipherKey, 0, cipherKey.length); + + cipher.init(true, new KeyParameter(cipherKey)); + cipher.processBlock(nonce, 0, this.encryptedNonce, 0); + } + + public String getAlgorithmName() + { + return "Poly1305-Ref-" + cipher.getAlgorithmName(); + } + + public int getMacSize() + { + return BLOCK_SIZE; + } + + public void update(byte in) + throws IllegalStateException + { + singleByte[0] = in; + update(singleByte, 0, 1); + } + + public void update(byte[] in, int inOff, int len) + throws DataLengthException, + IllegalStateException + { + int copied = 0; + while (len > copied) + { + if (currentBlockOffset == currentBlock.length) + { + processBlock(); + currentBlockOffset = 0; + } + + int toCopy = Math.min((len - copied), currentBlock.length - currentBlockOffset); + System.arraycopy(in, copied + inOff, currentBlock, currentBlockOffset, toCopy); + copied += toCopy; + currentBlockOffset += toCopy; + } + + } + + /** + * Add a full block of 16 bytes of data, padded to 17 bytes, to the MAC + */ + private void processBlock() + { + for (int i = 0; i < currentBlockOffset; i++) + { + c[i] = currentBlock[i] & 0xFF; + } + c[currentBlockOffset] = 1; + for (int i = currentBlockOffset + 1; i < c.length; i++) + { + c[i] = 0; + } + add(h, c); + mulmod(h, r); + } + + public int doFinal(byte[] out, int outOff) + throws DataLengthException, + IllegalStateException + { + if (outOff + BLOCK_SIZE > out.length) + { + throw new DataLengthException("Output buffer is too short."); + } + + if (currentBlockOffset > 0) + { + // Process padded final block + processBlock(); + } + + freeze(h); + + // Add encrypted nonce to result + for (int i = 0; i < BLOCK_SIZE; i++) + { + c[i] = encryptedNonce[i] & 0xFF; + } + c[BLOCK_SIZE] = 0; + add(h, c); + + for (int i = 0; i < BLOCK_SIZE; i++) + { + out[outOff + i] = (byte)h[i]; + } + + reset(); + return BLOCK_SIZE; + } + + public void reset() + { + currentBlockOffset = 0; + for (int i = 0; i < h.length; i++) + { + h[i] = 0; + } + } + + // 130 bit math adapted from nacl ref implementation + + /** + * 130 bit add with carry. + */ + private static void add(int[] h, int[] c) + { + int u = 0; + for (int j = 0; j < 17; ++j) + { + u += h[j] + c[j]; + h[j] = u & 255; + u >>= 8; + } + } + + /** + * 130 bit multiplication mod 2^130-5 + */ + private void mulmod(int[] h, int[] r) + { + final int[] hr = c; + + for (int i = 0; i < 17; ++i) + { + int u = 0; + /* Basic multiply to compute term i */ + for (int j = 0; j <= i; ++j) + { + u += h[j] * r[i - j]; + } + + /* + * Modular reduction + * + * Shift overflow >> 130 bits == (>> 17 bytes = 136 bits) + (<< 6 bits = * 64) + * + * Reduction mod 2^130-5 leaves 5x remainder, so 64 * 5 = 320. + */ + for (int j = i + 1; j < 17; ++j) + { + u += 320 * h[j] * r[i + 17 - j]; + } + hr[i] = u; + } + System.arraycopy(hr, 0, h, 0, h.length); + squeeze(h); + } + + /** + * Propagate carries following a modular multiplication. + */ + private static void squeeze(int[] h) + { + int u = 0; + for (int j = 0; j < 16; ++j) + { + u += h[j]; + h[j] = u & 255; + u >>= 8; + } + u += h[16]; + h[16] = u & 3; + u = 5 * (u >> 2); + for (int j = 0; j < 16; ++j) + { + u += h[j]; + h[j] = u & 255; + u >>= 8; + } + u += h[16]; + h[16] = u; + } + + /** + * Constant time correction of h to be < p (2^130 - 5). + */ + private void freeze(int[] h) + { + final int[] horig = c; + System.arraycopy(h, 0, horig, 0, h.length); + + add(h, minusp); + final int negative = -(h[16] >> 7); + for (int j = 0; j < 17; ++j) + { + h[j] ^= negative & (horig[j] ^ h[j]); + } + } + +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/speedy/ThreefishReferenceEngine.java b/core/src/test/java/org/spongycastle/crypto/test/speedy/ThreefishReferenceEngine.java new file mode 100644 index 00000000..768bb954 --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/speedy/ThreefishReferenceEngine.java @@ -0,0 +1,395 @@ +package org.spongycastle.crypto.test.speedy; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.DataLengthException; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.TweakableBlockCipherParameters; + +public class ThreefishReferenceEngine + implements BlockCipher +{ + + /** + * The tweak input is always 128 bits + */ + private static final int TWEAK_SIZE = 16; + + private static long C_240 = 0x1BD11BDAA9FC1A22L; + + private final int blocksize = 64; + private final int rounds = 72; + private final int words = 8; + + private boolean forEncryption; + + private long[] block = new long[words]; + + private int[][] rotations = R8; + + /** + * Rotation constants Rd,j for Nw = 8. + */ + private static final int[][] R8 = { + {46, 36, 19, 37}, + {33, 27, 14, 42}, + {17, 49, 36, 39}, + {44, 9, 54, 56}, + {39, 30, 34, 24}, + {13, 50, 10, 17}, + {25, 29, 39, 43}, + {8, 35, 56, 22}}; + + private long[] t; + + private long kw[]; + + public void init(boolean forEncryption, CipherParameters params) + throws IllegalArgumentException + { + if (params instanceof TweakableBlockCipherParameters) + { + init(forEncryption, (TweakableBlockCipherParameters)params); + } + else if (params instanceof KeyParameter) + { + init(forEncryption, new TweakableBlockCipherParameters((KeyParameter)params, new byte[TWEAK_SIZE])); + } + else + { + throw new IllegalArgumentException("Invalid parameter passed to Threefish init - " + + params.getClass().getName()); + } + } + + public void init(boolean forEncryption, TweakableBlockCipherParameters params) + throws IllegalArgumentException + { + // TODO: Remove some of the NPEs that can be avoided in the Params + // classes + if ((params.getKey() == null) || (params.getKey().getKey() == null) + || (params.getKey().getKey().length != blocksize)) + { + throw new IllegalArgumentException("Threefish key must be same size as block (%d bytes)" + blocksize); + } + + if ((params.getTweak() == null) || (params.getTweak().length != TWEAK_SIZE)) + { + throw new IllegalArgumentException("Threefish tweak must be %d bytes" + TWEAK_SIZE); + } + + this.forEncryption = forEncryption; + + generateKeySchedule(params.getKey().getKey(), params.getTweak()); + } + + private void generateKeySchedule(byte[] key, byte[] tweak) + { + // TODO: This key schedule can/should be generated incrementally/on demand during encrypt/decrypt + // to reduce memory overhead (currently 1.2MB = (rounds/4+1)=19 * words=8 * 8 bytes/word) + + t = new long[3]; + t[0] = BytesToWord(tweak, 0); + t[1] = BytesToWord(tweak, 8); + t[2] = t[0] ^ t[1]; + + kw = new long[words + 1]; + + long knw = C_240; + for (int i = 0; i < words; i++) + { + kw[i] = BytesToWord(key, i * 8); + knw = knw ^ kw[i]; + } + kw[kw.length - 1] = knw; + } + + private static long BytesToWord(byte[] bytes, int off) + { + long word = 0; + int index = off; + + word = (bytes[index++] & 0xffL); + word |= (bytes[index++] & 0xffL) << 8; + word |= (bytes[index++] & 0xffL) << 16; + word |= (bytes[index++] & 0xffL) << 24; + word |= (bytes[index++] & 0xffL) << 32; + word |= (bytes[index++] & 0xffL) << 40; + word |= (bytes[index++] & 0xffL) << 48; + word |= (bytes[index++] & 0xffL) << 56; + + return word; + } + + private static void WordToBytes(long word, byte[] bytes, int off) + { + int index = off; + + bytes[index++] = (byte)word; + bytes[index++] = (byte)(word >> 8); + bytes[index++] = (byte)(word >> 16); + bytes[index++] = (byte)(word >> 24); + bytes[index++] = (byte)(word >> 32); + bytes[index++] = (byte)(word >> 40); + bytes[index++] = (byte)(word >> 48); + bytes[index++] = (byte)(word >> 56); + } + + public String getAlgorithmName() + { + return "Threefish"; + } + + public int getBlockSize() + { + return blocksize; + } + + public int processBlock(byte[] in, int inOff, byte[] out, int outOff) + throws DataLengthException, + IllegalStateException + { + // TODO: Check init state + if (kw == null) + { + throw new IllegalStateException("Threefish engine not initialised"); + } + + if ((inOff + blocksize) > in.length) + { + throw new DataLengthException("Input buffer too short"); + } + + if ((outOff + blocksize) > out.length) + { + throw new DataLengthException("Output buffer too short"); + } + + if (forEncryption) + { + unpackBlock(in, inOff); + encryptBlock(); + packBlock(out, outOff); + } + else + { + unpackBlock(in, inOff); + decryptBlock(); + packBlock(out, outOff); + } + + return blocksize; + } + + private void decryptBlock() + { + for (int d = rounds; d > 0; d--) + { + // Add subkey every 4 rounds + if ((d % 4) == 0) + { + uninjectSubkey(d / 4); + } + + // Permute + unpermute(); + + // Mix + for (int j = 0; j < words / 2; j++) + { + unmix(j, d - 1); + } + } + + // Remove first subkey + uninjectSubkey(0); + } + + private void injectSubkey(int s) + { + for (int i = 0; i < (words - 3); i++) + { + block[i] += kw[(s + i) % (words + 1)]; + } + block[words - 3] += kw[(s + words - 3) % (words + 1)] + t[s % 3]; + block[words - 2] += kw[(s + words - 2) % (words + 1)] + t[(s + 1) % 3]; + block[words - 1] += kw[(s + words - 1) % (words + 1)] + s; + } + + private void uninjectSubkey(int s) + { + for (int i = 0; i < (words - 3); i++) + { + block[i] -= kw[(s + i) % (words + 1)]; + } + block[words - 3] -= kw[(s + words - 3) % (words + 1)] + t[s % 3]; + block[words - 2] -= kw[(s + words - 2) % (words + 1)] + t[(s + 1) % 3]; + block[words - 1] -= kw[(s + words - 1) % (words + 1)] + s; + } + + private void encryptBlock() + { + for (int d = 0; d < rounds; d++) + { + // Add subkey every 4 rounds + if ((d % 4) == 0) + { + injectSubkey(d / 4); + } + + // Mix + for (int j = 0; j < words / 2; j++) + { + mix(j, d); + } + + // Permute + permute(); + } + + // Final key addition + injectSubkey(rounds / 4); + } + + private void permute() + { + // Permute in place for Nw = 8 + long f0 = block[0]; + long f3 = block[3]; + + block[0] = block[2]; + block[1] = block[1]; + block[2] = block[4]; + block[3] = block[7]; + block[4] = block[6]; + block[5] = block[5]; + block[6] = f0; + block[7] = f3; + } + + private void unpermute() + { + // TODO: Change these to tables + // Permute in place for Nw = 8 + long f6 = block[6]; + long f7 = block[7]; + + block[7] = block[3]; + block[6] = block[4]; + block[5] = block[5]; + block[4] = block[2]; + block[3] = f7; + block[2] = block[0]; + block[1] = block[1]; + block[0] = f6; + } + + private void mix(int j, int d) + { + // ed,2j and ed,2j+1 + int b0 = 2 * j; + int b1 = b0 + 1; + + // y0 = x0 + x1 + block[b0] = block[b0] + block[b1]; + + // y1 = (x1 <<< R(d mod 8,j)) xor y0 + block[b1] = Long.rotateLeft(block[b1], rotations[d % 8][j]) ^ block[b0]; + } + + private void unmix(int j, int d) + { + // ed,2j and ed,2j+1 + int b0 = 2 * j; + int b1 = b0 + 1; + + // x1 = (y1 ^ y0) >>> R(d mod 8, j)) + block[b1] = Long.rotateRight(block[b1] ^ block[b0], rotations[d % 8][j]); + + // x0 = y0 - x1 + block[b0] = block[b0] - block[b1]; + + } + + public static void main(String[] args) + { + ThreefishReferenceEngine engine = new ThreefishReferenceEngine(); + engine.fu(); + } + + private void fu() + { + block[0] = 0x12; + block[1] = 0x34; + block[2] = 0x56; + block[3] = 0x78; + block[4] = 0x90; + block[5] = 0xAB; + block[6] = 0xCD; + block[7] = 0xEF; + + for (int i = 0; i < block.length; i++) + { + System.err.println(i + " : " + Long.toHexString(block[i])); + } + mix(0, 4); + System.err.println("========="); + for (int i = 0; i < block.length; i++) + { + System.err.println(i + " : " + Long.toHexString(block[i])); + } + unmix(0, 4); + System.err.println("========="); + for (int i = 0; i < block.length; i++) + { + System.err.println(i + " : " + Long.toHexString(block[i])); + } + permute(); + System.err.println("========="); + for (int i = 0; i < block.length; i++) + { + System.err.println(i + " : " + Long.toHexString(block[i])); + } + unpermute(); + System.err.println("========="); + for (int i = 0; i < block.length; i++) + { + System.err.println(i + " : " + Long.toHexString(block[i])); + } + generateKeySchedule(new byte[blocksize], new byte[TWEAK_SIZE]); + injectSubkey(5); + System.err.println("========="); + for (int i = 0; i < block.length; i++) + { + System.err.println(i + " : " + Long.toHexString(block[i])); + } + uninjectSubkey(5); + System.err.println("========="); + for (int i = 0; i < block.length; i++) + { + System.err.println(i + " : " + Long.toHexString(block[i])); + } + } + + private void packBlock(byte[] out, int outOff) + { + for (int i = 0; i < block.length; i++) + { + WordToBytes(block[i], out, outOff + (i * 8)); + } + } + + private long[] unpackBlock(byte[] bytes, int index) + { + for (int i = 0; i < block.length; i++) + { + block[i] = BytesToWord(bytes, index + (i * 8)); + } + return block; + } + + public void reset() + { + } + +} diff --git a/core/src/test/java/org/spongycastle/crypto/test/speedy/ThroughputTest.java b/core/src/test/java/org/spongycastle/crypto/test/speedy/ThroughputTest.java new file mode 100644 index 00000000..69b942fc --- /dev/null +++ b/core/src/test/java/org/spongycastle/crypto/test/speedy/ThroughputTest.java @@ -0,0 +1,203 @@ +package org.spongycastle.crypto.test.speedy; + +import java.io.IOException; +import java.security.SecureRandom; + +import org.spongycastle.crypto.BlockCipher; +import org.spongycastle.crypto.engines.AESFastEngine; +import org.spongycastle.crypto.engines.ThreefishEngine; +import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.crypto.params.TweakableBlockCipherParameters; +import org.spongycastle.util.encoders.Hex; + +public class ThroughputTest +{ + + private static final int DATA_SIZE = 100 * 1024 * 1024; + private static final int RUNS = 1; + private static final long CLOCK_SPEED = 2400000000L; + + private static SecureRandom rand = new SecureRandom(); + + public static void main(String[] args) + throws InterruptedException, IOException + { +// testTF_1024_1(); +// testTF_1024_2(); + testTF_512_1(); + testTF_512_2(); +// testTF_256_1(); +// testTF_256_2(); + System.out.println("Initialising test data."); + byte[] input = new byte[DATA_SIZE]; + rand.nextBytes(input); + + System.out.println("Init complete."); +// speedTestCipher(new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256), input); + speedTestCipher(new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), input); +// speedTestCipher(new Skein3FishEngine(), input); +// speedTestCipher(new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024), input); +// speedTestCipher(new ThreefishReferenceEngine(), input); + speedTestCipher(new AESFastEngine(), input); +// speedTestCipher(new TwofishEngine(), input); +// speedTestCipher(new BlowfishEngine(), input); + } + + private static void testTF_512_1() + throws IOException + { + byte[] key = new byte[64]; + byte[] tweak = new byte[16]; + byte[] plaintext = new byte[64]; + byte[] expected = Hex.decode("b1a2bbc6ef6025bc40eb3822161f36e375d1bb0aee3186fbd19e47c5d479947b7bc2f8586e35f0cff7e7f03084b0b7b1f1ab3961a580a3e97eb41ea14a6d7bbe"); + + runTestVector("Threefish-512-1: Fast", key, tweak, plaintext, expected, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512)); + runTestVector("Threefish-512-1: Reference", key, tweak, plaintext, expected, new ThreefishReferenceEngine()); + } + + private static void testTF_256_1() + throws IOException + { + byte[] key = new byte[32]; + byte[] tweak = new byte[16]; + byte[] plaintext = new byte[32]; + byte[] expected = Hex.decode("84da2a1f8beaee947066ae3e3103f1ad536db1f4a1192495116b9f3ce6133fd8"); + + runTestVector("Threefish-256-1: ", key, tweak, plaintext, expected, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256)); + } + + private static void testTF_1024_1() + throws IOException + { + byte[] key = new byte[128]; + byte[] tweak = new byte[16]; + byte[] plaintext = new byte[128]; + byte[] expected = Hex.decode("f05c3d0a3d05b304f785ddc7d1e036015c8aa76e2f217b06c6e1544c0bc1a90df0accb9473c24e0fd54fea68057f43329cb454761d6df5cf7b2e9b3614fbd5a20b2e4760b40603540d82eabc5482c171c832afbe68406bc39500367a592943fa9a5b4a43286ca3c4cf46104b443143d560a4b230488311df4feef7e1dfe8391e"); + + runTestVector("Threefish-1024-1: ", key, tweak, plaintext, expected, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024)); + } + + private static void runTestVector(String name, byte[] key, byte[] tweak, byte[] plaintext, byte[] expected, BlockCipher cipher) + { + System.out.println("===="); + System.out.println(name + ": "); + cipher.init(true, new TweakableBlockCipherParameters(new KeyParameter(key), tweak)); + + byte[] ciphertext = new byte[key.length]; + cipher.processBlock(plaintext, 0, ciphertext, 0); + + System.out.println("Plaintext : " + new String(Hex.encode(plaintext))); + System.out.println("Expected : " + new String(Hex.encode(expected))); + System.out.println("Ciphertext : " + new String(Hex.encode(ciphertext))); + System.out.println(" Encrypt : " + org.spongycastle.util.Arrays.areEqual(expected, ciphertext)); + + cipher.init(false, new TweakableBlockCipherParameters(new KeyParameter(key), tweak)); + byte[] replain = new byte[plaintext.length]; + cipher.processBlock(ciphertext, 0, replain, 0); + + System.out.println("Replain : " + new String(Hex.encode(replain))); + System.out.println(" Decrypt : " + org.spongycastle.util.Arrays.areEqual(plaintext, replain)); + } + + private static void testTF_512_2() + throws IOException + { + byte[] key = Hex.decode("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"); + byte[] tweak = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] plaintext = Hex.decode("fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0"); + byte[] expected = Hex.decode("e304439626d45a2cb401cad8d636249a6338330eb06d45dd8b36b90e97254779272a0a8d99463504784420ea18c9a725af11dffea10162348927673d5c1caf3d"); + + runTestVector("Threefish-512-2: Fast", key, tweak, plaintext, expected, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512)); + runTestVector("Threefish-512-2: Reference", key, tweak, plaintext, expected, new ThreefishReferenceEngine()); + } + + private static void testTF_256_2() + throws IOException + { + byte[] key = Hex.decode("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + byte[] tweak = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] plaintext = Hex.decode("FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0"); + byte[] expected = Hex.decode("e0d091ff0eea8fdfc98192e62ed80ad59d865d08588df476657056b5955e97df"); + + runTestVector("Threefish-256-2: ", key, tweak, plaintext, expected, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256)); + } + + private static void testTF_1024_2() + throws IOException + { + byte[] key = Hex.decode("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f"); + byte[] tweak = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] plaintext = Hex.decode("fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a09f9e9d9c9b9a999897969594939291908f8e8d8c8b8a89888786858483828180"); + byte[] expected = Hex.decode("a6654ddbd73cc3b05dd777105aa849bce49372eaaffc5568d254771bab85531c94f780e7ffaae430d5d8af8c70eebbe1760f3b42b737a89cb363490d670314bd8aa41ee63c2e1f45fbd477922f8360b388d6125ea6c7af0ad7056d01796e90c83313f4150a5716b30ed5f569288ae974ce2b4347926fce57de44512177dd7cde"); + + runTestVector("Threefish-1024-2: ", key, tweak, plaintext, expected, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024)); + } + + private static void speedTestCipher(BlockCipher cipher, byte[] input) + throws InterruptedException + { + byte[] key = new byte[cipher.getBlockSize()]; + rand.nextBytes(key); + + cipher.init(true, new KeyParameter(key)); + speedTestCipherForMode("encrypt", cipher, input); + cipher.init(false, new KeyParameter(key)); + speedTestCipherForMode("decrypt", cipher, input); + } + + private static void speedTestCipherForMode(String mode, BlockCipher cipher, byte[] input) + throws InterruptedException + { + System.out.println("======"); + System.out.println("Testing " + cipher.getAlgorithmName() + " " + cipher.getBlockSize() * 8 + " " + mode); + System.out.println("Beginning warmup run."); + + long warmup = testCipher(cipher, input); + System.out.println("Warmup run 1 in " + (warmup / 1000000) + "ms"); + Thread.sleep(100); + warmup = testCipher(cipher, input); + System.out.println("Warmup run 2 in " + (warmup / 1000000) + "ms"); + + System.gc(); + Thread.sleep(500); + System.gc(); + Thread.sleep(500); + + System.out.println("Beginning " + RUNS + " hot runs."); + + long[] runtimes = new long[RUNS]; + long total = 0; + for (int i = 0; i < RUNS; i++) + { + runtimes[i] = testCipher(cipher, input); + total += runtimes[i]; + System.out.println("Run " + (i + 1) + ": " + runtimes[i] / 100000 + "ms"); + } + long averageRuntime = total / RUNS; + System.out.println(cipher.getAlgorithmName() + " Average run time: " + averageRuntime / 1000000 + "ms"); + final long mbPerSecond = (long)((double)DATA_SIZE / averageRuntime * 1000000000 / (1024 * 1024)); + System.out.println(cipher.getAlgorithmName() + " Average speed: " + mbPerSecond + " MB/s"); + System.out.println(cipher.getAlgorithmName() + " Average speed: " + CLOCK_SPEED / (double)(mbPerSecond * (1024 * 1024)) + " c/b"); + } + + private static long testCipher(BlockCipher cipher, byte[] input) + { + long start = System.nanoTime(); + int blockSize = cipher.getBlockSize(); + byte[] out = new byte[blockSize]; + + for (int i = 0; i < (input.length - blockSize); i += blockSize) + { + cipher.processBlock(input, i, out, 0); +// byte[] test = new byte[blockSize]; +// System.arraycopy(input, i, test, 0, test.length); +// if (!Arrays.equals(out, test)) { +// System.err.println(":("); +// } + } + + long end = System.nanoTime(); + long delta = end - start; + return delta; + } +} |