Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/provider/CtrDrbg.java
41159 views
1
/*
2
* Copyright (c) 2016, 2021, 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 javax.crypto.Cipher;
29
import javax.crypto.NoSuchPaddingException;
30
import javax.crypto.spec.SecretKeySpec;
31
import java.security.*;
32
import java.util.Arrays;
33
import java.util.HexFormat;
34
import java.util.Locale;
35
36
public class CtrDrbg extends AbstractDrbg {
37
38
private static final int AES_LIMIT;
39
40
static {
41
try {
42
AES_LIMIT = Cipher.getMaxAllowedKeyLength("AES");
43
} catch (Exception e) {
44
// should not happen
45
throw new AssertionError("Cannot detect AES", e);
46
}
47
}
48
49
private Cipher cipher;
50
51
private String cipherAlg;
52
private String keyAlg;
53
54
private int ctrLen;
55
private int blockLen;
56
private int keyLen;
57
private int seedLen;
58
59
private byte[] v;
60
private byte[] k;
61
62
public CtrDrbg(SecureRandomParameters params) {
63
mechName = "CTR_DRBG";
64
configure(params);
65
}
66
67
private static int alg2strength(String algorithm) {
68
switch (algorithm.toUpperCase(Locale.ROOT)) {
69
case "AES-128":
70
return 128;
71
case "AES-192":
72
return 192;
73
case "AES-256":
74
return 256;
75
default:
76
throw new IllegalArgumentException(algorithm +
77
" not supported in CTR_DBRG");
78
}
79
}
80
81
@Override
82
protected void chooseAlgorithmAndStrength() {
83
if (requestedAlgorithm != null) {
84
algorithm = requestedAlgorithm.toUpperCase(Locale.ROOT);
85
int supportedStrength = alg2strength(algorithm);
86
if (requestedInstantiationSecurityStrength >= 0) {
87
int tryStrength = getStandardStrength(
88
requestedInstantiationSecurityStrength);
89
if (tryStrength > supportedStrength) {
90
throw new IllegalArgumentException(algorithm +
91
" does not support strength " +
92
requestedInstantiationSecurityStrength);
93
}
94
this.securityStrength = tryStrength;
95
} else {
96
this.securityStrength = (DEFAULT_STRENGTH > supportedStrength) ?
97
supportedStrength : DEFAULT_STRENGTH;
98
}
99
} else {
100
int tryStrength = (requestedInstantiationSecurityStrength < 0) ?
101
DEFAULT_STRENGTH : requestedInstantiationSecurityStrength;
102
tryStrength = getStandardStrength(tryStrength);
103
// Default algorithm, use AES-128 if AES-256 is not available.
104
// Remember to sync with "securerandom.drbg.config" in java.security
105
if (tryStrength <= 128 && AES_LIMIT < 256) {
106
algorithm = "AES-128";
107
} else if (AES_LIMIT >= 256) {
108
algorithm = "AES-256";
109
} else {
110
throw new IllegalArgumentException("unsupported strength " +
111
requestedInstantiationSecurityStrength);
112
}
113
this.securityStrength = tryStrength;
114
}
115
switch (algorithm.toUpperCase(Locale.ROOT)) {
116
case "AES-128":
117
case "AES-192":
118
case "AES-256":
119
this.keyAlg = "AES";
120
this.cipherAlg = "AES/ECB/NoPadding";
121
switch (algorithm) {
122
case "AES-128":
123
this.keyLen = 128 / 8;
124
break;
125
case "AES-192":
126
this.keyLen = 192 / 8;
127
if (AES_LIMIT < 192) {
128
throw new IllegalArgumentException(algorithm +
129
" not available (because policy) in CTR_DBRG");
130
}
131
break;
132
case "AES-256":
133
this.keyLen = 256 / 8;
134
if (AES_LIMIT < 256) {
135
throw new IllegalArgumentException(algorithm +
136
" not available (because policy) in CTR_DBRG");
137
}
138
break;
139
default:
140
throw new IllegalArgumentException(algorithm +
141
" not supported in CTR_DBRG");
142
}
143
this.blockLen = 128 / 8;
144
break;
145
default:
146
throw new IllegalArgumentException(algorithm +
147
" not supported in CTR_DBRG");
148
}
149
this.seedLen = this.blockLen + this.keyLen;
150
this.ctrLen = this.blockLen; // TODO
151
if (usedf) {
152
this.minLength = this.securityStrength / 8;
153
} else {
154
this.minLength = this.maxLength =
155
this.maxPersonalizationStringLength =
156
this.maxAdditionalInputLength = seedLen;
157
}
158
}
159
160
/**
161
* This call, used by the constructors, instantiates the digest.
162
*/
163
@Override
164
protected void initEngine() {
165
try {
166
/*
167
* Use the local SunJCE implementation to avoid native
168
* performance overhead.
169
*/
170
cipher = Cipher.getInstance(cipherAlg, "SunJCE");
171
} catch (NoSuchProviderException | NoSuchAlgorithmException
172
| NoSuchPaddingException e) {
173
// Fallback to any available.
174
try {
175
cipher = Cipher.getInstance(cipherAlg);
176
} catch (NoSuchAlgorithmException | NoSuchPaddingException exc) {
177
throw new InternalError(
178
"internal error: " + cipherAlg + " not available.", exc);
179
}
180
}
181
}
182
183
private void status() {
184
if (debug != null) {
185
debug.println(this, "Key = " + HexFormat.of().formatHex(k));
186
debug.println(this, "V = " + HexFormat.of().formatHex(v));
187
debug.println(this, "reseed counter = " + reseedCounter);
188
}
189
}
190
191
// 800-90Ar1 10.2.1.2. CTR_DRBG_Update
192
private void update(byte[] input) {
193
if (input.length != seedLen) {
194
// Should not happen
195
throw new IllegalArgumentException("input length not seedLen: "
196
+ input.length);
197
}
198
try {
199
200
int m = (seedLen + blockLen - 1) / blockLen;
201
byte[] temp = new byte[m * blockLen];
202
203
// Step 1. temp = Null.
204
205
// Step 2. Loop
206
for (int i = 0; i < m; i++) {
207
// Step 2.1. Increment
208
addOne(v, ctrLen);
209
// Step 2.2. Block_Encrypt
210
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(k, keyAlg));
211
// Step 2.3. Encrypt into right position, no need to cat
212
cipher.doFinal(v, 0, blockLen, temp, i * blockLen);
213
}
214
215
// Step 3. Truncate
216
temp = Arrays.copyOf(temp, seedLen);
217
218
// Step 4: Add
219
for (int i = 0; i < seedLen; i++) {
220
temp[i] ^= input[i];
221
}
222
223
// Step 5: leftmost
224
k = Arrays.copyOf(temp, keyLen);
225
226
// Step 6: rightmost
227
v = Arrays.copyOfRange(temp, seedLen - blockLen, seedLen);
228
229
// Step 7. Return
230
} catch (GeneralSecurityException e) {
231
throw new InternalError(e);
232
}
233
}
234
235
@Override
236
protected void instantiateAlgorithm(byte[] ei) {
237
if (debug != null) {
238
debug.println(this, "instantiate");
239
}
240
byte[] more;
241
if (usedf) {
242
// 800-90Ar1 10.2.1.3.2 Step 1-2. cat bytes
243
if (personalizationString == null) {
244
more = nonce;
245
} else {
246
if (nonce.length + personalizationString.length < 0) {
247
// Length must be represented as a 32 bit integer in df()
248
throw new IllegalArgumentException(
249
"nonce plus personalization string is too long");
250
}
251
more = Arrays.copyOf(
252
nonce, nonce.length + personalizationString.length);
253
System.arraycopy(personalizationString, 0, more, nonce.length,
254
personalizationString.length);
255
}
256
} else {
257
// 800-90Ar1 10.2.1.3.1
258
// Step 1-2, no need to expand personalizationString, we only XOR
259
// with shorter length
260
more = personalizationString;
261
}
262
reseedAlgorithm(ei, more);
263
}
264
265
/**
266
* Block_cipher_df in 10.3.2
267
*
268
* @param input the input string
269
* @return the output block (always of seedLen)
270
*/
271
private byte[] df(byte[] input) {
272
// 800-90Ar1 10.3.2
273
// 2. L = len (input_string)/8
274
int l = input.length;
275
// 3. N = number_of_bits_to_return/8
276
int n = seedLen;
277
// 4. S = L || N || input_string || 0x80
278
byte[] ln = new byte[8];
279
ln[0] = (byte)(l >> 24);
280
ln[1] = (byte)(l >> 16);
281
ln[2] = (byte)(l >> 8);
282
ln[3] = (byte)(l);
283
ln[4] = (byte)(n >> 24);
284
ln[5] = (byte)(n >> 16);
285
ln[6] = (byte)(n >> 8);
286
ln[7] = (byte)(n);
287
288
// 5. Zero padding of S
289
// Not necessary, see bcc
290
291
// 8. K = leftmost (0x00010203...1D1E1F, keylen).
292
byte[] k = new byte[keyLen];
293
for (int i = 0; i < k.length; i++) {
294
k[i] = (byte)i;
295
}
296
297
// 6. temp = the Null String
298
byte[] temp = new byte[seedLen];
299
300
// 7. i = 0
301
for (int i = 0; i * blockLen < temp.length; i++) {
302
// 9.1 IV = i || 0^(outlen - len (i)). outLen is blockLen
303
byte[] iv = new byte[blockLen];
304
iv[0] = (byte)(i >> 24);
305
iv[1] = (byte)(i >> 16);
306
iv[2] = (byte)(i >> 8);
307
iv[3] = (byte)(i);
308
309
int tailLen = temp.length - blockLen*i;
310
if (tailLen > blockLen) {
311
tailLen = blockLen;
312
}
313
// 9.2 temp = temp || BCC (K, (IV || S)).
314
System.arraycopy(bcc(k, iv, ln, input, new byte[]{(byte)0x80}),
315
0, temp, blockLen*i, tailLen);
316
}
317
318
// 10. K = leftmost(temp, keylen)
319
k = Arrays.copyOf(temp, keyLen);
320
321
// 11. x = select(temp, keylen+1, keylen+outlen)
322
byte[] x = Arrays.copyOfRange(temp, keyLen, temp.length);
323
324
// 12. temp = the Null string
325
// No need to clean up, temp will be overwritten
326
327
for (int i = 0; i * blockLen < seedLen; i++) {
328
try {
329
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(k, keyAlg));
330
int tailLen = temp.length - blockLen*i;
331
// 14. requested_bits = leftmost(temp, nuumber_of_bits_to_return)
332
if (tailLen > blockLen) {
333
tailLen = blockLen;
334
}
335
x = cipher.doFinal(x);
336
System.arraycopy(x, 0, temp, blockLen * i, tailLen);
337
} catch (GeneralSecurityException e) {
338
throw new InternalError(e);
339
}
340
}
341
342
// 15. Return
343
return temp;
344
}
345
346
/**
347
* Block_Encrypt in 10.3.3
348
*
349
* @param k the key
350
* @param data after concatenated, the data to be operated upon. This is
351
* a series of byte[], each with an arbitrary length. Note
352
* that the full length is not necessarily a multiple of
353
* outlen. XOR with zero is no-op.
354
* @return the result
355
*/
356
private byte[] bcc(byte[] k, byte[]... data) {
357
byte[] chain = new byte[blockLen];
358
int n1 = 0; // index in data
359
int n2 = 0; // index in data[n1]
360
// pack blockLen of bytes into chain from data[][], again and again
361
while (n1 < data.length) {
362
int j;
363
out: for (j = 0; j < blockLen; j++) {
364
while (n2 >= data[n1].length) {
365
n1++;
366
if (n1 >= data.length) {
367
break out;
368
}
369
n2 = 0;
370
}
371
chain[j] ^= data[n1][n2];
372
n2++;
373
}
374
if (j == 0) { // all data happens to be consumed in the last loop
375
break;
376
}
377
try {
378
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(k, keyAlg));
379
chain = cipher.doFinal(chain);
380
} catch (GeneralSecurityException e) {
381
throw new InternalError(e);
382
}
383
}
384
return chain;
385
}
386
387
@Override
388
protected synchronized void reseedAlgorithm(
389
byte[] ei,
390
byte[] additionalInput) {
391
if (usedf) {
392
// 800-90Ar1 10.2.1.3.2 Instantiate.
393
// 800-90Ar1 10.2.1.4.2 Reseed.
394
395
// Step 1: cat bytes
396
if (additionalInput != null) {
397
if (ei.length + additionalInput.length < 0) {
398
// Length must be represented as a 32 bit integer in df()
399
throw new IllegalArgumentException(
400
"entropy plus additional input is too long");
401
}
402
byte[] temp = Arrays.copyOf(
403
ei, ei.length + additionalInput.length);
404
System.arraycopy(additionalInput, 0, temp, ei.length,
405
additionalInput.length);
406
ei = temp;
407
}
408
// Step 2. df (seed_material, seedlen).
409
ei = df(ei);
410
} else {
411
// 800-90Ar1 10.2.1.3.1 Instantiate
412
// 800-90Ar1 10.2.1.4.1 Reseed
413
// Step 1-2. Needless
414
// Step 3. seed_material = entropy_input XOR more
415
if (additionalInput != null) {
416
// additionalInput.length <= seedLen
417
for (int i = 0; i < additionalInput.length; i++) {
418
ei[i] ^= additionalInput[i];
419
}
420
}
421
}
422
423
if (v == null) {
424
// 800-90Ar1 10.2.1.3.2 Instantiate. Step 3-4
425
// 800-90Ar1 10.2.1.3.1 Instantiate. Step 4-5
426
k = new byte[keyLen];
427
v = new byte[blockLen];
428
}
429
//status();
430
431
// 800-90Ar1 10.2.1.3.1 Instantiate. Step 6
432
// 800-90Ar1 10.2.1.3.2 Instantiate. Step 5
433
// 800-90Ar1 10.2.1.4.1 Reseed. Step 4
434
// 800-90Ar1 10.2.1.4.2 Reseed. Step 3
435
update(ei);
436
// 800-90Ar1 10.2.1.3.1 Instantiate. Step 7
437
// 800-90Ar1 10.2.1.3.2 Instantiate. Step 6
438
// 800-90Ar1 10.2.1.4.1 Reseed. Step 5
439
// 800-90Ar1 10.2.1.4.2 Reseed. Step 4
440
reseedCounter = 1;
441
//status();
442
443
// Whatever step. Return
444
}
445
446
/**
447
* Add one to data, only touch the last len bytes.
448
*/
449
private static void addOne(byte[] data, int len) {
450
for (int i = 0; i < len; i++) {
451
data[data.length - 1 - i]++;
452
if (data[data.length - 1 - i] != 0) {
453
break;
454
}
455
}
456
}
457
458
@Override
459
public synchronized void generateAlgorithm(
460
byte[] result, byte[] additionalInput) {
461
462
if (debug != null) {
463
debug.println(this, "generateAlgorithm");
464
}
465
466
// 800-90Ar1 10.2.1.5.1 Generate
467
// 800-90Ar1 10.2.1.5.2 Generate
468
469
// Step 1: Check reseed_counter. Will not fail. Already checked in
470
// AbstractDrbg#engineNextBytes.
471
472
if (additionalInput != null) {
473
if (usedf) {
474
// 10.2.1.5.2 Step 2.1
475
additionalInput = df(additionalInput);
476
} else {
477
// 10.2.1.5.1 Step 2.1-2.2
478
additionalInput = Arrays.copyOf(additionalInput, seedLen);
479
}
480
// 10.2.1.5.1 Step 2.3
481
// 10.2.1.5.2 Step 2.2
482
update(additionalInput);
483
} else {
484
// 10.2.1.5.1 Step 2 Else
485
// 10.2.1.5.2 Step 2 Else
486
additionalInput = new byte[seedLen];
487
}
488
489
// Step 3. temp = Null
490
int pos = 0;
491
int len = result.length;
492
493
// Step 4. Loop
494
while (len > 0) {
495
// Step 4.1. Increment
496
addOne(v, ctrLen);
497
try {
498
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(k, keyAlg));
499
// Step 4.2. Encrypt
500
// Step 4.3 and 5. Cat bytes and leftmost
501
if (len > blockLen) {
502
cipher.doFinal(v, 0, blockLen, result, pos);
503
} else {
504
byte[] out = cipher.doFinal(v);
505
System.arraycopy(out, 0, result, pos, len);
506
Arrays.fill(out, (byte)0);
507
}
508
} catch (GeneralSecurityException e) {
509
throw new InternalError(e);
510
}
511
len -= blockLen;
512
if (len <= 0) {
513
// shortcut, so that pos needn't be updated
514
break;
515
}
516
pos += blockLen;
517
}
518
519
// Step 6. Update
520
update(additionalInput);
521
522
// Step 7. reseed_counter++
523
reseedCounter++;
524
525
//status();
526
527
// Step 8. Return
528
}
529
530
@Override
531
public String toString() {
532
return super.toString() + ","
533
+ (usedf ? "use_df" : "no_df");
534
}
535
}
536
537