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/AESWrapCipher.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.util.Arrays;
29
import java.security.*;
30
import java.security.spec.*;
31
import javax.crypto.*;
32
import javax.crypto.spec.*;
33
34
/**
35
* This class implements the AES KeyWrap algorithm as defined
36
* in <a href=http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap>
37
* "XML Encryption Syntax and Processing" section 5.6.3 "AES Key Wrap".
38
* Note: only <code>ECB</code> mode and <code>NoPadding</code> padding
39
* can be used for this algorithm.
40
*
41
* @author Valerie Peng
42
*
43
*
44
* @see AESCipher
45
*/
46
abstract class AESWrapCipher extends CipherSpi {
47
public static final class General extends AESWrapCipher {
48
public General() {
49
super(-1);
50
}
51
}
52
public static final class AES128 extends AESWrapCipher {
53
public AES128() {
54
super(16);
55
}
56
}
57
public static final class AES192 extends AESWrapCipher {
58
public AES192() {
59
super(24);
60
}
61
}
62
public static final class AES256 extends AESWrapCipher {
63
public AES256() {
64
super(32);
65
}
66
}
67
private static final byte[] IV = {
68
(byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6,
69
(byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6
70
};
71
72
private static final int blksize = AESConstants.AES_BLOCK_SIZE;
73
74
/*
75
* internal cipher object which does the real work.
76
*/
77
private AESCrypt cipher;
78
79
/*
80
* are we encrypting or decrypting?
81
*/
82
private boolean decrypting = false;
83
84
/*
85
* needed to support AES oids which associates a fixed key size
86
* to the cipher object.
87
*/
88
private final int fixedKeySize; // in bytes, -1 if no restriction
89
90
/**
91
* Creates an instance of AES KeyWrap cipher with default
92
* mode, i.e. "ECB" and padding scheme, i.e. "NoPadding".
93
*/
94
public AESWrapCipher(int keySize) {
95
cipher = new AESCrypt();
96
fixedKeySize = keySize;
97
98
}
99
100
/**
101
* Sets the mode of this cipher. Only "ECB" mode is accepted for this
102
* cipher.
103
*
104
* @param mode the cipher mode
105
*
106
* @exception NoSuchAlgorithmException if the requested cipher mode
107
* is not "ECB".
108
*/
109
protected void engineSetMode(String mode)
110
throws NoSuchAlgorithmException {
111
if (!mode.equalsIgnoreCase("ECB")) {
112
throw new NoSuchAlgorithmException(mode + " cannot be used");
113
}
114
}
115
116
/**
117
* Sets the padding mechanism of this cipher. Only "NoPadding" schmem
118
* is accepted for this cipher.
119
*
120
* @param padding the padding mechanism
121
*
122
* @exception NoSuchPaddingException if the requested padding mechanism
123
* is not "NoPadding".
124
*/
125
protected void engineSetPadding(String padding)
126
throws NoSuchPaddingException {
127
if (!padding.equalsIgnoreCase("NoPadding")) {
128
throw new NoSuchPaddingException(padding + " cannot be used");
129
}
130
}
131
132
/**
133
* Returns the block size (in bytes). i.e. 16 bytes.
134
*
135
* @return the block size (in bytes), i.e. 16 bytes.
136
*/
137
protected int engineGetBlockSize() {
138
return blksize;
139
}
140
141
/**
142
* Returns the length in bytes that an output buffer would need to be
143
* given the input length <code>inputLen</code> (in bytes).
144
*
145
* <p>The actual output length of the next <code>update</code> or
146
* <code>doFinal</code> call may be smaller than the length returned
147
* by this method.
148
*
149
* @param inputLen the input length (in bytes)
150
*
151
* @return the required output buffer size (in bytes)
152
*/
153
protected int engineGetOutputSize(int inputLen) {
154
// can only return an upper-limit if not initialized yet.
155
int result = 0;
156
if (decrypting) {
157
result = inputLen - 8;
158
} else {
159
result = Math.addExact(inputLen, 8);
160
}
161
return (result < 0? 0:result);
162
}
163
164
/**
165
* Returns the initialization vector (IV) which is null for this cipher.
166
*
167
* @return null for this cipher.
168
*/
169
protected byte[] engineGetIV() {
170
return null;
171
}
172
173
/**
174
* Initializes this cipher with a key and a source of randomness.
175
*
176
* <p>The cipher only supports the following two operation modes:<b>
177
* Cipher.WRAP_MODE, and <b>
178
* Cipher.UNWRAP_MODE.
179
* <p>For modes other than the above two, UnsupportedOperationException
180
* will be thrown.
181
*
182
* @param opmode the operation mode of this cipher. Only
183
* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) are accepted.
184
* @param key the secret key.
185
* @param random the source of randomness.
186
*
187
* @exception InvalidKeyException if the given key is inappropriate for
188
* initializing this cipher.
189
*/
190
protected void engineInit(int opmode, Key key, SecureRandom random)
191
throws InvalidKeyException {
192
if (opmode == Cipher.WRAP_MODE) {
193
decrypting = false;
194
} else if (opmode == Cipher.UNWRAP_MODE) {
195
decrypting = true;
196
} else {
197
throw new UnsupportedOperationException("This cipher can " +
198
"only be used for key wrapping and unwrapping");
199
}
200
AESCipher.checkKeySize(key, fixedKeySize);
201
cipher.init(decrypting, key.getAlgorithm(), key.getEncoded());
202
}
203
204
/**
205
* Initializes this cipher with a key, a set of algorithm parameters,
206
* and a source of randomness.
207
*
208
* <p>The cipher only supports the following two operation modes:<b>
209
* Cipher.WRAP_MODE, and <b>
210
* Cipher.UNWRAP_MODE.
211
* <p>For modes other than the above two, UnsupportedOperationException
212
* will be thrown.
213
*
214
* @param opmode the operation mode of this cipher. Only
215
* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) are accepted.
216
* @param key the secret key.
217
* @param params the algorithm parameters; must be null for this cipher.
218
* @param random the source of randomness.
219
*
220
* @exception InvalidKeyException if the given key is inappropriate for
221
* initializing this cipher
222
* @exception InvalidAlgorithmParameterException if the given algorithm
223
* parameters is not null.
224
*/
225
protected void engineInit(int opmode, Key key,
226
AlgorithmParameterSpec params,
227
SecureRandom random)
228
throws InvalidKeyException, InvalidAlgorithmParameterException {
229
if (params != null) {
230
throw new InvalidAlgorithmParameterException("This cipher " +
231
"does not accept any parameters");
232
}
233
engineInit(opmode, key, random);
234
}
235
236
/**
237
* Initializes this cipher with a key, a set of algorithm parameters,
238
* and a source of randomness.
239
*
240
* <p>The cipher only supports the following two operation modes:<b>
241
* Cipher.WRAP_MODE, and <b>
242
* Cipher.UNWRAP_MODE.
243
* <p>For modes other than the above two, UnsupportedOperationException
244
* will be thrown.
245
*
246
* @param opmode the operation mode of this cipher. Only
247
* <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>) are accepted.
248
* @param key the secret key.
249
* @param params the algorithm parameters; must be null for this cipher.
250
* @param random the source of randomness.
251
*
252
* @exception InvalidKeyException if the given key is inappropriate.
253
* @exception InvalidAlgorithmParameterException if the given algorithm
254
* parameters is not null.
255
*/
256
protected void engineInit(int opmode, Key key,
257
AlgorithmParameters params,
258
SecureRandom random)
259
throws InvalidKeyException, InvalidAlgorithmParameterException {
260
if (params != null) {
261
throw new InvalidAlgorithmParameterException("This cipher " +
262
"does not accept any parameters");
263
}
264
engineInit(opmode, key, random);
265
}
266
267
/**
268
* This operation is not supported by this cipher.
269
* Since it's impossible to initialize this cipher given the
270
* current Cipher.engineInit(...) implementation,
271
* IllegalStateException will always be thrown upon invocation.
272
*
273
* @param in the input buffer.
274
* @param inOffset the offset in <code>in</code> where the input
275
* starts.
276
* @param inLen the input length.
277
*
278
* @return n/a.
279
*
280
* @exception IllegalStateException upon invocation of this method.
281
*/
282
protected byte[] engineUpdate(byte[] in, int inOffset, int inLen) {
283
throw new IllegalStateException("Cipher has not been initialized");
284
}
285
286
/**
287
* This operation is not supported by this cipher.
288
* Since it's impossible to initialize this cipher given the
289
* current Cipher.engineInit(...) implementation,
290
* IllegalStateException will always be thrown upon invocation.
291
*
292
* @param in the input buffer.
293
* @param inOffset the offset in <code>in</code> where the input
294
* starts.
295
* @param inLen the input length.
296
* @param out the buffer for the result.
297
* @param outOffset the offset in <code>out</code> where the result
298
* is stored.
299
*
300
* @return n/a.
301
*
302
* @exception IllegalStateException upon invocation of this method.
303
*/
304
protected int engineUpdate(byte[] in, int inOffset, int inLen,
305
byte[] out, int outOffset)
306
throws ShortBufferException {
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
*
321
* @return n/a.
322
*
323
* @exception IllegalStateException upon invocation of this method.
324
*/
325
protected byte[] engineDoFinal(byte[] input, int inputOffset,
326
int inputLen)
327
throws IllegalBlockSizeException, BadPaddingException {
328
throw new IllegalStateException("Cipher has not been initialized");
329
}
330
331
/**
332
* This operation is not supported by this cipher.
333
* Since it's impossible to initialize this cipher given the
334
* current Cipher.engineInit(...) implementation,
335
* IllegalStateException will always be thrown upon invocation.
336
*
337
* @param in the input buffer.
338
* @param inOffset the offset in <code>in</code> where the input
339
* starts.
340
* @param inLen the input length.
341
* @param out the buffer for the result.
342
* @param outOffset the ofset in <code>out</code> where the result
343
* is stored.
344
*
345
* @return n/a.
346
*
347
* @exception IllegalStateException upon invocation of this method.
348
*/
349
protected int engineDoFinal(byte[] in, int inOffset, int inLen,
350
byte[] out, int outOffset)
351
throws IllegalBlockSizeException, ShortBufferException,
352
BadPaddingException {
353
throw new IllegalStateException("Cipher has not been initialized");
354
}
355
356
/**
357
* Returns the parameters used with this cipher which is always null
358
* for this cipher.
359
*
360
* @return null since this cipher does not use any parameters.
361
*/
362
protected AlgorithmParameters engineGetParameters() {
363
return null;
364
}
365
366
/**
367
* Returns the key size of the given key object in number of bits.
368
*
369
* @param key the key object.
370
*
371
* @return the "effective" key size of the given key object.
372
*
373
* @exception InvalidKeyException if <code>key</code> is invalid.
374
*/
375
protected int engineGetKeySize(Key key) throws InvalidKeyException {
376
byte[] encoded = key.getEncoded();
377
if (!AESCrypt.isKeySizeValid(encoded.length)) {
378
throw new InvalidKeyException("Invalid key length: " +
379
encoded.length + " bytes");
380
}
381
return Math.multiplyExact(encoded.length, 8);
382
}
383
384
/**
385
* Wrap a key.
386
*
387
* @param key the key to be wrapped.
388
*
389
* @return the wrapped key.
390
*
391
* @exception IllegalBlockSizeException if this cipher is a block
392
* cipher, no padding has been requested, and the length of the
393
* encoding of the key to be wrapped is not a
394
* multiple of the block size.
395
*
396
* @exception InvalidKeyException if it is impossible or unsafe to
397
* wrap the key with this cipher (e.g., a hardware protected key is
398
* being passed to a software only cipher).
399
*/
400
protected byte[] engineWrap(Key key)
401
throws IllegalBlockSizeException, InvalidKeyException {
402
byte[] keyVal = key.getEncoded();
403
if ((keyVal == null) || (keyVal.length == 0)) {
404
throw new InvalidKeyException("Cannot get an encoding of " +
405
"the key to be wrapped");
406
}
407
byte[] out = new byte[Math.addExact(keyVal.length, 8)];
408
409
if (keyVal.length == 8) {
410
System.arraycopy(IV, 0, out, 0, IV.length);
411
System.arraycopy(keyVal, 0, out, IV.length, 8);
412
cipher.encryptBlock(out, 0, out, 0);
413
} else {
414
if (keyVal.length % 8 != 0) {
415
throw new IllegalBlockSizeException("length of the " +
416
"to be wrapped key should be multiples of 8 bytes");
417
}
418
System.arraycopy(IV, 0, out, 0, IV.length);
419
System.arraycopy(keyVal, 0, out, IV.length, keyVal.length);
420
int N = keyVal.length/8;
421
byte[] buffer = new byte[blksize];
422
for (int j = 0; j < 6; j++) {
423
for (int i = 1; i <= N; i++) {
424
int T = i + j*N;
425
System.arraycopy(out, 0, buffer, 0, IV.length);
426
System.arraycopy(out, i*8, buffer, IV.length, 8);
427
cipher.encryptBlock(buffer, 0, buffer, 0);
428
for (int k = 1; T != 0; k++) {
429
byte v = (byte) T;
430
buffer[IV.length - k] ^= v;
431
T >>>= 8;
432
}
433
System.arraycopy(buffer, 0, out, 0, IV.length);
434
System.arraycopy(buffer, 8, out, 8*i, 8);
435
}
436
}
437
}
438
return out;
439
}
440
441
/**
442
* Unwrap a previously wrapped key.
443
*
444
* @param wrappedKey the key to be unwrapped.
445
*
446
* @param wrappedKeyAlgorithm the algorithm the wrapped key is for.
447
*
448
* @param wrappedKeyType the type of the wrapped key.
449
* This is one of <code>Cipher.SECRET_KEY</code>,
450
* <code>Cipher.PRIVATE_KEY</code>, or <code>Cipher.PUBLIC_KEY</code>.
451
*
452
* @return the unwrapped key.
453
*
454
* @exception NoSuchAlgorithmException if no installed providers
455
* can create keys of type <code>wrappedKeyType</code> for the
456
* <code>wrappedKeyAlgorithm</code>.
457
*
458
* @exception InvalidKeyException if <code>wrappedKey</code> does not
459
* represent a wrapped key of type <code>wrappedKeyType</code> for
460
* the <code>wrappedKeyAlgorithm</code>.
461
*/
462
protected Key engineUnwrap(byte[] wrappedKey,
463
String wrappedKeyAlgorithm,
464
int wrappedKeyType)
465
throws InvalidKeyException, NoSuchAlgorithmException {
466
int wrappedKeyLen = wrappedKey.length;
467
// ensure the wrappedKey length is multiples of 8 bytes and non-zero
468
if (wrappedKeyLen == 0) {
469
throw new InvalidKeyException("The wrapped key is empty");
470
}
471
if (wrappedKeyLen % 8 != 0) {
472
throw new InvalidKeyException
473
("The wrapped key has invalid key length");
474
}
475
byte[] out = new byte[wrappedKeyLen - 8];
476
byte[] buffer = new byte[blksize];
477
if (wrappedKeyLen == 16) {
478
cipher.decryptBlock(wrappedKey, 0, buffer, 0);
479
for (int i = 0; i < IV.length; i++) {
480
if (IV[i] != buffer[i]) {
481
throw new InvalidKeyException("Integrity check failed");
482
}
483
}
484
System.arraycopy(buffer, IV.length, out, 0, out.length);
485
} else {
486
System.arraycopy(wrappedKey, 0, buffer, 0, IV.length);
487
System.arraycopy(wrappedKey, IV.length, out, 0, out.length);
488
int N = out.length/8;
489
for (int j = 5; j >= 0; j--) {
490
for (int i = N; i > 0; i--) {
491
int T = i + j*N;
492
System.arraycopy(out, 8*(i-1), buffer, IV.length, 8);
493
for (int k = 1; T != 0; k++) {
494
byte v = (byte) T;
495
buffer[IV.length - k] ^= v;
496
T >>>= 8;
497
}
498
cipher.decryptBlock(buffer, 0, buffer, 0);
499
System.arraycopy(buffer, IV.length, out, 8*(i-1), 8);
500
}
501
}
502
for (int i = 0; i < IV.length; i++) {
503
if (IV[i] != buffer[i]) {
504
throw new InvalidKeyException("Integrity check failed");
505
}
506
}
507
}
508
return ConstructKeys.constructKey(out, wrappedKeyAlgorithm,
509
wrappedKeyType);
510
}
511
}
512
513