1 /*
  2  * Copyright (c) 1996, 2020, Oracle and/or its affiliates. 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.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package sun.security.provider;
 27 
 28 import java.io.*;
 29 import java.util.*;
 30 import java.math.BigInteger;
 31 import java.nio.ByteBuffer;
 32 
 33 import java.security.*;
 34 import java.security.SecureRandom;
 35 import java.security.interfaces.*;
 36 import java.security.spec.*;
 37 
 38 import sun.security.util.Debug;
 39 import sun.security.util.DerValue;
 40 import sun.security.util.DerInputStream;
 41 import sun.security.util.DerOutputStream;
 42 import sun.security.jca.JCAUtil;
 43 
 44 /**
 45  * The Digital Signature Standard (using the Digital Signature
 46  * Algorithm), as described in fips186-3 of the National Instute of
 47  * Standards and Technology (NIST), using SHA digest algorithms
 48  * from FIPS180-3.
 49  *
 50  * This file contains both the signature implementation for the
 51  * commonly used SHA1withDSA (DSS), SHA224withDSA, SHA256withDSA,
 52  * SHA384withDSA, SHA512withDSA, SHA3-224withDSA, SHA3-256withDSA,
 53  * SHA3-384withDSA, SHA3-512withDSA, as well as RawDSA, used by
 54  * TLS among others. RawDSA expects the 20 byte SHA-1 digest as
 55  * input via update rather than the original data like other signature
 56  * implementations.
 57  *
 58  * @author Benjamin Renaud
 59  *
 60  * @since   1.1
 61  *
 62  * @see DSAPublicKey
 63  * @see DSAPrivateKey
 64  */
 65 abstract class DSA extends SignatureSpi {
 66 
 67     /* Are we debugging? */
 68     private static final boolean debug = false;
 69 
 70     /* The number of bits used in exponent blinding */
 71     private static final int BLINDING_BITS = 7;
 72 
 73     /* The constant component of the exponent blinding value */
 74     private static final BigInteger BLINDING_CONSTANT =
 75         BigInteger.valueOf(1 << BLINDING_BITS);
 76 
 77     /* The parameter object */
 78     private DSAParams params;
 79 
 80     /* algorithm parameters */
 81     private BigInteger presetP, presetQ, presetG;
 82 
 83     /* The public key, if any */
 84     private BigInteger presetY;
 85 
 86     /* The private key, if any */
 87     private BigInteger presetX;
 88 
 89     /* The RNG used to output a seed for generating k */
 90     private SecureRandom signingRandom;
 91 
 92     /* The message digest object used */
 93     private final MessageDigest md;
 94 
 95     /* The format. true for the IEEE P1363 format. false (default) for ASN.1 */
 96     private final boolean p1363Format;
 97 
 98     /**
 99      * Construct a blank DSA object. It must be
100      * initialized before being usable for signing or verifying.
101      */
102     DSA(MessageDigest md) {
103         this(md, false);
104     }
105 
106     /**
107      * Construct a blank DSA object that will use the specified
108      * signature format. {@code p1363Format} should be {@code true} to
109      * use the IEEE P1363 format. If {@code p1363Format} is {@code false},
110      * the DER-encoded ASN.1 format will be used. The DSA object must be
111      * initialized before being usable for signing or verifying.
112      */
113     DSA(MessageDigest md, boolean p1363Format) {
114         super();
115         this.md = md;
116         this.p1363Format = p1363Format;
117     }
118 
119     private static void checkKey(DSAParams params, int digestLen, String mdAlgo)
120         throws InvalidKeyException {
121         // FIPS186-3 states in sec4.2 that a hash function which provides
122         // a lower security strength than the (L, N) pair ordinarily should
123         // not be used.
124         int valueN = params.getQ().bitLength();
125         if (valueN > digestLen) {
126             throw new InvalidKeyException("The security strength of " +
127                 mdAlgo + " digest algorithm is not sufficient for this key size");
128         }
129     }
130 
131     /**
132      * Initialize the DSA object with a DSA private key.
133      *
134      * @param privateKey the DSA private key
135      *
136      * @exception InvalidKeyException if the key is not a valid DSA private
137      * key.
138      */
139     protected void engineInitSign(PrivateKey privateKey)
140             throws InvalidKeyException {
141         if (!(privateKey instanceof java.security.interfaces.DSAPrivateKey)) {
142             throw new InvalidKeyException("not a DSA private key: " +
143                                           privateKey);
144         }
145 
146         java.security.interfaces.DSAPrivateKey priv =
147             (java.security.interfaces.DSAPrivateKey)privateKey;
148 
149         // check for algorithm specific constraints before doing initialization
150         DSAParams params = priv.getParams();
151         if (params == null) {
152             throw new InvalidKeyException("DSA private key lacks parameters");
153         }
154 
155         // check key size against hash output size for signing
156         // skip this check for verification to minimize impact on existing apps
157         if (!"NullDigest20".equals(md.getAlgorithm())) {
158             checkKey(params, md.getDigestLength()*8, md.getAlgorithm());
159         }
160 
161         this.params = params;
162         this.presetX = priv.getX();
163         this.presetY = null;
164         this.presetP = params.getP();
165         this.presetQ = params.getQ();
166         this.presetG = params.getG();
167         this.md.reset();
168     }
169     /**
170      * Initialize the DSA object with a DSA public key.
171      *
172      * @param publicKey the DSA public key.
173      *
174      * @exception InvalidKeyException if the key is not a valid DSA public
175      * key.
176      */
177     protected void engineInitVerify(PublicKey publicKey)
178             throws InvalidKeyException {
179         if (!(publicKey instanceof java.security.interfaces.DSAPublicKey)) {
180             throw new InvalidKeyException("not a DSA public key: " +
181                                           publicKey);
182         }
183         java.security.interfaces.DSAPublicKey pub =
184             (java.security.interfaces.DSAPublicKey)publicKey;
185 
186         // check for algorithm specific constraints before doing initialization
187         DSAParams params = pub.getParams();
188         if (params == null) {
189             throw new InvalidKeyException("DSA public key lacks parameters");
190         }
191         this.params = params;
192         this.presetY = pub.getY();
193         this.presetX = null;
194         this.presetP = params.getP();
195         this.presetQ = params.getQ();
196         this.presetG = params.getG();
197         this.md.reset();
198     }
199 
200     /**
201      * Update a byte to be signed or verified.
202      */
203     protected void engineUpdate(byte b) {
204         md.update(b);
205     }
206 
207     /**
208      * Update an array of bytes to be signed or verified.
209      */
210     protected void engineUpdate(byte[] data, int off, int len) {
211         md.update(data, off, len);
212     }
213 
214     protected void engineUpdate(ByteBuffer b) {
215         md.update(b);
216     }
217 
218 
219     /**
220      * Sign all the data thus far updated. The signature format is
221      * determined by {@code p1363Format}. If {@code p1363Format} is
222      * {@code false} (the default), then the signature is formatted
223      * according to the Canonical Encoding Rules, returned as a DER
224      * sequence of Integers, r and s. If {@code p1363Format} is
225      * {@code false}, the signature is returned in the IEEE P1363
226      * format, which is the concatenation or r and s.
227      *
228      * @return a signature block formatted according to the format
229      * indicated by {@code p1363Format}
230      *
231      * @exception SignatureException if the signature object was not
232      * properly initialized, or if another exception occurs.
233      *
234      * @see sun.security.DSA#engineUpdate
235      * @see sun.security.DSA#engineVerify
236      */
237     protected byte[] engineSign() throws SignatureException {
238         BigInteger k = generateK(presetQ);
239         BigInteger r = generateR(presetP, presetQ, presetG, k);
240         BigInteger s = generateS(presetX, presetQ, r, k);
241 
242         if (p1363Format) {
243             // Return the concatenation of r and s
244             byte[] rBytes = r.toByteArray();
245             byte[] sBytes = s.toByteArray();
246 
247             int size = presetQ.bitLength() / 8;
248             byte[] outseq = new byte[size * 2];
249 
250             int rLength = rBytes.length;
251             int sLength = sBytes.length;
252             int i;
253             for (i = rLength; i > 0 && rBytes[rLength - i] == 0; i--);
254 
255             int j;
256             for (j = sLength;
257                     j > 0 && sBytes[sLength - j] == 0; j--);
258 
259             System.arraycopy(rBytes, rLength - i, outseq, size - i, i);
260             System.arraycopy(sBytes, sLength - j, outseq, size * 2 - j, j);
261 
262             return outseq;
263         } else {
264             // Return the DER-encoded ASN.1 form
265             try {
266                 DerOutputStream outseq = new DerOutputStream(100);
267                 outseq.putInteger(r);
268                 outseq.putInteger(s);
269                 DerValue result = new DerValue(DerValue.tag_Sequence,
270                         outseq.toByteArray());
271 
272                 return result.toByteArray();
273 
274             } catch (IOException e) {
275                 throw new SignatureException("error encoding signature");
276             }
277         }
278     }
279 
280     /**
281      * Verify all the data thus far updated.
282      *
283      * @param signature the alleged signature, encoded using the
284      * Canonical Encoding Rules, as a sequence of integers, r and s.
285      *
286      * @exception SignatureException if the signature object was not
287      * properly initialized, or if another exception occurs.
288      *
289      * @see sun.security.DSA#engineUpdate
290      * @see sun.security.DSA#engineSign
291      */
292     protected boolean engineVerify(byte[] signature)
293             throws SignatureException {
294         return engineVerify(signature, 0, signature.length);
295     }
296 
297     /**
298      * Verify all the data thus far updated.
299      *
300      * @param signature the alleged signature, encoded using the
301      * format indicated by {@code p1363Format}. If {@code p1363Format}
302      * is {@code false} (the default), then the signature is formatted
303      * according to the Canonical Encoding Rules, as a DER sequence of
304      * Integers, r and s. If {@code p1363Format} is {@code false},
305      * the signature is in the IEEE P1363 format, which is the
306      * concatenation or r and s.
307      *
308      * @param offset the offset to start from in the array of bytes.
309      *
310      * @param length the number of bytes to use, starting at offset.
311      *
312      * @exception SignatureException if the signature object was not
313      * properly initialized, or if another exception occurs.
314      *
315      * @see sun.security.DSA#engineUpdate
316      * @see sun.security.DSA#engineSign
317      */
318     protected boolean engineVerify(byte[] signature, int offset, int length)
319             throws SignatureException {
320 
321         BigInteger r = null;
322         BigInteger s = null;
323 
324         if (p1363Format) {
325             if ((length & 1) == 1) {
326                 // length of signature byte array should be even
327                 throw new SignatureException("invalid signature format");
328             }
329             int mid = length/2;
330             r = new BigInteger(Arrays.copyOfRange(signature, 0, mid));
331             s = new BigInteger(Arrays.copyOfRange(signature, mid, length));
332         } else {
333             // first decode the signature.
334             try {
335                 // Enforce strict DER checking for signatures
336                 DerInputStream in =
337                     new DerInputStream(signature, offset, length, false);
338                 DerValue[] values = in.getSequence(2);
339 
340                 // check number of components in the read sequence
341                 // and trailing data
342                 if ((values.length != 2) || (in.available() != 0)) {
343                     throw new IOException("Invalid encoding for signature");
344                 }
345                 r = values[0].getBigInteger();
346                 s = values[1].getBigInteger();
347             } catch (IOException e) {
348                 throw new SignatureException("Invalid encoding for signature", e);
349             }
350         }
351 
352         // some implementations do not correctly encode values in the ASN.1
353         // 2's complement format. force r and s to be positive in order to
354         // to validate those signatures
355         if (r.signum() < 0) {
356             r = new BigInteger(1, r.toByteArray());
357         }
358         if (s.signum() < 0) {
359             s = new BigInteger(1, s.toByteArray());
360         }
361 
362         if ((r.compareTo(presetQ) == -1) && (s.compareTo(presetQ) == -1)) {
363             BigInteger w = generateW(presetP, presetQ, presetG, s);
364             BigInteger v = generateV(presetY, presetP, presetQ, presetG, w, r);
365             return v.equals(r);
366         } else {
367             throw new SignatureException("invalid signature: out of range values");
368         }
369     }
370 
371     @Deprecated
372     protected void engineSetParameter(String key, Object param) {
373         throw new InvalidParameterException("No parameter accepted");
374     }
375 
376     @Override
377     protected void engineSetParameter(AlgorithmParameterSpec params)
378             throws InvalidAlgorithmParameterException {
379         if (params != null) {
380             throw new InvalidAlgorithmParameterException("No parameter accepted");
381         }
382     }
383 
384     @Deprecated
385     protected Object engineGetParameter(String key) {
386         return null;
387     }
388 
389     @Override
390     protected AlgorithmParameters engineGetParameters() {
391         return null;
392     }
393 
394 
395     private BigInteger generateR(BigInteger p, BigInteger q, BigInteger g,
396                          BigInteger k) {
397 
398         // exponent blinding to hide information from timing channel
399         SecureRandom random = getSigningRandom();
400         // start with a random blinding component
401         BigInteger blindingValue = new BigInteger(BLINDING_BITS, random);
402         // add the fixed blinding component
403         blindingValue = blindingValue.add(BLINDING_CONSTANT);
404         // replace k with a blinded value that is congruent (mod q)
405         k = k.add(q.multiply(blindingValue));
406 
407         BigInteger temp = g.modPow(k, p);
408         return temp.mod(q);
409     }
410 
411     private BigInteger generateS(BigInteger x, BigInteger q,
412             BigInteger r, BigInteger k) throws SignatureException {
413 
414         byte[] s2;
415         try {
416             s2 = md.digest();
417         } catch (RuntimeException re) {
418             // Only for RawDSA due to its 20-byte length restriction
419             throw new SignatureException(re.getMessage());
420         }
421         // get the leftmost min(N, outLen) bits of the digest value
422         int nBytes = q.bitLength()/8;
423         if (nBytes < s2.length) {
424             s2 = Arrays.copyOfRange(s2, 0, nBytes);
425         }
426         BigInteger z = new BigInteger(1, s2);
427         BigInteger k1 = k.modInverse(q);
428 
429         return x.multiply(r).add(z).multiply(k1).mod(q);
430     }
431 
432     private BigInteger generateW(BigInteger p, BigInteger q,
433                          BigInteger g, BigInteger s) {
434         return s.modInverse(q);
435     }
436 
437     private BigInteger generateV(BigInteger y, BigInteger p,
438              BigInteger q, BigInteger g, BigInteger w, BigInteger r)
439              throws SignatureException {
440 
441         byte[] s2;
442         try {
443             s2 = md.digest();
444         } catch (RuntimeException re) {
445             // Only for RawDSA due to its 20-byte length restriction
446             throw new SignatureException(re.getMessage());
447         }
448         // get the leftmost min(N, outLen) bits of the digest value
449         int nBytes = q.bitLength()/8;
450         if (nBytes < s2.length) {
451             s2 = Arrays.copyOfRange(s2, 0, nBytes);
452         }
453         BigInteger z = new BigInteger(1, s2);
454 
455         BigInteger u1 = z.multiply(w).mod(q);
456         BigInteger u2 = (r.multiply(w)).mod(q);
457 
458         BigInteger t1 = g.modPow(u1,p);
459         BigInteger t2 = y.modPow(u2,p);
460         BigInteger t3 = t1.multiply(t2);
461         BigInteger t5 = t3.mod(p);
462         return t5.mod(q);
463     }
464 
465     protected BigInteger generateK(BigInteger q) {
466         // Implementation defined in FIPS 186-4 AppendixB.2.1.
467         SecureRandom random = getSigningRandom();
468         byte[] kValue = new byte[(q.bitLength() + 7)/8 + 8];
469 
470         random.nextBytes(kValue);
471         return new BigInteger(1, kValue).mod(
472                 q.subtract(BigInteger.ONE)).add(BigInteger.ONE);
473     }
474 
475     // Use the application-specified SecureRandom Object if provided.
476     // Otherwise, use our default SecureRandom Object.
477     protected SecureRandom getSigningRandom() {
478         if (signingRandom == null) {
479             if (appRandom != null) {
480                 signingRandom = appRandom;
481             } else {
482                 signingRandom = JCAUtil.getSecureRandom();
483             }
484         }
485         return signingRandom;
486     }
487 
488     /**
489      * Return a human readable rendition of the engine.
490      */
491     public String toString() {
492         String printable = "DSA Signature";
493         if (presetP != null && presetQ != null && presetG != null) {
494             printable += "\n\tp: " + Debug.toHexString(presetP);
495             printable += "\n\tq: " + Debug.toHexString(presetQ);
496             printable += "\n\tg: " + Debug.toHexString(presetG);
497         } else {
498             printable += "\n\t P, Q or G not initialized.";
499         }
500         if (presetY != null) {
501             printable += "\n\ty: " + Debug.toHexString(presetY);
502         }
503         if (presetY == null && presetX == null) {
504             printable += "\n\tUNINIIALIZED";
505         }
506         return printable;
507     }
508 
509     public static final class SHA3_224withDSA extends DSA {
510         public SHA3_224withDSA() throws NoSuchAlgorithmException {
511             super(MessageDigest.getInstance("SHA3-224"));
512         }
513     }
514     public static final class SHA3_224withDSAinP1363Format extends DSA {
515         public SHA3_224withDSAinP1363Format() throws NoSuchAlgorithmException {
516             super(MessageDigest.getInstance("SHA3-224"), true);
517         }
518     }
519 
520     public static final class SHA3_256withDSA extends DSA {
521         public SHA3_256withDSA() throws NoSuchAlgorithmException {
522             super(MessageDigest.getInstance("SHA3-256"));
523         }
524     }
525     public static final class SHA3_256withDSAinP1363Format extends DSA {
526         public SHA3_256withDSAinP1363Format() throws NoSuchAlgorithmException {
527             super(MessageDigest.getInstance("SHA3-256"), true);
528         }
529     }
530 
531     public static final class SHA3_384withDSA extends DSA {
532         public SHA3_384withDSA() throws NoSuchAlgorithmException {
533             super(MessageDigest.getInstance("SHA3-384"));
534         }
535     }
536     public static final class SHA3_384withDSAinP1363Format extends DSA {
537         public SHA3_384withDSAinP1363Format() throws NoSuchAlgorithmException {
538             super(MessageDigest.getInstance("SHA3-384"), true);
539         }
540     }
541 
542     public static final class SHA3_512withDSA extends DSA {
543         public SHA3_512withDSA() throws NoSuchAlgorithmException {
544             super(MessageDigest.getInstance("SHA3-512"));
545         }
546     }
547     public static final class SHA3_512withDSAinP1363Format extends DSA {
548         public SHA3_512withDSAinP1363Format() throws NoSuchAlgorithmException {
549             super(MessageDigest.getInstance("SHA3-512"), true);
550         }
551     }
552 
553     /**
554      * Standard SHA224withDSA implementation as defined in FIPS186-3.
555      */
556     public static final class SHA224withDSA extends DSA {
557         public SHA224withDSA() throws NoSuchAlgorithmException {
558             super(MessageDigest.getInstance("SHA-224"));
559         }
560     }
561 
562     /**
563      * SHA224withDSA implementation that uses the IEEE P1363 format.
564      */
565     public static final class SHA224withDSAinP1363Format extends DSA {
566         public SHA224withDSAinP1363Format() throws NoSuchAlgorithmException {
567             super(MessageDigest.getInstance("SHA-224"), true);
568         }
569     }
570 
571     /**
572      * Standard SHA256withDSA implementation as defined in FIPS186-3.
573      */
574     public static final class SHA256withDSA extends DSA {
575         public SHA256withDSA() throws NoSuchAlgorithmException {
576             super(MessageDigest.getInstance("SHA-256"));
577         }
578     }
579 
580     /**
581      * SHA256withDSA implementation that uses the IEEE P1363 format.
582      */
583     public static final class SHA256withDSAinP1363Format extends DSA {
584         public SHA256withDSAinP1363Format() throws NoSuchAlgorithmException {
585             super(MessageDigest.getInstance("SHA-256"), true);
586         }
587     }
588 
589     /**
590      * Standard SHA384withDSA implementation as defined in FIPS186-3.
591      */
592     public static final class SHA384withDSA extends DSA {
593         public SHA384withDSA() throws NoSuchAlgorithmException {
594             super(MessageDigest.getInstance("SHA-384"));
595         }
596     }
597 
598     /**
599      * SHA384withDSA implementation that uses the IEEE P1363 format.
600      */
601     public static final class SHA384withDSAinP1363Format extends DSA {
602         public SHA384withDSAinP1363Format() throws NoSuchAlgorithmException {
603             super(MessageDigest.getInstance("SHA-384"), true);
604         }
605     }
606 
607     /**
608      * Standard SHA512withDSA implementation as defined in FIPS186-3.
609      */
610     public static final class SHA512withDSA extends DSA {
611         public SHA512withDSA() throws NoSuchAlgorithmException {
612             super(MessageDigest.getInstance("SHA-512"));
613         }
614     }
615 
616     /**
617      * SHA512withDSA implementation that uses the IEEE P1363 format.
618      */
619     public static final class SHA512withDSAinP1363Format extends DSA {
620         public SHA512withDSAinP1363Format() throws NoSuchAlgorithmException {
621             super(MessageDigest.getInstance("SHA-512"), true);
622         }
623     }
624 
625     /**
626      * Standard SHA1withDSA implementation.
627      */
628     public static final class SHA1withDSA extends DSA {
629         public SHA1withDSA() throws NoSuchAlgorithmException {
630             super(MessageDigest.getInstance("SHA-1"));
631         }
632     }
633 
634     /**
635      * SHA1withDSA implementation that uses the IEEE P1363 format.
636      */
637     public static final class SHA1withDSAinP1363Format extends DSA {
638         public SHA1withDSAinP1363Format() throws NoSuchAlgorithmException {
639             super(MessageDigest.getInstance("SHA-1"), true);
640         }
641     }
642 
643     /**
644      * Raw DSA.
645      *
646      * Raw DSA requires the data to be exactly 20 bytes long. If it is
647      * not, a SignatureException is thrown when sign()/verify() is called
648      * per JCA spec.
649      */
650     static class Raw extends DSA {
651         // Internal special-purpose MessageDigest impl for RawDSA
652         // Only override whatever methods used
653         // NOTE: no clone support
654         public static final class NullDigest20 extends MessageDigest {
655             // 20 byte digest buffer
656             private final byte[] digestBuffer = new byte[20];
657 
658             // offset into the buffer; use Integer.MAX_VALUE to indicate
659             // out-of-bound condition
660             private int ofs = 0;
661 
662             protected NullDigest20() {
663                 super("NullDigest20");
664             }
665             protected void engineUpdate(byte input) {
666                 if (ofs == digestBuffer.length) {
667                     ofs = Integer.MAX_VALUE;
668                 } else {
669                     digestBuffer[ofs++] = input;
670                 }
671             }
672             protected void engineUpdate(byte[] input, int offset, int len) {
673                 if (len > (digestBuffer.length - ofs)) {
674                     ofs = Integer.MAX_VALUE;
675                 } else {
676                     System.arraycopy(input, offset, digestBuffer, ofs, len);
677                     ofs += len;
678                 }
679             }
680             protected final void engineUpdate(ByteBuffer input) {
681                 int inputLen = input.remaining();
682                 if (inputLen > (digestBuffer.length - ofs)) {
683                     ofs = Integer.MAX_VALUE;
684                 } else {
685                     input.get(digestBuffer, ofs, inputLen);
686                     ofs += inputLen;
687                 }
688             }
689             protected byte[] engineDigest() throws RuntimeException {
690                 if (ofs != digestBuffer.length) {
691                     throw new RuntimeException
692                         ("Data for RawDSA must be exactly 20 bytes long");
693                 }
694                 reset();
695                 return digestBuffer;
696             }
697             protected int engineDigest(byte[] buf, int offset, int len)
698                 throws DigestException {
699                 if (ofs != digestBuffer.length) {
700                     throw new DigestException
701                         ("Data for RawDSA must be exactly 20 bytes long");
702                 }
703                 if (len < digestBuffer.length) {
704                     throw new DigestException
705                         ("Output buffer too small; must be at least 20 bytes");
706                 }
707                 System.arraycopy(digestBuffer, 0, buf, offset, digestBuffer.length);
708                 reset();
709                 return digestBuffer.length;
710             }
711 
712             protected void engineReset() {
713                 ofs = 0;
714             }
715             protected final int engineGetDigestLength() {
716                 return digestBuffer.length;
717             }
718         }
719 
720         private Raw(boolean p1363Format) throws NoSuchAlgorithmException {
721             super(new NullDigest20(), p1363Format);
722         }
723 
724     }
725 
726     /**
727      * Standard Raw DSA implementation.
728      */
729     public static final class RawDSA extends Raw {
730         public RawDSA() throws NoSuchAlgorithmException {
731             super(false);
732         }
733     }
734 
735     /**
736      * Raw DSA implementation that uses the IEEE P1363 format.
737      */
738     public static final class RawDSAinP1363Format extends Raw {
739         public RawDSAinP1363Format() throws NoSuchAlgorithmException {
740             super(true);
741         }
742     }
743 }