diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg')
3 files changed, 169 insertions, 52 deletions
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 new file mode 100644 index 0000000..c3715bc --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECPoints.java @@ -0,0 +1,82 @@ +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> + * </p> + * @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 index 3cee39c..8d326ff 100644 --- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java +++ b/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java @@ -6,7 +6,6 @@ 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.ECFieldElement; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.BigIntegers; @@ -35,6 +34,26 @@ public class DualECSP800DRBG 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); @@ -65,6 +84,23 @@ public class DualECSP800DRBG */ 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; @@ -82,43 +118,23 @@ public class DualECSP800DRBG 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(); - _P = new ECPoint.Fp(_curve, new ECFieldElement.Fp(_curve.getQ(), p256_Px), new ECFieldElement.Fp(_curve.getQ(), p256_Py)); - _Q = new ECPoint.Fp(_curve, new ECFieldElement.Fp(_curve.getQ(), p256_Qx), new ECFieldElement.Fp(_curve.getQ(), p256_Qy)); - } - else if (securityStrength <= 192) + for (int i = 0; i != pointSet.length; i++) { - if (Utils.getMaxSecurityStrength(digest) < 192) + if (securityStrength <= pointSet[i].getSecurityStrength()) { - throw new IllegalArgumentException("Requested security strength is not supported by digest"); + 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; } - _seedlen = 384; - _outlen = 368 / 8; - _curve = (ECCurve.Fp)NISTNamedCurves.getByName("P-384").getCurve(); - _P = new ECPoint.Fp(_curve, new ECFieldElement.Fp(_curve.getQ(), p384_Px), new ECFieldElement.Fp(_curve.getQ(), p384_Py)); - _Q = new ECPoint.Fp(_curve, new ECFieldElement.Fp(_curve.getQ(), p384_Qx), new ECFieldElement.Fp(_curve.getQ(), p384_Qy)); } - 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(); - _P = new ECPoint.Fp(_curve, new ECFieldElement.Fp(_curve.getQ(), p521_Px), new ECFieldElement.Fp(_curve.getQ(), p521_Py)); - _Q = new ECPoint.Fp(_curve, new ECFieldElement.Fp(_curve.getQ(), p521_Qx), new ECFieldElement.Fp(_curve.getQ(), p521_Qy)); - } - else + + if (_P == null) { throw new IllegalArgumentException("security strength cannot be greater than 256 bits"); } @@ -159,50 +175,69 @@ public class DualECSP800DRBG 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++) { - BigInteger t = new BigInteger(1, xor(_s, additionalInput)); - - _s = _P.multiply(t).getX().toBigInteger().toByteArray(); + s = getScalarMultipleXCoord(_P, s); //System.err.println("S: " + new String(Hex.encode(_s))); - byte[] r = _Q.multiply(new BigInteger(1, _s)).getX().toBigInteger().toByteArray(); + byte[] r = _Q.multiply(s).normalize().getAffineXCoord().toBigInteger().toByteArray(); if (r.length > _outlen) { - System.arraycopy(r, r.length - _outlen, output, i * _outlen, _outlen); + System.arraycopy(r, r.length - _outlen, output, outOffset, _outlen); } else { - System.arraycopy(r, 0, output, i * _outlen + (_outlen - r.length), r.length); + System.arraycopy(r, 0, output, outOffset + (_outlen - r.length), r.length); } //System.err.println("R: " + new String(Hex.encode(r))); - additionalInput = null; + outOffset += _outlen; _reseedCounter++; } - if (m * _outlen < output.length) + if (outOffset < output.length) { - BigInteger t = new BigInteger(1, xor(_s, additionalInput)); + s = getScalarMultipleXCoord(_P, s); - _s = _P.multiply(t).getX().toBigInteger().toByteArray(); + byte[] r = _Q.multiply(s).normalize().getAffineXCoord().toBigInteger().toByteArray(); - byte[] r = _Q.multiply(new BigInteger(1, _s)).getX().toBigInteger().toByteArray(); + int required = output.length - outOffset; - System.arraycopy(r, 0, output, m * _outlen, output.length - (m * _outlen)); + 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, _P.multiply(new BigInteger(1, _s)).getX().toBigInteger()); + _s = BigIntegers.asUnsignedByteArray(_sLength, _P.multiply(s).normalize().getAffineXCoord().toBigInteger()); return numberOfBits; } @@ -264,4 +299,9 @@ public class DualECSP800DRBG return s; } + + private BigInteger getScalarMultipleXCoord(ECPoint p, BigInteger s) + { + return p.multiply(s).normalize().getAffineXCoord().toBigInteger(); + } } 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 630809b..0000000 --- a/bcprov/src/main/java/org/bouncycastle/crypto/prng/drbg/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<html> -<body bgcolor="#ffffff"> -NIST Deterministic Random Bit Generators (SP 800-90A). -</body> -</html> |