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