summaryrefslogtreecommitdiff
path: root/android_bcprov/src/main/java/com/android/org/bouncycastle/crypto/signers/ECDSASigner.java
diff options
context:
space:
mode:
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.java253
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();
+ }
+}