Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java
41152 views
1
/*
2
* Copyright (c) 2001, 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 javax.crypto;
27
28
import java.io.*;
29
import java.security.*;
30
import java.security.spec.*;
31
import sun.security.x509.AlgorithmId;
32
import sun.security.util.DerValue;
33
import sun.security.util.DerInputStream;
34
import sun.security.util.DerOutputStream;
35
36
/**
37
* This class implements the <code>EncryptedPrivateKeyInfo</code> type
38
* as defined in PKCS #8.
39
* <p>Its ASN.1 definition is as follows:
40
*
41
* <pre>
42
* EncryptedPrivateKeyInfo ::= SEQUENCE {
43
* encryptionAlgorithm AlgorithmIdentifier,
44
* encryptedData OCTET STRING }
45
*
46
* AlgorithmIdentifier ::= SEQUENCE {
47
* algorithm OBJECT IDENTIFIER,
48
* parameters ANY DEFINED BY algorithm OPTIONAL }
49
* </pre>
50
*
51
* @author Valerie Peng
52
*
53
* @see java.security.spec.PKCS8EncodedKeySpec
54
*
55
* @since 1.4
56
*/
57
58
public class EncryptedPrivateKeyInfo {
59
60
// the "encryptionAlgorithm" field
61
private AlgorithmId algid;
62
63
// the algorithm name of the encrypted private key
64
private String keyAlg;
65
66
// the "encryptedData" field
67
private byte[] encryptedData;
68
69
// the ASN.1 encoded contents of this class
70
private byte[] encoded = null;
71
72
/**
73
* Constructs (i.e., parses) an <code>EncryptedPrivateKeyInfo</code> from
74
* its ASN.1 encoding.
75
* @param encoded the ASN.1 encoding of this object. The contents of
76
* the array are copied to protect against subsequent modification.
77
* @exception NullPointerException if the <code>encoded</code> is null.
78
* @exception IOException if error occurs when parsing the ASN.1 encoding.
79
*/
80
public EncryptedPrivateKeyInfo(byte[] encoded)
81
throws IOException {
82
if (encoded == null) {
83
throw new NullPointerException("the encoded parameter " +
84
"must be non-null");
85
}
86
this.encoded = encoded.clone();
87
DerValue val = new DerValue(this.encoded);
88
89
DerValue[] seq = new DerValue[2];
90
91
seq[0] = val.data.getDerValue();
92
seq[1] = val.data.getDerValue();
93
94
if (val.data.available() != 0) {
95
throw new IOException("overrun, bytes = " + val.data.available());
96
}
97
98
this.algid = AlgorithmId.parse(seq[0]);
99
if (seq[0].data.available() != 0) {
100
throw new IOException("encryptionAlgorithm field overrun");
101
}
102
103
this.encryptedData = seq[1].getOctetString();
104
if (seq[1].data.available() != 0) {
105
throw new IOException("encryptedData field overrun");
106
}
107
}
108
109
/**
110
* Constructs an <code>EncryptedPrivateKeyInfo</code> from the
111
* encryption algorithm name and the encrypted data.
112
*
113
* <p>Note: This constructor will use null as the value of the
114
* algorithm parameters. If the encryption algorithm has
115
* parameters whose value is not null, a different constructor,
116
* e.g. EncryptedPrivateKeyInfo(AlgorithmParameters, byte[]),
117
* should be used.
118
*
119
* @param algName encryption algorithm name. See the
120
* <a href="{@docRoot}/../specs/security/standard-names.html">
121
* Java Security Standard Algorithm Names</a> document
122
* for information about standard Cipher algorithm names.
123
* @param encryptedData encrypted data. The contents of
124
* <code>encrypedData</code> are copied to protect against subsequent
125
* modification when constructing this object.
126
* @exception NullPointerException if <code>algName</code> or
127
* <code>encryptedData</code> is null.
128
* @exception IllegalArgumentException if <code>encryptedData</code>
129
* is empty, i.e. 0-length.
130
* @exception NoSuchAlgorithmException if the specified algName is
131
* not supported.
132
*/
133
public EncryptedPrivateKeyInfo(String algName, byte[] encryptedData)
134
throws NoSuchAlgorithmException {
135
136
if (algName == null)
137
throw new NullPointerException("the algName parameter " +
138
"must be non-null");
139
this.algid = AlgorithmId.get(algName);
140
141
if (encryptedData == null) {
142
throw new NullPointerException("the encryptedData " +
143
"parameter must be non-null");
144
} else if (encryptedData.length == 0) {
145
throw new IllegalArgumentException("the encryptedData " +
146
"parameter must not be empty");
147
} else {
148
this.encryptedData = encryptedData.clone();
149
}
150
// delay the generation of ASN.1 encoding until
151
// getEncoded() is called
152
this.encoded = null;
153
}
154
155
/**
156
* Constructs an <code>EncryptedPrivateKeyInfo</code> from the
157
* encryption algorithm parameters and the encrypted data.
158
*
159
* @param algParams the algorithm parameters for the encryption
160
* algorithm. <code>algParams.getEncoded()</code> should return
161
* the ASN.1 encoded bytes of the <code>parameters</code> field
162
* of the <code>AlgorithmIdentifer</code> component of the
163
* <code>EncryptedPrivateKeyInfo</code> type.
164
* @param encryptedData encrypted data. The contents of
165
* <code>encrypedData</code> are copied to protect against
166
* subsequent modification when constructing this object.
167
* @exception NullPointerException if <code>algParams</code> or
168
* <code>encryptedData</code> is null.
169
* @exception IllegalArgumentException if <code>encryptedData</code>
170
* is empty, i.e. 0-length.
171
* @exception NoSuchAlgorithmException if the specified algName of
172
* the specified <code>algParams</code> parameter is not supported.
173
*/
174
public EncryptedPrivateKeyInfo(AlgorithmParameters algParams,
175
byte[] encryptedData) throws NoSuchAlgorithmException {
176
177
if (algParams == null) {
178
throw new NullPointerException("algParams must be non-null");
179
}
180
this.algid = AlgorithmId.get(algParams);
181
182
if (encryptedData == null) {
183
throw new NullPointerException("encryptedData must be non-null");
184
} else if (encryptedData.length == 0) {
185
throw new IllegalArgumentException("the encryptedData " +
186
"parameter must not be empty");
187
} else {
188
this.encryptedData = encryptedData.clone();
189
}
190
191
// delay the generation of ASN.1 encoding until
192
// getEncoded() is called
193
this.encoded = null;
194
}
195
196
197
/**
198
* Returns the encryption algorithm.
199
* <p>Note: Standard name is returned instead of the specified one
200
* in the constructor when such mapping is available.
201
* See the <a href="{@docRoot}/../specs/security/standard-names.html">
202
* Java Security Standard Algorithm Names</a> document
203
* for information about standard Cipher algorithm names.
204
*
205
* @return the encryption algorithm name.
206
*/
207
public String getAlgName() {
208
return this.algid.getName();
209
}
210
211
/**
212
* Returns the algorithm parameters used by the encryption algorithm.
213
* @return the algorithm parameters.
214
*/
215
public AlgorithmParameters getAlgParameters() {
216
return this.algid.getParameters();
217
}
218
219
/**
220
* Returns the encrypted data.
221
* @return the encrypted data. Returns a new array
222
* each time this method is called.
223
*/
224
public byte[] getEncryptedData() {
225
return this.encryptedData.clone();
226
}
227
228
/**
229
* Extract the enclosed PKCS8EncodedKeySpec object from the
230
* encrypted data and return it.
231
* <br>Note: In order to successfully retrieve the enclosed
232
* PKCS8EncodedKeySpec object, <code>cipher</code> needs
233
* to be initialized to either Cipher.DECRYPT_MODE or
234
* Cipher.UNWRAP_MODE, with the same key and parameters used
235
* for generating the encrypted data.
236
*
237
* @param cipher the initialized cipher object which will be
238
* used for decrypting the encrypted data.
239
* @return the PKCS8EncodedKeySpec object.
240
* @exception NullPointerException if <code>cipher</code>
241
* is null.
242
* @exception InvalidKeySpecException if the given cipher is
243
* inappropriate for the encrypted data or the encrypted
244
* data is corrupted and cannot be decrypted.
245
*/
246
public PKCS8EncodedKeySpec getKeySpec(Cipher cipher)
247
throws InvalidKeySpecException {
248
byte[] encoded = null;
249
try {
250
encoded = cipher.doFinal(encryptedData);
251
checkPKCS8Encoding(encoded);
252
} catch (GeneralSecurityException |
253
IOException |
254
IllegalStateException ex) {
255
throw new InvalidKeySpecException(
256
"Cannot retrieve the PKCS8EncodedKeySpec", ex);
257
}
258
return new PKCS8EncodedKeySpec(encoded, keyAlg);
259
}
260
261
private PKCS8EncodedKeySpec getKeySpecImpl(Key decryptKey,
262
Provider provider) throws NoSuchAlgorithmException,
263
InvalidKeyException {
264
byte[] encoded = null;
265
Cipher c;
266
try {
267
if (provider == null) {
268
// use the most preferred one
269
c = Cipher.getInstance(algid.getName());
270
} else {
271
c = Cipher.getInstance(algid.getName(), provider);
272
}
273
c.init(Cipher.DECRYPT_MODE, decryptKey, algid.getParameters());
274
encoded = c.doFinal(encryptedData);
275
checkPKCS8Encoding(encoded);
276
} catch (NoSuchAlgorithmException nsae) {
277
// rethrow
278
throw nsae;
279
} catch (GeneralSecurityException | IOException ex) {
280
throw new InvalidKeyException(
281
"Cannot retrieve the PKCS8EncodedKeySpec", ex);
282
}
283
return new PKCS8EncodedKeySpec(encoded, keyAlg);
284
}
285
286
/**
287
* Extract the enclosed PKCS8EncodedKeySpec object from the
288
* encrypted data and return it.
289
* @param decryptKey key used for decrypting the encrypted data.
290
* @return the PKCS8EncodedKeySpec object.
291
* @exception NullPointerException if <code>decryptKey</code>
292
* is null.
293
* @exception NoSuchAlgorithmException if cannot find appropriate
294
* cipher to decrypt the encrypted data.
295
* @exception InvalidKeyException if <code>decryptKey</code>
296
* cannot be used to decrypt the encrypted data or the decryption
297
* result is not a valid PKCS8KeySpec.
298
*
299
* @since 1.5
300
*/
301
public PKCS8EncodedKeySpec getKeySpec(Key decryptKey)
302
throws NoSuchAlgorithmException, InvalidKeyException {
303
if (decryptKey == null) {
304
throw new NullPointerException("decryptKey is null");
305
}
306
return getKeySpecImpl(decryptKey, null);
307
}
308
309
/**
310
* Extract the enclosed PKCS8EncodedKeySpec object from the
311
* encrypted data and return it.
312
* @param decryptKey key used for decrypting the encrypted data.
313
* @param providerName the name of provider whose Cipher
314
* implementation will be used.
315
* @return the PKCS8EncodedKeySpec object.
316
* @exception NullPointerException if <code>decryptKey</code>
317
* or <code>providerName</code> is null.
318
* @exception NoSuchProviderException if no provider
319
* <code>providerName</code> is registered.
320
* @exception NoSuchAlgorithmException if cannot find appropriate
321
* cipher to decrypt the encrypted data.
322
* @exception InvalidKeyException if <code>decryptKey</code>
323
* cannot be used to decrypt the encrypted data or the decryption
324
* result is not a valid PKCS8KeySpec.
325
*
326
* @since 1.5
327
*/
328
public PKCS8EncodedKeySpec getKeySpec(Key decryptKey,
329
String providerName) throws NoSuchProviderException,
330
NoSuchAlgorithmException, InvalidKeyException {
331
if (decryptKey == null) {
332
throw new NullPointerException("decryptKey is null");
333
}
334
if (providerName == null) {
335
throw new NullPointerException("provider is null");
336
}
337
Provider provider = Security.getProvider(providerName);
338
if (provider == null) {
339
throw new NoSuchProviderException("provider " +
340
providerName + " not found");
341
}
342
return getKeySpecImpl(decryptKey, provider);
343
}
344
345
/**
346
* Extract the enclosed PKCS8EncodedKeySpec object from the
347
* encrypted data and return it.
348
* @param decryptKey key used for decrypting the encrypted data.
349
* @param provider the name of provider whose Cipher implementation
350
* will be used.
351
* @return the PKCS8EncodedKeySpec object.
352
* @exception NullPointerException if <code>decryptKey</code>
353
* or <code>provider</code> is null.
354
* @exception NoSuchAlgorithmException if cannot find appropriate
355
* cipher to decrypt the encrypted data in <code>provider</code>.
356
* @exception InvalidKeyException if <code>decryptKey</code>
357
* cannot be used to decrypt the encrypted data or the decryption
358
* result is not a valid PKCS8KeySpec.
359
*
360
* @since 1.5
361
*/
362
public PKCS8EncodedKeySpec getKeySpec(Key decryptKey,
363
Provider provider) throws NoSuchAlgorithmException,
364
InvalidKeyException {
365
if (decryptKey == null) {
366
throw new NullPointerException("decryptKey is null");
367
}
368
if (provider == null) {
369
throw new NullPointerException("provider is null");
370
}
371
return getKeySpecImpl(decryptKey, provider);
372
}
373
374
/**
375
* Returns the ASN.1 encoding of this object.
376
* @return the ASN.1 encoding. Returns a new array
377
* each time this method is called.
378
* @exception IOException if error occurs when constructing its
379
* ASN.1 encoding.
380
*/
381
public byte[] getEncoded() throws IOException {
382
if (this.encoded == null) {
383
DerOutputStream out = new DerOutputStream();
384
DerOutputStream tmp = new DerOutputStream();
385
386
// encode encryption algorithm
387
algid.encode(tmp);
388
389
// encode encrypted data
390
tmp.putOctetString(encryptedData);
391
392
// wrap everything into a SEQUENCE
393
out.write(DerValue.tag_Sequence, tmp);
394
this.encoded = out.toByteArray();
395
}
396
return this.encoded.clone();
397
}
398
399
private static void checkTag(DerValue val, byte tag, String valName)
400
throws IOException {
401
if (val.getTag() != tag) {
402
throw new IOException("invalid key encoding - wrong tag for " +
403
valName);
404
}
405
}
406
407
@SuppressWarnings("fallthrough")
408
private void checkPKCS8Encoding(byte[] encodedKey)
409
throws IOException {
410
DerInputStream in = new DerInputStream(encodedKey);
411
DerValue[] values = in.getSequence(3);
412
413
switch (values.length) {
414
case 4:
415
checkTag(values[3], DerValue.TAG_CONTEXT, "attributes");
416
/* fall through */
417
case 3:
418
checkTag(values[0], DerValue.tag_Integer, "version");
419
keyAlg = AlgorithmId.parse(values[1]).getName();
420
checkTag(values[2], DerValue.tag_OctetString, "privateKey");
421
break;
422
default:
423
throw new IOException("invalid key encoding");
424
}
425
}
426
}
427
428