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