ECDSASigner.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
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 ECKeyParameters key; 23 24 SecureRandom random; 25 26 public void init( 27 boolean forSigning, 28 CipherParameters param) 29 { 30 if (forSigning) 31 { 32 if (param instanceof ParametersWithRandom) 33 { 34 ParametersWithRandom rParam = (ParametersWithRandom)param; 35 36 this.random = rParam.getRandom(); 37 this.key = (ECPrivateKeyParameters)rParam.getParameters(); 38 } 39 else 40 { 41 this.random = new SecureRandom(); 42 this.key = (ECPrivateKeyParameters)param; 43 } 44 } 45 else 46 { 47 this.key = (ECPublicKeyParameters)param; 48 } 49 } 50 51 // 5.3 pg 28 52 /** 53 * generate a signature for the given message using the key we were 54 * initialised with. For conventional DSA the message should be a SHA-1 55 * hash of the message of interest. 56 * 57 * @param message the message that will be verified later. 58 */ 59 public BigInteger[] generateSignature( 60 byte[] message) 61 { 62 BigInteger n = key.getParameters().getN(); 63 BigInteger e = calculateE(n, message); 64 BigInteger r = null; 65 BigInteger s = null; 66 67 // 5.3.2 68 do // generate s 69 { 70 BigInteger k = null; 71 int nBitLength = n.bitLength(); 72 73 do // generate r 74 { 75 do 76 { 77 k = new BigInteger(nBitLength, random); 78 } 79 while (k.equals(ZERO) || k.compareTo(n) >= 0); 80 81 ECPoint p = key.getParameters().getG().multiply(k); 82 83 // 5.3.3 84 BigInteger x = p.getX().toBigInteger(); 85 86 r = x.mod(n); 87 } 88 while (r.equals(ZERO)); 89 90 BigInteger d = ((ECPrivateKeyParameters)key).getD(); 91 92 s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n); 93 } 94 while (s.equals(ZERO)); 95 96 BigInteger[] res = new BigInteger[2]; 97 98 res[0] = r; 99 res[1] = s; 100 101 return res; 102 } 103 104 // 5.4 pg 29 105 /** 106 * return true if the value r and s represent a DSA signature for 107 * the passed in message (for standard DSA the message should be 108 * a SHA-1 hash of the real message to be verified). 109 */ 110 public boolean verifySignature( 111 byte[] message, 112 BigInteger r, 113 BigInteger s) 114 { 115 BigInteger n = key.getParameters().getN(); 116 BigInteger e = calculateE(n, message); 117 118 // r in the range [1,n-1] 119 if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0) 120 { 121 return false; 122 } 123 124 // s in the range [1,n-1] 125 if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0) 126 { 127 return false; 128 } 129 130 BigInteger c = s.modInverse(n); 131 132 BigInteger u1 = e.multiply(c).mod(n); 133 BigInteger u2 = r.multiply(c).mod(n); 134 135 ECPoint G = key.getParameters().getG(); 136 ECPoint Q = ((ECPublicKeyParameters)key).getQ(); 137 138 ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2); 139 140 BigInteger v = point.getX().toBigInteger().mod(n); 141 142 return v.equals(r); 143 } 144 145 private BigInteger calculateE(BigInteger n, byte[] message) 146 { 147 int log2n = n.bitLength(); 148 int messageBitLength = message.length * 8; 149 150 if (log2n >= messageBitLength) 151 { 152 return new BigInteger(1, message); 153 } 154 else 155 { 156 BigInteger trunc = new BigInteger(1, message); 157 158 trunc = trunc.shiftRight(messageBitLength - log2n); 159 160 return trunc; 161 } 162 } 163} 164