diff options
Diffstat (limited to 'core/src/main/java/org/spongycastle/crypto/signers/ECDSASigner.java')
-rw-r--r-- | core/src/main/java/org/spongycastle/crypto/signers/ECDSASigner.java | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/core/src/main/java/org/spongycastle/crypto/signers/ECDSASigner.java b/core/src/main/java/org/spongycastle/crypto/signers/ECDSASigner.java new file mode 100644 index 00000000..b0cfdf6c --- /dev/null +++ b/core/src/main/java/org/spongycastle/crypto/signers/ECDSASigner.java @@ -0,0 +1,197 @@ +package org.spongycastle.crypto.signers; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.DSA; +import org.spongycastle.crypto.params.ECDomainParameters; +import org.spongycastle.crypto.params.ECKeyParameters; +import org.spongycastle.crypto.params.ECPrivateKeyParameters; +import org.spongycastle.crypto.params.ECPublicKeyParameters; +import org.spongycastle.crypto.params.ParametersWithRandom; +import org.spongycastle.math.ec.ECAlgorithms; +import org.spongycastle.math.ec.ECConstants; +import org.spongycastle.math.ec.ECMultiplier; +import org.spongycastle.math.ec.ECPoint; +import org.spongycastle.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).normalize(); + + // components must be bogus. + if (point.isInfinity()) + { + return false; + } + + BigInteger v = point.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 SecureRandom initSecureRandom(boolean needed, SecureRandom provided) + { + return !needed ? null : (provided != null) ? provided : new SecureRandom(); + } +} |