Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/provider/DSA.java
38830 views
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.x509.AlgIdDSA;
43
import sun.security.jca.JCAUtil;
44
45
/**
46
* The Digital Signature Standard (using the Digital Signature
47
* Algorithm), as described in fips186-3 of the National Instute of
48
* Standards and Technology (NIST), using SHA digest algorithms
49
* from FIPS180-3.
50
*
51
* This file contains both the signature implementation for the
52
* commonly used SHA1withDSA (DSS), SHA224withDSA, SHA256withDSA,
53
* as well as RawDSA, used by TLS among others. RawDSA expects
54
* the 20 byte SHA-1 digest as input via update rather than the
55
* original data like other signature implementations.
56
*
57
* @author Benjamin Renaud
58
*
59
* @since 1.1
60
*
61
* @see DSAPublicKey
62
* @see DSAPrivateKey
63
*/
64
abstract class DSA extends SignatureSpi {
65
66
/* Are we debugging? */
67
private static final boolean debug = false;
68
69
/* The number of bits used in exponent blinding */
70
private static final int BLINDING_BITS = 7;
71
72
/* The constant component of the exponent blinding value */
73
private static final BigInteger BLINDING_CONSTANT =
74
BigInteger.valueOf(1 << BLINDING_BITS);
75
76
/* The parameter object */
77
private DSAParams params;
78
79
/* algorithm parameters */
80
private BigInteger presetP, presetQ, presetG;
81
82
/* The public key, if any */
83
private BigInteger presetY;
84
85
/* The private key, if any */
86
private BigInteger presetX;
87
88
/* The RNG used to output a seed for generating k */
89
private SecureRandom signingRandom;
90
91
/* The message digest object used */
92
private final MessageDigest md;
93
94
/**
95
* Construct a blank DSA object. It must be
96
* initialized before being usable for signing or verifying.
97
*/
98
DSA(MessageDigest md) {
99
super();
100
this.md = md;
101
}
102
103
private static void checkKey(DSAParams params, int digestLen, String mdAlgo)
104
throws InvalidKeyException {
105
// FIPS186-3 states in sec4.2 that a hash function which provides
106
// a lower security strength than the (L, N) pair ordinarily should
107
// not be used.
108
int valueN = params.getQ().bitLength();
109
if (valueN > digestLen) {
110
throw new InvalidKeyException("The security strength of " +
111
mdAlgo + " digest algorithm is not sufficient for this key size");
112
}
113
}
114
115
/**
116
* Initialize the DSA object with a DSA private key.
117
*
118
* @param privateKey the DSA private key
119
*
120
* @exception InvalidKeyException if the key is not a valid DSA private
121
* key.
122
*/
123
protected void engineInitSign(PrivateKey privateKey)
124
throws InvalidKeyException {
125
if (!(privateKey instanceof java.security.interfaces.DSAPrivateKey)) {
126
throw new InvalidKeyException("not a DSA private key: " +
127
privateKey);
128
}
129
130
java.security.interfaces.DSAPrivateKey priv =
131
(java.security.interfaces.DSAPrivateKey)privateKey;
132
133
// check for algorithm specific constraints before doing initialization
134
DSAParams params = priv.getParams();
135
if (params == null) {
136
throw new InvalidKeyException("DSA private key lacks parameters");
137
}
138
139
// check key size against hash output size for signing
140
// skip this check for verification to minimize impact on existing apps
141
if (md.getAlgorithm() != "NullDigest20") {
142
checkKey(params, md.getDigestLength()*8, md.getAlgorithm());
143
}
144
145
this.params = params;
146
this.presetX = priv.getX();
147
this.presetY = null;
148
this.presetP = params.getP();
149
this.presetQ = params.getQ();
150
this.presetG = params.getG();
151
this.md.reset();
152
}
153
/**
154
* Initialize the DSA object with a DSA public key.
155
*
156
* @param publicKey the DSA public key.
157
*
158
* @exception InvalidKeyException if the key is not a valid DSA public
159
* key.
160
*/
161
protected void engineInitVerify(PublicKey publicKey)
162
throws InvalidKeyException {
163
if (!(publicKey instanceof java.security.interfaces.DSAPublicKey)) {
164
throw new InvalidKeyException("not a DSA public key: " +
165
publicKey);
166
}
167
java.security.interfaces.DSAPublicKey pub =
168
(java.security.interfaces.DSAPublicKey)publicKey;
169
170
// check for algorithm specific constraints before doing initialization
171
DSAParams params = pub.getParams();
172
if (params == null) {
173
throw new InvalidKeyException("DSA public key lacks parameters");
174
}
175
this.params = params;
176
this.presetY = pub.getY();
177
this.presetX = null;
178
this.presetP = params.getP();
179
this.presetQ = params.getQ();
180
this.presetG = params.getG();
181
this.md.reset();
182
}
183
184
/**
185
* Update a byte to be signed or verified.
186
*/
187
protected void engineUpdate(byte b) {
188
md.update(b);
189
}
190
191
/**
192
* Update an array of bytes to be signed or verified.
193
*/
194
protected void engineUpdate(byte[] data, int off, int len) {
195
md.update(data, off, len);
196
}
197
198
protected void engineUpdate(ByteBuffer b) {
199
md.update(b);
200
}
201
202
203
/**
204
* Sign all the data thus far updated. The signature is formatted
205
* according to the Canonical Encoding Rules, returned as a DER
206
* sequence of Integer, r and s.
207
*
208
* @return a signature block formatted according to the Canonical
209
* Encoding Rules.
210
*
211
* @exception SignatureException if the signature object was not
212
* properly initialized, or if another exception occurs.
213
*
214
* @see sun.security.DSA#engineUpdate
215
* @see sun.security.DSA#engineVerify
216
*/
217
protected byte[] engineSign() throws SignatureException {
218
BigInteger k = generateK(presetQ);
219
BigInteger r = generateR(presetP, presetQ, presetG, k);
220
BigInteger s = generateS(presetX, presetQ, r, k);
221
222
try {
223
DerOutputStream outseq = new DerOutputStream(100);
224
outseq.putInteger(r);
225
outseq.putInteger(s);
226
DerValue result = new DerValue(DerValue.tag_Sequence,
227
outseq.toByteArray());
228
229
return result.toByteArray();
230
231
} catch (IOException e) {
232
throw new SignatureException("error encoding signature");
233
}
234
}
235
236
/**
237
* Verify all the data thus far updated.
238
*
239
* @param signature the alledged signature, encoded using the
240
* Canonical Encoding Rules, as a sequence of integers, r and s.
241
*
242
* @exception SignatureException if the signature object was not
243
* properly initialized, or if another exception occurs.
244
*
245
* @see sun.security.DSA#engineUpdate
246
* @see sun.security.DSA#engineSign
247
*/
248
protected boolean engineVerify(byte[] signature)
249
throws SignatureException {
250
return engineVerify(signature, 0, signature.length);
251
}
252
253
/**
254
* Verify all the data thus far updated.
255
*
256
* @param signature the alledged signature, encoded using the
257
* Canonical Encoding Rules, as a sequence of integers, r and s.
258
*
259
* @param offset the offset to start from in the array of bytes.
260
*
261
* @param length the number of bytes to use, starting at offset.
262
*
263
* @exception SignatureException if the signature object was not
264
* properly initialized, or if another exception occurs.
265
*
266
* @see sun.security.DSA#engineUpdate
267
* @see sun.security.DSA#engineSign
268
*/
269
protected boolean engineVerify(byte[] signature, int offset, int length)
270
throws SignatureException {
271
272
BigInteger r = null;
273
BigInteger s = null;
274
// first decode the signature.
275
try {
276
// Enforce strict DER checking for signatures
277
DerInputStream in =
278
new DerInputStream(signature, offset, length, false);
279
DerValue[] values = in.getSequence(2);
280
281
// check number of components in the read sequence
282
// and trailing data
283
if ((values.length != 2) || (in.available() != 0)) {
284
throw new IOException("Invalid encoding for signature");
285
}
286
r = values[0].getBigInteger();
287
s = values[1].getBigInteger();
288
} catch (IOException e) {
289
throw new SignatureException("Invalid encoding for signature", e);
290
}
291
292
// some implementations do not correctly encode values in the ASN.1
293
// 2's complement format. force r and s to be positive in order to
294
// to validate those signatures
295
if (r.signum() < 0) {
296
r = new BigInteger(1, r.toByteArray());
297
}
298
if (s.signum() < 0) {
299
s = new BigInteger(1, s.toByteArray());
300
}
301
302
if ((r.compareTo(presetQ) == -1) && (s.compareTo(presetQ) == -1)) {
303
BigInteger w = generateW(presetP, presetQ, presetG, s);
304
BigInteger v = generateV(presetY, presetP, presetQ, presetG, w, r);
305
return v.equals(r);
306
} else {
307
throw new SignatureException("invalid signature: out of range values");
308
}
309
}
310
311
@Deprecated
312
protected void engineSetParameter(String key, Object param) {
313
throw new InvalidParameterException("No parameter accepted");
314
}
315
316
@Override
317
protected void engineSetParameter(AlgorithmParameterSpec params)
318
throws InvalidAlgorithmParameterException {
319
if (params != null) {
320
throw new InvalidAlgorithmParameterException("No parameter accepted");
321
}
322
}
323
324
@Deprecated
325
protected Object engineGetParameter(String key) {
326
return null;
327
}
328
329
@Override
330
protected AlgorithmParameters engineGetParameters() {
331
return null;
332
}
333
334
335
private BigInteger generateR(BigInteger p, BigInteger q, BigInteger g,
336
BigInteger k) {
337
338
// exponent blinding to hide information from timing channel
339
SecureRandom random = getSigningRandom();
340
// start with a random blinding component
341
BigInteger blindingValue = new BigInteger(BLINDING_BITS, random);
342
// add the fixed blinding component
343
blindingValue = blindingValue.add(BLINDING_CONSTANT);
344
// replace k with a blinded value that is congruent (mod q)
345
k = k.add(q.multiply(blindingValue));
346
347
BigInteger temp = g.modPow(k, p);
348
return temp.mod(q);
349
}
350
351
private BigInteger generateS(BigInteger x, BigInteger q,
352
BigInteger r, BigInteger k) throws SignatureException {
353
354
byte[] s2;
355
try {
356
s2 = md.digest();
357
} catch (RuntimeException re) {
358
// Only for RawDSA due to its 20-byte length restriction
359
throw new SignatureException(re.getMessage());
360
}
361
// get the leftmost min(N, outLen) bits of the digest value
362
int nBytes = q.bitLength()/8;
363
if (nBytes < s2.length) {
364
s2 = Arrays.copyOfRange(s2, 0, nBytes);
365
}
366
BigInteger z = new BigInteger(1, s2);
367
BigInteger k1 = k.modInverse(q);
368
369
return x.multiply(r).add(z).multiply(k1).mod(q);
370
}
371
372
private BigInteger generateW(BigInteger p, BigInteger q,
373
BigInteger g, BigInteger s) {
374
return s.modInverse(q);
375
}
376
377
private BigInteger generateV(BigInteger y, BigInteger p,
378
BigInteger q, BigInteger g, BigInteger w, BigInteger r)
379
throws SignatureException {
380
381
byte[] s2;
382
try {
383
s2 = md.digest();
384
} catch (RuntimeException re) {
385
// Only for RawDSA due to its 20-byte length restriction
386
throw new SignatureException(re.getMessage());
387
}
388
// get the leftmost min(N, outLen) bits of the digest value
389
int nBytes = q.bitLength()/8;
390
if (nBytes < s2.length) {
391
s2 = Arrays.copyOfRange(s2, 0, nBytes);
392
}
393
BigInteger z = new BigInteger(1, s2);
394
395
BigInteger u1 = z.multiply(w).mod(q);
396
BigInteger u2 = (r.multiply(w)).mod(q);
397
398
BigInteger t1 = g.modPow(u1,p);
399
BigInteger t2 = y.modPow(u2,p);
400
BigInteger t3 = t1.multiply(t2);
401
BigInteger t5 = t3.mod(p);
402
return t5.mod(q);
403
}
404
405
protected BigInteger generateK(BigInteger q) {
406
// Implementation defined in FIPS 186-4 AppendixB.2.1.
407
SecureRandom random = getSigningRandom();
408
byte[] kValue = new byte[(q.bitLength() + 7)/8 + 8];
409
410
random.nextBytes(kValue);
411
return new BigInteger(1, kValue).mod(
412
q.subtract(BigInteger.ONE)).add(BigInteger.ONE);
413
}
414
415
// Use the application-specified SecureRandom Object if provided.
416
// Otherwise, use our default SecureRandom Object.
417
protected SecureRandom getSigningRandom() {
418
if (signingRandom == null) {
419
if (appRandom != null) {
420
signingRandom = appRandom;
421
} else {
422
signingRandom = JCAUtil.getSecureRandom();
423
}
424
}
425
return signingRandom;
426
}
427
428
/**
429
* Return a human readable rendition of the engine.
430
*/
431
public String toString() {
432
String printable = "DSA Signature";
433
if (presetP != null && presetQ != null && presetG != null) {
434
printable += "\n\tp: " + Debug.toHexString(presetP);
435
printable += "\n\tq: " + Debug.toHexString(presetQ);
436
printable += "\n\tg: " + Debug.toHexString(presetG);
437
} else {
438
printable += "\n\t P, Q or G not initialized.";
439
}
440
if (presetY != null) {
441
printable += "\n\ty: " + Debug.toHexString(presetY);
442
}
443
if (presetY == null && presetX == null) {
444
printable += "\n\tUNINIIALIZED";
445
}
446
return printable;
447
}
448
449
/**
450
* Standard SHA224withDSA implementation as defined in FIPS186-3.
451
*/
452
public static final class SHA224withDSA extends DSA {
453
public SHA224withDSA() throws NoSuchAlgorithmException {
454
super(MessageDigest.getInstance("SHA-224"));
455
}
456
}
457
458
/**
459
* Standard SHA256withDSA implementation as defined in FIPS186-3.
460
*/
461
public static final class SHA256withDSA extends DSA {
462
public SHA256withDSA() throws NoSuchAlgorithmException {
463
super(MessageDigest.getInstance("SHA-256"));
464
}
465
}
466
467
/**
468
* Standard SHA1withDSA implementation.
469
*/
470
public static final class SHA1withDSA extends DSA {
471
public SHA1withDSA() throws NoSuchAlgorithmException {
472
super(MessageDigest.getInstance("SHA-1"));
473
}
474
}
475
476
/**
477
* RawDSA implementation.
478
*
479
* RawDSA requires the data to be exactly 20 bytes long. If it is
480
* not, a SignatureException is thrown when sign()/verify() is called
481
* per JCA spec.
482
*/
483
public static final class RawDSA extends DSA {
484
// Internal special-purpose MessageDigest impl for RawDSA
485
// Only override whatever methods used
486
// NOTE: no clone support
487
public static final class NullDigest20 extends MessageDigest {
488
// 20 byte digest buffer
489
private final byte[] digestBuffer = new byte[20];
490
491
// offset into the buffer; use Integer.MAX_VALUE to indicate
492
// out-of-bound condition
493
private int ofs = 0;
494
495
protected NullDigest20() {
496
super("NullDigest20");
497
}
498
protected void engineUpdate(byte input) {
499
if (ofs == digestBuffer.length) {
500
ofs = Integer.MAX_VALUE;
501
} else {
502
digestBuffer[ofs++] = input;
503
}
504
}
505
protected void engineUpdate(byte[] input, int offset, int len) {
506
if (len > (digestBuffer.length - ofs)) {
507
ofs = Integer.MAX_VALUE;
508
} else {
509
System.arraycopy(input, offset, digestBuffer, ofs, len);
510
ofs += len;
511
}
512
}
513
protected final void engineUpdate(ByteBuffer input) {
514
int inputLen = input.remaining();
515
if (inputLen > (digestBuffer.length - ofs)) {
516
ofs = Integer.MAX_VALUE;
517
} else {
518
input.get(digestBuffer, ofs, inputLen);
519
ofs += inputLen;
520
}
521
}
522
protected byte[] engineDigest() throws RuntimeException {
523
if (ofs != digestBuffer.length) {
524
throw new RuntimeException
525
("Data for RawDSA must be exactly 20 bytes long");
526
}
527
reset();
528
return digestBuffer;
529
}
530
protected int engineDigest(byte[] buf, int offset, int len)
531
throws DigestException {
532
if (ofs != digestBuffer.length) {
533
throw new DigestException
534
("Data for RawDSA must be exactly 20 bytes long");
535
}
536
if (len < digestBuffer.length) {
537
throw new DigestException
538
("Output buffer too small; must be at least 20 bytes");
539
}
540
System.arraycopy(digestBuffer, 0, buf, offset, digestBuffer.length);
541
reset();
542
return digestBuffer.length;
543
}
544
545
protected void engineReset() {
546
ofs = 0;
547
}
548
protected final int engineGetDigestLength() {
549
return digestBuffer.length;
550
}
551
}
552
553
public RawDSA() throws NoSuchAlgorithmException {
554
super(new NullDigest20());
555
}
556
}
557
}
558
559