diff options
Diffstat (limited to 'android_bcprov/src/main/java/com/android/org/bouncycastle/crypto/signers/ECDSASigner.java')
-rw-r--r-- | android_bcprov/src/main/java/com/android/org/bouncycastle/crypto/signers/ECDSASigner.java | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/android_bcprov/src/main/java/com/android/org/bouncycastle/crypto/signers/ECDSASigner.java b/android_bcprov/src/main/java/com/android/org/bouncycastle/crypto/signers/ECDSASigner.java new file mode 100644 index 00000000..015dcf8a --- /dev/null +++ b/android_bcprov/src/main/java/com/android/org/bouncycastle/crypto/signers/ECDSASigner.java @@ -0,0 +1,253 @@ +/* GENERATED SOURCE. DO NOT MODIFY. */ +package com.android.org.bouncycastle.crypto.signers; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.android.org.bouncycastle.crypto.CipherParameters; +import com.android.org.bouncycastle.crypto.DSA; +import com.android.org.bouncycastle.crypto.params.ECDomainParameters; +import com.android.org.bouncycastle.crypto.params.ECKeyParameters; +import com.android.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.android.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.android.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.android.org.bouncycastle.math.ec.ECAlgorithms; +import com.android.org.bouncycastle.math.ec.ECConstants; +import com.android.org.bouncycastle.math.ec.ECCurve; +import com.android.org.bouncycastle.math.ec.ECFieldElement; +import com.android.org.bouncycastle.math.ec.ECMultiplier; +import com.android.org.bouncycastle.math.ec.ECPoint; +import com.android.org.bouncycastle.math.ec.FixedPointCombMultiplier; + +/** + * EC-DSA as described in X9.62 + */ +public class ECDSASigner + implements ECConstants, DSA +{ + private final DSAKCalculator kCalculator; + + private ECKeyParameters key; + private SecureRandom random; + + /** + * Default configuration, random K values. + */ + public ECDSASigner() + { + this.kCalculator = new RandomDSAKCalculator(); + } + + /** + * Configuration with an alternate, possibly deterministic calculator of K. + * + * @param kCalculator a K value calculator. + */ + public ECDSASigner(DSAKCalculator kCalculator) + { + this.kCalculator = kCalculator; + } + + public void init( + boolean forSigning, + CipherParameters param) + { + SecureRandom providedRandom = null; + + if (forSigning) + { + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + this.key = (ECPrivateKeyParameters)rParam.getParameters(); + providedRandom = rParam.getRandom(); + } + else + { + this.key = (ECPrivateKeyParameters)param; + } + } + else + { + this.key = (ECPublicKeyParameters)param; + } + + this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom); + } + + // 5.3 pg 28 + /** + * generate a signature for the given message using the key we were + * initialised with. For conventional DSA the message should be a SHA-1 + * hash of the message of interest. + * + * @param message the message that will be verified later. + */ + public BigInteger[] generateSignature( + byte[] message) + { + ECDomainParameters ec = key.getParameters(); + BigInteger n = ec.getN(); + BigInteger e = calculateE(n, message); + BigInteger d = ((ECPrivateKeyParameters)key).getD(); + + if (kCalculator.isDeterministic()) + { + kCalculator.init(n, d, message); + } + else + { + kCalculator.init(n, random); + } + + BigInteger r, s; + + ECMultiplier basePointMultiplier = createBasePointMultiplier(); + + // 5.3.2 + do // generate s + { + BigInteger k; + do // generate r + { + k = kCalculator.nextK(); + + ECPoint p = basePointMultiplier.multiply(ec.getG(), k).normalize(); + + // 5.3.3 + r = p.getAffineXCoord().toBigInteger().mod(n); + } + while (r.equals(ZERO)); + + s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n); + } + while (s.equals(ZERO)); + + return new BigInteger[]{ r, s }; + } + + // 5.4 pg 29 + /** + * return true if the value r and s represent a DSA signature for + * the passed in message (for standard DSA the message should be + * a SHA-1 hash of the real message to be verified). + */ + public boolean verifySignature( + byte[] message, + BigInteger r, + BigInteger s) + { + ECDomainParameters ec = key.getParameters(); + BigInteger n = ec.getN(); + BigInteger e = calculateE(n, message); + + // r in the range [1,n-1] + if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0) + { + return false; + } + + // s in the range [1,n-1] + if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0) + { + return false; + } + + BigInteger c = s.modInverse(n); + + BigInteger u1 = e.multiply(c).mod(n); + BigInteger u2 = r.multiply(c).mod(n); + + ECPoint G = ec.getG(); + ECPoint Q = ((ECPublicKeyParameters)key).getQ(); + + ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2); + + // components must be bogus. + if (point.isInfinity()) + { + return false; + } + + /* + * If possible, avoid normalizing the point (to save a modular inversion in the curve field). + * + * There are ~cofactor elements of the curve field that reduce (modulo the group order) to 'r'. + * If the cofactor is known and small, we generate those possible field values and project each + * of them to the same "denominator" (depending on the particular projective coordinates in use) + * as the calculated point.X. If any of the projected values matches point.X, then we have: + * (point.X / Denominator mod p) mod n == r + * as required, and verification succeeds. + * + * Based on an original idea by Gregory Maxwell (https://github.com/gmaxwell), as implemented in + * the libsecp256k1 project (https://github.com/bitcoin/secp256k1). + */ + ECCurve curve = point.getCurve(); + if (curve != null) + { + BigInteger cofactor = curve.getCofactor(); + if (cofactor != null && cofactor.compareTo(EIGHT) <= 0) + { + ECFieldElement D = getDenominator(curve.getCoordinateSystem(), point); + if (D != null && !D.isZero()) + { + ECFieldElement X = point.getXCoord(); + while (curve.isValidFieldElement(r)) + { + ECFieldElement R = curve.fromBigInteger(r).multiply(D); + if (R.equals(X)) + { + return true; + } + r = r.add(n); + } + return false; + } + } + } + + BigInteger v = point.normalize().getAffineXCoord().toBigInteger().mod(n); + return v.equals(r); + } + + protected BigInteger calculateE(BigInteger n, byte[] message) + { + int log2n = n.bitLength(); + int messageBitLength = message.length * 8; + + BigInteger e = new BigInteger(1, message); + if (log2n < messageBitLength) + { + e = e.shiftRight(messageBitLength - log2n); + } + return e; + } + + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } + + protected ECFieldElement getDenominator(int coordinateSystem, ECPoint p) + { + switch (coordinateSystem) + { + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + case ECCurve.COORD_SKEWED: + return p.getZCoord(0); + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + case ECCurve.COORD_JACOBIAN_MODIFIED: + return p.getZCoord(0).square(); + default: + return null; + } + } + + protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided) + { + return !needed ? null : (provided != null) ? provided : new SecureRandom(); + } +} |