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 04:39:58 +0400
committerDavid Hook <dgh@cryptoworkshop.com>2013-05-11 04:39:58 +0400
commitc5bb1a5fdc5cc68a650d97e86039823560525197 (patch)
treec8b5872b8f273d55f89d5c035b459b27eba7c663
parentf733f717fb13387a61dedc0a57d23487069d9b67 (diff)
finishing touches for Hash/HMAC DRBG
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java5
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/EntropySource.java17
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java4
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java55
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java156
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java16
-rw-r--r--src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java37
-rw-r--r--src/main/java/org/bouncycastle/util/Arrays.java10
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java2
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/HashDRBGTest.java2
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java5
11 files changed, 231 insertions, 78 deletions
diff --git a/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java b/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java
index 38527107..9f1d0427 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java
@@ -43,6 +43,11 @@ public class BasicEntropySourceProvider
{
return _sr.generateSeed((bitsRequired + 7) / 8);
}
+
+ public int entropySize()
+ {
+ return bitsRequired;
+ }
};
}
}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/EntropySource.java b/src/main/java/org/bouncycastle/crypto/prng/EntropySource.java
index 56a19711..53bc549d 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/EntropySource.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/EntropySource.java
@@ -2,7 +2,24 @@ package org.bouncycastle.crypto.prng;
public interface EntropySource
{
+ /**
+ * Return whether or not this entropy source is regarded as prediction resistant.
+ *
+ * @return true if it is, false otherwise.
+ */
boolean isPredictionResistant();
+ /**
+ * Return a byte array of entropy.
+ *
+ * @return entropy bytes.
+ */
byte[] getEntropy();
+
+ /**
+ * Return the number of bits of entropy this source can produce.
+ *
+ * @return size in bits of the return value of getEntropy.
+ */
+ int entropySize();
}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java b/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java
index c5c5827a..e517f4de 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java
@@ -174,7 +174,7 @@ public class SP800SecureRandomBuilder
public SP80090DRBG get(EntropySource entropySource)
{
- return new HashSP800DRBG(digest, entropySource, nonce, personalizationString, securityStrength);
+ return new HashSP800DRBG(digest, securityStrength, entropySource, personalizationString, nonce);
}
}
@@ -218,7 +218,7 @@ public class SP800SecureRandomBuilder
public SP80090DRBG get(EntropySource entropySource)
{
- return new HMacSP800DRBG(hMac, entropySource, nonce, personalizationString, securityStrength);
+ return new HMacSP800DRBG(hMac, securityStrength, entropySource, personalizationString, nonce);
}
}
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 de448f7b..6d342309 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java
@@ -5,24 +5,45 @@ import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.prng.EntropySource;
import org.bouncycastle.util.Arrays;
+/**
+ * A SP800-90A HMAC DRBG.
+ */
public class HMacSP800DRBG
implements SP80090DRBG
{
+ private final static int RESEED_MAX = 1 << (48 - 1);
+ private final static int MAX_BITS_REQUEST = 1 << (19 - 1);
+
private byte[] _K;
private byte[] _V;
private int _reseedCounter;
private EntropySource _entropySource;
private Mac _hMac;
- public HMacSP800DRBG(Mac hMac, EntropySource entropySource, byte[] nonce,
- byte[] personalisationString, int securityStrength)
+ /**
+ * Construct a SP800-90A Hash DRBG.
+ *
+ * @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.
+ * @param personalisationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public HMacSP800DRBG(Mac hMac, int securityStrength, EntropySource entropySource, byte[] personalisationString, byte[] nonce)
{
- // TODO: validate security strength
+ if (securityStrength > Utils.getMaxSecurityStrength(hMac))
+ {
+ throw new IllegalArgumentException("Security strength is not supported by the derivation function");
+ }
+
+ if (entropySource.entropySize() < securityStrength)
+ {
+ throw new IllegalArgumentException("Not enough entropy for security strength required");
+ }
_entropySource = entropySource;
_hMac = hMac;
- // TODO: validate entropy length
byte[] entropy = entropySource.getEntropy();
byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalisationString);
@@ -64,12 +85,29 @@ public class HMacSP800DRBG
_hMac.doFinal(_V, 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)
{
- // TODO: check reseed counter
-
int numberOfBits = output.length * 8;
+ if (numberOfBits > MAX_BITS_REQUEST)
+ {
+ throw new IllegalArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST);
+ }
+
+ if (_reseedCounter > RESEED_MAX)
+ {
+ return -1;
+ }
+
if (predictionResistant)
{
reseed(additionalInput);
@@ -114,6 +152,11 @@ public class HMacSP800DRBG
return numberOfBits;
}
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
public void reseed(byte[] additionalInput)
{
byte[] entropy = _entropySource.getEntropy();
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 489054b0..f0c6ead7 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java
@@ -7,10 +7,17 @@ import org.bouncycastle.crypto.prng.EntropySource;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Integers;
-public class HashSP800DRBG implements SP80090DRBG
+/**
+ * A SP800-90A Hash DRBG.
+ */
+public class HashSP800DRBG
+ implements SP80090DRBG
{
private final static byte[] ONE = { 0x01 };
- private final static int RESEED_MAX = 100000;
+
+ private final static int RESEED_MAX = 1 << (48 - 1);
+ private final static int MAX_BITS_REQUEST = 1 << (19 - 1);
+
private final static Hashtable seedlens = new Hashtable();
static
@@ -24,23 +31,35 @@ public class HashSP800DRBG implements SP80090DRBG
seedlens.put("SHA-512", Integers.valueOf(888));
}
- private Digest _digest;
- private byte[] _V;
- private byte[] _C;
- private int _reseedCounter;
+ private Digest _digest;
+ private byte[] _V;
+ private byte[] _C;
+ private int _reseedCounter;
private EntropySource _entropySource;
- private int _securityStrength;
- private int _seedLength;
-
- public HashSP800DRBG(Digest digest, EntropySource entropySource, byte[] nonce,
- byte[] personalisationString, int securityStrength)
+ private int _securityStrength;
+ private int _seedLength;
+
+ /**
+ * Construct a SP800-90A Hash DRBG.
+ *
+ * @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.
+ * @param personalisationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public HashSP800DRBG(Digest digest, int securityStrength, EntropySource entropySource, byte[] personalisationString, byte[] nonce)
{
- if (securityStrength > digest.getDigestSize() * 8) // TODO: this may, or may not be correct, but it's good enough for now
+ if (securityStrength > Utils.getMaxSecurityStrength(digest))
{
- throw new IllegalStateException(
- "Security strength is not supported by the derivation function");
+ throw new IllegalArgumentException("Security strength is not supported by the derivation function");
}
-
+
+ if (entropySource.entropySize() < securityStrength)
+ {
+ throw new IllegalArgumentException("Not enough entropy for security strength required");
+ }
+
_digest = digest;
_entropySource = entropySource;
_securityStrength = securityStrength;
@@ -62,31 +81,47 @@ public class HashSP800DRBG implements SP80090DRBG
byte[] subV = new byte[_V.length + 1];
System.arraycopy(_V, 0, subV, 1, _V.length);
_C = hash_df(subV, _seedLength);
- _reseedCounter = 1;
-
-// System.out.println("Constructor V: "+ new String(Hex.encode(_V)));
-// System.out.println("Constructor C: "+ new String(Hex.encode(_C)));
+ _reseedCounter = 1;
}
- // 1. If reseed_counter > reseed_interval, then return an indication that a
- // reseed is required.
- // 2. If (additional_input != Null), then do
- // 2.1 w = Hash (0x02 || V || additional_input).
- // 2.2 V = (V + w) mod 2^seedlen
- // .
- // 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
- // 4. H = Hash (0x03 || V).
- // 5. V = (V + H + C + reseed_counter) mod 2^seedlen
- // .
- // 6. reseed_counter = reseed_counter + 1.
- // 7. Return SUCCESS, returned_bits, and the new values of V, C, and
- // reseed_counter for the new_working_state.
+ /**
+ * 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)
{
+ // 1. If reseed_counter > reseed_interval, then return an indication that a
+ // reseed is required.
+ // 2. If (additional_input != Null), then do
+ // 2.1 w = Hash (0x02 || V || additional_input).
+ // 2.2 V = (V + w) mod 2^seedlen
+ // .
+ // 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
+ // 4. H = Hash (0x03 || V).
+ // 5. V = (V + H + C + reseed_counter) mod 2^seedlen
+ // .
+ // 6. reseed_counter = reseed_counter + 1.
+ // 7. Return SUCCESS, returned_bits, and the new values of V, C, and
+ // reseed_counter for the new_working_state.
int numberOfBits = output.length*8;
-
- if (predictionResistant || _reseedCounter > RESEED_MAX)
+
+ if (numberOfBits > MAX_BITS_REQUEST)
+ {
+ throw new IllegalArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST);
+ }
+
+ if (_reseedCounter > RESEED_MAX)
+ {
+ return -1;
+ }
+
+ if (predictionResistant)
{
reseed(additionalInput);
additionalInput = null;
@@ -125,11 +160,10 @@ public class HashSP800DRBG implements SP80090DRBG
c[3] = (byte)_reseedCounter;
addTo(_V, c);
+
_reseedCounter++;
System.arraycopy(rv, 0, output, 0, output.length);
-// System.out.println("Generate V: "+ new String(Hex.encode(_V)));
-// System.out.println("Generate C: "+ new String(Hex.encode(_C)));
return numberOfBits;
}
@@ -155,47 +189,37 @@ public class HashSP800DRBG implements SP80090DRBG
}
}
- // 1. seed_material = 0x01 || V || entropy_input || additional_input.
- //
- // 2. seed = Hash_df (seed_material, seedlen).
- //
- // 3. V = seed.
- //
- // 4. C = Hash_df ((0x00 || V), seedlen).
- //
- // 5. reseed_counter = 1.
- //
- // 6. Return V, C, and reseed_counter for the new_working_state.
- //
- // Comment: Precede with a byte of all zeros.
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
public void reseed(byte[] additionalInput)
{
- if (additionalInput == null)
- {
- additionalInput = new byte[0];
- }
-
+ // 1. seed_material = 0x01 || V || entropy_input || additional_input.
+ //
+ // 2. seed = Hash_df (seed_material, seedlen).
+ //
+ // 3. V = seed.
+ //
+ // 4. C = Hash_df ((0x00 || V), seedlen).
+ //
+ // 5. reseed_counter = 1.
+ //
+ // 6. Return V, C, and reseed_counter for the new_working_state.
+ //
+ // Comment: Precede with a byte of all zeros.
byte[] entropy = _entropySource.getEntropy();
-
-// System.out.println("Reseed Entropy: "+ new String(Hex.encode(entropy)));
-
byte[] seedMaterial = Arrays.concatenate(ONE, _V, entropy, additionalInput);
-
-// System.out.println("Reseed SeedMaterial: "+ new String(Hex.encode(seedMaterial)));
-
byte[] seed = hash_df(seedMaterial, _seedLength);
-
-// System.out.println("Reseed Seed: "+ new String(Hex.encode(seed)));
_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);
+
_reseedCounter = 1;
-
-// System.out.println("Reseed V: "+ new String(Hex.encode(_V)));
-// System.out.println("Reseed C: "+ new String(Hex.encode(_C)));
}
@@ -303,4 +327,4 @@ public class HashSP800DRBG implements SP80090DRBG
return W;
}
-}
+} \ No newline at end of file
diff --git a/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java
index c93eb54c..8a132708 100644
--- a/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java
@@ -2,8 +2,22 @@ package org.bouncycastle.crypto.prng.drbg;
public interface SP80090DRBG
{
-
+
+ /**
+ * 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.
+ */
int generate(byte[] output, byte[] additionalInput, boolean predictionResistant);
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
void reseed(byte[] additionalInput);
}
diff --git a/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java b/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java
new file mode 100644
index 00000000..26516dea
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java
@@ -0,0 +1,37 @@
+package org.bouncycastle.crypto.prng.drbg;
+
+import java.util.Hashtable;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.util.Integers;
+
+class Utils
+{
+ static final Hashtable maxSecurityStrengths = new Hashtable();
+
+ static
+ {
+ maxSecurityStrengths.put("SHA-1", Integers.valueOf(128));
+
+ maxSecurityStrengths.put("SHA-224", Integers.valueOf(192));
+ maxSecurityStrengths.put("SHA-256", Integers.valueOf(256));
+ maxSecurityStrengths.put("SHA-384", Integers.valueOf(256));
+ maxSecurityStrengths.put("SHA-512", Integers.valueOf(256));
+
+ maxSecurityStrengths.put("SHA-512/224", Integers.valueOf(192));
+ maxSecurityStrengths.put("SHA-512/256", Integers.valueOf(256));
+ }
+
+ static int getMaxSecurityStrength(Digest d)
+ {
+ return ((Integer)maxSecurityStrengths.get(d.getAlgorithmName())).intValue();
+ }
+
+ static int getMaxSecurityStrength(Mac m)
+ {
+ String name = m.getAlgorithmName();
+
+ return ((Integer)maxSecurityStrengths.get(name.substring(0, name.indexOf("/")))).intValue();
+ }
+}
diff --git a/src/main/java/org/bouncycastle/util/Arrays.java b/src/main/java/org/bouncycastle/util/Arrays.java
index bbabc8b8..6c825cd2 100644
--- a/src/main/java/org/bouncycastle/util/Arrays.java
+++ b/src/main/java/org/bouncycastle/util/Arrays.java
@@ -716,13 +716,21 @@ public final class Arrays
return rv;
}
+ else if (d == null)
+ {
+ return concatenate(a, b, c);
+ }
+ else if (c == null)
+ {
+ return concatenate(a, b, d);
+ }
else if (b == null)
{
return concatenate(a, c, d);
}
else
{
- return concatenate(a, b, d);
+ return concatenate(b, c, d);
}
}
}
diff --git a/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java b/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java
index 06f2b25b..9a154fe5 100644
--- a/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java
+++ b/src/test/java/org/bouncycastle/crypto/test/HMacDRBGTest.java
@@ -388,7 +388,7 @@ public class HMacDRBGTest
byte[] nonce = tv.nonce();
byte[] personalisationString = tv.personalizationString();
- SP80090DRBG d = new HMacSP800DRBG(new HMac(tv.getDigest()), tv.entropySource(), nonce, personalisationString, tv.securityStrength());
+ SP80090DRBG d = new HMacSP800DRBG(new HMac(tv.getDigest()), tv.securityStrength(), tv.entropySource(), personalisationString, nonce);
byte[] output = new byte[tv.expectedValue(0).length];
diff --git a/src/test/java/org/bouncycastle/crypto/test/HashDRBGTest.java b/src/test/java/org/bouncycastle/crypto/test/HashDRBGTest.java
index 93920d64..db194044 100644
--- a/src/test/java/org/bouncycastle/crypto/test/HashDRBGTest.java
+++ b/src/test/java/org/bouncycastle/crypto/test/HashDRBGTest.java
@@ -348,7 +348,7 @@ public class HashDRBGTest
byte[] nonce = tv.nonce();
byte[] personalisationString = tv.personalizationString();
- SP80090DRBG d = new HashSP800DRBG(tv.getDigest(), tv.entropySource(), nonce, personalisationString, tv.securityStrength());
+ SP80090DRBG d = new HashSP800DRBG(tv.getDigest(), tv.securityStrength(), tv.entropySource(), personalisationString, nonce);
byte[] output = new byte[tv.expectedValue(0).length];
diff --git a/src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java b/src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java
index 08576977..9aee5521 100644
--- a/src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java
+++ b/src/test/java/org/bouncycastle/crypto/test/TestEntropySourceProvider.java
@@ -36,6 +36,11 @@ public class TestEntropySourceProvider
return rv;
}
+
+ public int entropySize()
+ {
+ return bitsRequired;
+ }
};
}
}