diff options
author | David Hook <dgh@cryptoworkshop.com> | 2013-05-07 13:46:36 +0400 |
---|---|---|
committer | David Hook <dgh@cryptoworkshop.com> | 2013-05-07 13:46:36 +0400 |
commit | 20209c8bfaf3a6998ce63c52b4b315a46e8af229 (patch) | |
tree | 9a344313d6c74cbca4ef44a61b89b23ef761c82d | |
parent | 5af5e909e4888637ec7618b3ee8a5da8833bbb7b (diff) |
further work on SecureRandom implementation, moved seedlen for hash digest into class.
added tests for DualEC and HMAC SecureRandom DRBG.
11 files changed, 352 insertions, 97 deletions
diff --git a/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java b/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java index a9b8a543..9a3a2d15 100644 --- a/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java +++ b/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java @@ -2,18 +2,34 @@ package org.bouncycastle.crypto.prng; import java.security.SecureRandom; +/** + * An EntropySourceProvider where entropy generation is based on a SecureRandom. + */ public class BasicEntropySourceProvider implements EntropySourceProvider { private final SecureRandom _sr; private final boolean _predictionResistant; + /** + * Create a entropy source provider based on the passed in SecureRandom. + * + * @param random the SecureRandom to base EntropySource construction on. + * @param isPredictionResistant boolean indicating if the SecureRandom is based on prediction resistant entropy or not (true if it is). + */ public BasicEntropySourceProvider(SecureRandom random, boolean isPredictionResistant) { _sr = random; _predictionResistant = isPredictionResistant; } + /** + * Return an entropy source that will create bitsRequired bits of entropy on + * each invocation of getEntropy(). + * + * @param bitsRequired size (in bits) of entropy to be created by the provided source. + * @return an EntropySource that generates bitsRequired bits of entropy on each call to its getEntropy() method. + */ public EntropySource get(final int bitsRequired) { return new EntropySource() diff --git a/src/main/java/org/bouncycastle/crypto/prng/HMacSP800DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/HMacSP800DRBG.java index 36655311..7602ca51 100644 --- a/src/main/java/org/bouncycastle/crypto/prng/HMacSP800DRBG.java +++ b/src/main/java/org/bouncycastle/crypto/prng/HMacSP800DRBG.java @@ -1,6 +1,6 @@ package org.bouncycastle.crypto.prng; -import org.bouncycastle.crypto.macs.HMac; +import org.bouncycastle.crypto.Mac; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.util.Arrays; @@ -11,9 +11,9 @@ public class HMacSP800DRBG private byte[] _V; private int _reseedCounter; private EntropySource _entropySource; - private HMac _hMac; + private Mac _hMac; - public HMacSP800DRBG(HMac hMac, EntropySource entropySource, byte[] nonce, + public HMacSP800DRBG(Mac hMac, EntropySource entropySource, byte[] nonce, byte[] personalisationString, int securityStrength) { // TODO: validate security strength @@ -30,7 +30,7 @@ public class HMacSP800DRBG System.arraycopy(nonce, 0, seedMaterial, entropy.length, nonce.length); System.arraycopy(personalisationString, 0, seedMaterial, entropy.length + nonce.length, personalisationString.length); - _K = new byte[hMac.getUnderlyingDigest().getDigestSize()]; + _K = new byte[hMac.getMacSize()]; _V = new byte[_K.length]; Arrays.fill(_V, (byte)1); diff --git a/src/main/java/org/bouncycastle/crypto/prng/HashSP800DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/HashSP800DRBG.java index 13c3e930..4249fcee 100644 --- a/src/main/java/org/bouncycastle/crypto/prng/HashSP800DRBG.java +++ b/src/main/java/org/bouncycastle/crypto/prng/HashSP800DRBG.java @@ -1,22 +1,37 @@ package org.bouncycastle.crypto.prng;
+import java.util.Hashtable;
+
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.util.Integers;
import org.bouncycastle.util.encoders.Hex;
public class HashSP800DRBG implements SP80090DRBG
{
private final static byte[] ONE = { 0x01 };
private final static int RESEED_MAX = 100000;
-
+ private final static Hashtable seedlens = new Hashtable();
+
+ static
+ {
+ seedlens.put("SHA-1", Integers.valueOf(440));
+ seedlens.put("SHA-224", Integers.valueOf(440));
+ seedlens.put("SHA-256", Integers.valueOf(440));
+ seedlens.put("SHA-512/256", Integers.valueOf(440));
+ seedlens.put("SHA-512/224", Integers.valueOf(440));
+ seedlens.put("SHA-384", Integers.valueOf(888));
+ seedlens.put("SHA-512", Integers.valueOf(888));
+ }
+
private Digest _digest;
private byte[] _V;
private byte[] _C;
private int _reseedCounter;
private EntropySource _entropySource;
private int _securityStrength;
- private int _seedLength;
+ private int _seedLength;
- public HashSP800DRBG(Digest digest, int seedlen, EntropySource entropySource, byte[] nonce,
+ public HashSP800DRBG(Digest digest, EntropySource entropySource, byte[] nonce,
byte[] personalisationString, int securityStrength)
{
if (securityStrength > digest.getDigestSize() * 8) // TODO: this may, or may not be correct, but it's good enough for now
@@ -28,7 +43,7 @@ public class HashSP800DRBG implements SP80090DRBG _digest = digest;
_entropySource = entropySource;
_securityStrength = securityStrength;
- _seedLength = seedlen;
+ _seedLength = ((Integer)seedlens.get(digest.getAlgorithmName())).intValue();
// 1. seed_material = entropy_input || nonce || personalization_string.
// 2. seed = Hash_df (seed_material, seedlen).
diff --git a/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandom.java b/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandom.java index 27e2bf86..0b54ac54 100644 --- a/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandom.java +++ b/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandom.java @@ -2,7 +2,7 @@ package org.bouncycastle.crypto.random; import java.security.SecureRandom; -import org.bouncycastle.crypto.prng.BasicEntropySourceProvider; +import org.bouncycastle.crypto.prng.EntropySource; import org.bouncycastle.crypto.prng.SP80090DRBG; public class SP800SecureRandom @@ -11,25 +11,26 @@ public class SP800SecureRandom private final DRBGProvider drbgProvider; private final boolean predictionResistant; private final SecureRandom randomSource; - private final boolean randomPredictionResistant; - private final int entropyBitsRequired; + private final EntropySource entropySource; private SP80090DRBG drbg; - SP800SecureRandom(SecureRandom randomSource, boolean randomPredictionResistant, DRBGProvider drbgProvider, boolean predictionResistant, int entropyBitsRequired) + SP800SecureRandom(SecureRandom randomSource, EntropySource entropySource, DRBGProvider drbgProvider, boolean predictionResistant) { this.randomSource = randomSource; - this.randomPredictionResistant = randomPredictionResistant; + this.entropySource = entropySource; this.drbgProvider = drbgProvider; this.predictionResistant = predictionResistant; - this.entropyBitsRequired = entropyBitsRequired; } public void setSeed(byte[] seed) { synchronized (this) { - this.randomSource.setSeed(seed); + if (randomSource != null) + { + this.randomSource.setSeed(seed); + } } } @@ -37,7 +38,7 @@ public class SP800SecureRandom { synchronized (this) { - // this will happen when SecureRandom() is created. + // this will happen when SecureRandom() is created if (randomSource != null) { this.randomSource.setSeed(seed); @@ -51,7 +52,7 @@ public class SP800SecureRandom { if (drbg == null) { - drbg = drbgProvider.get(new BasicEntropySourceProvider(randomSource, randomPredictionResistant).get(entropyBitsRequired)); + drbg = drbgProvider.get(entropySource); } drbg.generate(bytes, null, predictionResistant); diff --git a/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandomBuilder.java b/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandomBuilder.java index dd5df992..feb61bc3 100644 --- a/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandomBuilder.java +++ b/src/main/java/org/bouncycastle/crypto/random/SP800SecureRandomBuilder.java @@ -4,27 +4,68 @@ import java.security.SecureRandom; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.macs.HMac; +import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.prng.BasicEntropySourceProvider; import org.bouncycastle.crypto.prng.CTRSP800DRBG; -import org.bouncycastle.crypto.prng.HMacSP800DRBG; -import org.bouncycastle.crypto.prng.SP80090DRBG; +import org.bouncycastle.crypto.prng.DualECSP800DRBG; import org.bouncycastle.crypto.prng.EntropySource; +import org.bouncycastle.crypto.prng.EntropySourceProvider; +import org.bouncycastle.crypto.prng.HMacSP800DRBG; import org.bouncycastle.crypto.prng.HashSP800DRBG; +import org.bouncycastle.crypto.prng.SP80090DRBG; +/** + * Builder class for making SecureRandom objects based on SP 800-90A Deterministic Random Bit Generators (DRBG). + */ public class SP800SecureRandomBuilder { - private byte[] nonce; + private final SecureRandom random; + private final EntropySourceProvider entropySourceProvider; + private byte[] personalizationString; - private SecureRandom random; - private boolean predictionResistantSource; - private int seedLength; - private int securityStrength; + private int securityStrength = 256; + private int entropyBitsRequired = 256; + + /** + * Basic constructor, creates a builder using an EntropySourceProvider based on the default SecureRandom with + * predictionResistant set to false. + * <p> + * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if + * the passed in SecureRandom does. + * </p> + */ + public SP800SecureRandomBuilder() + { + this(new SecureRandom(), false); + } - public SP800SecureRandomBuilder setNonce(byte[] nonce) + /** + * Construct a builder with an EntropySourceProvider based on the passed in SecureRandom and the passed in value + * for prediction resistance. + * <p> + * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if + * the passed in SecureRandom does. + * </p> + * @param entropySource + * @param predictionResistant + */ + public SP800SecureRandomBuilder(SecureRandom entropySource, boolean predictionResistant) { - this.nonce = nonce; + this.random = entropySource; + this.entropySourceProvider = new BasicEntropySourceProvider(random, predictionResistant); + } - return this; + /** + * Create a builder which makes creates the SecureRandom objects from a specified entropy source provider. + * <p> + * <b>Note:</b> If this constructor is used any calls to setSeed() in the resulting SecureRandom will be ignored. + * </p> + * @param entropySourceProvider a provider of EntropySource objects. + */ + public SP800SecureRandomBuilder(EntropySourceProvider entropySourceProvider) + { + this.random = null; + this.entropySourceProvider = entropySourceProvider; } public SP800SecureRandomBuilder setPersonalizationString(byte[] personalizationString) @@ -34,72 +75,97 @@ public class SP800SecureRandomBuilder return this; } - public SP800SecureRandomBuilder setEntropySource(SecureRandom entropySource, boolean predictionResistant) + public SP800SecureRandomBuilder setSecurityStrength(int securityStrength) { - this.random = entropySource; - this.predictionResistantSource = predictionResistant; + this.securityStrength = securityStrength; return this; } - public SP800SecureRandomBuilder setSeedLength(int seedLength) + public SP800SecureRandomBuilder setEntropyBitsRequired(int entropyBitsRequired) { - this.seedLength = seedLength; + this.entropyBitsRequired = entropyBitsRequired; return this; } - public SP800SecureRandomBuilder setSecurityStrength(int securityStrength) + /** + * Build a SecureRandom based on a SP 800-90A Hash DRBG. + * + * @param digest digest algorithm to use in the DRBG underneath the SecureRandom. + * @param nonce nonce value to use in DRBG construction. + * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes. + * @return a SecureRandom supported by a Hash DRBG. + */ + public SP800SecureRandom buildHash(Digest digest, byte[] nonce, boolean predictionResistant) { - this.securityStrength = securityStrength; - - return this; + return new SP800SecureRandom(random, entropySourceProvider.get(entropyBitsRequired), new HashDRBGProvider(digest, nonce, personalizationString, securityStrength), predictionResistant); } - public SP800SecureRandom build(Digest digest, boolean predictionResistant, int entropyBitsRequired) + public SP800SecureRandom build(BlockCipher cipher, int keySizeInBits, int seedLength, byte[] nonce, boolean predictionResistant) { - checkSettings(); - - return new SP800SecureRandom(random, predictionResistantSource, new HashDRBGProvider(digest, seedLength, nonce, personalizationString, securityStrength), predictionResistant, entropyBitsRequired); + return new SP800SecureRandom(random, entropySourceProvider.get(entropyBitsRequired), new CTRDRBGProvider(cipher, keySizeInBits, seedLength, nonce, personalizationString, securityStrength), predictionResistant); } - public SP800SecureRandom build(BlockCipher cipher, int keySizeInBits, boolean predictionResistant, int entropyBitsRequired) + /** + * Build a SecureRandom based on a SP 800-90A HMAC DRBG. + * + * @param hMac HMAC algorithm to use in the DRBG underneath the SecureRandom. + * @param nonce nonce value to use in DRBG construction. + * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes. + * @return a SecureRandom supported by a HMAC DRBG. + */ + public SP800SecureRandom buildHMAC(Mac hMac, byte[] nonce, boolean predictionResistant) { - checkSettings(); - - return new SP800SecureRandom(random, predictionResistantSource, new CTRDRBGProvider(cipher, keySizeInBits, seedLength, nonce, personalizationString, securityStrength), predictionResistant, entropyBitsRequired); + return new SP800SecureRandom(random, entropySourceProvider.get(entropyBitsRequired), new HMacDRBGProvider(hMac, nonce, personalizationString, securityStrength), predictionResistant); } - public SP800SecureRandom build(HMac hMac, boolean predictionResistant, int entropyBitsRequired) + /** + * Build a SecureRandom based on a SP 800-90A Dual EC DRBG. + * + * @param digest digest algorithm to use in the DRBG underneath the SecureRandom. + * @param nonce nonce value to use in DRBG construction. + * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes. + * @return a SecureRandom supported by a Dual EC DRBG. + */ + public SP800SecureRandom buildDualEC(Digest digest, byte[] nonce, boolean predictionResistant) { - checkSettings(); - - return new SP800SecureRandom(random, predictionResistantSource, new HMacDRBGProvider(hMac, nonce, personalizationString, securityStrength), predictionResistant, entropyBitsRequired); + return new SP800SecureRandom(random, entropySourceProvider.get(entropyBitsRequired), new DualECDRBGProvider(digest, nonce, personalizationString, securityStrength), predictionResistant); } - private void checkSettings() + private static class HashDRBGProvider + implements DRBGProvider { - if (random == null) + private final Digest digest; + private final byte[] nonce; + private final byte[] personalizationString; + private final int securityStrength; + + public HashDRBGProvider(Digest digest, byte[] nonce, byte[] personalizationString, int securityStrength) + { + this.digest = digest; + this.nonce = nonce; + this.personalizationString = personalizationString; + this.securityStrength = securityStrength; + } + + public SP80090DRBG get(EntropySource entropySource) { - random = new SecureRandom(); - predictionResistantSource = false; + return new HashSP800DRBG(digest, entropySource, nonce, personalizationString, securityStrength); } } - private static class HashDRBGProvider + private static class DualECDRBGProvider implements DRBGProvider { - private final Digest digest; - private final int seedLength; private final byte[] nonce; private final byte[] personalizationString; private final int securityStrength; - public HashDRBGProvider(Digest digest, int seedLength, byte[] nonce, byte[] personalizationString, int securityStrength) + public DualECDRBGProvider(Digest digest, byte[] nonce, byte[] personalizationString, int securityStrength) { this.digest = digest; - this.seedLength = seedLength; this.nonce = nonce; this.personalizationString = personalizationString; this.securityStrength = securityStrength; @@ -107,20 +173,19 @@ public class SP800SecureRandomBuilder public SP80090DRBG get(EntropySource entropySource) { - return new HashSP800DRBG(digest, seedLength, entropySource, nonce, personalizationString, securityStrength); + return new DualECSP800DRBG(digest, entropySource, nonce, personalizationString, securityStrength); } } private static class HMacDRBGProvider implements DRBGProvider { - - private final HMac hMac; + private final Mac hMac; private final byte[] nonce; private final byte[] personalizationString; private final int securityStrength; - public HMacDRBGProvider(HMac hMac, byte[] nonce, byte[] personalizationString, int securityStrength) + public HMacDRBGProvider(Mac hMac, byte[] nonce, byte[] personalizationString, int securityStrength) { this.hMac = hMac; this.nonce = nonce; diff --git a/src/test/java/org/bouncycastle/crypto/random/test/SP800RandomTest.java b/src/test/java/org/bouncycastle/crypto/random/test/SP800RandomTest.java index 41eec215..6b6e7f76 100644 --- a/src/test/java/org/bouncycastle/crypto/random/test/SP800RandomTest.java +++ b/src/test/java/org/bouncycastle/crypto/random/test/SP800RandomTest.java @@ -5,8 +5,12 @@ import java.util.ArrayList; import java.util.List; import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.engines.AESFastEngine; +import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.random.SP800SecureRandomBuilder; +import org.bouncycastle.crypto.test.DRBGTestVector; +import org.bouncycastle.crypto.test.TestEntropySourceProvider; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.FixedSecureRandom; @@ -23,17 +27,15 @@ public class SP800RandomTest private void testDigestRandom() { - SP800SecureRandomBuilder rBuild = new SP800SecureRandomBuilder(); - TestVector tv = new TestVector("a37a3e08d8393feb01c4d78cb6a4d1e210c288c89e9838176bc78946745f1c5bea44cf15e061601bfd45f7b3b95be924", true, "8243299805c0877e", 128, "a05002f98d5676e1b2e3b3d4686bb9055a830a39"); - rBuild.setNonce(tv.nonce()); + SP800SecureRandomBuilder rBuild = new SP800SecureRandomBuilder(new FixedSecureRandom(tv.entropy()), true); + rBuild.setPersonalizationString(tv.personalisation()); rBuild.setSecurityStrength(tv.securityStrength()); - rBuild.setEntropySource(new FixedSecureRandom(tv.entropy()), true); - rBuild.setSeedLength(440); + rBuild.setEntropyBitsRequired(tv.securityStrength()); - SecureRandom random = rBuild.build(new SHA1Digest(), true, tv.securityStrength()); + SecureRandom random = rBuild.buildHash(new SHA1Digest(), tv.nonce(), true); byte[] expected = tv.expectedValue(); byte[] produced = new byte[expected.length]; @@ -48,19 +50,136 @@ public class SP800RandomTest } } - private void testCTRRandom() + private void testHMACRandom() + { + DRBGTestVector tv = new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + true, + "2021222324", + 80, + new String[] + { + "6C37FDD729AA40F80BC6AB08CA7CC649794F6998B57081E4220F22C5C283E2C91B8E305AB869C625", + "CAF57DCFEA393B9236BF691FA456FEA7FDF1DF8361482CA54D5FA723F4C88B4FA504BF03277FA783" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"); + + doHMACTest(tv); + + tv = new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + false, + "2021222324", + 80, + new String[] + { + "5A7D3B449F481CB38DF79AD2B1FCC01E57F8135E8C0B22CD0630BFB0127FB5408C8EFC17A929896E", + "82cf772ec3e84b00fc74f5df104efbfb2428554e9ce367d03aeade37827fa8e9cb6a08196115d948" + }); + + doHMACTest(tv); + } + + private void doHMACTest(DRBGTestVector tv) { - SP800SecureRandomBuilder rBuild = new SP800SecureRandomBuilder(); + SP800SecureRandomBuilder rBuild = new SP800SecureRandomBuilder(new SHA1EntropyProvider()); + + rBuild.setPersonalizationString(tv.personalizationString()); + rBuild.setSecurityStrength(tv.securityStrength()); + rBuild.setEntropyBitsRequired(tv.entropySource().getEntropy().length * 8); + + SecureRandom random = rBuild.buildHMAC(new HMac(tv.getDigest()), tv.nonce(), tv.predictionResistance()); + + byte[] expected = tv.expectedValue(0); + byte[] produced = new byte[expected.length]; + + random.nextBytes(produced); + if (!Arrays.areEqual(expected, produced)) + { + fail("SP800 HMAC SecureRandom produced incorrect result (1)"); + } + + random.nextBytes(produced); + expected = tv.expectedValue(1); + + if (!Arrays.areEqual(expected, produced)) + { + fail("SP800 HMAC SecureRandom produced incorrect result (2)"); + } + } + + private void testDualECRandom() + { + DRBGTestVector tv = new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(128), + false, + "2021222324252627", + 128, + new String[] + { + "3AB095CC493A8730D70DE923108B2E4710799044FFC27D0A1156250DDF97E8B05ACE055E49F3E3F5B928CCD18317A3E68FCB0B6F0459ADF9ECF79C87", + "7B902FC35B0AF50F57F8822936D08A96E41B16967C6B1AA0BC05032F0D53919DC587B664C883E2FE8F3948002FCD8BCBFC4706BCAA2075EF6BF41167" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F"); + + doDualECTest(1, tv); + + tv = new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(128), + true, + "2021222324252627", + 128, + new String[] + { + "8C77288EDBEA9A742464F78D55E33593C1BF5F9D8CD8609D6D53BAC4E4B42252A227A99BAD0F2358B05955CD35723B549401C71C9C1F32F8A2018E24", + "56ECA61C64F69C1C232E992623C71418BD0B96D783118FAAD94A09E3A9DB74D15E805BA7F14625995CA77612B2EF7A05863699ECBABF70D3D422C014" + }); + + doDualECTest(2, tv); + } + + private void doDualECTest(int index, DRBGTestVector tv) + { + SP800SecureRandomBuilder rBuild = new SP800SecureRandomBuilder(new SHA256EntropyProvider()); + + rBuild.setPersonalizationString(tv.personalizationString()); + rBuild.setSecurityStrength(tv.securityStrength()); + rBuild.setEntropyBitsRequired(tv.securityStrength()); + + SecureRandom random = rBuild.buildDualEC(tv.getDigest(), tv.nonce(), tv.predictionResistance()); + + byte[] expected = tv.expectedValue(0); + byte[] produced = new byte[expected.length]; + random.nextBytes(produced); + if (!Arrays.areEqual(expected, produced)) + { + fail(index + " SP800 Dual EC SecureRandom produced incorrect result (1)"); + } + + random.nextBytes(produced); + expected = tv.expectedValue(1); + + if (!Arrays.areEqual(expected, produced)) + { + fail(index + " SP800 Dual EC SecureRandom produced incorrect result (2)"); + } + } + + private void testCTRRandom() + { TestVector tv = new TestVector("a37a3e08d8393feb01c4d78cb6a4d1e210c288c89e9838176bc78946745f1c5bea44cf15e061601bfd45f7b3b95be924", true, "8243299805c0877e", 128, "a05002f98d5676e1b2e3b3d4686bb9055a830a39"); - rBuild.setNonce(tv.nonce()); + SP800SecureRandomBuilder rBuild = new SP800SecureRandomBuilder(new FixedSecureRandom(tv.entropy()), true); + rBuild.setPersonalizationString(tv.personalisation()); rBuild.setSecurityStrength(tv.securityStrength()); - rBuild.setEntropySource(new FixedSecureRandom(tv.entropy()), true); - rBuild.setSeedLength(440); - SecureRandom random = rBuild.build(new AESFastEngine(), 192, true, tv.securityStrength()); + SecureRandom random = rBuild.build(new AESFastEngine(), 192, 440, tv.nonce(), true); byte[] expected = tv.expectedValue(); byte[] produced = new byte[expected.length]; @@ -80,7 +199,9 @@ public class SP800RandomTest throws Exception { testDigestRandom(); + testHMACRandom(); testCTRRandom(); + testDualECRandom(); } public static void main(String[] args) @@ -157,4 +278,31 @@ public class SP800RandomTest } } + + // for HMAC + private class SHA1EntropyProvider + extends TestEntropySourceProvider + { + SHA1EntropyProvider() + { + super( + Hex.decode( + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F30313233343536" + + "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6"), true); + } + } + + // for Dual EC + private class SHA256EntropyProvider + extends TestEntropySourceProvider + { + SHA256EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E0F " + + "808182838485868788898A8B8C8D8E8F" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"), true); + } + } } diff --git a/src/test/java/org/bouncycastle/crypto/test/DRBGTestVector.java b/src/test/java/org/bouncycastle/crypto/test/DRBGTestVector.java index 84c26ec0..f68aa962 100644 --- a/src/test/java/org/bouncycastle/crypto/test/DRBGTestVector.java +++ b/src/test/java/org/bouncycastle/crypto/test/DRBGTestVector.java @@ -58,14 +58,24 @@ public class DRBGTestVector return _pr; } - public String nonce() + public byte[] nonce() { - return _nonce; + if (_nonce == null) + { + return null; + } + + return Hex.decode(_nonce); } - public String personalisation() + public byte[] personalizationString() { - return _personalisation; + if (_personalisation == null) + { + return null; + } + + return Hex.decode(_personalisation); } public int securityStrength() @@ -73,9 +83,9 @@ public class DRBGTestVector return _ss; } - public String[] expectedValue() + public byte[] expectedValue(int index) { - return _ev; + return Hex.decode(_ev[index]); } public byte[] additionalInput(int position) diff --git a/src/test/java/org/bouncycastle/crypto/test/DualECDRBGTest.java b/src/test/java/org/bouncycastle/crypto/test/DualECDRBGTest.java index 7add092a..ec61c9f9 100644 --- a/src/test/java/org/bouncycastle/crypto/test/DualECDRBGTest.java +++ b/src/test/java/org/bouncycastle/crypto/test/DualECDRBGTest.java @@ -270,29 +270,29 @@ public class DualECDRBGTest DRBGTestVector tv = tests[i]; byte[] nonce = Hex.decode(tv.nonce()); - byte[] personalisationString = Hex.decode(tv.personalisation()); + byte[] personalisationString = Hex.decode(tv.personalizationString()); SP80090DRBG d = new DualECSP800DRBG(tv.getDigest(), tv.entropySource(), nonce, personalisationString, tv.securityStrength()); - byte[] output = new byte[tv.expectedValue()[0].length() / 2]; + byte[] output = new byte[tv.expectedValue(0).length]; d.generate(output, tv.additionalInput(0), tv.predictionResistance()); - byte[] expected = Hex.decode(tv.expectedValue()[0]); + byte[] expected = tv.expectedValue(0); if (!areEqual(expected, output)) { - fail("Test #" + (i + 1) + ".1 failed, expected " + tv.expectedValue()[0] + " got " + new String(Hex.encode(output))); + fail("Test #" + (i + 1) + ".1 failed, expected " + new String(Hex.encode(tv.expectedValue(0))) + " got " + new String(Hex.encode(output))); } - output = new byte[tv.expectedValue()[0].length() / 2]; + output = new byte[tv.expectedValue(1).length]; d.generate(output, tv.additionalInput(1), tv.predictionResistance()); - expected = Hex.decode(tv.expectedValue()[1]); + expected = tv.expectedValue(1); if (!areEqual(expected, output)) { - fail("Test #" + (i + 1) + ".2 failed, expected " + tv.expectedValue()[1] + " got " + new String(Hex.encode(output))); + fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output))); } } } diff --git a/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java b/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java index 18bae761..d8209ad7 100644 --- a/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java +++ b/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java @@ -386,29 +386,29 @@ public class HMacDRBGTest DRBGTestVector tv = tests[i]; byte[] nonce = Hex.decode(tv.nonce()); - byte[] personalisationString = Hex.decode(tv.personalisation()); + byte[] personalisationString = Hex.decode(tv.personalizationString()); SP80090DRBG d = new HMacSP800DRBG(new HMac(tv.getDigest()), tv.entropySource(), nonce, personalisationString, tv.securityStrength()); - byte[] output = new byte[tv.expectedValue()[0].length() / 2]; + byte[] output = new byte[tv.expectedValue(0).length]; d.generate(output, tv.additionalInput(0), tv.predictionResistance()); - byte[] expected = Hex.decode(tv.expectedValue()[0]); + byte[] expected = tv.expectedValue(0); if (!areEqual(expected, output)) { - fail("Test #" + (i + 1) + ".1 failed, expected " + tv.expectedValue()[0] + " got " + new String(Hex.encode(output))); + fail("Test #" + (i + 1) + ".1 failed, expected " + new String(Hex.encode(tv.expectedValue(0))) + " got " + new String(Hex.encode(output))); } - output = new byte[tv.expectedValue()[0].length() / 2]; + output = new byte[tv.expectedValue(0).length]; d.generate(output, tv.additionalInput(1), tv.predictionResistance()); - expected = Hex.decode(tv.expectedValue()[1]); + expected = tv.expectedValue(1); if (!areEqual(expected, output)) { - fail("Test #" + (i + 1) + ".2 failed, expected " + tv.expectedValue()[1] + " got " + new String(Hex.encode(output))); + fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output))); } } } diff --git a/src/test/java/org/bouncycastle/crypto/test/HashDRGBTest.java b/src/test/java/org/bouncycastle/crypto/test/HashDRGBTest.java index 5143bc97..933e57f5 100644 --- a/src/test/java/org/bouncycastle/crypto/test/HashDRGBTest.java +++ b/src/test/java/org/bouncycastle/crypto/test/HashDRGBTest.java @@ -6,9 +6,9 @@ import java.util.List; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA1Digest; -import org.bouncycastle.crypto.prng.SP80090DRBG; import org.bouncycastle.crypto.prng.EntropySource; import org.bouncycastle.crypto.prng.HashSP800DRBG; +import org.bouncycastle.crypto.prng.SP80090DRBG; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; import org.bouncycastle.util.test.TestResult; @@ -253,7 +253,7 @@ public class HashDRGBTest extends SimpleTest byte[] nonce = Hex.decode(tv.nonce()); byte[] personalisationString = Hex.decode(tv.personalisation()); int securityStrength = tv.securityStrength(); - SP80090DRBG d = new HashSP800DRBG(digest, 440, tes, nonce, personalisationString, securityStrength); + SP80090DRBG d = new HashSP800DRBG(digest, tes, nonce, personalisationString, securityStrength); byte[] output = new byte[20]; diff --git a/src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java b/src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java index 18ed2894..08576977 100644 --- a/src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java +++ b/src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java @@ -9,7 +9,7 @@ public class TestEntropySourceProvider private final byte[] data; private final boolean isPredictionResistant; - TestEntropySourceProvider(byte[] data, boolean isPredictionResistant) + protected TestEntropySourceProvider(byte[] data, boolean isPredictionResistant) { this.data = data; this.isPredictionResistant = isPredictionResistant; |