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