From fa3784d35754c6829175a8dea749c431a8954993 Mon Sep 17 00:00:00 2001 From: Tim Whittington Date: Sat, 6 Jul 2013 20:53:43 +1200 Subject: [PATCH 1/9] Remove unnecessary tracking of workingKey/workingIV in Salsa20Engine - engine state already tracks these. --- .../crypto/engines/Salsa20Engine.java | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java index 6d4210d6ac..6967b483f1 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java @@ -31,9 +31,7 @@ public class Salsa20Engine private int index = 0; private int[] engineState = new int[STATE_SIZE]; // state private int[] x = new int[STATE_SIZE] ; // internal buffer - private byte[] keyStream = new byte[STATE_SIZE * 4], // expanded state, 64 bytes - workingKey = null, - workingIV = null; + private byte[] keyStream = new byte[STATE_SIZE * 4]; // expanded state, 64 bytes private boolean initialised = false; /* @@ -80,10 +78,10 @@ public void init( KeyParameter key = (KeyParameter) ivParams.getParameters(); - workingKey = key.getKey(); - workingIV = iv; + setKey(key.getKey(), iv); + reset(); + initialised = true; - setKey(workingKey, workingIV); } public String getAlgorithmName() @@ -160,28 +158,29 @@ public void processBytes( public void reset() { - setKey(workingKey, workingIV); + index = 0; + resetCounter(); + engineState[8] = engineState[9] = 0; } // Private implementation private void setKey(byte[] keyBytes, byte[] ivBytes) { - workingKey = keyBytes; - workingIV = ivBytes; - - index = 0; - resetCounter(); + if ((keyBytes.length != 16) && (keyBytes.length != 32)) { + throw new IllegalArgumentException(getAlgorithmName() + " requires 128 bit or 256 bit key"); + } + int offset = 0; byte[] constants; // Key - engineState[1] = Pack.littleEndianToInt(workingKey, 0); - engineState[2] = Pack.littleEndianToInt(workingKey, 4); - engineState[3] = Pack.littleEndianToInt(workingKey, 8); - engineState[4] = Pack.littleEndianToInt(workingKey, 12); + engineState[1] = Pack.littleEndianToInt(keyBytes, 0); + engineState[2] = Pack.littleEndianToInt(keyBytes, 4); + engineState[3] = Pack.littleEndianToInt(keyBytes, 8); + engineState[4] = Pack.littleEndianToInt(keyBytes, 12); - if (workingKey.length == 32) + if (keyBytes.length == 32) { constants = sigma; offset = 16; @@ -191,21 +190,20 @@ private void setKey(byte[] keyBytes, byte[] ivBytes) constants = tau; } - engineState[11] = Pack.littleEndianToInt(workingKey, offset); - engineState[12] = Pack.littleEndianToInt(workingKey, offset+4); - engineState[13] = Pack.littleEndianToInt(workingKey, offset+8); - engineState[14] = Pack.littleEndianToInt(workingKey, offset+12); + engineState[11] = Pack.littleEndianToInt(keyBytes, offset); + engineState[12] = Pack.littleEndianToInt(keyBytes, offset+4); + engineState[13] = Pack.littleEndianToInt(keyBytes, offset+8); + engineState[14] = Pack.littleEndianToInt(keyBytes, offset+12); + engineState[0 ] = Pack.littleEndianToInt(constants, 0); engineState[5 ] = Pack.littleEndianToInt(constants, 4); engineState[10] = Pack.littleEndianToInt(constants, 8); engineState[15] = Pack.littleEndianToInt(constants, 12); // IV - engineState[6] = Pack.littleEndianToInt(workingIV, 0); - engineState[7] = Pack.littleEndianToInt(workingIV, 4); + engineState[6] = Pack.littleEndianToInt(ivBytes, 0); + engineState[7] = Pack.littleEndianToInt(ivBytes, 4); engineState[8] = engineState[9] = 0; - - initialised = true; } private void generateKeyStream(byte[] output) From aae56b4939b8fdd726e2457832530366dabee1ca Mon Sep 17 00:00:00 2001 From: Tim Whittington Date: Sat, 6 Jul 2013 20:57:49 +1200 Subject: [PATCH 2/9] Implementation of XSalsa20 stream cipher, based on Salsa20Engine. Salsa20Engine is refactored slightly to allow XSalsa20Engine to override key setup, algorithm name and nonce size. XSalsa20 test vectors copied from CryptoPP (which generated them using nacl xsalsa20 implementation). --- .../crypto/engines/Salsa20Engine.java | 20 ++- .../crypto/engines/XSalsa20Engine.java | 65 +++++++ .../crypto/test/RegressionTest.java | 1 + .../crypto/test/XSalsa20Test.java | 168 ++++++++++++++++++ 4 files changed, 246 insertions(+), 8 deletions(-) create mode 100644 core/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java create mode 100644 core/src/test/java/org/bouncycastle/crypto/test/XSalsa20Test.java diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java index 6967b483f1..13c7c1a634 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java @@ -29,7 +29,7 @@ public class Salsa20Engine * during encryption and decryption */ private int index = 0; - private int[] engineState = new int[STATE_SIZE]; // state + protected int[] engineState = new int[STATE_SIZE]; // state private int[] x = new int[STATE_SIZE] ; // internal buffer private byte[] keyStream = new byte[STATE_SIZE * 4]; // expanded state, 64 bytes private boolean initialised = false; @@ -59,21 +59,21 @@ public void init( if (!(params instanceof ParametersWithIV)) { - throw new IllegalArgumentException("Salsa20 Init parameters must include an IV"); + throw new IllegalArgumentException(getAlgorithmName() + " Init parameters must include an IV"); } ParametersWithIV ivParams = (ParametersWithIV) params; byte[] iv = ivParams.getIV(); - - if (iv == null || iv.length != 8) + if (iv == null || iv.length != getNonceSize()) { - throw new IllegalArgumentException("Salsa20 requires exactly 8 bytes of IV"); + throw new IllegalArgumentException(getAlgorithmName() + " requires exactly " + getNonceSize() + + " bytes of IV"); } if (!(ivParams.getParameters() instanceof KeyParameter)) { - throw new IllegalArgumentException("Salsa20 Init parameters must include a key"); + throw new IllegalArgumentException(getAlgorithmName() + " Init parameters must include a key"); } KeyParameter key = (KeyParameter) ivParams.getParameters(); @@ -81,7 +81,11 @@ public void init( setKey(key.getKey(), iv); reset(); initialised = true; + } + protected int getNonceSize() + { + return 8; } public String getAlgorithmName() @@ -121,7 +125,7 @@ public void processBytes( { if (!initialised) { - throw new IllegalStateException(getAlgorithmName()+" not initialised"); + throw new IllegalStateException(getAlgorithmName() + " not initialised"); } if ((inOff + len) > in.length) @@ -165,7 +169,7 @@ public void reset() // Private implementation - private void setKey(byte[] keyBytes, byte[] ivBytes) + protected void setKey(byte[] keyBytes, byte[] ivBytes) { if ((keyBytes.length != 16) && (keyBytes.length != 32)) { throw new IllegalArgumentException(getAlgorithmName() + " requires 128 bit or 256 bit key"); diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java b/core/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java new file mode 100644 index 0000000000..437c16ec4e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java @@ -0,0 +1,65 @@ +package org.bouncycastle.crypto.engines; + +import org.bouncycastle.crypto.util.Pack; + +/** + * Implementation of Daniel J. Bernstein's XSalsa20 stream cipher - Salsa20 with an extended nonce. + *

