History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/crypto/SealedObject.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/crypto/SealedObject.java+497−0
@@ -0,0 +1,497 @@
1+/*
2+ * Copyright (c) 1997, 2007, 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.AlgorithmParameters;
30+import java.security.Key;
31+import java.security.InvalidKeyException;
32+import java.security.InvalidAlgorithmParameterException;
33+import java.security.NoSuchAlgorithmException;
34+import java.security.NoSuchProviderException;
35+
36+/**
37+ * This class enables a programmer to create an object and protect its
38+ * confidentiality with a cryptographic algorithm.
39+ *
40+ * <p> Given any Serializable object, one can create a SealedObject
41+ * that encapsulates the original object, in serialized
42+ * format (i.e., a "deep copy"), and seals (encrypts) its serialized contents,
43+ * using a cryptographic algorithm such as DES, to protect its
44+ * confidentiality. The encrypted content can later be decrypted (with
45+ * the corresponding algorithm using the correct decryption key) and
46+ * de-serialized, yielding the original object.
47+ *
48+ * <p> Note that the Cipher object must be fully initialized with the
49+ * correct algorithm, key, padding scheme, etc., before being applied
50+ * to a SealedObject.
51+ *
52+ * <p> The original object that was sealed can be recovered in two different
53+ * ways: <p>
54+ *
55+ * <ul>
56+ *
57+ * <li>by using the {@link #getObject(javax.crypto.Cipher) getObject}
58+ * method that takes a <code>Cipher</code> object.
59+ *
60+ * <p> This method requires a fully initialized <code>Cipher</code> object,
61+ * initialized with the
62+ * exact same algorithm, key, padding scheme, etc., that were used to seal the
63+ * object.
64+ *
65+ * <p> This approach has the advantage that the party who unseals the
66+ * sealed object does not require knowledge of the decryption key. For example,
67+ * after one party has initialized the cipher object with the required
68+ * decryption key, it could hand over the cipher object to
69+ * another party who then unseals the sealed object.
70+ *
71+ * <p>
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 = (byte[]) so.encryptedContent.clone();
197+ this.sealAlg = so.sealAlg;
198+ this.paramsAlg = so.paramsAlg;
199+ if (so.encodedParams != null) {
200+ this.encodedParams = (byte[]) 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+ /*
293+ * Unseal the object
294+ */
295+ byte[] content = c.doFinal(this.encryptedContent);
296+
297+ /*
298+ * De-serialize it
299+ */
300+ // creating a stream pipe-line, from b to a
301+ ByteArrayInputStream b = new ByteArrayInputStream(content);
302+ ObjectInput a = new extObjectInputStream(b);
303+ try {
304+ Object obj = a.readObject();
305+ return obj;
306+ } finally {
307+ a.close();
308+ }
309+ }
310+
311+ /**
312+ * Retrieves the original (encapsulated) object.
313+ *
314+ * <p>This method creates a cipher for the algorithm that had been used in
315+ * the sealing operation, using an implementation of that algorithm from
316+ * the given <code>provider</code>.
317+ * The Cipher object is initialized for decryption, using the given
318+ * <code>key</code> and the parameters (if any) that had been used in the
319+ * sealing operation.
320+ *
321+ * <p>The encapsulated object is unsealed and de-serialized, before it is
322+ * returned.
323+ *
324+ * @param key the key used to unseal the object.
325+ * @param provider the name of the provider of the algorithm to unseal
326+ * the object.
327+ *
328+ * @return the original object.
329+ *
330+ * @exception IllegalArgumentException if the given provider is null
331+ * or empty.
332+ * @exception IOException if an error occurs during de-serialiazation.
333+ * @exception ClassNotFoundException if an error occurs during
334+ * de-serialiazation.
335+ * @exception NoSuchAlgorithmException if the algorithm to unseal the
336+ * object is not available.
337+ * @exception NoSuchProviderException if the given provider is not
338+ * configured.
339+ * @exception InvalidKeyException if the given key cannot be used to unseal
340+ * the object (e.g., it has the wrong algorithm).
341+ * @exception NullPointerException if <code>key</code> is null.
342+ */
343+ public final Object getObject(Key key, String provider)
344+ throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
345+ NoSuchProviderException, InvalidKeyException
346+ {
347+ if (key == null) {
348+ throw new NullPointerException("key is null");
349+ }
350+ if (provider == null || provider.length() == 0) {
351+ throw new IllegalArgumentException("missing provider");
352+ }
353+
354+ try {
355+ return unseal(key, provider);
356+ } catch (IllegalBlockSizeException ibse) {
357+ throw new InvalidKeyException(ibse.getMessage());
358+ } catch (BadPaddingException bpe) {
359+ throw new InvalidKeyException(bpe.getMessage());
360+ }
361+ }
362+
363+
364+ private Object unseal(Key key, String provider)
365+ throws IOException, ClassNotFoundException, NoSuchAlgorithmException,
366+ NoSuchProviderException, InvalidKeyException,
367+ IllegalBlockSizeException, BadPaddingException
368+ {
369+ /*
370+ * Create the parameter object.
371+ */
372+ AlgorithmParameters params = null;
373+ if (this.encodedParams != null) {
374+ try {
375+ if (provider != null)
376+ params = AlgorithmParameters.getInstance(this.paramsAlg,
377+ provider);
378+ else
379+ params = AlgorithmParameters.getInstance(this.paramsAlg);
380+
381+ } catch (NoSuchProviderException nspe) {
382+ if (provider == null) {
383+ throw new NoSuchAlgorithmException(this.paramsAlg
384+ + " not found");
385+ } else {
386+ throw new NoSuchProviderException(nspe.getMessage());
387+ }
388+ }
389+ params.init(this.encodedParams);
390+ }
391+
392+ /*
393+ * Create and initialize the cipher.
394+ */
395+ Cipher c;
396+ try {
397+ if (provider != null)
398+ c = Cipher.getInstance(this.sealAlg, provider);
399+ else
400+ c = Cipher.getInstance(this.sealAlg);
401+ } catch (NoSuchPaddingException nspe) {
402+ throw new NoSuchAlgorithmException("Padding that was used in "
403+ + "sealing operation not "
404+ + "available");
405+ } catch (NoSuchProviderException nspe) {
406+ if (provider == null) {
407+ throw new NoSuchAlgorithmException(this.sealAlg+" not found");
408+ } else {
409+ throw new NoSuchProviderException(nspe.getMessage());
410+ }
411+ }
412+
413+ try {
414+ if (params != null)
415+ c.init(Cipher.DECRYPT_MODE, key, params);
416+ else
417+ c.init(Cipher.DECRYPT_MODE, key);
418+ } catch (InvalidAlgorithmParameterException iape) {
419+ // this should never happen, because we use the exact same
420+ // parameters that were used in the sealing operation
421+ throw new RuntimeException(iape.getMessage());
422+ }
423+
424+ /*
425+ * Unseal the object
426+ */
427+ byte[] content = c.doFinal(this.encryptedContent);
428+
429+ /*
430+ * De-serialize it
431+ */
432+ // creating a stream pipe-line, from b to a
433+ ByteArrayInputStream b = new ByteArrayInputStream(content);
434+ ObjectInput a = new extObjectInputStream(b);
435+ try {
436+ Object obj = a.readObject();
437+ return obj;
438+ } finally {
439+ a.close();
440+ }
441+ }
442+
443+ /**
444+ * Restores the state of the SealedObject from a stream.
445+ * @param s the object input stream.
446+ * @exception NullPointerException if s is null.
447+ */
448+ private void readObject(java.io.ObjectInputStream s)
449+ throws java.io.IOException, ClassNotFoundException
450+ {
451+ s.defaultReadObject();
452+ if (encryptedContent != null)
453+ encryptedContent = (byte[])encryptedContent.clone();
454+ if (encodedParams != null)
455+ encodedParams = (byte[])encodedParams.clone();
456+ }
457+}
458+
459+final class extObjectInputStream extends ObjectInputStream {
460+
461+ private static ClassLoader systemClassLoader = null;
462+
463+ extObjectInputStream(InputStream in)
464+ throws IOException, StreamCorruptedException {
465+ super(in);
466+ }
467+
468+ protected Class resolveClass(ObjectStreamClass v)
469+ throws IOException, ClassNotFoundException
470+ {
471+
472+ try {
473+ /*
474+ * Calling the super.resolveClass() first
475+ * will let us pick up bug fixes in the super
476+ * class (e.g., 4171142).
477+ */
478+ return super.resolveClass(v);
479+ } catch (ClassNotFoundException cnfe) {
480+ /*
481+ * This is a workaround for bug 4224921.
482+ */
483+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
484+ if (loader == null) {
485+ if (systemClassLoader == null) {
486+ systemClassLoader = ClassLoader.getSystemClassLoader();
487+ }
488+ loader = systemClassLoader;
489+ if (loader == null) {
490+ throw new ClassNotFoundException(v.getName());
491+ }
492+ }
493+
494+ return Class.forName(v.getName(), false, loader);
495+ }
496+ }
497+}