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.DSAKeyParameters;
9import org.bouncycastle.crypto.params.DSAParameters;
10import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
11import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
12import org.bouncycastle.crypto.params.ParametersWithRandom;
13
14/**
15 * The Digital Signature Algorithm - as described in "Handbook of Applied
16 * Cryptography", pages 452 - 453.
17 */
18public class DSASigner
19    implements DSA
20{
21    private final DSAKCalculator kCalculator;
22
23    private DSAKeyParameters key;
24    private SecureRandom    random;
25
26    /**
27     * Default configuration, random K values.
28     */
29    public DSASigner()
30    {
31        this.kCalculator = new RandomDSAKCalculator();
32    }
33
34    /**
35     * Configuration with an alternate, possibly deterministic calculator of K.
36     *
37     * @param kCalculator a K value calculator.
38     */
39    public DSASigner(DSAKCalculator kCalculator)
40    {
41        this.kCalculator = kCalculator;
42    }
43
44    public void init(
45        boolean                 forSigning,
46        CipherParameters        param)
47    {
48        if (forSigning)
49        {
50            if (param instanceof ParametersWithRandom)
51            {
52                ParametersWithRandom    rParam = (ParametersWithRandom)param;
53
54                this.random = rParam.getRandom();
55                this.key = (DSAPrivateKeyParameters)rParam.getParameters();
56            }
57            else
58            {
59                this.random = new SecureRandom();
60                this.key = (DSAPrivateKeyParameters)param;
61            }
62        }
63        else
64        {
65            this.key = (DSAPublicKeyParameters)param;
66        }
67    }
68
69    /**
70     * generate a signature for the given message using the key we were
71     * initialised with. For conventional DSA the message should be a SHA-1
72     * hash of the message of interest.
73     *
74     * @param message the message that will be verified later.
75     */
76    public BigInteger[] generateSignature(
77        byte[] message)
78    {
79        DSAParameters   params = key.getParameters();
80        BigInteger      m = calculateE(params.getQ(), message);
81
82        if (kCalculator.isDeterministic())
83        {
84            kCalculator.init(params.getQ(), ((DSAPrivateKeyParameters)key).getX(), message);
85        }
86        else
87        {
88            kCalculator.init(params.getQ(), random);
89        }
90
91        BigInteger  k = kCalculator.nextK();
92
93        BigInteger  r = params.getG().modPow(k, params.getP()).mod(params.getQ());
94
95        k = k.modInverse(params.getQ()).multiply(
96                    m.add(((DSAPrivateKeyParameters)key).getX().multiply(r)));
97
98        BigInteger  s = k.mod(params.getQ());
99
100        BigInteger[]  res = new BigInteger[2];
101
102        res[0] = r;
103        res[1] = s;
104
105        return res;
106    }
107
108    /**
109     * return true if the value r and s represent a DSA signature for
110     * the passed in message for standard DSA the message should be a
111     * SHA-1 hash of the real message to be verified.
112     */
113    public boolean verifySignature(
114        byte[]      message,
115        BigInteger  r,
116        BigInteger  s)
117    {
118        DSAParameters   params = key.getParameters();
119        BigInteger      m = calculateE(params.getQ(), message);
120        BigInteger      zero = BigInteger.valueOf(0);
121
122        if (zero.compareTo(r) >= 0 || params.getQ().compareTo(r) <= 0)
123        {
124            return false;
125        }
126
127        if (zero.compareTo(s) >= 0 || params.getQ().compareTo(s) <= 0)
128        {
129            return false;
130        }
131
132        BigInteger  w = s.modInverse(params.getQ());
133
134        BigInteger  u1 = m.multiply(w).mod(params.getQ());
135        BigInteger  u2 = r.multiply(w).mod(params.getQ());
136
137        u1 = params.getG().modPow(u1, params.getP());
138        u2 = ((DSAPublicKeyParameters)key).getY().modPow(u2, params.getP());
139
140        BigInteger  v = u1.multiply(u2).mod(params.getP()).mod(params.getQ());
141
142        return v.equals(r);
143    }
144
145    private BigInteger calculateE(BigInteger n, byte[] message)
146    {
147        if (n.bitLength() >= message.length * 8)
148        {
149            return new BigInteger(1, message);
150        }
151        else
152        {
153            byte[] trunc = new byte[n.bitLength() / 8];
154
155            System.arraycopy(message, 0, trunc, 0, trunc.length);
156
157            return new BigInteger(1, trunc);
158        }
159    }
160}
161