1package org.bouncycastle.jcajce.provider.asymmetric.dsa;
2
3import java.io.IOException;
4import java.math.BigInteger;
5import java.security.InvalidKeyException;
6import java.security.PrivateKey;
7import java.security.PublicKey;
8import java.security.SecureRandom;
9import java.security.SignatureException;
10import java.security.SignatureSpi;
11import java.security.spec.AlgorithmParameterSpec;
12
13import org.bouncycastle.asn1.ASN1Encoding;
14import org.bouncycastle.asn1.ASN1Integer;
15import org.bouncycastle.asn1.ASN1Primitive;
16import org.bouncycastle.asn1.ASN1Sequence;
17import org.bouncycastle.asn1.DERSequence;
18import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
19import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
20import org.bouncycastle.crypto.CipherParameters;
21import org.bouncycastle.crypto.DSA;
22import org.bouncycastle.crypto.Digest;
23import org.bouncycastle.crypto.digests.NullDigest;
24// Android-added: Check DSA keys when generated
25import org.bouncycastle.crypto.params.DSAKeyParameters;
26import org.bouncycastle.crypto.params.DSAParameters;
27import org.bouncycastle.crypto.params.ParametersWithRandom;
28// Android-removed: Unsupported algorithm
29// import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
30// Android-changed: Use Android digests
31// import org.bouncycastle.crypto.util.DigestFactory;
32import org.bouncycastle.crypto.digests.AndroidDigestFactory;
33import org.bouncycastle.util.Arrays;
34
35public class DSASigner
36    extends SignatureSpi
37    implements PKCSObjectIdentifiers, X509ObjectIdentifiers
38{
39    private Digest                  digest;
40    private DSA                     signer;
41    private SecureRandom            random;
42
43    protected DSASigner(
44        Digest digest,
45        DSA signer)
46    {
47        this.digest = digest;
48        this.signer = signer;
49    }
50
51    protected void engineInitVerify(
52        PublicKey   publicKey)
53        throws InvalidKeyException
54    {
55        CipherParameters    param = DSAUtil.generatePublicKeyParameter(publicKey);
56
57        digest.reset();
58        signer.init(false, param);
59    }
60
61    protected void engineInitSign(
62        PrivateKey      privateKey,
63        SecureRandom    random)
64        throws InvalidKeyException
65    {
66        this.random = random;
67        engineInitSign(privateKey);
68    }
69
70    protected void engineInitSign(
71        PrivateKey  privateKey)
72        throws InvalidKeyException
73    {
74        CipherParameters    param = DSAUtil.generatePrivateKeyParameter(privateKey);
75
76        // Android-added: Check DSA keys when generated
77        DSAParameters dsaParam = ((DSAKeyParameters) param).getParameters();
78        checkKey(dsaParam);
79
80        if (random != null)
81        {
82            param = new ParametersWithRandom(param, random);
83        }
84
85        digest.reset();
86        signer.init(true, param);
87    }
88
89    protected void engineUpdate(
90        byte    b)
91        throws SignatureException
92    {
93        digest.update(b);
94    }
95
96    protected void engineUpdate(
97        byte[]  b,
98        int     off,
99        int     len)
100        throws SignatureException
101    {
102        digest.update(b, off, len);
103    }
104
105    protected byte[] engineSign()
106        throws SignatureException
107    {
108        byte[]  hash = new byte[digest.getDigestSize()];
109
110        digest.doFinal(hash, 0);
111
112        try
113        {
114            BigInteger[]    sig = signer.generateSignature(hash);
115
116            return derEncode(sig[0], sig[1]);
117        }
118        catch (Exception e)
119        {
120            throw new SignatureException(e.toString());
121        }
122    }
123
124    protected boolean engineVerify(
125        byte[]  sigBytes)
126        throws SignatureException
127    {
128        byte[]  hash = new byte[digest.getDigestSize()];
129
130        digest.doFinal(hash, 0);
131
132        BigInteger[]    sig;
133
134        try
135        {
136            sig = derDecode(sigBytes);
137        }
138        catch (Exception e)
139        {
140            throw new SignatureException("error decoding signature bytes.");
141        }
142
143        return signer.verifySignature(hash, sig[0], sig[1]);
144    }
145
146    protected void engineSetParameter(
147        AlgorithmParameterSpec params)
148    {
149        throw new UnsupportedOperationException("engineSetParameter unsupported");
150    }
151
152    // BEGIN Android-added: Check DSA keys when generated
153    protected void checkKey(DSAParameters params) throws InvalidKeyException {
154        int valueL = params.getP().bitLength();
155        int valueN = params.getQ().bitLength();
156        int digestSize = digest.getDigestSize();
157
158        // The checks are consistent with DSAParametersGenerator's init method.
159        if ((valueL < 1024 || valueL > 3072) || valueL % 1024 != 0) {
160            throw new InvalidKeyException("valueL values must be between 1024 and 3072 and a multiple of 1024");
161        } else if (valueL == 1024 && valueN != 160) {
162            throw new InvalidKeyException("valueN must be 160 for valueL = 1024");
163        } else if (valueL == 2048 && (valueN != 224 && valueN != 256)) {
164            throw new InvalidKeyException("valueN must be 224 or 256 for valueL = 2048");
165        } else if (valueL == 3072 && valueN != 256) {
166            throw new InvalidKeyException("valueN must be 256 for valueL = 3072");
167        }
168        if (!(digest instanceof NullDigest) && valueN > digestSize * 8) {
169            throw new InvalidKeyException("Key is too strong for this signature algorithm");
170        }
171    }
172
173    // END Android-added: Check DSA keys when generated
174    /**
175     * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
176     */
177    protected void engineSetParameter(
178        String  param,
179        Object  value)
180    {
181        throw new UnsupportedOperationException("engineSetParameter unsupported");
182    }
183
184    /**
185     * @deprecated
186     */
187    protected Object engineGetParameter(
188        String      param)
189    {
190        throw new UnsupportedOperationException("engineSetParameter unsupported");
191    }
192
193    private byte[] derEncode(
194        BigInteger  r,
195        BigInteger  s)
196        throws IOException
197    {
198        ASN1Integer[] rs = new ASN1Integer[]{ new ASN1Integer(r), new ASN1Integer(s) };
199        return new DERSequence(rs).getEncoded(ASN1Encoding.DER);
200    }
201
202    private BigInteger[] derDecode(
203        byte[]  encoding)
204        throws IOException
205    {
206        ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
207        if (s.size() != 2)
208        {
209            throw new IOException("malformed signature");
210        }
211        if (!Arrays.areEqual(encoding, s.getEncoded(ASN1Encoding.DER)))
212        {
213            throw new IOException("malformed signature");
214        }
215
216        return new BigInteger[]{
217            ((ASN1Integer)s.getObjectAt(0)).getValue(),
218            ((ASN1Integer)s.getObjectAt(1)).getValue()
219        };
220    }
221
222    static public class stdDSA
223        extends DSASigner
224    {
225        public stdDSA()
226        {
227            // Android-changed: Use Android digests
228            // super(DigestFactory.createSHA1(), new org.bouncycastle.crypto.signers.DSASigner());
229            super(AndroidDigestFactory.getSHA1(), new org.bouncycastle.crypto.signers.DSASigner());
230        }
231    }
232
233    // BEGIN Android-removed: Unsupported algorithm
234    /*
235    static public class detDSA
236        extends DSASigner
237    {
238        public detDSA()
239        {
240            super(DigestFactory.createSHA1(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1())));
241        }
242    }
243    */
244    // END Android-removed: Unsupported algorithm
245
246    static public class dsa224
247        extends DSASigner
248    {
249        public dsa224()
250        {
251            // Android-changed: Use Android digests
252            // super(DigestFactory.createSHA224(), new org.bouncycastle.crypto.signers.DSASigner());
253            super(AndroidDigestFactory.getSHA224(), new org.bouncycastle.crypto.signers.DSASigner());
254        }
255    }
256
257    // BEGIN Android-removed: Unsupported algorithm
258    /*
259    static public class detDSA224
260        extends DSASigner
261    {
262        public detDSA224()
263        {
264            super(DigestFactory.createSHA224(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224())));
265        }
266    }
267    */
268    // END Android-removed: Unsupported algorithm
269
270    static public class dsa256
271        extends DSASigner
272    {
273        public dsa256()
274        {
275            // Android-changed: Use Android digests
276            // super(DigestFactory.createSHA256(), new org.bouncycastle.crypto.signers.DSASigner());
277            super(AndroidDigestFactory.getSHA256(), new org.bouncycastle.crypto.signers.DSASigner());
278        }
279    }
280
281    // BEGIN Android-removed: Unsupported algorithms
282    /*
283    static public class detDSA256
284        extends DSASigner
285    {
286        public detDSA256()
287        {
288            super(DigestFactory.createSHA256(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256())));
289        }
290    }
291
292    static public class dsa384
293        extends DSASigner
294    {
295        public dsa384()
296        {
297            super(DigestFactory.createSHA384(), new org.bouncycastle.crypto.signers.DSASigner());
298        }
299    }
300
301    static public class detDSA384
302        extends DSASigner
303    {
304        public detDSA384()
305        {
306            super(DigestFactory.createSHA384(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384())));
307        }
308    }
309
310    static public class dsa512
311        extends DSASigner
312    {
313        public dsa512()
314        {
315            super(DigestFactory.createSHA512(), new org.bouncycastle.crypto.signers.DSASigner());
316        }
317    }
318
319    static public class detDSA512
320        extends DSASigner
321    {
322        public detDSA512()
323        {
324            super(DigestFactory.createSHA512(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512())));
325        }
326    }
327
328    static public class dsaSha3_224
329        extends DSASigner
330    {
331        public dsaSha3_224()
332        {
333            super(DigestFactory.createSHA3_224(), new org.bouncycastle.crypto.signers.DSASigner());
334        }
335    }
336
337    static public class detDSASha3_224
338        extends DSASigner
339    {
340        public detDSASha3_224()
341        {
342            super(DigestFactory.createSHA3_224(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224())));
343        }
344    }
345
346    static public class dsaSha3_256
347        extends DSASigner
348    {
349        public dsaSha3_256()
350        {
351            super(DigestFactory.createSHA3_256(), new org.bouncycastle.crypto.signers.DSASigner());
352        }
353    }
354
355    static public class detDSASha3_256
356        extends DSASigner
357    {
358        public detDSASha3_256()
359        {
360            super(DigestFactory.createSHA3_256(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256())));
361        }
362    }
363
364    static public class dsaSha3_384
365        extends DSASigner
366    {
367        public dsaSha3_384()
368        {
369            super(DigestFactory.createSHA3_384(), new org.bouncycastle.crypto.signers.DSASigner());
370        }
371    }
372
373    static public class detDSASha3_384
374        extends DSASigner
375    {
376        public detDSASha3_384()
377        {
378            super(DigestFactory.createSHA3_384(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384())));
379        }
380    }
381
382    static public class dsaSha3_512
383        extends DSASigner
384    {
385        public dsaSha3_512()
386        {
387            super(DigestFactory.createSHA3_512(), new org.bouncycastle.crypto.signers.DSASigner());
388        }
389    }
390
391    static public class detDSASha3_512
392        extends DSASigner
393    {
394        public detDSASha3_512()
395        {
396            super(DigestFactory.createSHA3_512(), new org.bouncycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512())));
397        }
398    }
399    */
400    // END Android-removed: Unsupported algorithms
401
402    static public class noneDSA
403        extends DSASigner
404    {
405        public noneDSA()
406        {
407            super(new NullDigest(), new org.bouncycastle.crypto.signers.DSASigner());
408        }
409    }
410}
411