blob: d9532547b1f60c556bb29a43b338cdbabcd2ddca [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.provider;
27
28import java.io.*;
29import java.util.*;
30import java.math.BigInteger;
31import java.nio.ByteBuffer;
32
33import java.security.*;
34import java.security.SecureRandom;
35import java.security.interfaces.*;
36import java.security.spec.DSAParameterSpec;
37import java.security.spec.InvalidParameterSpecException;
38
39import sun.security.util.Debug;
40import sun.security.util.DerValue;
41import sun.security.util.DerInputStream;
42import sun.security.util.DerOutputStream;
43import sun.security.x509.AlgIdDSA;
44import sun.security.jca.JCAUtil;
45
46/**
47 * The Digital Signature Standard (using the Digital Signature
48 * Algorithm), as described in fips186 of the National Instute of
49 * Standards and Technology (NIST), using fips180-1 (SHA-1).
50 *
51 * This file contains both the signature implementation for the
52 * commonly used SHA1withDSA (DSS) as well as RawDSA, used by TLS
53 * among others. RawDSA expects the 20 byte SHA-1 digest as input
54 * via update rather than the original data like other signature
55 * implementations.
56 *
57 * @author Benjamin Renaud
58 *
59 * @since 1.1
60 *
61 * @see DSAPublicKey
62 * @see DSAPrivateKey
63 */
64abstract class DSA extends SignatureSpi {
65
66 /* Are we debugging? */
67 private static final boolean debug = false;
68
69 /* The parameter object */
70 private DSAParams params;
71
72 /* algorithm parameters */
73 private BigInteger presetP, presetQ, presetG;
74
75 /* The public key, if any */
76 private BigInteger presetY;
77
78 /* The private key, if any */
79 private BigInteger presetX;
80
81 /* The random seed used to generate k */
82 private int[] Kseed;
83
84 /* The random seed used to generate k (specified by application) */
85 private byte[] KseedAsByteArray;
86
87 /*
88 * The random seed used to generate k
89 * (prevent the same Kseed from being used twice in a row
90 */
91 private int[] previousKseed;
92
93 /* The RNG used to output a seed for generating k */
94 private SecureRandom signingRandom;
95
96 /**
97 * Construct a blank DSA object. It must be
98 * initialized before being usable for signing or verifying.
99 */
100 DSA() {
101 super();
102 }
103
104 /**
105 * Return the 20 byte hash value and reset the digest.
106 */
107 abstract byte[] getDigest() throws SignatureException;
108
109 /**
110 * Reset the digest.
111 */
112 abstract void resetDigest();
113
114 /**
115 * Standard SHA1withDSA implementation.
116 */
117 public static final class SHA1withDSA extends DSA {
118
119 /* The SHA hash for the data */
120 private final MessageDigest dataSHA;
121
122 public SHA1withDSA() throws NoSuchAlgorithmException {
123 dataSHA = MessageDigest.getInstance("SHA-1");
124 }
125
126 /**
127 * Update a byte to be signed or verified.
128 */
129 protected void engineUpdate(byte b) {
130 dataSHA.update(b);
131 }
132
133 /**
134 * Update an array of bytes to be signed or verified.
135 */
136 protected void engineUpdate(byte[] data, int off, int len) {
137 dataSHA.update(data, off, len);
138 }
139
140 protected void engineUpdate(ByteBuffer b) {
141 dataSHA.update(b);
142 }
143
144 byte[] getDigest() {
145 return dataSHA.digest();
146 }
147
148 void resetDigest() {
149 dataSHA.reset();
150 }
151 }
152
153 /**
154 * RawDSA implementation.
155 *
156 * RawDSA requires the data to be exactly 20 bytes long. If it is
157 * not, a SignatureException is thrown when sign()/verify() is called
158 * per JCA spec.
159 */
160 public static final class RawDSA extends DSA {
161
162 // length of the SHA-1 digest (20 bytes)
163 private final static int SHA1_LEN = 20;
164
165 // 20 byte digest buffer
166 private final byte[] digestBuffer;
167
168 // offset into the buffer
169 private int ofs;
170
171 public RawDSA() {
172 digestBuffer = new byte[SHA1_LEN];
173 }
174
175 protected void engineUpdate(byte b) {
176 if (ofs == SHA1_LEN) {
177 ofs = SHA1_LEN + 1;
178 return;
179 }
180 digestBuffer[ofs++] = b;
181 }
182
183 protected void engineUpdate(byte[] data, int off, int len) {
184 if (ofs + len > SHA1_LEN) {
185 ofs = SHA1_LEN + 1;
186 return;
187 }
188 System.arraycopy(data, off, digestBuffer, ofs, len);
189 ofs += len;
190 }
191
192 byte[] getDigest() throws SignatureException {
193 if (ofs != SHA1_LEN) {
194 throw new SignatureException
195 ("Data for RawDSA must be exactly 20 bytes long");
196 }
197 ofs = 0;
198 return digestBuffer;
199 }
200
201 void resetDigest() {
202 ofs = 0;
203 }
204 }
205
206 /**
207 * Initialize the DSA object with a DSA private key.
208 *
209 * @param privateKey the DSA private key
210 *
211 * @exception InvalidKeyException if the key is not a valid DSA private
212 * key.
213 */
214 protected void engineInitSign(PrivateKey privateKey)
215 throws InvalidKeyException {
216 if (!(privateKey instanceof java.security.interfaces.DSAPrivateKey)) {
217 throw new InvalidKeyException("not a DSA private key: " +
218 privateKey);
219 }
220 java.security.interfaces.DSAPrivateKey priv =
221 (java.security.interfaces.DSAPrivateKey)privateKey;
222 this.presetX = priv.getX();
223 this.presetY = null;
224 initialize(priv.getParams());
225 }
226
227 /**
228 * Initialize the DSA object with a DSA public key.
229 *
230 * @param publicKey the DSA public key.
231 *
232 * @exception InvalidKeyException if the key is not a valid DSA public
233 * key.
234 */
235 protected void engineInitVerify(PublicKey publicKey)
236 throws InvalidKeyException {
237 if (!(publicKey instanceof java.security.interfaces.DSAPublicKey)) {
238 throw new InvalidKeyException("not a DSA public key: " +
239 publicKey);
240 }
241 java.security.interfaces.DSAPublicKey pub =
242 (java.security.interfaces.DSAPublicKey)publicKey;
243 this.presetY = pub.getY();
244 this.presetX = null;
245 initialize(pub.getParams());
246 }
247
248 private void initialize(DSAParams params) throws InvalidKeyException {
249 resetDigest();
250 setParams(params);
251 }
252
253 /**
254 * Sign all the data thus far updated. The signature is formatted
255 * according to the Canonical Encoding Rules, returned as a DER
256 * sequence of Integer, r and s.
257 *
258 * @return a signature block formatted according to the Canonical
259 * Encoding Rules.
260 *
261 * @exception SignatureException if the signature object was not
262 * properly initialized, or if another exception occurs.
263 *
264 * @see sun.security.DSA#engineUpdate
265 * @see sun.security.DSA#engineVerify
266 */
267 protected byte[] engineSign() throws SignatureException {
268 BigInteger k = generateK(presetQ);
269 BigInteger r = generateR(presetP, presetQ, presetG, k);
270 BigInteger s = generateS(presetX, presetQ, r, k);
271
272 try {
273 DerOutputStream outseq = new DerOutputStream(100);
274 outseq.putInteger(r);
275 outseq.putInteger(s);
276 DerValue result = new DerValue(DerValue.tag_Sequence,
277 outseq.toByteArray());
278
279 return result.toByteArray();
280
281 } catch (IOException e) {
282 throw new SignatureException("error encoding signature");
283 }
284 }
285
286 /**
287 * Verify all the data thus far updated.
288 *
289 * @param signature the alledged signature, encoded using the
290 * Canonical Encoding Rules, as a sequence of integers, r and s.
291 *
292 * @exception SignatureException if the signature object was not
293 * properly initialized, or if another exception occurs.
294 *
295 * @see sun.security.DSA#engineUpdate
296 * @see sun.security.DSA#engineSign
297 */
298 protected boolean engineVerify(byte[] signature)
299 throws SignatureException {
300 return engineVerify(signature, 0, signature.length);
301 }
302
303 /**
304 * Verify all the data thus far updated.
305 *
306 * @param signature the alledged signature, encoded using the
307 * Canonical Encoding Rules, as a sequence of integers, r and s.
308 *
309 * @param offset the offset to start from in the array of bytes.
310 *
311 * @param length the number of bytes to use, starting at offset.
312 *
313 * @exception SignatureException if the signature object was not
314 * properly initialized, or if another exception occurs.
315 *
316 * @see sun.security.DSA#engineUpdate
317 * @see sun.security.DSA#engineSign
318 */
319 protected boolean engineVerify(byte[] signature, int offset, int length)
320 throws SignatureException {
321
322 BigInteger r = null;
323 BigInteger s = null;
324 // first decode the signature.
325 try {
326 DerInputStream in = new DerInputStream(signature, offset, length);
327 DerValue[] values = in.getSequence(2);
328
329 r = values[0].getBigInteger();
330 s = values[1].getBigInteger();
331
332 } catch (IOException e) {
333 throw new SignatureException("invalid encoding for signature");
334 }
335
336 // some implementations do not correctly encode values in the ASN.1
337 // 2's complement format. force r and s to be positive in order to
338 // to validate those signatures
339 if (r.signum() < 0) {
340 r = new BigInteger(1, r.toByteArray());
341 }
342 if (s.signum() < 0) {
343 s = new BigInteger(1, s.toByteArray());
344 }
345
346 if ((r.compareTo(presetQ) == -1) && (s.compareTo(presetQ) == -1)) {
347 BigInteger w = generateW(presetP, presetQ, presetG, s);
348 BigInteger v = generateV(presetY, presetP, presetQ, presetG, w, r);
349 return v.equals(r);
350 } else {
351 throw new SignatureException("invalid signature: out of range values");
352 }
353 }
354
355 private BigInteger generateR(BigInteger p, BigInteger q, BigInteger g,
356 BigInteger k) {
357 BigInteger temp = g.modPow(k, p);
358 return temp.remainder(q);
359 }
360
361 private BigInteger generateS(BigInteger x, BigInteger q,
362 BigInteger r, BigInteger k) throws SignatureException {
363
364 byte[] s2 = getDigest();
365 BigInteger temp = new BigInteger(1, s2);
366 BigInteger k1 = k.modInverse(q);
367
368 BigInteger s = x.multiply(r);
369 s = temp.add(s);
370 s = k1.multiply(s);
371 return s.remainder(q);
372 }
373
374 private BigInteger generateW(BigInteger p, BigInteger q,
375 BigInteger g, BigInteger s) {
376 return s.modInverse(q);
377 }
378
379 private BigInteger generateV(BigInteger y, BigInteger p,
380 BigInteger q, BigInteger g, BigInteger w, BigInteger r)
381 throws SignatureException {
382
383 byte[] s2 = getDigest();
384 BigInteger temp = new BigInteger(1, s2);
385
386 temp = temp.multiply(w);
387 BigInteger u1 = temp.remainder(q);
388
389 BigInteger u2 = (r.multiply(w)).remainder(q);
390
391 BigInteger t1 = g.modPow(u1,p);
392 BigInteger t2 = y.modPow(u2,p);
393 BigInteger t3 = t1.multiply(t2);
394 BigInteger t5 = t3.remainder(p);
395 return t5.remainder(q);
396 }
397
398 /*
399 * Please read bug report 4044247 for an alternative, faster,
400 * NON-FIPS approved method to generate K
401 */
402 private BigInteger generateK(BigInteger q) {
403
404 BigInteger k = null;
405
406 // The application specified a Kseed for us to use.
407 // Note that we do not allow usage of the same Kseed twice in a row
408 if (Kseed != null && !Arrays.equals(Kseed, previousKseed)) {
409 k = generateK(Kseed, q);
410 if (k.signum() > 0 && k.compareTo(q) < 0) {
411 previousKseed = new int [Kseed.length];
412 System.arraycopy(Kseed, 0, previousKseed, 0, Kseed.length);
413 return k;
414 }
415 }
416
417 // The application did not specify a Kseed for us to use.
418 // We'll generate a new Kseed by getting random bytes from
419 // a SecureRandom object.
420 SecureRandom random = getSigningRandom();
421
422 while (true) {
423 int[] seed = new int[5];
424
425 for (int i = 0; i < 5; i++)
426 seed[i] = random.nextInt();
427 k = generateK(seed, q);
428 if (k.signum() > 0 && k.compareTo(q) < 0) {
429 previousKseed = new int [seed.length];
430 System.arraycopy(seed, 0, previousKseed, 0, seed.length);
431 return k;
432 }
433 }
434 }
435
436 // Use the application-specified SecureRandom Object if provided.
437 // Otherwise, use our default SecureRandom Object.
438 private SecureRandom getSigningRandom() {
439 if (signingRandom == null) {
440 if (appRandom != null) {
441 signingRandom = appRandom;
442 } else {
443 signingRandom = JCAUtil.getSecureRandom();
444 }
445 }
446 return signingRandom;
447 }
448
449 /**
450 * Compute k for a DSA signature.
451 *
452 * @param seed the seed for generating k. This seed should be
453 * secure. This is what is refered to as the KSEED in the DSA
454 * specification.
455 *
456 * @param g the g parameter from the DSA key pair.
457 */
458 private BigInteger generateK(int[] seed, BigInteger q) {
459
460 // check out t in the spec.
461 int[] t = { 0xEFCDAB89, 0x98BADCFE, 0x10325476,
462 0xC3D2E1F0, 0x67452301 };
463 //
464 int[] tmp = DSA.SHA_7(seed, t);
465 byte[] tmpBytes = new byte[tmp.length * 4];
466 for (int i = 0; i < tmp.length; i++) {
467 int k = tmp[i];
468 for (int j = 0; j < 4; j++) {
469 tmpBytes[(i * 4) + j] = (byte) (k >>> (24 - (j * 8)));
470 }
471 }
472 BigInteger k = new BigInteger(1, tmpBytes).mod(q);
473 return k;
474 }
475
476 // Constants for each round
477 private static final int round1_kt = 0x5a827999;
478 private static final int round2_kt = 0x6ed9eba1;
479 private static final int round3_kt = 0x8f1bbcdc;
480 private static final int round4_kt = 0xca62c1d6;
481
482 /**
483 * Computes set 1 thru 7 of SHA-1 on m1. */
484 static int[] SHA_7(int[] m1, int[] h) {
485
486 int[] W = new int[80];
487 System.arraycopy(m1,0,W,0,m1.length);
488 int temp = 0;
489
490 for (int t = 16; t <= 79; t++){
491 temp = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16];
492 W[t] = ((temp << 1) | (temp >>>(32 - 1)));
493 }
494
495 int a = h[0],b = h[1],c = h[2], d = h[3], e = h[4];
496 for (int i = 0; i < 20; i++) {
497 temp = ((a<<5) | (a>>>(32-5))) +
498 ((b&c)|((~b)&d))+ e + W[i] + round1_kt;
499 e = d;
500 d = c;
501 c = ((b<<30) | (b>>>(32-30)));
502 b = a;
503 a = temp;
504 }
505
506 // Round 2
507 for (int i = 20; i < 40; i++) {
508 temp = ((a<<5) | (a>>>(32-5))) +
509 (b ^ c ^ d) + e + W[i] + round2_kt;
510 e = d;
511 d = c;
512 c = ((b<<30) | (b>>>(32-30)));
513 b = a;
514 a = temp;
515 }
516
517 // Round 3
518 for (int i = 40; i < 60; i++) {
519 temp = ((a<<5) | (a>>>(32-5))) +
520 ((b&c)|(b&d)|(c&d)) + e + W[i] + round3_kt;
521 e = d;
522 d = c;
523 c = ((b<<30) | (b>>>(32-30)));
524 b = a;
525 a = temp;
526 }
527
528 // Round 4
529 for (int i = 60; i < 80; i++) {
530 temp = ((a<<5) | (a>>>(32-5))) +
531 (b ^ c ^ d) + e + W[i] + round4_kt;
532 e = d;
533 d = c;
534 c = ((b<<30) | (b>>>(32-30)));
535 b = a;
536 a = temp;
537 }
538 int[] md = new int[5];
539 md[0] = h[0] + a;
540 md[1] = h[1] + b;
541 md[2] = h[2] + c;
542 md[3] = h[3] + d;
543 md[4] = h[4] + e;
544 return md;
545 }
546
547
548 /**
549 * This implementation recognizes the following parameter:<dl>
550 *
551 * <dt><tt>Kseed</tt>
552 *
553 * <dd>a byte array.
554 *
555 * </dl>
556 *
557 * @deprecated
558 */
559 @Deprecated
560 protected void engineSetParameter(String key, Object param) {
561 if (key.equals("KSEED")) {
562 if (param instanceof byte[]) {
563 Kseed = byteArray2IntArray((byte[])param);
564 KseedAsByteArray = (byte[])param;
565 } else {
566 debug("unrecognized param: " + key);
567 throw new InvalidParameterException("Kseed not a byte array");
568 }
569 } else {
570 throw new InvalidParameterException("invalid parameter");
571 }
572 }
573
574 /**
575 * Return the value of the requested parameter. Recognized
576 * parameters are:
577 *
578 * <dl>
579 *
580 * <dt><tt>Kseed</tt>
581 *
582 * <dd>a byte array.
583 *
584 * </dl>
585 *
586 * @return the value of the requested parameter.
587 *
588 * @see java.security.SignatureEngine
589 *
590 * @deprecated
591 */
592 @Deprecated
593 protected Object engineGetParameter(String key) {
594 if (key.equals("KSEED")) {
595 return KseedAsByteArray;
596 } else {
597 return null;
598 }
599 }
600
601 /**
602 * Set the algorithm object.
603 */
604 private void setParams(DSAParams params) throws InvalidKeyException {
605 if (params == null) {
606 throw new InvalidKeyException("DSA public key lacks parameters");
607 }
608 this.params = params;
609 this.presetP = params.getP();
610 this.presetQ = params.getQ();
611 this.presetG = params.getG();
612 }
613
614 /**
615 * Return a human readable rendition of the engine.
616 */
617 public String toString() {
618 String printable = "DSA Signature";
619 if (presetP != null && presetQ != null && presetG != null) {
620 printable += "\n\tp: " + Debug.toHexString(presetP);
621 printable += "\n\tq: " + Debug.toHexString(presetQ);
622 printable += "\n\tg: " + Debug.toHexString(presetG);
623 } else {
624 printable += "\n\t P, Q or G not initialized.";
625 }
626 if (presetY != null) {
627 printable += "\n\ty: " + Debug.toHexString(presetY);
628 }
629 if (presetY == null && presetX == null) {
630 printable += "\n\tUNINIIALIZED";
631 }
632 return printable;
633 }
634
635 /*
636 * Utility routine for converting a byte array into an int array
637 */
638 private int[] byteArray2IntArray(byte[] byteArray) {
639
640 int j = 0;
641 byte[] newBA;
642 int mod = byteArray.length % 4;
643
644 // guarantee that the incoming byteArray is a multiple of 4
645 // (pad with 0's)
646 switch (mod) {
647 case 3: newBA = new byte[byteArray.length + 1]; break;
648 case 2: newBA = new byte[byteArray.length + 2]; break;
649 case 1: newBA = new byte[byteArray.length + 3]; break;
650 default: newBA = new byte[byteArray.length + 0]; break;
651 }
652 System.arraycopy(byteArray, 0, newBA, 0, byteArray.length);
653
654 // copy each set of 4 bytes in the byte array into an integer
655 int[] newSeed = new int[newBA.length / 4];
656 for (int i = 0; i < newBA.length; i += 4) {
657 newSeed[j] = newBA[i + 3] & 0xFF;
658 newSeed[j] |= (newBA[i + 2] << 8) & 0xFF00;
659 newSeed[j] |= (newBA[i + 1] << 16) & 0xFF0000;
660 newSeed[j] |= (newBA[i + 0] << 24) & 0xFF000000;
661 j++;
662 }
663
664 return newSeed;
665 }
666
667 private static void debug(Exception e) {
668 if (debug) {
669 e.printStackTrace();
670 }
671 }
672
673 private static void debug(String s) {
674 if (debug) {
675 System.err.println(s);
676 }
677 }
678}