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/javax/crypto/SealedObject.java
38829 views
1
/*
2
* Copyright (c) 1997, 2018, 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 sun.misc.SharedSecrets;
29
30
import java.io.*;
31
import java.security.AlgorithmParameters;
32
import java.security.Key;
33
import java.security.InvalidKeyException;
34
import java.security.InvalidAlgorithmParameterException;
35
import java.security.NoSuchAlgorithmException;
36
import java.security.NoSuchProviderException;
37
38
/**
39
* This class enables a programmer to create an object and protect its
40
* confidentiality with a cryptographic algorithm.
41
*
42
* <p> Given any Serializable object, one can create a SealedObject
43
* that encapsulates the original object, in serialized
44
* format (i.e., a "deep copy"), and seals (encrypts) its serialized contents,
45
* using a cryptographic algorithm such as AES, to protect its
46
* confidentiality. The encrypted content can later be decrypted (with
47
* the corresponding algorithm using the correct decryption key) and
48
* de-serialized, yielding the original object.
49
*
50
* <p> Note that the Cipher object must be fully initialized with the
51
* correct algorithm, key, padding scheme, etc., before being applied
52
* to a SealedObject.
53
*
54
* <p> The original object that was sealed can be recovered in two different
55
* ways:
56
*
57
* <ul>
58
*
59
* <li>by using the {@link #getObject(javax.crypto.Cipher) getObject}
60
* method that takes a <code>Cipher</code> object.
61
*
62
* <p> This method requires a fully initialized <code>Cipher</code> object,
63
* initialized with the
64
* exact same algorithm, key, padding scheme, etc., that were used to seal the
65
* object.
66
*
67
* <p> This approach has the advantage that the party who unseals the
68
* sealed object does not require knowledge of the decryption key. For example,
69
* after one party has initialized the cipher object with the required
70
* decryption key, it could hand over the cipher object to
71
* another party who then unseals the sealed object.
72
*
73
* <li>by using one of the
74
* {@link #getObject(java.security.Key) getObject} methods
75
* that take a <code>Key</code> object.
76
*
77
* <p> In this approach, the <code>getObject</code> method creates a cipher
78
* object for the appropriate decryption algorithm and initializes it with the
79
* given decryption key and the algorithm parameters (if any) that were stored
80
* in the sealed object.
81
*
82
* <p> This approach has the advantage that the party who
83
* unseals the object does not need to keep track of the parameters (e.g., an
84
* IV) that were used to seal the object.
85
*
86
* </ul>
87
*
88
* @author Li Gong
89
* @author Jan Luehe
90
* @see Cipher
91
* @since 1.4
92
*/
93
94
public class SealedObject implements Serializable {
95
96
static final long serialVersionUID = 4482838265551344752L;
97
98
/**
99
* The serialized object contents in encrypted format.
100
*
101
* @serial
102
*/
103
private byte[] encryptedContent = null;
104
105
/**
106
* The algorithm that was used to seal this object.
107
*
108
* @serial
109
*/
110
private String sealAlg = null;
111
112
/**
113
* The algorithm of the parameters used.
114
*
115
* @serial
116
*/
117
private String paramsAlg = null;
118
119
/**
120
* The cryptographic parameters used by the sealing Cipher,
121
* encoded in the default format.
122
* <p>
123
* That is, <code>cipher.getParameters().getEncoded()</code>.
124
*
125
* @serial
126
*/
127
protected byte[] encodedParams = null;
128
129
/**
130
* Constructs a SealedObject from any Serializable object.
131
*
132
* <p>The given object is serialized, and its serialized contents are
133
* encrypted using the given Cipher, which must be fully initialized.
134
*
135
* <p>Any algorithm parameters that may be used in the encryption
136
* operation are stored inside of the new <code>SealedObject</code>.
137
*
138
* @param object the object to be sealed; can be null.
139
* @param c the cipher used to seal the object.
140
*
141
* @exception NullPointerException if the given cipher is null.
142
* @exception IOException if an error occurs during serialization
143
* @exception IllegalBlockSizeException if the given cipher is a block
144
* cipher, no padding has been requested, and the total input length
145
* (i.e., the length of the serialized object contents) is not a multiple
146
* of the cipher's block size
147
*/
148
public SealedObject(Serializable object, Cipher c) throws IOException,
149
IllegalBlockSizeException
150
{
151
/*
152
* Serialize the object
153
*/
154
155
// creating a stream pipe-line, from a to b
156
ByteArrayOutputStream b = new ByteArrayOutputStream();
157
ObjectOutput a = new ObjectOutputStream(b);
158
byte[] content;
159
try {
160
// write and flush the object content to byte array
161
a.writeObject(object);
162
a.flush();
163
content = b.toByteArray();
164
} finally {
165
a.close();
166
}
167
168
/*
169
* Seal the object
170
*/
171
try {
172
this.encryptedContent = c.doFinal(content);
173
}
174
catch (BadPaddingException ex) {
175
// if sealing is encryption only
176
// Should never happen??
177
}
178
179
// Save the parameters
180
if (c.getParameters() != null) {
181
this.encodedParams = c.getParameters().getEncoded();
182
this.paramsAlg = c.getParameters().getAlgorithm();
183
}
184
185
// Save the encryption algorithm
186
this.sealAlg = c.getAlgorithm();
187
}
188
189
/**
190
* Constructs a SealedObject object from the passed-in SealedObject.
191
*
192
* @param so a SealedObject object
193
* @exception NullPointerException if the given sealed object is null.
194
*/
195
protected SealedObject(SealedObject so) {
196
this.encryptedContent = so.encryptedContent.clone();
197
this.sealAlg = so.sealAlg;
198
this.paramsAlg = so.paramsAlg;
199
if (so.encodedParams != null) {
200
this.encodedParams = so.encodedParams.clone();
201
} else {
202
this.encodedParams = null;
203
}
204
}
205
206
/**
207
* Returns the algorithm that was used to seal this object.
208
*
209
* @return the algorithm that was used to seal this object.
210
*/
211
public final String getAlgorithm() {
212
return this.sealAlg;
213
}
214
215
/**
216
* Retrieves the original (encapsulated) object.
217
*
218
* <p>This method creates a cipher for the algorithm that had been used in
219
* the sealing operation.
220
* If the default provider package provides an implementation of that
221
* algorithm, an instance of Cipher containing that implementation is used.
222
* If the algorithm is not available in the default package, other
223
* packages are searched.
224
* The Cipher object is initialized for decryption, using the given
225
* <code>key</code> and the parameters (if any) that had been used in the
226
* sealing operation.
227
*
228
* <p>The encapsulated object is unsealed and de-serialized, before it is
229
* returned.
230
*
231
* @param key the key used to unseal the object.
232
*
233
* @return the original object.
234
*
235
* @exception IOException if an error occurs during de-serialiazation.
236
* @exception ClassNotFoundException if an error occurs during
237
* de-serialiazation.
238
* @exception NoSuchAlgorithmException if the algorithm to unseal the
239
* object is not available.
240
* @exception InvalidKeyException if the given key cannot be used to unseal
241
* the object (e.g., it has the wrong algorithm).
242
* @exception NullPointerException if <code>key</code> is null.
243
*/
244
public final Object getObject(Key key)
245
throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
246
InvalidKeyException
247
{
248
if (key == null) {
249
throw new NullPointerException("key is null");
250
}
251
252
try {
253
return unseal(key, null);
254
} catch (NoSuchProviderException nspe) {
255
// we've already caught NoSuchProviderException's and converted
256
// them into NoSuchAlgorithmException's with details about
257
// the failing algorithm
258
throw new NoSuchAlgorithmException("algorithm not found");
259
} catch (IllegalBlockSizeException ibse) {
260
throw new InvalidKeyException(ibse.getMessage());
261
} catch (BadPaddingException bpe) {
262
throw new InvalidKeyException(bpe.getMessage());
263
}
264
}
265
266
/**
267
* Retrieves the original (encapsulated) object.
268
*
269
* <p>The encapsulated object is unsealed (using the given Cipher,
270
* assuming that the Cipher is already properly initialized) and
271
* de-serialized, before it is returned.
272
*
273
* @param c the cipher used to unseal the object
274
*
275
* @return the original object.
276
*
277
* @exception NullPointerException if the given cipher is null.
278
* @exception IOException if an error occurs during de-serialiazation
279
* @exception ClassNotFoundException if an error occurs during
280
* de-serialiazation
281
* @exception IllegalBlockSizeException if the given cipher is a block
282
* cipher, no padding has been requested, and the total input length is
283
* not a multiple of the cipher's block size
284
* @exception BadPaddingException if the given cipher has been
285
* initialized for decryption, and padding has been specified, but
286
* the input data does not have proper expected padding bytes
287
*/
288
public final Object getObject(Cipher c)
289
throws IOException, ClassNotFoundException, IllegalBlockSizeException,
290
BadPaddingException
291
{
292
ObjectInput a = getExtObjectInputStream(c);
293
try {
294
Object obj = a.readObject();
295
return obj;
296
} finally {
297
a.close();
298
}
299
}
300
301
/**
302
* Retrieves the original (encapsulated) object.
303
*
304
* <p>This method creates a cipher for the algorithm that had been used in
305
* the sealing operation, using an implementation of that algorithm from
306
* the given <code>provider</code>.
307
* The Cipher object is initialized for decryption, using the given
308
* <code>key</code> and the parameters (if any) that had been used in the
309
* sealing operation.
310
*
311
* <p>The encapsulated object is unsealed and de-serialized, before it is
312
* returned.
313
*
314
* @param key the key used to unseal the object.
315
* @param provider the name of the provider of the algorithm to unseal
316
* the object.
317
*
318
* @return the original object.
319
*
320
* @exception IllegalArgumentException if the given provider is null
321
* or empty.
322
* @exception IOException if an error occurs during de-serialiazation.
323
* @exception ClassNotFoundException if an error occurs during
324
* de-serialiazation.
325
* @exception NoSuchAlgorithmException if the algorithm to unseal the
326
* object is not available.
327
* @exception NoSuchProviderException if the given provider is not
328
* configured.
329
* @exception InvalidKeyException if the given key cannot be used to unseal
330
* the object (e.g., it has the wrong algorithm).
331
* @exception NullPointerException if <code>key</code> is null.
332
*/
333
public final Object getObject(Key key, String provider)
334
throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
335
NoSuchProviderException, InvalidKeyException
336
{
337
if (key == null) {
338
throw new NullPointerException("key is null");
339
}
340
if (provider == null || provider.length() == 0) {
341
throw new IllegalArgumentException("missing provider");
342
}
343
344
try {
345
return unseal(key, provider);
346
} catch (IllegalBlockSizeException | BadPaddingException ex) {
347
throw new InvalidKeyException(ex.getMessage());
348
}
349
}
350
351
352
private Object unseal(Key key, String provider)
353
throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
354
NoSuchProviderException, InvalidKeyException,
355
IllegalBlockSizeException, BadPaddingException
356
{
357
/*
358
* Create the parameter object.
359
*/
360
AlgorithmParameters params = null;
361
if (this.encodedParams != null) {
362
try {
363
if (provider != null)
364
params = AlgorithmParameters.getInstance(this.paramsAlg,
365
provider);
366
else
367
params = AlgorithmParameters.getInstance(this.paramsAlg);
368
369
} catch (NoSuchProviderException nspe) {
370
if (provider == null) {
371
throw new NoSuchAlgorithmException(this.paramsAlg
372
+ " not found");
373
} else {
374
throw new NoSuchProviderException(nspe.getMessage());
375
}
376
}
377
params.init(this.encodedParams);
378
}
379
380
/*
381
* Create and initialize the cipher.
382
*/
383
Cipher c;
384
try {
385
if (provider != null)
386
c = Cipher.getInstance(this.sealAlg, provider);
387
else
388
c = Cipher.getInstance(this.sealAlg);
389
} catch (NoSuchPaddingException nspe) {
390
throw new NoSuchAlgorithmException("Padding that was used in "
391
+ "sealing operation not "
392
+ "available");
393
} catch (NoSuchProviderException nspe) {
394
if (provider == null) {
395
throw new NoSuchAlgorithmException(this.sealAlg+" not found");
396
} else {
397
throw new NoSuchProviderException(nspe.getMessage());
398
}
399
}
400
401
try {
402
if (params != null)
403
c.init(Cipher.DECRYPT_MODE, key, params);
404
else
405
c.init(Cipher.DECRYPT_MODE, key);
406
} catch (InvalidAlgorithmParameterException iape) {
407
// this should never happen, because we use the exact same
408
// parameters that were used in the sealing operation
409
throw new RuntimeException(iape.getMessage());
410
}
411
412
ObjectInput a = getExtObjectInputStream(c);
413
try {
414
Object obj = a.readObject();
415
return obj;
416
} finally {
417
a.close();
418
}
419
}
420
421
/**
422
* Restores the state of the SealedObject from a stream.
423
* @param s the object input stream.
424
* @exception NullPointerException if s is null.
425
*/
426
private void readObject(java.io.ObjectInputStream s)
427
throws java.io.IOException, ClassNotFoundException
428
{
429
s.defaultReadObject();
430
if (encryptedContent != null)
431
encryptedContent = encryptedContent.clone();
432
if (encodedParams != null)
433
encodedParams = encodedParams.clone();
434
}
435
436
// This method is also called inside SealedObjectForKeyProtector.java.
437
private ObjectInputStream getExtObjectInputStream(Cipher c)
438
throws BadPaddingException, IllegalBlockSizeException, IOException {
439
440
byte[] content = c.doFinal(this.encryptedContent);
441
ByteArrayInputStream b = new ByteArrayInputStream(content);
442
return new extObjectInputStream(b);
443
}
444
445
static {
446
SharedSecrets.setJavaxCryptoSealedObjectAccess((obj,c) -> obj.getExtObjectInputStream(c));
447
}
448
}
449
450
final class extObjectInputStream extends ObjectInputStream {
451
452
private static ClassLoader systemClassLoader = null;
453
454
extObjectInputStream(InputStream in)
455
throws IOException, StreamCorruptedException {
456
super(in);
457
}
458
459
protected Class<?> resolveClass(ObjectStreamClass v)
460
throws IOException, ClassNotFoundException
461
{
462
463
try {
464
/*
465
* Calling the super.resolveClass() first
466
* will let us pick up bug fixes in the super
467
* class (e.g., 4171142).
468
*/
469
return super.resolveClass(v);
470
} catch (ClassNotFoundException cnfe) {
471
/*
472
* This is a workaround for bug 4224921.
473
*/
474
ClassLoader loader = Thread.currentThread().getContextClassLoader();
475
if (loader == null) {
476
if (systemClassLoader == null) {
477
systemClassLoader = ClassLoader.getSystemClassLoader();
478
}
479
loader = systemClassLoader;
480
if (loader == null) {
481
throw new ClassNotFoundException(v.getName());
482
}
483
}
484
485
return Class.forName(v.getName(), false, loader);
486
}
487
}
488
}
489
490