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