• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.bouncycastle.crypto.signers;
2 
3 import java.math.BigInteger;
4 import java.security.SecureRandom;
5 
6 import org.bouncycastle.crypto.CipherParameters;
7 import org.bouncycastle.crypto.DSA;
8 import org.bouncycastle.crypto.params.DSAKeyParameters;
9 import org.bouncycastle.crypto.params.DSAParameters;
10 import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
11 import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
12 import org.bouncycastle.crypto.params.ParametersWithRandom;
13 
14 /**
15  * The Digital Signature Algorithm - as described in "Handbook of Applied
16  * Cryptography", pages 452 - 453.
17  */
18 public 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      */
DSASigner()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      */
DSASigner(DSAKCalculator kCalculator)39     public DSASigner(DSAKCalculator kCalculator)
40     {
41         this.kCalculator = kCalculator;
42     }
43 
init( boolean forSigning, CipherParameters param)44     public void init(
45         boolean                 forSigning,
46         CipherParameters        param)
47     {
48         SecureRandom providedRandom = null;
49 
50         if (forSigning)
51         {
52             if (param instanceof ParametersWithRandom)
53             {
54                 ParametersWithRandom rParam = (ParametersWithRandom)param;
55 
56                 this.key = (DSAPrivateKeyParameters)rParam.getParameters();
57                 providedRandom = rParam.getRandom();
58             }
59             else
60             {
61                 this.key = (DSAPrivateKeyParameters)param;
62             }
63         }
64         else
65         {
66             this.key = (DSAPublicKeyParameters)param;
67         }
68 
69         this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom);
70     }
71 
72     /**
73      * generate a signature for the given message using the key we were
74      * initialised with. For conventional DSA the message should be a SHA-1
75      * hash of the message of interest.
76      *
77      * @param message the message that will be verified later.
78      */
generateSignature( byte[] message)79     public BigInteger[] generateSignature(
80         byte[] message)
81     {
82         DSAParameters   params = key.getParameters();
83         BigInteger      q = params.getQ();
84         BigInteger      m = calculateE(q, message);
85         BigInteger      x = ((DSAPrivateKeyParameters)key).getX();
86 
87         if (kCalculator.isDeterministic())
88         {
89             kCalculator.init(q, x, message);
90         }
91         else
92         {
93             kCalculator.init(q, random);
94         }
95 
96         BigInteger  k = kCalculator.nextK();
97 
98         BigInteger  r = params.getG().modPow(k, params.getP()).mod(q);
99 
100         k = k.modInverse(q).multiply(m.add(x.multiply(r)));
101 
102         BigInteger  s = k.mod(q);
103 
104         return new BigInteger[]{ r, s };
105     }
106 
107     /**
108      * return true if the value r and s represent a DSA signature for
109      * the passed in message for standard DSA the message should be a
110      * SHA-1 hash of the real message to be verified.
111      */
verifySignature( byte[] message, BigInteger r, BigInteger s)112     public boolean verifySignature(
113         byte[]      message,
114         BigInteger  r,
115         BigInteger  s)
116     {
117         DSAParameters   params = key.getParameters();
118         BigInteger      q = params.getQ();
119         BigInteger      m = calculateE(q, message);
120         BigInteger      zero = BigInteger.valueOf(0);
121 
122         if (zero.compareTo(r) >= 0 || q.compareTo(r) <= 0)
123         {
124             return false;
125         }
126 
127         if (zero.compareTo(s) >= 0 || q.compareTo(s) <= 0)
128         {
129             return false;
130         }
131 
132         BigInteger  w = s.modInverse(q);
133 
134         BigInteger  u1 = m.multiply(w).mod(q);
135         BigInteger  u2 = r.multiply(w).mod(q);
136 
137         BigInteger p = params.getP();
138         u1 = params.getG().modPow(u1, p);
139         u2 = ((DSAPublicKeyParameters)key).getY().modPow(u2, p);
140 
141         BigInteger  v = u1.multiply(u2).mod(p).mod(q);
142 
143         return v.equals(r);
144     }
145 
calculateE(BigInteger n, byte[] message)146     private BigInteger calculateE(BigInteger n, byte[] message)
147     {
148         if (n.bitLength() >= message.length * 8)
149         {
150             return new BigInteger(1, message);
151         }
152         else
153         {
154             byte[] trunc = new byte[n.bitLength() / 8];
155 
156             System.arraycopy(message, 0, trunc, 0, trunc.length);
157 
158             return new BigInteger(1, trunc);
159         }
160     }
161 
initSecureRandom(boolean needed, SecureRandom provided)162     protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided)
163     {
164         return !needed ? null : (provided != null) ? provided : new SecureRandom();
165     }
166 }
167