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/EncryptedPrivateKeyInfo.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/crypto/EncryptedPrivateKeyInfo.java+448−0
@@ -0,0 +1,448 @@
1+/*
2+ * Copyright (c) 2001, 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.*;
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 "encryptedData" field
64+ private byte[] encryptedData;
65+
66+ // the ASN.1 encoded contents of this class
67+ private byte[] encoded = null;
68+
69+ /**
70+ * Constructs (i.e., parses) an <code>EncryptedPrivateKeyInfo</code> from
71+ * its ASN.1 encoding.
72+ * @param encoded the ASN.1 encoding of this object. The contents of
73+ * the array are copied to protect against subsequent modification.
74+ * @exception NullPointerException if the <code>encoded</code> is null.
75+ * @exception IOException if error occurs when parsing the ASN.1 encoding.
76+ */
77+ public EncryptedPrivateKeyInfo(byte[] encoded)
78+ throws IOException {
79+ if (encoded == null) {
80+ throw new NullPointerException("the encoded parameter " +
81+ "must be non-null");
82+ }
83+ this.encoded = (byte[])encoded.clone();
84+ DerValue val = new DerValue(this.encoded);
85+
86+ DerValue[] seq = new DerValue[2];
87+
88+ seq[0] = val.data.getDerValue();
89+ seq[1] = val.data.getDerValue();
90+
91+ if (val.data.available() != 0) {
92+ throw new IOException("overrun, bytes = " + val.data.available());
93+ }
94+
95+ this.algid = AlgorithmId.parse(seq[0]);
96+ if (seq[0].data.available() != 0) {
97+ throw new IOException("encryptionAlgorithm field overrun");
98+ }
99+
100+ this.encryptedData = seq[1].getOctetString();
101+ if (seq[1].data.available() != 0) {
102+ throw new IOException("encryptedData field overrun");
103+ }
104+ }
105+
106+ /**
107+ * Constructs an <code>EncryptedPrivateKeyInfo</code> from the
108+ * encryption algorithm name and the encrypted data.
109+ *
110+ * <p>Note: This constructor will use null as the value of the
111+ * algorithm parameters. If the encryption algorithm has
112+ * parameters whose value is not null, a different constructor,
113+ * e.g. EncryptedPrivateKeyInfo(AlgorithmParameters, byte[]),
114+ * should be used.
115+ *
116+ * @param algName encryption algorithm name. See Appendix A in the
117+ * <a href=
118+ * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
119+ * Java Cryptography Architecture Reference Guide</a>
120+ * for information about standard Cipher algorithm names.
121+ * @param encryptedData encrypted data. The contents of
122+ * <code>encrypedData</code> are copied to protect against subsequent
123+ * modification when constructing this object.
124+ * @exception NullPointerException if <code>algName</code> or
125+ * <code>encryptedData</code> is null.
126+ * @exception IllegalArgumentException if <code>encryptedData</code>
127+ * is empty, i.e. 0-length.
128+ * @exception NoSuchAlgorithmException if the specified algName is
129+ * not supported.
130+ */
131+ public EncryptedPrivateKeyInfo(String algName, byte[] encryptedData)
132+ throws NoSuchAlgorithmException {
133+
134+ if (algName == null)
135+ throw new NullPointerException("the algName parameter " +
136+ "must be non-null");
137+ this.algid = AlgorithmId.get(algName);
138+
139+ if (encryptedData == null) {
140+ throw new NullPointerException("the encryptedData " +
141+ "parameter must be non-null");
142+ } else if (encryptedData.length == 0) {
143+ throw new IllegalArgumentException("the encryptedData " +
144+ "parameter must not be empty");
145+ } else {
146+ this.encryptedData = (byte[])encryptedData.clone();
147+ }
148+ // delay the generation of ASN.1 encoding until
149+ // getEncoded() is called
150+ this.encoded = null;
151+ }
152+
153+ /**
154+ * Constructs an <code>EncryptedPrivateKeyInfo</code> from the
155+ * encryption algorithm parameters and the encrypted data.
156+ *
157+ * @param algParams the algorithm parameters for the encryption
158+ * algorithm. <code>algParams.getEncoded()</code> should return
159+ * the ASN.1 encoded bytes of the <code>parameters</code> field
160+ * of the <code>AlgorithmIdentifer</code> component of the
161+ * <code>EncryptedPrivateKeyInfo</code> type.
162+ * @param encryptedData encrypted data. The contents of
163+ * <code>encrypedData</code> are copied to protect against
164+ * subsequent modification when constructing this object.
165+ * @exception NullPointerException if <code>algParams</code> or
166+ * <code>encryptedData</code> is null.
167+ * @exception IllegalArgumentException if <code>encryptedData</code>
168+ * is empty, i.e. 0-length.
169+ * @exception NoSuchAlgorithmException if the specified algName of
170+ * the specified <code>algParams</code> parameter is not supported.
171+ */
172+ public EncryptedPrivateKeyInfo(AlgorithmParameters algParams,
173+ byte[] encryptedData) throws NoSuchAlgorithmException {
174+
175+ if (algParams == null) {
176+ throw new NullPointerException("algParams must be non-null");
177+ }
178+ this.algid = AlgorithmId.get(algParams);
179+
180+ if (encryptedData == null) {
181+ throw new NullPointerException("encryptedData must be non-null");
182+ } else if (encryptedData.length == 0) {
183+ throw new IllegalArgumentException("the encryptedData " +
184+ "parameter must not be empty");
185+ } else {
186+ this.encryptedData = (byte[])encryptedData.clone();
187+ }
188+
189+ // delay the generation of ASN.1 encoding until
190+ // getEncoded() is called
191+ this.encoded = null;
192+ }
193+
194+
195+ /**
196+ * Returns the encryption algorithm.
197+ * <p>Note: Standard name is returned instead of the specified one
198+ * in the constructor when such mapping is available.
199+ * See Appendix A in the
200+ * <a href=
201+ * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
202+ * Java Cryptography Architecture Reference Guide</a>
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 (byte[])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((byte[])encryptedData);
251+ checkPKCS8Encoding(encoded);
252+ } catch (GeneralSecurityException gse) {
253+ InvalidKeySpecException ikse = new
254+ InvalidKeySpecException(
255+ "Cannot retrieve the PKCS8EncodedKeySpec");
256+ ikse.initCause(gse);
257+ throw ikse;
258+ } catch (IOException ioe) {
259+ InvalidKeySpecException ikse = new
260+ InvalidKeySpecException(
261+ "Cannot retrieve the PKCS8EncodedKeySpec");
262+ ikse.initCause(ioe);
263+ throw ikse;
264+ } catch (IllegalStateException ise) {
265+ InvalidKeySpecException ikse = new
266+ InvalidKeySpecException(
267+ "Cannot retrieve the PKCS8EncodedKeySpec");
268+ ikse.initCause(ise);
269+ throw ikse;
270+ }
271+ return new PKCS8EncodedKeySpec(encoded);
272+ }
273+
274+ private PKCS8EncodedKeySpec getKeySpecImpl(Key decryptKey,
275+ Provider provider) throws NoSuchAlgorithmException,
276+ InvalidKeyException {
277+ byte[] encoded = null;
278+ Cipher c;
279+ try {
280+ if (provider == null) {
281+ // use the most preferred one
282+ c = Cipher.getInstance(algid.getName());
283+ } else {
284+ c = Cipher.getInstance(algid.getName(), provider);
285+ }
286+ c.init(Cipher.DECRYPT_MODE, decryptKey, algid.getParameters());
287+ encoded = c.doFinal(encryptedData);
288+ checkPKCS8Encoding(encoded);
289+ } catch (NoSuchAlgorithmException nsae) {
290+ // rethrow
291+ throw nsae;
292+ } catch (GeneralSecurityException gse) {
293+ InvalidKeyException ike = new InvalidKeyException
294+ ("Cannot retrieve the PKCS8EncodedKeySpec");
295+ ike.initCause(gse);
296+ throw ike;
297+ } catch (IOException ioe) {
298+ InvalidKeyException ike = new InvalidKeyException
299+ ("Cannot retrieve the PKCS8EncodedKeySpec");
300+ ike.initCause(ioe);
301+ throw ike;
302+ }
303+ return new PKCS8EncodedKeySpec(encoded);
304+ }
305+
306+ /**
307+ * Extract the enclosed PKCS8EncodedKeySpec object from the
308+ * encrypted data and return it.
309+ * @param decryptKey key used for decrypting the encrypted data.
310+ * @return the PKCS8EncodedKeySpec object.
311+ * @exception NullPointerException if <code>decryptKey</code>
312+ * is null.
313+ * @exception NoSuchAlgorithmException if cannot find appropriate
314+ * cipher to decrypt the encrypted data.
315+ * @exception InvalidKeyException if <code>decryptKey</code>
316+ * cannot be used to decrypt the encrypted data or the decryption
317+ * result is not a valid PKCS8KeySpec.
318+ *
319+ * @since 1.5
320+ */
321+ public PKCS8EncodedKeySpec getKeySpec(Key decryptKey)
322+ throws NoSuchAlgorithmException, InvalidKeyException {
323+ if (decryptKey == null) {
324+ throw new NullPointerException("decryptKey is null");
325+ }
326+ return getKeySpecImpl(decryptKey, null);
327+ }
328+
329+ /**
330+ * Extract the enclosed PKCS8EncodedKeySpec object from the
331+ * encrypted data and return it.
332+ * @param decryptKey key used for decrypting the encrypted data.
333+ * @param providerName the name of provider whose Cipher
334+ * implementation will be used.
335+ * @return the PKCS8EncodedKeySpec object.
336+ * @exception NullPointerException if <code>decryptKey</code>
337+ * or <code>providerName</code> is null.
338+ * @exception NoSuchProviderException if no provider
339+ * <code>providerName</code> is registered.
340+ * @exception NoSuchAlgorithmException if cannot find appropriate
341+ * cipher to decrypt the encrypted data.
342+ * @exception InvalidKeyException if <code>decryptKey</code>
343+ * cannot be used to decrypt the encrypted data or the decryption
344+ * result is not a valid PKCS8KeySpec.
345+ *
346+ * @since 1.5
347+ */
348+ public PKCS8EncodedKeySpec getKeySpec(Key decryptKey,
349+ String providerName) throws NoSuchProviderException,
350+ NoSuchAlgorithmException, InvalidKeyException {
351+ if (decryptKey == null) {
352+ throw new NullPointerException("decryptKey is null");
353+ }
354+ if (providerName == null) {
355+ throw new NullPointerException("provider is null");
356+ }
357+ Provider provider = Security.getProvider(providerName);
358+ if (provider == null) {
359+ throw new NoSuchProviderException("provider " +
360+ providerName + " not found");
361+ }
362+ return getKeySpecImpl(decryptKey, provider);
363+ }
364+
365+ /**
366+ * Extract the enclosed PKCS8EncodedKeySpec object from the
367+ * encrypted data and return it.
368+ * @param decryptKey key used for decrypting the encrypted data.
369+ * @param provider the name of provider whose Cipher implementation
370+ * will be used.
371+ * @return the PKCS8EncodedKeySpec object.
372+ * @exception NullPointerException if <code>decryptKey</code>
373+ * or <code>provider</code> is null.
374+ * @exception NoSuchAlgorithmException if cannot find appropriate
375+ * cipher to decrypt the encrypted data in <code>provider</code>.
376+ * @exception InvalidKeyException if <code>decryptKey</code>
377+ * cannot be used to decrypt the encrypted data or the decryption
378+ * result is not a valid PKCS8KeySpec.
379+ *
380+ * @since 1.5
381+ */
382+ public PKCS8EncodedKeySpec getKeySpec(Key decryptKey,
383+ Provider provider) throws NoSuchAlgorithmException,
384+ InvalidKeyException {
385+ if (decryptKey == null) {
386+ throw new NullPointerException("decryptKey is null");
387+ }
388+ if (provider == null) {
389+ throw new NullPointerException("provider is null");
390+ }
391+ return getKeySpecImpl(decryptKey, provider);
392+ }
393+
394+ /**
395+ * Returns the ASN.1 encoding of this object.
396+ * @return the ASN.1 encoding. Returns a new array
397+ * each time this method is called.
398+ * @exception IOException if error occurs when constructing its
399+ * ASN.1 encoding.
400+ */
401+ public byte[] getEncoded() throws IOException {
402+ if (this.encoded == null) {
403+ DerOutputStream out = new DerOutputStream();
404+ DerOutputStream tmp = new DerOutputStream();
405+
406+ // encode encryption algorithm
407+ algid.encode(tmp);
408+
409+ // encode encrypted data
410+ tmp.putOctetString(encryptedData);
411+
412+ // wrap everything into a SEQUENCE
413+ out.write(DerValue.tag_Sequence, tmp);
414+ this.encoded = out.toByteArray();
415+ }
416+ return (byte[])this.encoded.clone();
417+ }
418+
419+ private static void checkTag(DerValue val, byte tag, String valName)
420+ throws IOException {
421+ if (val.getTag() != tag) {
422+ throw new IOException("invalid key encoding - wrong tag for " +
423+ valName);
424+ }
425+ }
426+
427+ private static void checkPKCS8Encoding(byte[] encodedKey)
428+ throws IOException {
429+ DerInputStream in = new DerInputStream(encodedKey);
430+ DerValue[] values = in.getSequence(3);
431+
432+ switch (values.length) {
433+ case 4:
434+ checkTag(values[3], DerValue.TAG_CONTEXT, "attributes");
435+ case 3:
436+ checkTag(values[0], DerValue.tag_Integer, "version");
437+ DerInputStream algid = values[1].toDerInputStream();
438+ algid.getOID();
439+ if (algid.available() != 0) {
440+ algid.getDerValue();
441+ }
442+ checkTag(values[2], DerValue.tag_OctetString, "privateKey");
443+ break;
444+ default:
445+ throw new IOException("invalid key encoding");
446+ }
447+ }
448+}