+ * XSalsa20 requires a 256 bit key, and a 192 bit nonce. + */ +public class XSalsa20Engine extends Salsa20Engine +{ + + public String getAlgorithmName() + { + return "XSalsa20"; + } + + protected int getNonceSize() + { + return 24; + } + + /** + * XSalsa20 key generation: process 256 bit input key and 128 bits of the input nonce + * using a core Salsa20 function without input addition to produce 256 bit working key + * and use that with the remaining 64 bits of nonce to initialize a standard Salsa20 engine state. + */ + protected void setKey(byte[] keyBytes, byte[] ivBytes) + { + if (keyBytes.length != 32) + { + throw new IllegalArgumentException(getAlgorithmName() + " requires a 256 bit key"); + } + + // Set key for HSalsa20 + super.setKey(keyBytes, ivBytes); + + // Pack next 64 bits of IV into engine state instead of counter + engineState[8] = Pack.littleEndianToInt(ivBytes, 8); + engineState[9] = Pack.littleEndianToInt(ivBytes, 12); + + // Process engine state to generate Salsa20 key + int[] hsalsa20Out = new int[engineState.length]; + salsaCore(20, engineState, hsalsa20Out); + + // Set new key, removing addition in last round of salsaCore + engineState[1] = hsalsa20Out[0] - engineState[0]; + engineState[2] = hsalsa20Out[5] - engineState[5]; + engineState[3] = hsalsa20Out[10] - engineState[10]; + engineState[4] = hsalsa20Out[15] - engineState[15]; + + engineState[11] = hsalsa20Out[6] - engineState[6]; + engineState[12] = hsalsa20Out[7] - engineState[7]; + engineState[13] = hsalsa20Out[8] - engineState[8]; + engineState[14] = hsalsa20Out[9] - engineState[9]; + + // Last 64 bits of input IV + engineState[6] = Pack.littleEndianToInt(ivBytes, 16); + engineState[7] = Pack.littleEndianToInt(ivBytes, 20); + + // Counter reset + engineState[8] = engineState[9] = 0; + } + +} diff --git a/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java b/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java index 7f3732d62b..8912acc1ba 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java @@ -93,6 +93,7 @@ public class RegressionTest new RFC3211WrapTest(), new SEEDTest(), new Salsa20Test(), + new XSalsa20Test(), new CMacTest(), new EAXTest(), new GCMTest(), diff --git a/core/src/test/java/org/bouncycastle/crypto/test/XSalsa20Test.java b/core/src/test/java/org/bouncycastle/crypto/test/XSalsa20Test.java new file mode 100644 index 0000000000..e0c589eb00 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/test/XSalsa20Test.java @@ -0,0 +1,168 @@ +package org.bouncycastle.crypto.test; + +import org.bouncycastle.crypto.engines.XSalsa20Engine; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.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") }; + + @Override + public String getName() + { + return "XSalsa20"; + } + + @Override + 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()); + } +} From 62775d85b7a3ae53e722af79b7fa394c9a8a57d4 Mon Sep 17 00:00:00 2001 From: Tim Whittington Date: Mon, 8 Jul 2013 08:57:29 +1200 Subject: [PATCH 3/9] Add support for reduced round Salsa20 (e.g. Salsa20/12, Salsa20/8). Test vectors generated with the reference implementations in estreambench-20080905. --- .../crypto/engines/Salsa20Engine.java | 31 +++++++++- .../bouncycastle/crypto/test/Salsa20Test.java | 61 ++++++++++++++++--- 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java index 13c7c1a634..a07c391a2c 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java @@ -39,6 +39,29 @@ public class Salsa20Engine */ private int cW0, cW1, cW2; + protected int rounds; + + /** + * Creates a 20 round Salsa20 engine. + */ + public Salsa20Engine() + { + this(20); + } + + /** + * Creates a Salsa20 engine with a specific number of rounds. + * @param rounds the number of rounds (must be an even number). + */ + public Salsa20Engine(int rounds) + { + this.rounds = rounds; + if (rounds % 2 != 0) { + throw new IllegalArgumentException("Number of rounds must be even"); + } + } + + /** * initialise a Salsa20 cipher. * @@ -90,7 +113,7 @@ protected int getNonceSize() public String getAlgorithmName() { - return "Salsa20"; + return (rounds == 20) ? "Salsa20" : "Salsa20/" + rounds; } public byte returnByte(byte in) @@ -212,7 +235,7 @@ protected void setKey(byte[] keyBytes, byte[] ivBytes) private void generateKeyStream(byte[] output) { - salsaCore(20, engineState, x); + salsaCore(rounds, engineState, x); Pack.intToLittleEndian(x, output, 0); } @@ -225,7 +248,9 @@ private void generateKeyStream(byte[] output) */ public static void salsaCore(int rounds, int[] input, int[] x) { - // TODO Exception if rounds odd? + if (rounds % 2 != 0) { + throw new IllegalArgumentException("Number of rounds must be even"); + } System.arraycopy(input, 0, x, 0, input.length); diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Salsa20Test.java b/core/src/test/java/org/bouncycastle/crypto/test/Salsa20Test.java index 8f3b587676..8cd35cc999 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/Salsa20Test.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/Salsa20Test.java @@ -90,6 +90,49 @@ public class Salsa20Test + "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"; @@ -97,10 +140,14 @@ public String getName() public void performTest() { - salsa20Test1(new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + salsa20Test1(20, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), set1v0_0, set1v0_192, set1v0_256, set1v0_448); - salsa20Test1(new ParametersWithIV(new KeyParameter(Hex.decode("00400000000000000000000000000000")), Hex.decode("0000000000000000")), + 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")), @@ -108,9 +155,9 @@ public void performTest() reinitBug(); } - private void salsa20Test1(CipherParameters params, String v0, String v192, String v256, String v448) + private void salsa20Test1(int rounds, CipherParameters params, String v0, String v192, String v256, String v448) { - StreamCipher salsa = new Salsa20Engine(); + StreamCipher salsa = new Salsa20Engine(rounds); byte[] buf = new byte[64]; salsa.init(true, params); @@ -123,19 +170,19 @@ private void salsa20Test1(CipherParameters params, String v0, String v192, Strin case 0: if (!areEqual(buf, Hex.decode(v0))) { - mismatch("v0", v0, buf); + mismatch("v0/" + rounds, v0, buf); } break; case 3: if (!areEqual(buf, Hex.decode(v192))) { - mismatch("v192", v192, buf); + mismatch("v192/" + rounds, v192, buf); } break; case 4: if (!areEqual(buf, Hex.decode(v256))) { - mismatch("v256", v256, buf); + mismatch("v256/" + rounds, v256, buf); } break; default: From 155a0c15eda048d037686e1361138e69547c840d Mon Sep 17 00:00:00 2001 From: Tim Whittington Date: Mon, 8 Jul 2013 08:59:29 +1200 Subject: [PATCH 4/9] Refactor Salsa20Engine to allow variants (e.g. ChaCha) to override key setup, block counter and state permutation. --- .../crypto/engines/Salsa20Engine.java | 39 ++++++++++--------- .../crypto/engines/XSalsa20Engine.java | 2 +- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java index a07c391a2c..125af9c73a 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java @@ -20,7 +20,7 @@ public class Salsa20Engine /** Constants */ private final static int STATE_SIZE = 16; // 16, 32 bit ints = 64 bytes - private final static byte[] + protected final static byte[] sigma = Strings.toByteArray("expand 32-byte k"), tau = Strings.toByteArray("expand 16-byte k"); @@ -30,7 +30,7 @@ public class Salsa20Engine */ private int index = 0; protected int[] engineState = new int[STATE_SIZE]; // state - private int[] x = new int[STATE_SIZE] ; // internal buffer + protected int[] x = new int[STATE_SIZE] ; // internal buffer private byte[] keyStream = new byte[STATE_SIZE * 4]; // expanded state, 64 bytes private boolean initialised = false; @@ -126,11 +126,7 @@ public byte returnByte(byte in) if (index == 0) { generateKeyStream(keyStream); - - if (++engineState[8] == 0) - { - ++engineState[9]; - } + advanceCounter(); } byte out = (byte)(keyStream[index]^in); @@ -139,6 +135,14 @@ public byte returnByte(byte in) return out; } + protected void advanceCounter() + { + if (++engineState[8] == 0) + { + ++engineState[9]; + } + } + public void processBytes( byte[] in, int inOff, @@ -171,11 +175,7 @@ public void processBytes( if (index == 0) { generateKeyStream(keyStream); - - if (++engineState[8] == 0) - { - ++engineState[9]; - } + advanceCounter(); } out[i+outOff] = (byte)(keyStream[index]^in[i+inOff]); @@ -186,11 +186,14 @@ public void processBytes( public void reset() { index = 0; + resetLimitCounter(); resetCounter(); - engineState[8] = engineState[9] = 0; } - // Private implementation + protected void resetCounter() + { + engineState[8] = engineState[9] = 0; + } protected void setKey(byte[] keyBytes, byte[] ivBytes) { @@ -230,10 +233,10 @@ protected void setKey(byte[] keyBytes, byte[] ivBytes) // IV engineState[6] = Pack.littleEndianToInt(ivBytes, 0); engineState[7] = Pack.littleEndianToInt(ivBytes, 4); - engineState[8] = engineState[9] = 0; + resetCounter(); } - private void generateKeyStream(byte[] output) + protected void generateKeyStream(byte[] output) { salsaCore(rounds, engineState, x); Pack.intToLittleEndian(x, output, 0); @@ -304,12 +307,12 @@ public static void salsaCore(int rounds, int[] input, int[] x) * * @return rotated x */ - private static int rotl(int x, int y) + protected static int rotl(int x, int y) { return (x << y) | (x >>> -y); } - private void resetCounter() + private void resetLimitCounter() { cW0 = 0; cW1 = 0; diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java b/core/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java index 437c16ec4e..5b2181dae9 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/XSalsa20Engine.java @@ -59,7 +59,7 @@ protected void setKey(byte[] keyBytes, byte[] ivBytes) engineState[7] = Pack.littleEndianToInt(ivBytes, 20); // Counter reset - engineState[8] = engineState[9] = 0; + resetCounter(); } } From 288b499a46f355935462af34a6c2940ea4d5d284 Mon Sep 17 00:00:00 2001 From: Tim Whittington Date: Sun, 7 Jul 2013 22:26:22 +1200 Subject: [PATCH 5/9] Implementation of ChaCha variant of Salsa20 stream cipher. Standard 20 round, and reduced round variants are supported. Test vectors for 20/12/8 round variants generated with reference implementation from estreambench-20080905. --- .../crypto/engines/ChaChaEngine.java | 186 ++++++++++++ .../bouncycastle/crypto/test/ChaChaTest.java | 274 ++++++++++++++++++ 2 files changed, 460 insertions(+) create mode 100644 core/src/main/java/org/bouncycastle/crypto/engines/ChaChaEngine.java create mode 100644 core/src/test/java/org/bouncycastle/crypto/test/ChaChaTest.java diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/ChaChaEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/ChaChaEngine.java new file mode 100644 index 0000000000..2d1de39cf2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/engines/ChaChaEngine.java @@ -0,0 +1,186 @@ +package org.bouncycastle.crypto.engines; + +import org.bouncycastle.crypto.util.Pack; + +/** + * Implementation of Daniel J. Bernstein's ChaCha stream cipher. + */ +public class ChaChaEngine extends Salsa20Engine +{ + + /** + * Creates a 20 rounds ChaCha engine. + */ + public ChaChaEngine() + { + super(); + } + + /** + * Creates a ChaCha engine with a specific number of rounds. + * @param rounds the number of rounds (must be an even number). + */ + public ChaChaEngine(int rounds) + { + super(rounds); + } + + public String getAlgorithmName() + { + return "ChaCha" + rounds; + } + + protected void advanceCounter() + { + if (++engineState[12] == 0) + { + ++engineState[13]; + } + } + + protected void resetCounter() + { + engineState[12] = engineState[13] = 0; + } + + protected void setKey(byte[] keyBytes, byte[] ivBytes) + { + if ((keyBytes.length != 16) && (keyBytes.length != 32)) + { + throw new IllegalArgumentException(getAlgorithmName() + " requires 128 bit or 256 bit key"); + } + + int offset = 0; + byte[] constants; + + // Key + engineState[4] = Pack.littleEndianToInt(keyBytes, 0); + engineState[5] = Pack.littleEndianToInt(keyBytes, 4); + engineState[6] = Pack.littleEndianToInt(keyBytes, 8); + engineState[7] = Pack.littleEndianToInt(keyBytes, 12); + + if (keyBytes.length == 32) + { + constants = sigma; + offset = 16; + } else + { + constants = tau; + } + + engineState[8] = Pack.littleEndianToInt(keyBytes, offset); + engineState[9] = Pack.littleEndianToInt(keyBytes, offset + 4); + engineState[10] = Pack.littleEndianToInt(keyBytes, offset + 8); + engineState[11] = Pack.littleEndianToInt(keyBytes, offset + 12); + + engineState[0] = Pack.littleEndianToInt(constants, 0); + engineState[1] = Pack.littleEndianToInt(constants, 4); + engineState[2] = Pack.littleEndianToInt(constants, 8); + engineState[3] = Pack.littleEndianToInt(constants, 12); + + // Counter + engineState[12] = engineState[13] = 0; + + // IV + engineState[14] = Pack.littleEndianToInt(ivBytes, 0); + engineState[15] = Pack.littleEndianToInt(ivBytes, 4); + } + + protected void generateKeyStream(byte[] output) + { + chachaCore(rounds, engineState, x); + Pack.intToLittleEndian(x, output, 0); + } + + /** + * ChacCha function + * + * @param input input data + * + * @return keystream + */ + public static void chachaCore(int rounds, int[] input, int[] x) + { + if (input.length != 16) { + throw new IllegalArgumentException(); + } + if (x.length != 16) { + throw new IllegalArgumentException(); + } + if (rounds % 2 != 0) { + throw new IllegalArgumentException("Number of rounds must be even"); + } + + int x00 = input[ 0]; + int x01 = input[ 1]; + int x02 = input[ 2]; + int x03 = input[ 3]; + int x04 = input[ 4]; + int x05 = input[ 5]; + int x06 = input[ 6]; + int x07 = input[ 7]; + int x08 = input[ 8]; + int x09 = input[ 9]; + int x10 = input[10]; + int x11 = input[11]; + int x12 = input[12]; + int x13 = input[13]; + int x14 = input[14]; + int x15 = input[15]; + + for (int i = rounds; i > 0; i -= 2) + { + x00 += x04; x12 = rotl(x12 ^ x00, 16); + x08 += x12; x04 = rotl(x04 ^ x08, 12); + x00 += x04; x12 = rotl(x12 ^ x00, 8); + x08 += x12; x04 = rotl(x04 ^ x08, 7); + x01 += x05; x13 = rotl(x13 ^ x01, 16); + x09 += x13; x05 = rotl(x05 ^ x09, 12); + x01 += x05; x13 = rotl(x13 ^ x01, 8); + x09 += x13; x05 = rotl(x05 ^ x09, 7); + x02 += x06; x14 = rotl(x14 ^ x02, 16); + x10 += x14; x06 = rotl(x06 ^ x10, 12); + x02 += x06; x14 = rotl(x14 ^ x02, 8); + x10 += x14; x06 = rotl(x06 ^ x10, 7); + x03 += x07; x15 = rotl(x15 ^ x03, 16); + x11 += x15; x07 = rotl(x07 ^ x11, 12); + x03 += x07; x15 = rotl(x15 ^ x03, 8); + x11 += x15; x07 = rotl(x07 ^ x11, 7); + x00 += x05; x15 = rotl(x15 ^ x00, 16); + x10 += x15; x05 = rotl(x05 ^ x10, 12); + x00 += x05; x15 = rotl(x15 ^ x00, 8); + x10 += x15; x05 = rotl(x05 ^ x10, 7); + x01 += x06; x12 = rotl(x12 ^ x01, 16); + x11 += x12; x06 = rotl(x06 ^ x11, 12); + x01 += x06; x12 = rotl(x12 ^ x01, 8); + x11 += x12; x06 = rotl(x06 ^ x11, 7); + x02 += x07; x13 = rotl(x13 ^ x02, 16); + x08 += x13; x07 = rotl(x07 ^ x08, 12); + x02 += x07; x13 = rotl(x13 ^ x02, 8); + x08 += x13; x07 = rotl(x07 ^ x08, 7); + x03 += x04; x14 = rotl(x14 ^ x03, 16); + x09 += x14; x04 = rotl(x04 ^ x09, 12); + x03 += x04; x14 = rotl(x14 ^ x03, 8); + x09 += x14; x04 = rotl(x04 ^ x09, 7); + + } + + x[ 0] = x00 + input[ 0]; + x[ 1] = x01 + input[ 1]; + x[ 2] = x02 + input[ 2]; + x[ 3] = x03 + input[ 3]; + x[ 4] = x04 + input[ 4]; + x[ 5] = x05 + input[ 5]; + x[ 6] = x06 + input[ 6]; + x[ 7] = x07 + input[ 7]; + x[ 8] = x08 + input[ 8]; + x[ 9] = x09 + input[ 9]; + x[10] = x10 + input[10]; + x[11] = x11 + input[11]; + x[12] = x12 + input[12]; + x[13] = x13 + input[13]; + x[14] = x14 + input[14]; + x[15] = x15 + input[15]; + } + +} diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ChaChaTest.java b/core/src/test/java/org/bouncycastle/crypto/test/ChaChaTest.java new file mode 100644 index 0000000000..b5e84d33d5 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/test/ChaChaTest.java @@ -0,0 +1,274 @@ +package org.bouncycastle.crypto.test; + +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.StreamCipher; +import org.bouncycastle.crypto.engines.ChaChaEngine; +import org.bouncycastle.crypto.engines.Salsa20Engine; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.test.SimpleTest; + +/** + * ChaChat Test + *

+ * 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(); + } + + private void chachaTest1(int rounds, CipherParameters params, String v0, String v192, String v256, String v448) + { + StreamCipher salsa = new ChaChaEngine(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 chachaTest2(CipherParameters params, String v0, String v65472, String v65536) + { + StreamCipher salsa = new ChaChaEngine(); + 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) + { + } + } + + public static void main( + String[] args) + { + runTest(new ChaChaTest()); + } +} From 43764fa34d5d3620dd68a7b03a9c11cd33dd73f1 Mon Sep 17 00:00:00 2001 From: Tim Whittington Date: Mon, 8 Jul 2013 09:10:41 +1200 Subject: [PATCH 6/9] Registerize variables in core Salsa20 state permutation. This boosts speed on 64 bit Java 7, OS X Macbook Pro 2.5GHz Core i5 from 100MB/s (23 c/b) to 114MB/s (21 c/b) (measured on long streams). --- .../crypto/engines/Salsa20Engine.java | 108 ++++++++++++------ 1 file changed, 71 insertions(+), 37 deletions(-) diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java index 125af9c73a..0e025070b8 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/Salsa20Engine.java @@ -251,52 +251,86 @@ protected void generateKeyStream(byte[] output) */ public static void salsaCore(int rounds, int[] input, int[] x) { + if (input.length != 16) { + throw new IllegalArgumentException(); + } + if (x.length != 16) { + throw new IllegalArgumentException(); + } if (rounds % 2 != 0) { throw new IllegalArgumentException("Number of rounds must be even"); } - System.arraycopy(input, 0, x, 0, input.length); + int x00 = input[ 0]; + int x01 = input[ 1]; + int x02 = input[ 2]; + int x03 = input[ 3]; + int x04 = input[ 4]; + int x05 = input[ 5]; + int x06 = input[ 6]; + int x07 = input[ 7]; + int x08 = input[ 8]; + int x09 = input[ 9]; + int x10 = input[10]; + int x11 = input[11]; + int x12 = input[12]; + int x13 = input[13]; + int x14 = input[14]; + int x15 = input[15]; for (int i = rounds; i > 0; i -= 2) { - x[ 4] ^= rotl((x[ 0]+x[12]), 7); - x[ 8] ^= rotl((x[ 4]+x[ 0]), 9); - x[12] ^= rotl((x[ 8]+x[ 4]),13); - x[ 0] ^= rotl((x[12]+x[ 8]),18); - x[ 9] ^= rotl((x[ 5]+x[ 1]), 7); - x[13] ^= rotl((x[ 9]+x[ 5]), 9); - x[ 1] ^= rotl((x[13]+x[ 9]),13); - x[ 5] ^= rotl((x[ 1]+x[13]),18); - x[14] ^= rotl((x[10]+x[ 6]), 7); - x[ 2] ^= rotl((x[14]+x[10]), 9); - x[ 6] ^= rotl((x[ 2]+x[14]),13); - x[10] ^= rotl((x[ 6]+x[ 2]),18); - x[ 3] ^= rotl((x[15]+x[11]), 7); - x[ 7] ^= rotl((x[ 3]+x[15]), 9); - x[11] ^= rotl((x[ 7]+x[ 3]),13); - x[15] ^= rotl((x[11]+x[ 7]),18); - x[ 1] ^= rotl((x[ 0]+x[ 3]), 7); - x[ 2] ^= rotl((x[ 1]+x[ 0]), 9); - x[ 3] ^= rotl((x[ 2]+x[ 1]),13); - x[ 0] ^= rotl((x[ 3]+x[ 2]),18); - x[ 6] ^= rotl((x[ 5]+x[ 4]), 7); - x[ 7] ^= rotl((x[ 6]+x[ 5]), 9); - x[ 4] ^= rotl((x[ 7]+x[ 6]),13); - x[ 5] ^= rotl((x[ 4]+x[ 7]),18); - x[11] ^= rotl((x[10]+x[ 9]), 7); - x[ 8] ^= rotl((x[11]+x[10]), 9); - x[ 9] ^= rotl((x[ 8]+x[11]),13); - x[10] ^= rotl((x[ 9]+x[ 8]),18); - x[12] ^= rotl((x[15]+x[14]), 7); - x[13] ^= rotl((x[12]+x[15]), 9); - x[14] ^= rotl((x[13]+x[12]),13); - x[15] ^= rotl((x[14]+x[13]),18); + x04 ^= rotl((x00+x12), 7); + x08 ^= rotl((x04+x00), 9); + x12 ^= rotl((x08+x04),13); + x00 ^= rotl((x12+x08),18); + x09 ^= rotl((x05+x01), 7); + x13 ^= rotl((x09+x05), 9); + x01 ^= rotl((x13+x09),13); + x05 ^= rotl((x01+x13),18); + x14 ^= rotl((x10+x06), 7); + x02 ^= rotl((x14+x10), 9); + x06 ^= rotl((x02+x14),13); + x10 ^= rotl((x06+x02),18); + x03 ^= rotl((x15+x11), 7); + x07 ^= rotl((x03+x15), 9); + x11 ^= rotl((x07+x03),13); + x15 ^= rotl((x11+x07),18); + + x01 ^= rotl((x00+x03), 7); + x02 ^= rotl((x01+x00), 9); + x03 ^= rotl((x02+x01),13); + x00 ^= rotl((x03+x02),18); + x06 ^= rotl((x05+x04), 7); + x07 ^= rotl((x06+x05), 9); + x04 ^= rotl((x07+x06),13); + x05 ^= rotl((x04+x07),18); + x11 ^= rotl((x10+x09), 7); + x08 ^= rotl((x11+x10), 9); + x09 ^= rotl((x08+x11),13); + x10 ^= rotl((x09+x08),18); + x12 ^= rotl((x15+x14), 7); + x13 ^= rotl((x12+x15), 9); + x14 ^= rotl((x13+x12),13); + x15 ^= rotl((x14+x13),18); } - for (int i = 0; i < STATE_SIZE; ++i) - { - x[i] += input[i]; - } + x[ 0] = x00 + input[ 0]; + x[ 1] = x01 + input[ 1]; + x[ 2] = x02 + input[ 2]; + x[ 3] = x03 + input[ 3]; + x[ 4] = x04 + input[ 4]; + x[ 5] = x05 + input[ 5]; + x[ 6] = x06 + input[ 6]; + x[ 7] = x07 + input[ 7]; + x[ 8] = x08 + input[ 8]; + x[ 9] = x09 + input[ 9]; + x[10] = x10 + input[10]; + x[11] = x11 + input[11]; + x[12] = x12 + input[12]; + x[13] = x13 + input[13]; + x[14] = x14 + input[14]; + x[15] = x15 + input[15]; } /** From b29f9105af73d4ea82fccefdde361badc3a73fd8 Mon Sep 17 00:00:00 2001 From: Tim Whittington Date: Tue, 9 Jul 2013 10:08:35 +1200 Subject: [PATCH 7/9] JCE registrations for ChaCha and XSalsa20 --- .../jcajce/provider/symmetric/ChaCha.java | 51 +++++++++++++++++++ .../jcajce/provider/symmetric/XSalsa20.java | 51 +++++++++++++++++++ .../jce/provider/BouncyCastleProvider.java | 4 +- .../provider/test/PrivateConstructorTest.java | 4 ++ 4 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java create mode 100644 prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/XSalsa20.java diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java new file mode 100644 index 0000000000..ff748ae496 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java @@ -0,0 +1,51 @@ +package org.bouncycastle.jcajce.provider.symmetric; + +import org.bouncycastle.crypto.CipherKeyGenerator; +import org.bouncycastle.crypto.engines.ChaChaEngine; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; +import org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher; +import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; + +public final class ChaCha +{ + private ChaCha() + { + } + + public static class Base + extends BaseStreamCipher + { + public Base() + { + super(new ChaChaEngine(), 8); + } + } + + public static class KeyGen + extends BaseKeyGenerator + { + public KeyGen() + { + super("ChaCha", 128, new CipherKeyGenerator()); + } + } + + public static class Mappings + extends AlgorithmProvider + { + private static final String PREFIX = ChaCha.class.getName(); + + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + + provider.addAlgorithm("Cipher.CHACHA", PREFIX + "$Base"); + provider.addAlgorithm("KeyGenerator.CHACHA", PREFIX + "$KeyGen"); + + } + } +} diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/XSalsa20.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/XSalsa20.java new file mode 100644 index 0000000000..5be06401ac --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/XSalsa20.java @@ -0,0 +1,51 @@ +package org.bouncycastle.jcajce.provider.symmetric; + +import org.bouncycastle.crypto.CipherKeyGenerator; +import org.bouncycastle.crypto.engines.XSalsa20Engine; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; +import org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher; +import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; + +public final class XSalsa20 +{ + private XSalsa20() + { + } + + public static class Base + extends BaseStreamCipher + { + public Base() + { + super(new XSalsa20Engine(), 24); + } + } + + public static class KeyGen + extends BaseKeyGenerator + { + public KeyGen() + { + super("XSalsa20", 256, new CipherKeyGenerator()); + } + } + + public static class Mappings + extends AlgorithmProvider + { + private static final String PREFIX = XSalsa20.class.getName(); + + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + + provider.addAlgorithm("Cipher.XSALSA20", PREFIX + "$Base"); + provider.addAlgorithm("KeyGenerator.XSALSA20", PREFIX + "$KeyGen"); + + } + } +} diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java index 7a1465dc51..6b7881c699 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java @@ -69,8 +69,8 @@ public final class BouncyCastleProvider extends Provider private static final String[] SYMMETRIC_CIPHERS = { - "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DES", "DESede", "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", - "Noekeon", "RC2", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA" + "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede", "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", + "Noekeon", "RC2", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA", "XSalsa20" }; /* diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/PrivateConstructorTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/PrivateConstructorTest.java index d02e932c52..a885af5794 100644 --- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/PrivateConstructorTest.java +++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/PrivateConstructorTest.java @@ -28,6 +28,7 @@ import org.bouncycastle.jcajce.provider.symmetric.CAST5; import org.bouncycastle.jcajce.provider.symmetric.CAST6; import org.bouncycastle.jcajce.provider.symmetric.Camellia; +import org.bouncycastle.jcajce.provider.symmetric.ChaCha; import org.bouncycastle.jcajce.provider.symmetric.DES; import org.bouncycastle.jcajce.provider.symmetric.DESede; import org.bouncycastle.jcajce.provider.symmetric.GOST28147; @@ -51,6 +52,7 @@ import org.bouncycastle.jcajce.provider.symmetric.Twofish; import org.bouncycastle.jcajce.provider.symmetric.VMPC; import org.bouncycastle.jcajce.provider.symmetric.VMPCKSA3; +import org.bouncycastle.jcajce.provider.symmetric.XSalsa20; import org.bouncycastle.jcajce.provider.symmetric.XTEA; public class PrivateConstructorTest @@ -80,7 +82,9 @@ public void testSymmetric() evilNoConstructionTest(RC5.class); evilNoConstructionTest(RC6.class); evilNoConstructionTest(Rijndael.class); + evilNoConstructionTest(ChaCha.class); evilNoConstructionTest(Salsa20.class); + evilNoConstructionTest(XSalsa20.class); evilNoConstructionTest(SEED.class); evilNoConstructionTest(Serpent.class); evilNoConstructionTest(Skipjack.class); From e8cb3ba3eeb16d5c69d02d147febcdcefb32f8a2 Mon Sep 17 00:00:00 2001 From: Tim Whittington Date: Tue, 9 Jul 2013 10:09:59 +1200 Subject: [PATCH 8/9] Fix Salsa20 reference in ChaCha test. --- .../src/test/java/org/bouncycastle/crypto/test/ChaChaTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ChaChaTest.java b/core/src/test/java/org/bouncycastle/crypto/test/ChaChaTest.java index b5e84d33d5..2f44559be1 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/ChaChaTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/ChaChaTest.java @@ -3,7 +3,6 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.StreamCipher; import org.bouncycastle.crypto.engines.ChaChaEngine; -import org.bouncycastle.crypto.engines.Salsa20Engine; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.util.encoders.Hex; @@ -252,7 +251,7 @@ private void reinitBug() KeyParameter key = new KeyParameter(Hex.decode("80000000000000000000000000000000")); ParametersWithIV parameters = new ParametersWithIV(key, Hex.decode("0000000000000000")); - StreamCipher salsa = new Salsa20Engine(); + StreamCipher salsa = new ChaChaEngine(); salsa.init(true, parameters); From 7a63e8154633b6562a4491277321445bae462775 Mon Sep 17 00:00:00 2001 From: Tim Whittington Date: Tue, 9 Jul 2013 10:10:18 +1200 Subject: [PATCH 9/9] Add ChaCha and XSalsa20 to specs. --- docs/specifications.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/specifications.html b/docs/specifications.html index 15d2e6e927..11ca04f0c4 100644 --- a/docs/specifications.html +++ b/docs/specifications.html @@ -231,7 +231,9 @@

Symmetric (Stream)

RC4Engine40 .. 2048  HC128Engine128  HC256Engine256  -Salsa20Engine128/256  +ChaChaEngine128/25664 bit IV +Salsa20Engine128/25664 bit IV +XSalsa20Engine256192 bit IV ISAACEngine32 .. 8192  VMPCEngine8 .. 6144  Grainv1Engine8064 bit IV @@ -575,7 +577,9 @@

Symmetric (Stream)

RC440 .. 2048 bits (128)  HC128(128)  HC256(256)  -Salsa20128/256(128)  +ChaCha128/25664 bit IV +Salsa20128/25664 bit IV +XSalsa20256182 bit IV VMPC128/6144(128)  Grainv18064 bit IV Grain12812896 bit IV