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-11 07:35:31 +0400
committerDavid Hook <dgh@cryptoworkshop.com>2013-05-11 07:35:31 +0400
commit90fc0fc0f372ec58fffb5a7a2c7f234040fdefc4 (patch)
treee73667bf1c42eb5b7dea0f258ea0b83ac23d9840
parentdf64b5e5c271bf4cb322871f5b7a6c94f0eb0f5f (diff)
final clean ups, added some exception testing.
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java4
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java120
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java153
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java10
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java81
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java66
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/package.html2
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/AllTests.java39
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/CTRDRBGTest.java (renamed from src/test/java/org/bouncycastle/crypto/test/CTRDRBGTest.java)58
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/DRBGTestVector.java (renamed from src/test/java/org/bouncycastle/crypto/test/DRBGTestVector.java)2
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/DualECDRBGTest.java (renamed from src/test/java/org/bouncycastle/crypto/test/DualECDRBGTest.java)48
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/HMacDRBGTest.java (renamed from src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java)19
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/HashDRBGTest.java (renamed from src/test/java/org/bouncycastle/crypto/test/HashDRBGTest.java)32
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/RegressionTest.java (renamed from src/test/java/org/bouncycastle/crypto/random/test/RegressionTest.java)6
-rw-r--r--src/test/java/org/bouncycastle/crypto/prng/test/SP800RandomTest.java (renamed from src/test/java/org/bouncycastle/crypto/random/test/SP800RandomTest.java)3
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/RegressionTest.java6
16 files changed, 450 insertions, 199 deletions
diff --git a/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java b/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java
index 203d78f9..66f05c5f 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java
@@ -28,7 +28,7 @@ public class SP800SecureRandomBuilder
* 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.
+ * the default SecureRandom does for its generateSeed() call.
* </p>
*/
public SP800SecureRandomBuilder()
@@ -41,7 +41,7 @@ public class SP800SecureRandomBuilder
* 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.
+ * the passed in SecureRandom does for its generateSeed() call.
* </p>
* @param entropySource
* @param predictionResistant
diff --git a/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java
index b33a7664..ae038e7b 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java
@@ -6,10 +6,18 @@ import org.bouncycastle.crypto.prng.EntropySource;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
+/**
+ * A SP800-90A CTR DRBG.
+ */
public class CTRSP800DRBG
implements SP80090DRBG
{
- private EntropySource _entropySource;
+ private static final long TDEA_RESEED_MAX = 1L << (32 - 1);
+ private static final long AES_RESEED_MAX = 1L << (48 - 1);
+ private static final int TDEA_MAX_BITS_REQUEST = 1 << (13 - 1);
+ private static final int AES_MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private EntropySource _entropySource;
private BlockCipher _engine;
private int _keySizeInBits;
private int _seedLength;
@@ -17,28 +25,48 @@ public class CTRSP800DRBG
// internal state
private byte[] _Key;
private byte[] _V;
- private int _reseedCounter = 0;
-
- public CTRSP800DRBG(BlockCipher engine, int keySizeInBits, int securityStrength, EntropySource entropySource, byte[] personalisationString, byte[] nonce)
+ private long _reseedCounter = 0;
+ private boolean _isTDEA = false;
+
+ /**
+ * Construct a SP800-90A CTR DRBG.
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
+ * @param engine underlying block cipher to use to support DRBG
+ * @param keySizeInBits size of the key to use with the block cipher.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public CTRSP800DRBG(BlockCipher engine, int keySizeInBits, int securityStrength, EntropySource entropySource, byte[] personalizationString, byte[] nonce)
{
-
_entropySource = entropySource;
_engine = engine;
_keySizeInBits = keySizeInBits;
_seedLength = keySizeInBits + engine.getBlockSize() * 8;
+ _isTDEA = isTDEA(engine);
- int entropyLengthInBytes = securityStrength;
-
if (securityStrength > 256)
{
- throw new IllegalStateException(
- "Security strength is not supported by the derivation function");
+ throw new IllegalArgumentException("Requested security strength is not supported by the derivation function");
}
-
+
+ if (getMaxSecurityStrength(engine, keySizeInBits) < securityStrength)
+ {
+ throw new IllegalArgumentException("Requested security strength is not supported by block cipher and key size");
+ }
+
+ if (entropySource.entropySize() < securityStrength)
+ {
+ throw new IllegalArgumentException("Not enough entropy for security strength required");
+ }
+
byte[] entropy = entropySource.getEntropy(); // Get_entropy_input
- CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalisationString);
+ CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalizationString);
}
private void CTR_DRBG_Instantiate_algorithm(byte[] entropy, byte[] nonce,
@@ -118,16 +146,6 @@ public class CTRSP800DRBG
// -- Internal state migration ---
private static final byte[] K_BITS = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
-
- private byte[] getBytes(byte[] input)
- {
- byte[] K = new byte[_keySizeInBits / 8];
- System.arraycopy(K_BITS, 0, K, 0, K.length);
- _engine.init(true, new KeyParameter(K));
- byte[] out = new byte[_engine.getBlockSize()];
- _engine.processBlock(input, 0, out, 0);
- return out;
- }
// 1. If (number_of_bits_to_return > max_number_of_bits), then return an
// ERROR_FLAG.
@@ -250,7 +268,6 @@ public class CTRSP800DRBG
return temp;
}
-
/*
* 1. chaining_value = 0^outlen
* . Comment: Set the first chaining value to outlen zeros.
@@ -292,8 +309,42 @@ public class CTRSP800DRBG
buf[offSet + 3] = ((byte)(value));
}
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
public int generate(byte[] output, byte[] additionalInput, boolean predictionResistant)
{
+ if (_isTDEA)
+ {
+ if (_reseedCounter > TDEA_RESEED_MAX)
+ {
+ return -1;
+ }
+
+ if (Utils.isTooLarge(output, TDEA_MAX_BITS_REQUEST / 8))
+ {
+ throw new IllegalArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST);
+ }
+ }
+ else
+ {
+ if (_reseedCounter > AES_RESEED_MAX)
+ {
+ return -1;
+ }
+
+ if (Utils.isTooLarge(output, AES_MAX_BITS_REQUEST / 8))
+ {
+ throw new IllegalArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST);
+ }
+ }
+
if (predictionResistant)
{
CTR_DRBG_Reseed_algorithm(_entropySource, additionalInput);
@@ -327,7 +378,6 @@ public class CTRSP800DRBG
System.arraycopy(out, 0, output, i * out.length, bytesToCopy);
}
-
CTR_DRBG_Update(additionalInput, _Key, _V);
_reseedCounter++;
@@ -335,8 +385,32 @@ public class CTRSP800DRBG
return output.length * 8;
}
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
public void reseed(byte[] additionalInput)
{
CTR_DRBG_Reseed_algorithm(_entropySource, additionalInput);
}
+
+ private boolean isTDEA(BlockCipher cipher)
+ {
+ return cipher.getAlgorithmName().equals("DESede") || cipher.getAlgorithmName().equals("TDEA");
+ }
+
+ private int getMaxSecurityStrength(BlockCipher cipher, int keySizeInBits)
+ {
+ if (isTDEA(cipher) && keySizeInBits == 168)
+ {
+ return 112;
+ }
+ if (cipher.getAlgorithmName().equals("AES"))
+ {
+ return keySizeInBits;
+ }
+
+ return -1;
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java
index ef529a8e..3cee39cb 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java
@@ -11,6 +11,9 @@ import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
+/**
+ * A SP800-90A Dual EC DRBG.
+ */
public class DualECSP800DRBG
implements SP80090DRBG
{
@@ -32,11 +35,14 @@ public class DualECSP800DRBG
private static final BigInteger p521_Qx = new BigInteger("1b9fa3e518d683c6b65763694ac8efbaec6fab44f2276171a42726507dd08add4c3b3f4c1ebc5b1222ddba077f722943b24c3edfa0f85fe24d0c8c01591f0be6f63", 16);
private static final BigInteger p521_Qy = new BigInteger("1f3bdba585295d9a1110d1df1f9430ef8442c5018976ff3437ef91b81dc0b8132c8d5c39c32d0e004a3092b7d327c0e7a4d26d2c7b69b58f9066652911e457779de", 16);
- private final static int RESEED_MAX = 100000;
+ private static final long RESEED_MAX = 1L << (32 - 1);
+ private static final int MAX_ADDITIONAL_INPUT = 1 << (13 - 1);
+ private static final int MAX_ENTROPY_LENGTH = 1 << (13 - 1);
+ private static final int MAX_PERSONALIZATION_STRING = 1 << (13 -1);
private Digest _digest;
- private int _reseedCounter;
- private EntropySource _entropySource;
+ private long _reseedCounter;
+ private EntropySource _entropySource;
private int _securityStrength;
private int _seedlen;
private int _outlen;
@@ -44,11 +50,13 @@ public class DualECSP800DRBG
private ECPoint _P;
private ECPoint _Q;
private byte[] _s;
- private int _sLength;
+ private int _sLength;
/**
* Construct a SP800-90A Dual EC DRBG.
- *
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
* @param digest source digest to use with the DRB stream.
* @param securityStrength security strength required (in bits)
* @param entropySource source of entropy to use for seeding/reseeding.
@@ -57,23 +65,29 @@ public class DualECSP800DRBG
*/
public DualECSP800DRBG(Digest digest, int securityStrength, EntropySource entropySource, byte[] personalizationString, byte[] nonce)
{
- if (securityStrength > digest.getDigestSize() * 8) // TODO: this may, or may not be correct, but it's good enough for now
- {
- throw new IllegalStateException(
- "Security strength is not supported by the derivation function");
- }
-
- // TODO: validate digest choice
_digest = digest;
_entropySource = entropySource;
_securityStrength = securityStrength;
- // TODO: validate entropy length
+ if (Utils.isTooLarge(personalizationString, MAX_PERSONALIZATION_STRING / 8))
+ {
+ throw new IllegalArgumentException("Personalization string too large");
+ }
+
+ if (entropySource.entropySize() < securityStrength || entropySource.entropySize() > MAX_ENTROPY_LENGTH)
+ {
+ throw new IllegalArgumentException("EntropySource must provide between " + securityStrength + " and " + MAX_ENTROPY_LENGTH + " bits");
+ }
+
byte[] entropy = entropySource.getEntropy();
byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalizationString);
if (securityStrength <= 128)
{
+ if (Utils.getMaxSecurityStrength(digest) < 128)
+ {
+ throw new IllegalArgumentException("Requested security strength is not supported by digest");
+ }
_seedlen = 256;
_outlen = 240 / 8;
_curve = (ECCurve.Fp)NISTNamedCurves.getByName("P-256").getCurve();
@@ -82,6 +96,10 @@ public class DualECSP800DRBG
}
else if (securityStrength <= 192)
{
+ if (Utils.getMaxSecurityStrength(digest) < 192)
+ {
+ throw new IllegalArgumentException("Requested security strength is not supported by digest");
+ }
_seedlen = 384;
_outlen = 368 / 8;
_curve = (ECCurve.Fp)NISTNamedCurves.getByName("P-384").getCurve();
@@ -90,6 +108,10 @@ public class DualECSP800DRBG
}
else if (securityStrength <= 256)
{
+ if (Utils.getMaxSecurityStrength(digest) < 256)
+ {
+ throw new IllegalArgumentException("Requested security strength is not supported by digest");
+ }
_seedlen = 521;
_outlen = 504 / 8;
_curve = (ECCurve.Fp)NISTNamedCurves.getByName("P-521").getCurve();
@@ -101,19 +123,37 @@ public class DualECSP800DRBG
throw new IllegalArgumentException("security strength cannot be greater than 256 bits");
}
- _s = hash_df(seedMaterial, _seedlen);
+ _s = Utils.hash_df(_digest, seedMaterial, _seedlen);
_sLength = _s.length;
- //System.err.println(new String(Hex.encode(_s)));
_reseedCounter = 0;
-
}
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
public int generate(byte[] output, byte[] additionalInput, boolean predictionResistant)
{
int numberOfBits = output.length*8;
-
- if (predictionResistant || _reseedCounter > RESEED_MAX)
+ int m = output.length / _outlen;
+
+ if (Utils.isTooLarge(additionalInput, MAX_ADDITIONAL_INPUT / 8))
+ {
+ throw new IllegalArgumentException("Additional input too large");
+ }
+
+ if (_reseedCounter + m > RESEED_MAX)
+ {
+ return -1;
+ }
+
+ if (predictionResistant)
{
reseed(additionalInput);
additionalInput = null;
@@ -122,11 +162,9 @@ public class DualECSP800DRBG
if (additionalInput != null)
{
// Note: we ignore the use of pad8 on the additional input as we mandate byte arrays for it.
- additionalInput = hash_df(additionalInput, _seedlen);
+ additionalInput = Utils.hash_df(_digest, additionalInput, _seedlen);
}
- int m = output.length / _outlen;
-
for (int i = 0; i < m; i++)
{
BigInteger t = new BigInteger(1, xor(_s, additionalInput));
@@ -148,6 +186,8 @@ public class DualECSP800DRBG
//System.err.println("R: " + new String(Hex.encode(r)));
additionalInput = null;
+
+ _reseedCounter++;
}
if (m * _outlen < output.length)
@@ -164,84 +204,29 @@ public class DualECSP800DRBG
// Need to preserve length of S as unsigned int.
_s = BigIntegers.asUnsignedByteArray(_sLength, _P.multiply(new BigInteger(1, _s)).getX().toBigInteger());
- _reseedCounter++;
-
return numberOfBits;
}
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
public void reseed(byte[] additionalInput)
{
- if (additionalInput == null)
+ if (Utils.isTooLarge(additionalInput, MAX_ADDITIONAL_INPUT / 8))
{
- additionalInput = new byte[0];
+ throw new IllegalArgumentException("Additional input string too large");
}
byte[] entropy = _entropySource.getEntropy();
byte[] seedMaterial = Arrays.concatenate(pad8(_s, _seedlen), entropy, additionalInput);
- _s = hash_df(seedMaterial, _seedlen);
+ _s = Utils.hash_df(_digest, seedMaterial, _seedlen);
_reseedCounter = 0;
}
- // 1. temp = the Null string.
- // 2. .
- // 3. counter = an 8-bit binary value representing the integer "1".
- // 4. For i = 1 to len do
- // Comment : In step 4.1, no_of_bits_to_return
- // is used as a 32-bit string.
- // 4.1 temp = temp || Hash (counter || no_of_bits_to_return ||
- // input_string).
- // 4.2 counter = counter + 1.
- // 5. requested_bits = Leftmost (no_of_bits_to_return) of temp.
- // 6. Return SUCCESS and requested_bits.
- private byte[] hash_df(byte[] seedMaterial, int seedLength)
- {
- byte[] temp = new byte[(seedLength + 7) / 8];
-
- int len = temp.length / _digest.getDigestSize();
- int counter = 1;
-
- byte[] dig = new byte[_digest.getDigestSize()];
-
- for (int i = 0; i <= len; i++)
- {
- _digest.update((byte)counter);
-
- _digest.update((byte)(seedLength >> 24));
- _digest.update((byte)(seedLength >> 16));
- _digest.update((byte)(seedLength >> 8));
- _digest.update((byte)seedLength);
-
- _digest.update(seedMaterial, 0, seedMaterial.length);
-
- _digest.doFinal(dig, 0);
-
- int bytesToCopy = ((temp.length - i * dig.length) > dig.length)
- ? dig.length
- : (temp.length - i * dig.length);
- System.arraycopy(dig, 0, temp, i * dig.length, bytesToCopy);
-
- counter++;
- }
-
- // do a left shift to get rid of excess bits.
- if (seedLength % 8 != 0)
- {
- int shift = 8 - (seedLength % 8);
- int carry = 0;
-
- for (int i = 0; i != temp.length; i++)
- {
- int b = temp[i] & 0xff;
- temp[i] = (byte)((b >>> shift) | (carry << (8 - shift)));
- carry = b;
- }
- }
-
- return temp;
- }
-
private byte[] xor(byte[] a, byte[] b)
{
if (b == null)
diff --git a/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java
index 11bdf963..3ddeaac6 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java
@@ -11,18 +11,20 @@ import org.bouncycastle.util.Arrays;
public class HMacSP800DRBG
implements SP80090DRBG
{
- private final static int RESEED_MAX = 1 << (48 - 1);
+ private final static long RESEED_MAX = 1L << (48 - 1);
private final static int MAX_BITS_REQUEST = 1 << (19 - 1);
private byte[] _K;
private byte[] _V;
- private int _reseedCounter;
+ private long _reseedCounter;
private EntropySource _entropySource;
private Mac _hMac;
/**
* Construct a SP800-90A Hash DRBG.
- *
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
* @param hMac Hash MAC to base the DRBG on.
* @param securityStrength security strength required (in bits)
* @param entropySource source of entropy to use for seeding/reseeding.
@@ -33,7 +35,7 @@ public class HMacSP800DRBG
{
if (securityStrength > Utils.getMaxSecurityStrength(hMac))
{
- throw new IllegalArgumentException("Security strength is not supported by the derivation function");
+ throw new IllegalArgumentException("Requested security strength is not supported by the derivation function");
}
if (entropySource.entropySize() < securityStrength)
diff --git a/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java
index 9a318ed1..4ed57163 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java
@@ -15,7 +15,7 @@ public class HashSP800DRBG
{
private final static byte[] ONE = { 0x01 };
- private final static int RESEED_MAX = 1 << (48 - 1);
+ private final static long RESEED_MAX = 1L << (48 - 1);
private final static int MAX_BITS_REQUEST = 1 << (19 - 1);
private final static Hashtable seedlens = new Hashtable();
@@ -34,14 +34,16 @@ public class HashSP800DRBG
private Digest _digest;
private byte[] _V;
private byte[] _C;
- private int _reseedCounter;
+ private long _reseedCounter;
private EntropySource _entropySource;
private int _securityStrength;
private int _seedLength;
/**
* Construct a SP800-90A Hash DRBG.
- *
+ * <p>
+ * Minimum entropy requirement is the security strength requested.
+ * </p>
* @param digest source digest to use for DRB stream.
* @param securityStrength security strength required (in bits)
* @param entropySource source of entropy to use for seeding/reseeding.
@@ -52,7 +54,7 @@ public class HashSP800DRBG
{
if (securityStrength > Utils.getMaxSecurityStrength(digest))
{
- throw new IllegalArgumentException("Security strength is not supported by the derivation function");
+ throw new IllegalArgumentException("Requested security strength is not supported by the derivation function");
}
if (entropySource.entropySize() < securityStrength)
@@ -75,12 +77,12 @@ public class HashSP800DRBG
byte[] entropy = entropySource.getEntropy();
byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalizationString);
- byte[] seed = hash_df(seedMaterial, _seedLength);
+ byte[] seed = Utils.hash_df(_digest, seedMaterial, _seedLength);
_V = seed;
byte[] subV = new byte[_V.length + 1];
System.arraycopy(_V, 0, subV, 1, _V.length);
- _C = hash_df(subV, _seedLength);
+ _C = Utils.hash_df(_digest, subV, _seedLength);
_reseedCounter = 1;
}
@@ -211,80 +213,17 @@ public class HashSP800DRBG
// Comment: Precede with a byte of all zeros.
byte[] entropy = _entropySource.getEntropy();
byte[] seedMaterial = Arrays.concatenate(ONE, _V, entropy, additionalInput);
- byte[] seed = hash_df(seedMaterial, _seedLength);
+ byte[] seed = Utils.hash_df(_digest, seedMaterial, _seedLength);
_V = seed;
byte[] subV = new byte[_V.length + 1];
subV[0] = 0x00;
System.arraycopy(_V, 0, subV, 1, _V.length);
- _C = hash_df(subV, _seedLength);
+ _C = Utils.hash_df(_digest, subV, _seedLength);
_reseedCounter = 1;
}
-
- // ---- Internal manipulation ---
- // ---- Migrating from the external HashDF class --
-
-
- // 1. temp = the Null string.
- // 2. .
- // 3. counter = an 8-bit binary value representing the integer "1".
- // 4. For i = 1 to len do
- // Comment : In step 4.1, no_of_bits_to_return
- // is used as a 32-bit string.
- // 4.1 temp = temp || Hash (counter || no_of_bits_to_return ||
- // input_string).
- // 4.2 counter = counter + 1.
- // 5. requested_bits = Leftmost (no_of_bits_to_return) of temp.
- // 6. Return SUCCESS and requested_bits.
- private byte[] hash_df(byte[] seedMaterial, int seedLength)
- {
- byte[] temp = new byte[seedLength / 8];
-
- int len = temp.length / _digest.getDigestSize();
- int counter = 1;
-
- byte[] dig = new byte[_digest.getDigestSize()];
-
- for (int i = 0; i <= len; i++)
- {
- _digest.update((byte)counter);
-
- _digest.update((byte)(seedLength >> 24));
- _digest.update((byte)(seedLength >> 16));
- _digest.update((byte)(seedLength >> 8));
- _digest.update((byte)seedLength);
-
- _digest.update(seedMaterial, 0, seedMaterial.length);
-
- _digest.doFinal(dig, 0);
-
- int bytesToCopy = ((temp.length - i * dig.length) > dig.length)
- ? dig.length
- : (temp.length - i * dig.length);
- System.arraycopy(dig, 0, temp, i * dig.length, bytesToCopy);
-
- counter++;
- }
-
- // do a left shift to get rid of excess bits.
- if (seedLength % 8 != 0)
- {
- int shift = 8 - (seedLength % 8);
- int carry = 0;
-
- for (int i = 0; i != temp.length; i++)
- {
- int b = temp[i] & 0xff;
- temp[i] = (byte)((b >>> shift) | (carry << (8 - shift)));
- carry = b;
- }
- }
-
- return temp;
- }
-
private byte[] hash(byte[] input)
{
_digest.update(input, 0, input.length);
diff --git a/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java
index 26516dea..f7a41176 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java
@@ -34,4 +34,70 @@ class Utils
return ((Integer)maxSecurityStrengths.get(name.substring(0, name.indexOf("/")))).intValue();
}
+
+ /**
+ * Used by both Dual EC and Hash.
+ */
+ static byte[] hash_df(Digest digest, byte[] seedMaterial, int seedLength)
+ {
+ // 1. temp = the Null string.
+ // 2. .
+ // 3. counter = an 8-bit binary value representing the integer "1".
+ // 4. For i = 1 to len do
+ // Comment : In step 4.1, no_of_bits_to_return
+ // is used as a 32-bit string.
+ // 4.1 temp = temp || Hash (counter || no_of_bits_to_return ||
+ // input_string).
+ // 4.2 counter = counter + 1.
+ // 5. requested_bits = Leftmost (no_of_bits_to_return) of temp.
+ // 6. Return SUCCESS and requested_bits.
+ byte[] temp = new byte[(seedLength + 7) / 8];
+
+ int len = temp.length / digest.getDigestSize();
+ int counter = 1;
+
+ byte[] dig = new byte[digest.getDigestSize()];
+
+ for (int i = 0; i <= len; i++)
+ {
+ digest.update((byte)counter);
+
+ digest.update((byte)(seedLength >> 24));
+ digest.update((byte)(seedLength >> 16));
+ digest.update((byte)(seedLength >> 8));
+ digest.update((byte)seedLength);
+
+ digest.update(seedMaterial, 0, seedMaterial.length);
+
+ digest.doFinal(dig, 0);
+
+ int bytesToCopy = ((temp.length - i * dig.length) > dig.length)
+ ? dig.length
+ : (temp.length - i * dig.length);
+ System.arraycopy(dig, 0, temp, i * dig.length, bytesToCopy);
+
+ counter++;
+ }
+
+ // do a left shift to get rid of excess bits.
+ if (seedLength % 8 != 0)
+ {
+ int shift = 8 - (seedLength % 8);
+ int carry = 0;
+
+ for (int i = 0; i != temp.length; i++)
+ {
+ int b = temp[i] & 0xff;
+ temp[i] = (byte)((b >>> shift) | (carry << (8 - shift)));
+ carry = b;
+ }
+ }
+
+ return temp;
+ }
+
+ static boolean isTooLarge(byte[] bytes, int maxBytes)
+ {
+ return bytes != null && bytes.length > maxBytes;
+ }
}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/drbg/package.html b/src/main/java/org/bouncycastle/crypto/prng/drbg/package.html
index b86c2064..c0061660 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/drbg/package.html
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/package.html
@@ -1,5 +1,5 @@
<html>
<body bgcolor="#ffffff">
-SP800-90A deterministic random bit generators.
+SP800-90A deterministic random bit generators, can be used stand alone or in conjunction with SP800SecureRandomBuilder class.
</body>
</html>
diff --git a/src/test/java/org/bouncycastle/crypto/prng/test/AllTests.java b/src/test/java/org/bouncycastle/crypto/prng/test/AllTests.java
new file mode 100644
index 00000000..4c0504f8
--- /dev/null
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/AllTests.java
@@ -0,0 +1,39 @@
+package org.bouncycastle.crypto.prng.test;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.bouncycastle.util.test.SimpleTestResult;
+
+public class AllTests
+ extends TestCase
+{
+ public void testCrypto()
+ {
+ org.bouncycastle.util.test.Test[] tests = RegressionTest.tests;
+
+ for (int i = 0; i != tests.length; i++)
+ {
+ SimpleTestResult result = (SimpleTestResult)tests[i].perform();
+
+ if (!result.isSuccessful())
+ {
+ fail(result.toString());
+ }
+ }
+ }
+
+ public static void main (String[] args)
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite("Lightweight Crypto PRNG Tests");
+
+ suite.addTestSuite(AllTests.class);
+
+ return suite;
+ }
+}
diff --git a/src/test/java/org/bouncycastle/crypto/test/CTRDRBGTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/CTRDRBGTest.java
index c5f2b9d2..45376ace 100644
--- a/src/test/java/org/bouncycastle/crypto/test/CTRDRBGTest.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/CTRDRBGTest.java
@@ -1,9 +1,11 @@
-package org.bouncycastle.crypto.test;
+package org.bouncycastle.crypto.prng.test;
+import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.prng.drbg.CTRSP800DRBG;
import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
+import org.bouncycastle.crypto.test.TestEntropySourceProvider;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -334,6 +336,60 @@ public class CTRDRBGTest
fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output)));
}
}
+
+ // Exception tests
+ SP80090DRBG d;
+ try
+ {
+ d = new CTRSP800DRBG(new AESEngine(), 256, 256, new Bit232EntropyProvider().get(128), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Not enough entropy for security strength required"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new CTRSP800DRBG(new DESedeEngine(), 256, 256, new Bit232EntropyProvider().get(232), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Requested security strength is not supported by block cipher and key size"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new CTRSP800DRBG(new DESedeEngine(), 168, 256, new Bit232EntropyProvider().get(232), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Requested security strength is not supported by block cipher and key size"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new CTRSP800DRBG(new AESEngine(), 192, 256, new Bit232EntropyProvider().get(232), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Requested security strength is not supported by block cipher and key size"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
}
private class Bit232EntropyProvider
diff --git a/src/test/java/org/bouncycastle/crypto/test/DRBGTestVector.java b/src/test/java/org/bouncycastle/crypto/prng/test/DRBGTestVector.java
index 482db87b..dd6801c5 100644
--- a/src/test/java/org/bouncycastle/crypto/test/DRBGTestVector.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/DRBGTestVector.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.crypto.test;
+package org.bouncycastle.crypto.prng.test;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/test/java/org/bouncycastle/crypto/test/DualECDRBGTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/DualECDRBGTest.java
index 9ae53bfb..9e33cbaf 100644
--- a/src/test/java/org/bouncycastle/crypto/test/DualECDRBGTest.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/DualECDRBGTest.java
@@ -1,15 +1,17 @@
-package org.bouncycastle.crypto.test;
+package org.bouncycastle.crypto.prng.test;
+import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.prng.drbg.DualECSP800DRBG;
import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
+import org.bouncycastle.crypto.test.TestEntropySourceProvider;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
/**
- * Dual EC SP800-90 DRBG
+ * Dual EC SP800-90 DRBG test
*/
public class DualECDRBGTest
extends SimpleTest
@@ -295,6 +297,48 @@ public class DualECDRBGTest
fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output)));
}
}
+
+ // Exception tests
+ //
+ SP80090DRBG d;
+ try
+ {
+ d = new DualECSP800DRBG(new SHA256Digest(), 256, new SHA256EntropyProvider().get(128), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("EntropySource must provide between 256 and 4096 bits"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new DualECSP800DRBG(new SHA256Digest(), 256, new SHA256EntropyProvider().get(1 << (13 - 1) + 1), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("EntropySource must provide between 256 and 4096 bits"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new DualECSP800DRBG(new SHA1Digest(), 256, new SHA256EntropyProvider().get(256), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Requested security strength is not supported by digest"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
}
private class SHA256EntropyProvider
diff --git a/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/HMacDRBGTest.java
index 9a154fe5..697f7b15 100644
--- a/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/HMacDRBGTest.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.crypto.test;
+package org.bouncycastle.crypto.prng.test;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
@@ -7,6 +7,7 @@ import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.prng.drbg.HMacSP800DRBG;
import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
+import org.bouncycastle.crypto.test.TestEntropySourceProvider;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -411,6 +412,22 @@ public class HMacDRBGTest
fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output)));
}
}
+
+ // Exception tests
+ //
+ SP80090DRBG d;
+ try
+ {
+ d = new HMacSP800DRBG(new HMac(new SHA256Digest()), 256, new SHA256EntropyProvider().get(128), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Not enough entropy for security strength required"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
}
private class SHA1EntropyProvider
diff --git a/src/test/java/org/bouncycastle/crypto/test/HashDRBGTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/HashDRBGTest.java
index db194044..beacc321 100644
--- a/src/test/java/org/bouncycastle/crypto/test/HashDRBGTest.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/HashDRBGTest.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.crypto.test;
+package org.bouncycastle.crypto.prng.test;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
@@ -6,6 +6,7 @@ import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.prng.drbg.HashSP800DRBG;
import org.bouncycastle.crypto.prng.drbg.SP80090DRBG;
+import org.bouncycastle.crypto.test.TestEntropySourceProvider;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -371,6 +372,35 @@ public class HashDRBGTest
fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output)));
}
}
+
+ // Exception tests
+ //
+ SP80090DRBG d;
+ try
+ {
+ d = new HashSP800DRBG(new SHA256Digest(), 256, new SHA256EntropyProvider().get(128), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Not enough entropy for security strength required"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
+
+ try
+ {
+ d = new HashSP800DRBG(new SHA1Digest(), 256, new SHA256EntropyProvider().get(256), null, null);
+ fail("no exception thrown");
+ }
+ catch (IllegalArgumentException e)
+ {
+ if (!e.getMessage().equals("Requested security strength is not supported by the derivation function"))
+ {
+ fail("Wrong exception", e);
+ }
+ }
}
private class SHA1EntropyProvider
diff --git a/src/test/java/org/bouncycastle/crypto/random/test/RegressionTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/RegressionTest.java
index e2f1e79c..d1f6f435 100644
--- a/src/test/java/org/bouncycastle/crypto/random/test/RegressionTest.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/RegressionTest.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.crypto.random.test;
+package org.bouncycastle.crypto.prng.test;
import org.bouncycastle.util.test.Test;
import org.bouncycastle.util.test.TestResult;
@@ -6,6 +6,10 @@ import org.bouncycastle.util.test.TestResult;
public class RegressionTest
{
public static Test[] tests = {
+ new CTRDRBGTest(),
+ new DualECDRBGTest(),
+ new HashDRBGTest(),
+ new HMacDRBGTest(),
new SP800RandomTest()
};
diff --git a/src/test/java/org/bouncycastle/crypto/random/test/SP800RandomTest.java b/src/test/java/org/bouncycastle/crypto/prng/test/SP800RandomTest.java
index 5a7ad692..c0cbb276 100644
--- a/src/test/java/org/bouncycastle/crypto/random/test/SP800RandomTest.java
+++ b/src/test/java/org/bouncycastle/crypto/prng/test/SP800RandomTest.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.crypto.random.test;
+package org.bouncycastle.crypto.prng.test;
import java.security.SecureRandom;
@@ -7,7 +7,6 @@ import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.prng.SP800SecureRandomBuilder;
-import org.bouncycastle.crypto.test.DRBGTestVector;
import org.bouncycastle.crypto.test.TestEntropySourceProvider;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
diff --git a/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java b/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
index aea3003d..90e63879 100644
--- a/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
+++ b/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
@@ -112,11 +112,7 @@ public class RegressionTest
new NullTest(),
new DSTU4145Test(),
new SipHashTest(),
- new OCBTest(),
- new HashDRBGTest(),
- new HMacDRBGTest(),
- new CTRDRBGTest(),
- new DualECDRBGTest()
+ new OCBTest()
};
public static void main(