ECDSASigner.java revision 5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96
1package org.bouncycastle.crypto.signers; 2 3import java.math.BigInteger; 4import java.security.SecureRandom; 5 6import org.bouncycastle.crypto.CipherParameters; 7import org.bouncycastle.crypto.DSA; 8import org.bouncycastle.crypto.params.ECKeyParameters; 9import org.bouncycastle.crypto.params.ECPrivateKeyParameters; 10import org.bouncycastle.crypto.params.ECPublicKeyParameters; 11import org.bouncycastle.crypto.params.ParametersWithRandom; 12import org.bouncycastle.math.ec.ECAlgorithms; 13import org.bouncycastle.math.ec.ECConstants; 14import org.bouncycastle.math.ec.ECPoint; 15 16/** 17 * EC-DSA as described in X9.62 18 */ 19public class ECDSASigner 20 implements ECConstants, DSA 21{ 22 private final DSAKCalculator kCalculator; 23 24 private ECKeyParameters key; 25 private SecureRandom random; 26 27 /** 28 * Default configuration, random K values. 29 */ 30 public ECDSASigner() 31 { 32 this.kCalculator = new RandomDSAKCalculator(); 33 } 34 35 /** 36 * Configuration with an alternate, possibly deterministic calculator of K. 37 * 38 * @param kCalculator a K value calculator. 39 */ 40 public ECDSASigner(DSAKCalculator kCalculator) 41 { 42 this.kCalculator = kCalculator; 43 } 44 45 public void init( 46 boolean forSigning, 47 CipherParameters param) 48 { 49 if (forSigning) 50 { 51 if (param instanceof ParametersWithRandom) 52 { 53 ParametersWithRandom rParam = (ParametersWithRandom)param; 54 55 this.random = rParam.getRandom(); 56 this.key = (ECPrivateKeyParameters)rParam.getParameters(); 57 } 58 else 59 { 60 this.random = new SecureRandom(); 61 this.key = (ECPrivateKeyParameters)param; 62 } 63 } 64 else 65 { 66 this.key = (ECPublicKeyParameters)param; 67 } 68 } 69 70 // 5.3 pg 28 71 /** 72 * generate a signature for the given message using the key we were 73 * initialised with. For conventional DSA the message should be a SHA-1 74 * hash of the message of interest. 75 * 76 * @param message the message that will be verified later. 77 */ 78 public BigInteger[] generateSignature( 79 byte[] message) 80 { 81 BigInteger n = key.getParameters().getN(); 82 BigInteger e = calculateE(n, message); 83 BigInteger r = null; 84 BigInteger s = null; 85 86 if (kCalculator.isDeterministic()) 87 { 88 kCalculator.init(n, ((ECPrivateKeyParameters)key).getD(), message); 89 } 90 else 91 { 92 kCalculator.init(n, random); 93 } 94 95 // 5.3.2 96 do // generate s 97 { 98 BigInteger k = null; 99 100 do // generate r 101 { 102 k = kCalculator.nextK(); 103 104 ECPoint p = key.getParameters().getG().multiply(k).normalize(); 105 106 // 5.3.3 107 BigInteger x = p.getAffineXCoord().toBigInteger(); 108 109 r = x.mod(n); 110 } 111 while (r.equals(ZERO)); 112 113 BigInteger d = ((ECPrivateKeyParameters)key).getD(); 114 115 s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n); 116 } 117 while (s.equals(ZERO)); 118 119 BigInteger[] res = new BigInteger[2]; 120 121 res[0] = r; 122 res[1] = s; 123 124 return res; 125 } 126 127 // 5.4 pg 29 128 /** 129 * return true if the value r and s represent a DSA signature for 130 * the passed in message (for standard DSA the message should be 131 * a SHA-1 hash of the real message to be verified). 132 */ 133 public boolean verifySignature( 134 byte[] message, 135 BigInteger r, 136 BigInteger s) 137 { 138 BigInteger n = key.getParameters().getN(); 139 BigInteger e = calculateE(n, message); 140 141 // r in the range [1,n-1] 142 if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0) 143 { 144 return false; 145 } 146 147 // s in the range [1,n-1] 148 if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0) 149 { 150 return false; 151 } 152 153 BigInteger c = s.modInverse(n); 154 155 BigInteger u1 = e.multiply(c).mod(n); 156 BigInteger u2 = r.multiply(c).mod(n); 157 158 ECPoint G = key.getParameters().getG(); 159 ECPoint Q = ((ECPublicKeyParameters)key).getQ(); 160 161 ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2).normalize(); 162 163 // components must be bogus. 164 if (point.isInfinity()) 165 { 166 return false; 167 } 168 169 BigInteger v = point.getAffineXCoord().toBigInteger().mod(n); 170 171 return v.equals(r); 172 } 173 174 private BigInteger calculateE(BigInteger n, byte[] message) 175 { 176 int log2n = n.bitLength(); 177 int messageBitLength = message.length * 8; 178 179 BigInteger e = new BigInteger(1, message); 180 if (log2n < messageBitLength) 181 { 182 e = e.shiftRight(messageBitLength - log2n); 183 } 184 return e; 185 } 186} 187