Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java
41161 views
1
/*
2
* Copyright (c) 2004, 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 com.sun.crypto.provider;
27
28
import java.security.*;
29
import java.security.spec.*;
30
import java.util.Arrays;
31
import javax.crypto.*;
32
import javax.crypto.spec.*;
33
34
/**
35
* This class implements the CMS DESede KeyWrap algorithm as defined
36
* in <a href=http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap></a>
37
* "XML Encryption Syntax and Processing" section 5.6.2
38
* "CMS Triple DES Key Wrap".
39
* Note: only <code>CBC</code> mode and <code>NoPadding</code> padding
40
* scheme can be used for this algorithm.
41
*
42
* @author Valerie Peng
43
*
44
*
45
* @see DESedeCipher
46
*/
47
public final class DESedeWrapCipher extends CipherSpi {
48
49
private static final byte[] IV2 = {
50
(byte) 0x4a, (byte) 0xdd, (byte) 0xa2, (byte) 0x2c,
51
(byte) 0x79, (byte) 0xe8, (byte) 0x21, (byte) 0x05
52
};
53
54
private static final int CHECKSUM_LEN = 8;
55
private static final int IV_LEN = 8;
56
57
/*
58
* internal cipher object which does the real work.
59
*/
60
private FeedbackCipher cipher;
61
62
/*
63
* iv for (re-)initializing the internal cipher object.
64
*/
65
private byte[] iv = null;
66
67
/*
68
* key for re-initializing the internal cipher object.
69
*/
70
private Key cipherKey = null;
71
72
/*
73
* are we encrypting or decrypting?
74
*/
75
private boolean decrypting = false;
76
77
/**
78
* Creates an instance of CMS DESede KeyWrap cipher with default
79
* mode, i.e. "CBC" and padding scheme, i.e. "NoPadding".
80
*/
81
public DESedeWrapCipher() {
82
cipher = new CipherBlockChaining(new DESedeCrypt());
83
}
84
85
/**
86
* Sets the mode of this cipher. Only "CBC" mode is accepted for this
87
* cipher.
88
*
89
* @param mode the cipher mode.
90
*
91
* @exception NoSuchAlgorithmException if the requested cipher mode
92
* is not "CBC".
93
*/
94
protected void engineSetMode(String mode)
95
throws NoSuchAlgorithmException {
96
if (!mode.equalsIgnoreCase("CBC")) {
97
throw new NoSuchAlgorithmException(mode + " cannot be used");
98
}
99
}
100
101
/**
102
* Sets the padding mechanism of this cipher. Only "NoPadding" schmem
103
* is accepted for this cipher.
104
*
105
* @param padding the padding mechanism.
106
*
107
* @exception NoSuchPaddingException if the requested padding mechanism
108
* is not "NoPadding".
109
*/
110
protected void engineSetPadding(String padding)
111
throws NoSuchPaddingException {
112
if (!padding.equalsIgnoreCase("NoPadding")) {
113
throw new NoSuchPaddingException(padding + " cannot be used");
114
}
115
}
116
117
/**
118
* Returns the block size (in bytes), i.e. 8 bytes.
119
*
120
* @return the block size (in bytes), i.e. 8 bytes.
121
*/
122
protected int engineGetBlockSize() {
123
return DESConstants.DES_BLOCK_SIZE;
124
}
125
126
/**
127
* Returns the length in bytes that an output buffer would need to be
128
* given the input length <code>inputLen</code> (in bytes).
129
*
130
* <p>The actual output length of the next <code>update</code> or
131
* <code>doFinal</code> call may be smaller than the length returned
132
* by this method.
133
*
134
* @param inputLen the input length (in bytes).
135
*
136
* @return the required output buffer size (in bytes).
137
*/
138
protected int engineGetOutputSize(int inputLen) {
139
// can only return an upper-limit if not initialized yet.
140
int result = 0;
141
if (decrypting) {
142
result = inputLen - 16; // CHECKSUM_LEN + IV_LEN;
143
} else {
144
result = Math.addExact(inputLen, 16);
145
}
146
return (result < 0? 0:result);
147
}
148
149
/**
150
* Returns the initialization vector (IV) in a new buffer.
151
*
152
* @return the initialization vector, or null if the underlying
153
* algorithm does not use an IV, or if the IV has not yet
154
* been set.
155
*/
156
protected byte[] engineGetIV() {
157
return (iv == null) ? null : iv.clone();
158
}
159
160
/**
161
* Initializes this cipher with a key and a source of randomness.
162
*
163
* <p>The cipher only supports the following two operation modes:
164
* {@code Cipher.WRAP_MODE}, and {@code Cipher.UNWRAP_MODE}.
165
* <p>For modes other than the above two, UnsupportedOperationException
166
* will be thrown.
167
* <p>If this cipher requires an initialization vector (IV), it will get
168
* it from <code>random</code>.
169
*
170
* @param opmode the operation mode of this cipher. Only
171
* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) are accepted.
172
* @param key the secret key.
173
* @param random the source of randomness.
174
*
175
* @exception InvalidKeyException if the given key is inappropriate
176
* or if parameters are required but not supplied.
177
*/
178
protected void engineInit(int opmode, Key key, SecureRandom random)
179
throws InvalidKeyException {
180
try {
181
engineInit(opmode, key, (AlgorithmParameterSpec) null, random);
182
} catch (InvalidAlgorithmParameterException iape) {
183
// should never happen
184
InvalidKeyException ike =
185
new InvalidKeyException("Parameters required");
186
ike.initCause(iape);
187
throw ike;
188
}
189
}
190
191
/**
192
* Initializes this cipher with a key, a set of algorithm parameters,
193
* and a source of randomness.
194
*
195
* <p>The cipher only supports the following two operation modes:
196
* {@code Cipher.WRAP_MODE}, and {@code Cipher.UNWRAP_MODE}.
197
* <p>For modes other than the above two, UnsupportedOperationException
198
* will be thrown.
199
* <p>If this cipher requires an initialization vector (IV), it will get
200
* it from <code>random</code>.
201
*
202
* @param opmode the operation mode of this cipher. Only
203
* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) are accepted.
204
* @param key the secret key.
205
* @param params the algorithm parameters.
206
* @param random the source of randomness.
207
*
208
* @exception InvalidKeyException if the given key is inappropriate.
209
* @exception InvalidAlgorithmParameterException if the given algorithm
210
* parameters are inappropriate for this cipher.
211
*/
212
protected void engineInit(int opmode, Key key,
213
AlgorithmParameterSpec params,
214
SecureRandom random)
215
throws InvalidKeyException, InvalidAlgorithmParameterException {
216
byte[] currIv = null;
217
if (opmode == Cipher.WRAP_MODE) {
218
decrypting = false;
219
if (params == null) {
220
iv = new byte[IV_LEN];
221
if (random == null) {
222
random = SunJCE.getRandom();
223
}
224
random.nextBytes(iv);
225
}
226
else if (params instanceof IvParameterSpec) {
227
iv = ((IvParameterSpec) params).getIV();
228
} else {
229
throw new InvalidAlgorithmParameterException
230
("Wrong parameter type: IV expected");
231
}
232
currIv = iv;
233
} else if (opmode == Cipher.UNWRAP_MODE) {
234
if (params != null) {
235
throw new InvalidAlgorithmParameterException
236
("No parameter accepted for unwrapping keys");
237
}
238
iv = null;
239
decrypting = true;
240
currIv = IV2;
241
} else {
242
throw new UnsupportedOperationException("This cipher can " +
243
"only be used for key wrapping and unwrapping");
244
}
245
byte[] encoded = key.getEncoded();
246
try {
247
cipher.init(decrypting, key.getAlgorithm(), encoded, currIv);
248
} finally {
249
if (encoded != null) {
250
Arrays.fill(encoded, (byte) 0);
251
}
252
}
253
cipherKey = key;
254
}
255
256
/**
257
* Initializes this cipher with a key, a set of algorithm parameters,
258
* and a source of randomness.
259
*
260
* <p>The cipher only supports the following two operation modes:
261
* {@code Cipher.WRAP_MODE}, and {@code Cipher.UNWRAP_MODE}.
262
* <p>For modes other than the above two, UnsupportedOperationException
263
* will be thrown.
264
* <p>If this cipher requires an initialization vector (IV), it will get
265
* it from <code>random</code>.
266
*
267
* @param opmode the operation mode of this cipher. Only
268
* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) are accepted.
269
* @param key the secret key.
270
* @param params the algorithm parameters.
271
* @param random the source of randomness.
272
*
273
* @exception InvalidKeyException if the given key is inappropriate.
274
* @exception InvalidAlgorithmParameterException if the given algorithm
275
* parameters are inappropriate for this cipher.
276
*/
277
protected void engineInit(int opmode, Key key,
278
AlgorithmParameters params,
279
SecureRandom random)
280
throws InvalidKeyException, InvalidAlgorithmParameterException {
281
IvParameterSpec ivSpec = null;
282
if (params != null) {
283
try {
284
DESedeParameters paramsEng = new DESedeParameters();
285
paramsEng.engineInit(params.getEncoded());
286
ivSpec = paramsEng.engineGetParameterSpec(IvParameterSpec.class);
287
} catch (Exception ex) {
288
InvalidAlgorithmParameterException iape =
289
new InvalidAlgorithmParameterException
290
("Wrong parameter type: IV expected");
291
iape.initCause(ex);
292
throw iape;
293
}
294
}
295
engineInit(opmode, key, ivSpec, random);
296
}
297
298
/**
299
* This operation is not supported by this cipher.
300
* Since it's impossible to initialize this cipher given the
301
* current Cipher.engineInit(...) implementation,
302
* IllegalStateException will always be thrown upon invocation.
303
*
304
* @param in the input buffer.
305
* @param inOffset the offset in <code>in</code> where the input
306
* starts.
307
* @param inLen the input length.
308
*
309
* @return n/a.
310
*
311
* @exception IllegalStateException upon invocation of this method.
312
*/
313
protected byte[] engineUpdate(byte[] in, int inOffset, int inLen) {
314
throw new IllegalStateException("Cipher has not been initialized");
315
}
316
317
/**
318
* This operation is not supported by this cipher.
319
* Since it's impossible to initialize this cipher given the
320
* current Cipher.engineInit(...) implementation,
321
* IllegalStateException will always be thrown upon invocation.
322
*
323
* @param in the input buffer.
324
* @param inOffset the offset in <code>in</code> where the input
325
* starts.
326
* @param inLen the input length.
327
* @param out the buffer for the result.
328
* @param outOffset the offset in <code>out</code> where the result
329
* is stored.
330
*
331
* @return n/a.
332
*
333
* @exception IllegalStateException upon invocation of this method.
334
*/
335
protected int engineUpdate(byte[] in, int inOffset, int inLen,
336
byte[] out, int outOffset)
337
throws ShortBufferException {
338
throw new IllegalStateException("Cipher has not been initialized");
339
}
340
341
/**
342
* This operation is not supported by this cipher.
343
* Since it's impossible to initialize this cipher given the
344
* current Cipher.engineInit(...) implementation,
345
* IllegalStateException will always be thrown upon invocation.
346
*
347
* @param in the input buffer.
348
* @param inOffset the offset in <code>in</code> where the input
349
* starts.
350
* @param inLen the input length.
351
*
352
* @return the new buffer with the result.
353
*
354
* @exception IllegalStateException upon invocation of this method.
355
*/
356
protected byte[] engineDoFinal(byte[] in, int inOffset, int inLen)
357
throws IllegalBlockSizeException, BadPaddingException {
358
throw new IllegalStateException("Cipher has not been initialized");
359
}
360
361
/**
362
* This operation is not supported by this cipher.
363
* Since it's impossible to initialize this cipher given the
364
* current Cipher.engineInit(...) implementation,
365
* IllegalStateException will always be thrown upon invocation.
366
*
367
* @param input the input buffer.
368
* @param inputOffset the offset in {@code input} where the input
369
* starts.
370
* @param inputLen the input length.
371
* @param output the buffer for the result.
372
* @param outputOffset the ofset in {@code output} where the result
373
* is stored.
374
*
375
* @return the number of bytes stored in {@code out}.
376
*
377
* @exception IllegalStateException upon invocation of this method.
378
*/
379
protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,
380
byte[] output, int outputOffset)
381
throws IllegalBlockSizeException, ShortBufferException,
382
BadPaddingException {
383
throw new IllegalStateException("Cipher has not been initialized");
384
}
385
386
/**
387
* Returns the parameters used with this cipher.
388
* Note that null maybe returned if this cipher does not use any
389
* parameters or when it has not be set, e.g. initialized with
390
* UNWRAP_MODE but wrapped key data has not been given.
391
*
392
* @return the parameters used with this cipher; can be null.
393
*/
394
protected AlgorithmParameters engineGetParameters() {
395
AlgorithmParameters params = null;
396
if (iv != null) {
397
String algo = cipherKey.getAlgorithm();
398
try {
399
params = AlgorithmParameters.getInstance(algo,
400
SunJCE.getInstance());
401
params.init(new IvParameterSpec(iv));
402
} catch (NoSuchAlgorithmException nsae) {
403
// should never happen
404
throw new RuntimeException("Cannot find " + algo +
405
" AlgorithmParameters implementation in SunJCE provider");
406
} catch (InvalidParameterSpecException ipse) {
407
// should never happen
408
throw new RuntimeException("IvParameterSpec not supported");
409
}
410
}
411
return params;
412
}
413
414
/**
415
* Returns the key size of the given key object in number of bits.
416
* This cipher always return the same key size as the DESede ciphers.
417
*
418
* @param key the key object.
419
*
420
* @return the "effective" key size of the given key object.
421
*
422
* @exception InvalidKeyException if <code>key</code> is invalid.
423
*/
424
protected int engineGetKeySize(Key key) throws InvalidKeyException {
425
byte[] encoded = key.getEncoded();
426
Arrays.fill(encoded, (byte)0);
427
if (encoded.length != 24) {
428
throw new InvalidKeyException("Invalid key length: " +
429
encoded.length + " bytes");
430
}
431
// Return the effective key length
432
return 112;
433
}
434
435
/**
436
* Wrap a key.
437
*
438
* @param key the key to be wrapped.
439
*
440
* @return the wrapped key.
441
*
442
* @exception IllegalBlockSizeException if this cipher is a block
443
* cipher, no padding has been requested, and the length of the
444
* encoding of the key to be wrapped is not a
445
* multiple of the block size.
446
*
447
* @exception InvalidKeyException if it is impossible or unsafe to
448
* wrap the key with this cipher (e.g., a hardware protected key is
449
* being passed to a software only cipher).
450
*/
451
protected byte[] engineWrap(Key key)
452
throws IllegalBlockSizeException, InvalidKeyException {
453
byte[] keyVal = key.getEncoded();
454
if ((keyVal == null) || (keyVal.length == 0)) {
455
throw new InvalidKeyException("Cannot get an encoding of " +
456
"the key to be wrapped");
457
}
458
459
byte[] in = new byte[Math.addExact(keyVal.length, CHECKSUM_LEN)];
460
byte[] cipherKeyEncoded = cipherKey.getEncoded();
461
byte[] out = new byte[Math.addExact(iv.length, in.length)];
462
try {
463
byte[] cks = getChecksum(keyVal);
464
System.arraycopy(keyVal, 0, in, 0, keyVal.length);
465
System.arraycopy(cks, 0, in, keyVal.length, CHECKSUM_LEN);
466
467
System.arraycopy(iv, 0, out, 0, iv.length);
468
469
cipher.encrypt(in, 0, in.length, out, iv.length);
470
471
// reverse the array content
472
for (int i = 0; i < out.length / 2; i++) {
473
byte temp = out[i];
474
out[i] = out[out.length - 1 - i];
475
out[out.length - 1 - i] = temp;
476
}
477
try {
478
cipher.init(false, cipherKey.getAlgorithm(),
479
cipherKeyEncoded, IV2);
480
} catch (InvalidKeyException ike) {
481
// should never happen
482
throw new RuntimeException("Internal cipher key is corrupted");
483
} catch (InvalidAlgorithmParameterException iape) {
484
// should never happen
485
throw new RuntimeException("Internal cipher IV is invalid");
486
}
487
byte[] out2 = new byte[out.length];
488
cipher.encrypt(out, 0, out.length, out2, 0);
489
490
// restore cipher state to prior to this call
491
try {
492
cipher.init(decrypting, cipherKey.getAlgorithm(),
493
cipherKeyEncoded, iv);
494
} catch (InvalidKeyException ike) {
495
// should never happen
496
throw new RuntimeException("Internal cipher key is corrupted");
497
} catch (InvalidAlgorithmParameterException iape) {
498
// should never happen
499
throw new RuntimeException("Internal cipher IV is invalid");
500
}
501
return out2;
502
} finally {
503
Arrays.fill(keyVal, (byte)0);
504
Arrays.fill(in, (byte)0);
505
Arrays.fill(out, (byte)0);
506
if (cipherKeyEncoded != null) {
507
Arrays.fill(cipherKeyEncoded, (byte) 0);
508
}
509
}
510
}
511
512
/**
513
* Unwrap a previously wrapped key.
514
*
515
* @param wrappedKey the key to be unwrapped.
516
*
517
* @param wrappedKeyAlgorithm the algorithm the wrapped key is for.
518
*
519
* @param wrappedKeyType the type of the wrapped key.
520
* This is one of <code>Cipher.SECRET_KEY</code>,
521
* <code>Cipher.PRIVATE_KEY</code>, or <code>Cipher.PUBLIC_KEY</code>.
522
*
523
* @return the unwrapped key.
524
*
525
* @exception NoSuchAlgorithmException if no installed providers
526
* can create keys of type <code>wrappedKeyType</code> for the
527
* <code>wrappedKeyAlgorithm</code>.
528
*
529
* @exception InvalidKeyException if <code>wrappedKey</code> does not
530
* represent a wrapped key of type <code>wrappedKeyType</code> for
531
* the <code>wrappedKeyAlgorithm</code>.
532
*/
533
protected Key engineUnwrap(byte[] wrappedKey,
534
String wrappedKeyAlgorithm,
535
int wrappedKeyType)
536
throws InvalidKeyException, NoSuchAlgorithmException {
537
if (wrappedKey.length == 0) {
538
throw new InvalidKeyException("The wrapped key is empty");
539
}
540
byte[] buffer = new byte[wrappedKey.length];
541
cipher.decrypt(wrappedKey, 0, wrappedKey.length, buffer, 0);
542
543
// reverse array content
544
for (int i = 0; i < buffer.length/2; i++) {
545
byte temp = buffer[i];
546
buffer[i] = buffer[buffer.length-1-i];
547
buffer[buffer.length-1-i] = temp;
548
}
549
iv = new byte[IV_LEN];
550
System.arraycopy(buffer, 0, iv, 0, iv.length);
551
byte[] cipherKeyEncoded = cipherKey.getEncoded();
552
byte[] out = null;
553
byte[] buffer2 = new byte[buffer.length - iv.length];
554
try {
555
try {
556
cipher.init(true, cipherKey.getAlgorithm(), cipherKeyEncoded,
557
iv);
558
} catch (InvalidAlgorithmParameterException iape) {
559
throw new InvalidKeyException("IV in wrapped key is invalid");
560
}
561
cipher.decrypt(buffer, iv.length, buffer2.length,
562
buffer2, 0);
563
int keyValLen = buffer2.length - CHECKSUM_LEN;
564
byte[] cks = getChecksum(buffer2, 0, keyValLen);
565
int offset = keyValLen;
566
for (int i = 0; i < CHECKSUM_LEN; i++) {
567
if (buffer2[offset + i] != cks[i]) {
568
throw new InvalidKeyException("Checksum comparison failed");
569
}
570
}
571
// restore cipher state to prior to this call
572
try {
573
cipher.init(decrypting, cipherKey.getAlgorithm(),
574
cipherKeyEncoded, IV2);
575
} catch (InvalidAlgorithmParameterException iape) {
576
throw new InvalidKeyException("IV in wrapped key is invalid");
577
}
578
out = new byte[keyValLen];
579
System.arraycopy(buffer2, 0, out, 0, keyValLen);
580
return ConstructKeys.constructKey(out, wrappedKeyAlgorithm,
581
wrappedKeyType);
582
} finally {
583
if (out != null) {
584
Arrays.fill(out, (byte)0);
585
}
586
if (cipherKeyEncoded != null) {
587
Arrays.fill(cipherKeyEncoded, (byte) 0);
588
}
589
Arrays.fill(buffer2, (byte)0);
590
}
591
}
592
593
private static final byte[] getChecksum(byte[] in) {
594
return getChecksum(in, 0, in.length);
595
}
596
private static final byte[] getChecksum(byte[] in, int offset, int len) {
597
MessageDigest md = null;
598
try {
599
md = MessageDigest.getInstance("SHA1");
600
} catch (NoSuchAlgorithmException nsae) {
601
throw new RuntimeException("SHA1 message digest not available");
602
}
603
md.update(in, offset, len);
604
byte[] cks = new byte[CHECKSUM_LEN];
605
System.arraycopy(md.digest(), 0, cks, 0, cks.length);
606
md.reset();
607
return cks;
608
}
609
}
610
611