Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2013-05-07 13:46:36 +0400
committerDavid Hook <dgh@cryptoworkshop.com>2013-05-07 13:46:36 +0400
commit20209c8bfaf3a6998ce63c52b4b315a46e8af229 (patch)
tree9a344313d6c74cbca4ef44a61b89b23ef761c82d
parent5af5e909e4888637ec7618b3ee8a5da8833bbb7b (diff)
further work on SecureRandom implementation, moved seedlen for hash digest into class.
added tests for DualEC and HMAC SecureRandom DRBG.
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java16
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/HMacSP800DRBG.java8
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/HashSP800DRBG.java23
-rw-r--r--src/main/java/org/bouncycastle/crypto/random/SP800SecureRandom.java19
-rw-r--r--src/main/java/org/bouncycastle/crypto/random/SP800SecureRandomBuilder.java155
-rw-r--r--src/test/java/org/bouncycastle/crypto/random/test/SP800RandomTest.java172
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/DRBGTestVector.java22
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/DualECDRBGTest.java14
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java14
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/HashDRGBTest.java4
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java2
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;