diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg')
8 files changed, 0 insertions, 1488 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java b/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java deleted file mode 100644 index 5701199..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java +++ /dev/null @@ -1,481 +0,0 @@ -package org.bouncycastle.crypto.prng.drbg; - -import org.bouncycastle.crypto.BlockCipher; -import org.bouncycastle.crypto.params.KeyParameter; -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 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; - - // internal state - private byte[] _Key; - private byte[] _V; - 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); - - if (securityStrength > 256) - { - 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, personalizationString); - } - - private void CTR_DRBG_Instantiate_algorithm(byte[] entropy, byte[] nonce, - byte[] personalisationString) - { - byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalisationString); - byte[] seed = Block_Cipher_df(seedMaterial, _seedLength); - - int outlen = _engine.getBlockSize(); - - _Key = new byte[(_keySizeInBits + 7) / 8]; - _V = new byte[outlen]; - - // _Key & _V are modified by this call - CTR_DRBG_Update(seed, _Key, _V); - - _reseedCounter = 1; - } - - private void CTR_DRBG_Update(byte[] seed, byte[] key, byte[] v) - { - byte[] temp = new byte[seed.length]; - byte[] outputBlock = new byte[_engine.getBlockSize()]; - - int i=0; - int outLen = _engine.getBlockSize(); - - _engine.init(true, new KeyParameter(expandKey(key))); - while (i*outLen < seed.length) - { - addOneTo(v); - _engine.processBlock(v, 0, outputBlock, 0); - - int bytesToCopy = ((temp.length - i * outLen) > outLen) - ? outLen : (temp.length - i * outLen); - - System.arraycopy(outputBlock, 0, temp, i * outLen, bytesToCopy); - ++i; - } - - XOR(temp, seed, temp, 0); - - System.arraycopy(temp, 0, key, 0, key.length); - System.arraycopy(temp, key.length, v, 0, v.length); - } - - private void CTR_DRBG_Reseed_algorithm(EntropySource entropy, byte[] additionalInput) - { - byte[] seedMaterial = Arrays.concatenate(entropy.getEntropy(), additionalInput); - - seedMaterial = Block_Cipher_df(seedMaterial, _seedLength); - - CTR_DRBG_Update(seedMaterial, _Key, _V); - - _reseedCounter = 1; - } - - private void XOR(byte[] out, byte[] a, byte[] b, int bOff) - { - for (int i=0; i< out.length; i++) - { - out[i] = (byte)(a[i] ^ b[i+bOff]); - } - } - - private void addOneTo(byte[] longer) - { - int carry = 1; - for (int i = 1; i <= longer.length; i++) // warning - { - int res = (longer[longer.length - i] & 0xff) + carry; - carry = (res > 0xff) ? 1 : 0; - longer[longer.length - i] = (byte)res; - } - } - - // -- Internal state migration --- - - private static final byte[] K_BITS = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); - - // 1. If (number_of_bits_to_return > max_number_of_bits), then return an - // ERROR_FLAG. - // 2. L = len (input_string)/8. - // 3. N = number_of_bits_to_return/8. - // Comment: L is the bitstring represention of - // the integer resulting from len (input_string)/8. - // L shall be represented as a 32-bit integer. - // - // Comment : N is the bitstring represention of - // the integer resulting from - // number_of_bits_to_return/8. N shall be - // represented as a 32-bit integer. - // - // 4. S = L || N || input_string || 0x80. - // 5. While (len (S) mod outlen) - // Comment : Pad S with zeros, if necessary. - // 0, S = S || 0x00. - // - // Comment : Compute the starting value. - // 6. temp = the Null string. - // 7. i = 0. - // 8. K = Leftmost keylen bits of 0x00010203...1D1E1F. - // 9. While len (temp) < keylen + outlen, do - // - // IV = i || 0outlen - len (i). - // - // 9.1 - // - // temp = temp || BCC (K, (IV || S)). - // - // 9.2 - // - // i = i + 1. - // - // 9.3 - // - // Comment : i shall be represented as a 32-bit - // integer, i.e., len (i) = 32. - // - // Comment: The 32-bit integer represenation of - // i is padded with zeros to outlen bits. - // - // Comment: Compute the requested number of - // bits. - // - // 10. K = Leftmost keylen bits of temp. - // - // 11. X = Next outlen bits of temp. - // - // 12. temp = the Null string. - // - // 13. While len (temp) < number_of_bits_to_return, do - // - // 13.1 X = Block_Encrypt (K, X). - // - // 13.2 temp = temp || X. - // - // 14. requested_bits = Leftmost number_of_bits_to_return of temp. - // - // 15. Return SUCCESS and requested_bits. - private byte[] Block_Cipher_df(byte[] inputString, int bitLength) - { - int outLen = _engine.getBlockSize(); - int L = inputString.length; // already in bytes - int N = bitLength / 8; - // 4 S = L || N || inputstring || 0x80 - int sLen = 4 + 4 + L + 1; - int blockLen = ((sLen + outLen - 1) / outLen) * outLen; - byte[] S = new byte[blockLen]; - copyIntToByteArray(S, L, 0); - copyIntToByteArray(S, N, 4); - System.arraycopy(inputString, 0, S, 8, L); - S[8 + L] = (byte)0x80; - // S already padded with zeros - - byte[] temp = new byte[_keySizeInBits / 8 + outLen]; - byte[] bccOut = new byte[outLen]; - - byte[] IV = new byte[outLen]; - - int i = 0; - byte[] K = new byte[_keySizeInBits / 8]; - System.arraycopy(K_BITS, 0, K, 0, K.length); - - while (i*outLen*8 < _keySizeInBits + outLen *8) - { - copyIntToByteArray(IV, i, 0); - BCC(bccOut, K, IV, S); - - int bytesToCopy = ((temp.length - i * outLen) > outLen) - ? outLen - : (temp.length - i * outLen); - - System.arraycopy(bccOut, 0, temp, i * outLen, bytesToCopy); - ++i; - } - - byte[] X = new byte[outLen]; - System.arraycopy(temp, 0, K, 0, K.length); - System.arraycopy(temp, K.length, X, 0, X.length); - - temp = new byte[bitLength / 2]; - - i = 0; - _engine.init(true, new KeyParameter(expandKey(K))); - - while (i * outLen < temp.length) - { - _engine.processBlock(X, 0, X, 0); - - int bytesToCopy = ((temp.length - i * outLen) > outLen) - ? outLen - : (temp.length - i * outLen); - - System.arraycopy(X, 0, temp, i * outLen, bytesToCopy); - i++; - } - - return temp; - } - - /* - * 1. chaining_value = 0^outlen - * . Comment: Set the first chaining value to outlen zeros. - * 2. n = len (data)/outlen. - * 3. Starting with the leftmost bits of data, split the data into n blocks of outlen bits - * each, forming block(1) to block(n). - * 4. For i = 1 to n do - * 4.1 input_block = chaining_value ^ block(i) . - * 4.2 chaining_value = Block_Encrypt (Key, input_block). - * 5. output_block = chaining_value. - * 6. Return output_block. - */ - private void BCC(byte[] bccOut, byte[] k, byte[] iV, byte[] data) - { - int outlen = _engine.getBlockSize(); - byte[] chainingValue = new byte[outlen]; // initial values = 0 - int n = data.length / outlen; - - byte[] inputBlock = new byte[outlen]; - - _engine.init(true, new KeyParameter(expandKey(k))); - - _engine.processBlock(iV, 0, chainingValue, 0); - - for (int i = 0; i < n; i++) - { - XOR(inputBlock, chainingValue, data, i*outlen); - _engine.processBlock(inputBlock, 0, chainingValue, 0); - } - - System.arraycopy(chainingValue, 0, bccOut, 0, bccOut.length); - } - - private void copyIntToByteArray(byte[] buf, int value, int offSet) - { - buf[offSet + 0] = ((byte)(value >> 24)); - buf[offSet + 1] = ((byte)(value >> 16)); - buf[offSet + 2] = ((byte)(value >> 8)); - buf[offSet + 3] = ((byte)(value)); - } - - /** - * Return the block size (in bits) of the DRBG. - * - * @return the number of bits produced on each internal round of the DRBG. - */ - public int getBlockSize() - { - return _V.length * 8; - } - - /** - * 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); - additionalInput = null; - } - - if (additionalInput != null) - { - additionalInput = Block_Cipher_df(additionalInput, _seedLength); - CTR_DRBG_Update(additionalInput, _Key, _V); - } - else - { - additionalInput = new byte[_seedLength]; - } - - byte[] out = new byte[_V.length]; - - _engine.init(true, new KeyParameter(expandKey(_Key))); - - for (int i = 0; i <= output.length / out.length; i++) - { - int bytesToCopy = ((output.length - i * out.length) > out.length) - ? out.length - : (output.length - i * _V.length); - - if (bytesToCopy != 0) - { - addOneTo(_V); - - _engine.processBlock(_V, 0, out, 0); - - System.arraycopy(out, 0, output, i * out.length, bytesToCopy); - } - } - - CTR_DRBG_Update(additionalInput, _Key, _V); - - _reseedCounter++; - - 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; - } - - byte[] expandKey(byte[] key) - { - if (_isTDEA) - { - // expand key to 192 bits. - byte[] tmp = new byte[24]; - - padKey(key, 0, tmp, 0); - padKey(key, 7, tmp, 8); - padKey(key, 14, tmp, 16); - - return tmp; - } - else - { - return key; - } - } - - /** - * Pad out a key for TDEA, setting odd parity for each byte. - * - * @param keyMaster - * @param keyOff - * @param tmp - * @param tmpOff - */ - private void padKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff) - { - tmp[tmpOff + 0] = (byte)(keyMaster[keyOff + 0] & 0xfe); - tmp[tmpOff + 1] = (byte)((keyMaster[keyOff + 0] << 7) | ((keyMaster[keyOff + 1] & 0xfc) >>> 1)); - tmp[tmpOff + 2] = (byte)((keyMaster[keyOff + 1] << 6) | ((keyMaster[keyOff + 2] & 0xf8) >>> 2)); - tmp[tmpOff + 3] = (byte)((keyMaster[keyOff + 2] << 5) | ((keyMaster[keyOff + 3] & 0xf0) >>> 3)); - tmp[tmpOff + 4] = (byte)((keyMaster[keyOff + 3] << 4) | ((keyMaster[keyOff + 4] & 0xe0) >>> 4)); - tmp[tmpOff + 5] = (byte)((keyMaster[keyOff + 4] << 3) | ((keyMaster[keyOff + 5] & 0xc0) >>> 5)); - tmp[tmpOff + 6] = (byte)((keyMaster[keyOff + 5] << 2) | ((keyMaster[keyOff + 6] & 0x80) >>> 6)); - tmp[tmpOff + 7] = (byte)(keyMaster[keyOff + 6] << 1); - - for (int i = tmpOff; i <= tmpOff + 7; i++) - { - int b = tmp[i]; - tmp[i] = (byte)((b & 0xfe) | - ((((b >> 1) ^ - (b >> 2) ^ - (b >> 3) ^ - (b >> 4) ^ - (b >> 5) ^ - (b >> 6) ^ - (b >> 7)) ^ 0x01) & 0x01)); - } - } -} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECPoints.java b/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECPoints.java deleted file mode 100644 index 7dcfa94..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECPoints.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.bouncycastle.crypto.prng.drbg; - -import org.bouncycastle.math.ec.ECPoint; - -/** - * General class for providing point pairs for use with DualEC DRBG. See NIST SP 800-90A for further details. - */ -public class DualECPoints -{ - private final ECPoint p; - private final ECPoint q; - private final int securityStrength; - private final int cofactor; - - /** - * Base Constructor. - * <p> - * The cofactor is used to calculate the output block length (maxOutlen) according to - * <pre> - * max_outlen = largest multiple of 8 less than ((field size in bits) - (13 + log2(cofactor)) - * </pre> - * - * @param securityStrength maximum security strength to be associated with these parameters - * @param p the P point. - * @param q the Q point. - * @param cofactor cofactor associated with the domain parameters for the point generation. - */ - public DualECPoints(int securityStrength, ECPoint p, ECPoint q, int cofactor) - { - if (!p.getCurve().equals(q.getCurve())) - { - throw new IllegalArgumentException("points need to be on the same curve"); - } - - this.securityStrength = securityStrength; - this.p = p; - this.q = q; - this.cofactor = cofactor; - } - - public int getSeedLen() - { - return p.getCurve().getFieldSize(); - } - - public int getMaxOutlen() - { - return ((p.getCurve().getFieldSize() - (13 + log2(cofactor))) / 8) * 8; - } - - public ECPoint getP() - { - return p; - } - - public ECPoint getQ() - { - return q; - } - - public int getSecurityStrength() - { - return securityStrength; - } - - public int getCofactor() - { - return cofactor; - } - - private static int log2(int value) - { - int log = 0; - - while ((value >>= 1) != 0) - { - log++; - } - - return log; - } -} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java b/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java deleted file mode 100644 index 4e1b881..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java +++ /dev/null @@ -1,320 +0,0 @@ -package org.bouncycastle.crypto.prng.drbg; - -import java.math.BigInteger; - -import org.bouncycastle.asn1.nist.NISTNamedCurves; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.prng.EntropySource; -import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.math.ec.ECMultiplier; -import org.bouncycastle.math.ec.ECPoint; -import org.bouncycastle.math.ec.FixedPointCombMultiplier; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.BigIntegers; - -/** - * A SP800-90A Dual EC DRBG. - */ -public class DualECSP800DRBG - implements SP80090DRBG -{ - /* - * Default P, Q values for each curve - */ - private static final BigInteger p256_Px = new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16); - private static final BigInteger p256_Py = new BigInteger("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16); - private static final BigInteger p256_Qx = new BigInteger("c97445f45cdef9f0d3e05e1e585fc297235b82b5be8ff3efca67c59852018192", 16); - private static final BigInteger p256_Qy = new BigInteger("b28ef557ba31dfcbdd21ac46e2a91e3c304f44cb87058ada2cb815151e610046", 16); - - private static final BigInteger p384_Px = new BigInteger("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", 16); - private static final BigInteger p384_Py = new BigInteger("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", 16); - private static final BigInteger p384_Qx = new BigInteger("8e722de3125bddb05580164bfe20b8b432216a62926c57502ceede31c47816edd1e89769124179d0b695106428815065", 16); - private static final BigInteger p384_Qy = new BigInteger("023b1660dd701d0839fd45eec36f9ee7b32e13b315dc02610aa1b636e346df671f790f84c5e09b05674dbb7e45c803dd", 16); - - private static final BigInteger p521_Px = new BigInteger("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16); - private static final BigInteger p521_Py = new BigInteger("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16); - private static final BigInteger p521_Qx = new BigInteger("1b9fa3e518d683c6b65763694ac8efbaec6fab44f2276171a42726507dd08add4c3b3f4c1ebc5b1222ddba077f722943b24c3edfa0f85fe24d0c8c01591f0be6f63", 16); - private static final BigInteger p521_Qy = new BigInteger("1f3bdba585295d9a1110d1df1f9430ef8442c5018976ff3437ef91b81dc0b8132c8d5c39c32d0e004a3092b7d327c0e7a4d26d2c7b69b58f9066652911e457779de", 16); - - private static final DualECPoints[] nistPoints; - - static - { - nistPoints = new DualECPoints[3]; - - ECCurve.Fp curve = (ECCurve.Fp)NISTNamedCurves.getByName("P-256").getCurve(); - - nistPoints[0] = new DualECPoints(128, curve.createPoint(p256_Px, p256_Py), curve.createPoint(p256_Qx, p256_Qy), 1); - - curve = (ECCurve.Fp)NISTNamedCurves.getByName("P-384").getCurve(); - - nistPoints[1] = new DualECPoints(192, curve.createPoint(p384_Px, p384_Py), curve.createPoint(p384_Qx, p384_Qy), 1); - - curve = (ECCurve.Fp)NISTNamedCurves.getByName("P-521").getCurve(); - - nistPoints[2] = new DualECPoints(256, curve.createPoint(p521_Px, p521_Py), curve.createPoint(p521_Qx, p521_Qy), 1); - } - - - 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 long _reseedCounter; - private EntropySource _entropySource; - private int _securityStrength; - private int _seedlen; - private int _outlen; - private ECCurve.Fp _curve; - private ECPoint _P; - private ECPoint _Q; - private byte[] _s; - private int _sLength; - private ECMultiplier _fixedPointMultiplier = new FixedPointCombMultiplier(); - - /** - * 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. - * @param personalizationString personalization string to distinguish this DRBG (may be null). - * @param nonce nonce to further distinguish this DRBG (may be null). - */ - public DualECSP800DRBG(Digest digest, int securityStrength, EntropySource entropySource, byte[] personalizationString, byte[] nonce) - { - this(nistPoints, digest, securityStrength, entropySource, personalizationString, nonce); - } - - /** - * Construct a SP800-90A Dual EC DRBG. - * <p> - * Minimum entropy requirement is the security strength requested. - * </p> - * @param pointSet an array of points to choose from, in order of increasing security strength - * @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. - * @param personalizationString personalization string to distinguish this DRBG (may be null). - * @param nonce nonce to further distinguish this DRBG (may be null). - */ - public DualECSP800DRBG(DualECPoints[] pointSet, Digest digest, int securityStrength, EntropySource entropySource, byte[] personalizationString, byte[] nonce) - { - _digest = digest; - _entropySource = entropySource; - _securityStrength = securityStrength; - - 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); - - for (int i = 0; i != pointSet.length; i++) - { - if (securityStrength <= pointSet[i].getSecurityStrength()) - { - if (Utils.getMaxSecurityStrength(digest) < pointSet[i].getSecurityStrength()) - { - throw new IllegalArgumentException("Requested security strength is not supported by digest"); - } - _seedlen = pointSet[i].getSeedLen(); - _outlen = pointSet[i].getMaxOutlen() / 8; - _P = pointSet[i].getP(); - _Q = pointSet[i].getQ(); - break; - } - } - - if (_P == null) - { - throw new IllegalArgumentException("security strength cannot be greater than 256 bits"); - } - - _s = Utils.hash_df(_digest, seedMaterial, _seedlen); - _sLength = _s.length; - - _reseedCounter = 0; - } - - /** - * Return the block size (in bits) of the DRBG. - * - * @return the number of bits produced on each internal round of the DRBG. - */ - public int getBlockSize() - { - return _outlen * 8; - } - - /** - * 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; - 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; - } - - BigInteger s; - - if (additionalInput != null) - { - // Note: we ignore the use of pad8 on the additional input as we mandate byte arrays for it. - additionalInput = Utils.hash_df(_digest, additionalInput, _seedlen); - s = new BigInteger(1, xor(_s, additionalInput)); - } - else - { - s = new BigInteger(1, _s); - } - - // make sure we start with a clean output array. - Arrays.fill(output, (byte)0); - - int outOffset = 0; - - for (int i = 0; i < m; i++) - { - s = getScalarMultipleXCoord(_P, s); - - //System.err.println("S: " + new String(Hex.encode(_s))); - - byte[] r = getScalarMultipleXCoord(_Q, s).toByteArray(); - - if (r.length > _outlen) - { - System.arraycopy(r, r.length - _outlen, output, outOffset, _outlen); - } - else - { - System.arraycopy(r, 0, output, outOffset + (_outlen - r.length), r.length); - } - - //System.err.println("R: " + new String(Hex.encode(r))); - outOffset += _outlen; - - _reseedCounter++; - } - - if (outOffset < output.length) - { - s = getScalarMultipleXCoord(_P, s); - - byte[] r = getScalarMultipleXCoord(_Q, s).toByteArray(); - - int required = output.length - outOffset; - - if (r.length > _outlen) - { - System.arraycopy(r, r.length - _outlen, output, outOffset, required); - } - else - { - System.arraycopy(r, 0, output, outOffset + (_outlen - r.length), required); - } - - _reseedCounter++; - } - - // Need to preserve length of S as unsigned int. - _s = BigIntegers.asUnsignedByteArray(_sLength, getScalarMultipleXCoord(_P, s)); - - return numberOfBits; - } - - /** - * Reseed the DRBG. - * - * @param additionalInput additional input to be added to the DRBG in this step. - */ - public void reseed(byte[] additionalInput) - { - if (Utils.isTooLarge(additionalInput, MAX_ADDITIONAL_INPUT / 8)) - { - throw new IllegalArgumentException("Additional input string too large"); - } - - byte[] entropy = _entropySource.getEntropy(); - byte[] seedMaterial = Arrays.concatenate(pad8(_s, _seedlen), entropy, additionalInput); - - _s = Utils.hash_df(_digest, seedMaterial, _seedlen); - - _reseedCounter = 0; - } - - private byte[] xor(byte[] a, byte[] b) - { - if (b == null) - { - return a; - } - - byte[] rv = new byte[a.length]; - - for (int i = 0; i != rv.length; i++) - { - rv[i] = (byte)(a[i] ^ b[i]); - } - - return rv; - } - - // Note: works in place - private byte[] pad8(byte[] s, int seedlen) - { - if (seedlen % 8 == 0) - { - return s; - } - - int shift = 8 - (seedlen % 8); - int carry = 0; - - for (int i = s.length - 1; i >= 0; i--) - { - int b = s[i] & 0xff; - s[i] = (byte)((b << shift) | (carry >> (8 - shift))); - carry = b; - } - - return s; - } - - private BigInteger getScalarMultipleXCoord(ECPoint p, BigInteger s) - { - return _fixedPointMultiplier.multiply(p, s).normalize().getAffineXCoord().toBigInteger(); - } -} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java b/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java deleted file mode 100644 index f4ef2c4..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.bouncycastle.crypto.prng.drbg; - -import org.bouncycastle.crypto.Mac; -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 long RESEED_MAX = 1L << (48 - 1); - private final static int MAX_BITS_REQUEST = 1 << (19 - 1); - - private byte[] _K; - private byte[] _V; - 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. - * @param personalizationString 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[] personalizationString, byte[] nonce) - { - if (securityStrength > Utils.getMaxSecurityStrength(hMac)) - { - throw new IllegalArgumentException("Requested 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; - - byte[] entropy = entropySource.getEntropy(); - byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalizationString); - - _K = new byte[hMac.getMacSize()]; - _V = new byte[_K.length]; - Arrays.fill(_V, (byte)1); - - hmac_DRBG_Update(seedMaterial); - - _reseedCounter = 1; - } - - private void hmac_DRBG_Update(byte[] seedMaterial) - { - hmac_DRBG_Update_Func(seedMaterial, (byte)0x00); - if (seedMaterial != null) - { - hmac_DRBG_Update_Func(seedMaterial, (byte)0x01); - } - } - - private void hmac_DRBG_Update_Func(byte[] seedMaterial, byte vValue) - { - _hMac.init(new KeyParameter(_K)); - - _hMac.update(_V, 0, _V.length); - _hMac.update(vValue); - - if (seedMaterial != null) - { - _hMac.update(seedMaterial, 0, seedMaterial.length); - } - - _hMac.doFinal(_K, 0); - - _hMac.init(new KeyParameter(_K)); - _hMac.update(_V, 0, _V.length); - - _hMac.doFinal(_V, 0); - } - - /** - * Return the block size (in bits) of the DRBG. - * - * @return the number of bits produced on each round of the DRBG. - */ - public int getBlockSize() - { - return _V.length * 8; - } - - /** - * 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 (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; - } - - // 2. - if (additionalInput != null) - { - hmac_DRBG_Update(additionalInput); - } - - // 3. - byte[] rv = new byte[output.length]; - - int m = output.length / _V.length; - - _hMac.init(new KeyParameter(_K)); - - for (int i = 0; i < m; i++) - { - _hMac.update(_V, 0, _V.length); - _hMac.doFinal(_V, 0); - - System.arraycopy(_V, 0, rv, i * _V.length, _V.length); - } - - if (m * _V.length < rv.length) - { - _hMac.update(_V, 0, _V.length); - _hMac.doFinal(_V, 0); - - System.arraycopy(_V, 0, rv, m * _V.length, rv.length - (m * _V.length)); - } - - hmac_DRBG_Update(additionalInput); - - _reseedCounter++; - - System.arraycopy(rv, 0, output, 0, output.length); - - 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(); - byte[] seedMaterial = Arrays.concatenate(entropy, additionalInput); - - hmac_DRBG_Update(seedMaterial); - - _reseedCounter = 1; - } -} diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java b/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java deleted file mode 100644 index d6ab4f5..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java +++ /dev/null @@ -1,284 +0,0 @@ -package org.bouncycastle.crypto.prng.drbg; - -import java.util.Hashtable; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.prng.EntropySource; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Integers; - -/** - * A SP800-90A Hash DRBG. - */ -public class HashSP800DRBG - implements SP80090DRBG -{ - private final static byte[] ONE = { 0x01 }; - - 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(); - - 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 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. - * @param personalizationString 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[] personalizationString, byte[] nonce) - { - if (securityStrength > Utils.getMaxSecurityStrength(digest)) - { - throw new IllegalArgumentException("Requested 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; - _seedLength = ((Integer)seedlens.get(digest.getAlgorithmName())).intValue(); - - // 1. seed_material = entropy_input || nonce || personalization_string. - // 2. seed = Hash_df (seed_material, seedlen). - // 3. V = seed. - // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed V with a byte - // of zeros. - // 5. reseed_counter = 1. - // 6. Return V, C, and reseed_counter as the initial_working_state - - byte[] entropy = entropySource.getEntropy(); - byte[] seedMaterial = Arrays.concatenate(entropy, nonce, personalizationString); - 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 = Utils.hash_df(_digest, subV, _seedLength); - - _reseedCounter = 1; - } - - /** - * Return the block size (in bits) of the DRBG. - * - * @return the number of bits produced on each internal round of the DRBG. - */ - public int getBlockSize() - { - return _digest.getDigestSize() * 8; - } - - /** - * 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 (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; - } - - // 2. - if (additionalInput != null) - { - byte[] newInput = new byte[1 + _V.length + additionalInput.length]; - newInput[0] = 0x02; - System.arraycopy(_V, 0, newInput, 1, _V.length); - // TODO: inOff / inLength - System.arraycopy(additionalInput, 0, newInput, 1 + _V.length, additionalInput.length); - byte[] w = hash(newInput); - - addTo(_V, w); - } - - // 3. - byte[] rv = hashgen(_V, numberOfBits); - - // 4. - byte[] subH = new byte[_V.length + 1]; - System.arraycopy(_V, 0, subH, 1, _V.length); - subH[0] = 0x03; - - byte[] H = hash(subH); - - // 5. - addTo(_V, H); - addTo(_V, _C); - byte[] c = new byte[4]; - c[0] = (byte)(_reseedCounter >> 24); - c[1] = (byte)(_reseedCounter >> 16); - c[2] = (byte)(_reseedCounter >> 8); - c[3] = (byte)_reseedCounter; - - addTo(_V, c); - - _reseedCounter++; - - System.arraycopy(rv, 0, output, 0, output.length); - - return numberOfBits; - } - - // this will always add the shorter length byte array mathematically to the - // longer length byte array. - // be careful.... - private void addTo(byte[] longer, byte[] shorter) - { - int carry = 0; - for (int i=1;i <= shorter.length; i++) // warning - { - int res = (longer[longer.length-i] & 0xff) + (shorter[shorter.length-i] & 0xff) + carry; - carry = (res > 0xff) ? 1 : 0; - longer[longer.length-i] = (byte)res; - } - - for (int i=shorter.length+1;i <= longer.length; i++) // warning - { - int res = (longer[longer.length-i] & 0xff) + carry; - carry = (res > 0xff) ? 1 : 0; - longer[longer.length-i] = (byte)res; - } - } - - /** - * Reseed the DRBG. - * - * @param additionalInput additional input to be added to the DRBG in this step. - */ - public void reseed(byte[] additionalInput) - { - // 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(); - byte[] seedMaterial = Arrays.concatenate(ONE, _V, entropy, additionalInput); - 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 = Utils.hash_df(_digest, subV, _seedLength); - - _reseedCounter = 1; - } - - private byte[] hash(byte[] input) - { - byte[] hash = new byte[_digest.getDigestSize()]; - doHash(input, hash); - return hash; - } - - private void doHash(byte[] input, byte[] output) - { - _digest.update(input, 0, input.length); - _digest.doFinal(output, 0); - } - - // 1. m = [requested_number_of_bits / outlen] - // 2. data = V. - // 3. W = the Null string. - // 4. For i = 1 to m - // 4.1 wi = Hash (data). - // 4.2 W = W || wi. - // 4.3 data = (data + 1) mod 2^seedlen - // . - // 5. returned_bits = Leftmost (requested_no_of_bits) bits of W. - private byte[] hashgen(byte[] input, int lengthInBits) - { - int digestSize = _digest.getDigestSize(); - int m = (lengthInBits / 8) / digestSize; - - byte[] data = new byte[input.length]; - System.arraycopy(input, 0, data, 0, input.length); - - byte[] W = new byte[lengthInBits / 8]; - - byte[] dig = new byte[_digest.getDigestSize()]; - for (int i = 0; i <= m; i++) - { - doHash(data, dig); - - int bytesToCopy = ((W.length - i * dig.length) > dig.length) - ? dig.length - : (W.length - i * dig.length); - System.arraycopy(dig, 0, W, i * dig.length, bytesToCopy); - - addTo(data, ONE); - } - - return W; - } -}
\ No newline at end of file diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java b/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java deleted file mode 100644 index 7a919f3..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.bouncycastle.crypto.prng.drbg; - -/** - * Interface to SP800-90A deterministic random bit generators. - */ -public interface SP80090DRBG -{ - /** - * Return the block size of the DRBG. - * - * @return the block size (in bits) produced by each round of the DRBG. - */ - int getBlockSize(); - - /** - * 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/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java b/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java deleted file mode 100644 index f7a4117..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/Utils.java +++ /dev/null @@ -1,103 +0,0 @@ -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(); - } - - /** - * 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/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/package.html b/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/package.html deleted file mode 100644 index c006166..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<html> -<body bgcolor="#ffffff"> -SP800-90A deterministic random bit generators, can be used stand alone or in conjunction with SP800SecureRandomBuilder class. -</body> -</html> |