/*
 * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package javax.crypto;

import java.io.*;
import java.security.*;
import java.security.spec.*;
import sun.security.x509.AlgorithmId;
import sun.security.util.DerValue;
import sun.security.util.DerInputStream;
import sun.security.util.DerOutputStream;

This class implements the EncryptedPrivateKeyInfo type as defined in PKCS #8.

Its ASN.1 definition is as follows:

EncryptedPrivateKeyInfo ::=  SEQUENCE {
    encryptionAlgorithm   AlgorithmIdentifier,
    encryptedData   OCTET STRING }
AlgorithmIdentifier  ::=  SEQUENCE  {
    algorithm              OBJECT IDENTIFIER,
    parameters             ANY DEFINED BY algorithm OPTIONAL  }
Author:Valerie Peng
See Also:
Since:1.4
/** * This class implements the <code>EncryptedPrivateKeyInfo</code> type * as defined in PKCS #8. * <p>Its ASN.1 definition is as follows: * * <pre> * EncryptedPrivateKeyInfo ::= SEQUENCE { * encryptionAlgorithm AlgorithmIdentifier, * encryptedData OCTET STRING } * * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL } * </pre> * * @author Valerie Peng * * @see java.security.spec.PKCS8EncodedKeySpec * * @since 1.4 */
public class EncryptedPrivateKeyInfo { // the "encryptionAlgorithm" field private AlgorithmId algid; // the "encryptedData" field private byte[] encryptedData; // the ASN.1 encoded contents of this class private byte[] encoded = null;
Constructs (i.e., parses) an EncryptedPrivateKeyInfo from its ASN.1 encoding.
Params:
  • encoded – the ASN.1 encoding of this object. The contents of the array are copied to protect against subsequent modification.
Throws:
/** * Constructs (i.e., parses) an <code>EncryptedPrivateKeyInfo</code> from * its ASN.1 encoding. * @param encoded the ASN.1 encoding of this object. The contents of * the array are copied to protect against subsequent modification. * @exception NullPointerException if the <code>encoded</code> is null. * @exception IOException if error occurs when parsing the ASN.1 encoding. */
public EncryptedPrivateKeyInfo(byte[] encoded) throws IOException { if (encoded == null) { throw new NullPointerException("the encoded parameter " + "must be non-null"); } this.encoded = encoded.clone(); DerValue val = new DerValue(this.encoded); DerValue[] seq = new DerValue[2]; seq[0] = val.data.getDerValue(); seq[1] = val.data.getDerValue(); if (val.data.available() != 0) { throw new IOException("overrun, bytes = " + val.data.available()); } this.algid = AlgorithmId.parse(seq[0]); if (seq[0].data.available() != 0) { throw new IOException("encryptionAlgorithm field overrun"); } this.encryptedData = seq[1].getOctetString(); if (seq[1].data.available() != 0) { throw new IOException("encryptedData field overrun"); } }
Constructs an EncryptedPrivateKeyInfo from the encryption algorithm name and the encrypted data.

Note: This constructor will use null as the value of the algorithm parameters. If the encryption algorithm has parameters whose value is not null, a different constructor, e.g. EncryptedPrivateKeyInfo(AlgorithmParameters, byte[]), should be used.

Params:
  • algName – encryption algorithm name. See Appendix A in the Java Cryptography Architecture Reference Guide for information about standard Cipher algorithm names.
  • encryptedData – encrypted data. The contents of encrypedData are copied to protect against subsequent modification when constructing this object.
Throws:
/** * Constructs an <code>EncryptedPrivateKeyInfo</code> from the * encryption algorithm name and the encrypted data. * * <p>Note: This constructor will use null as the value of the * algorithm parameters. If the encryption algorithm has * parameters whose value is not null, a different constructor, * e.g. EncryptedPrivateKeyInfo(AlgorithmParameters, byte[]), * should be used. * * @param algName encryption algorithm name. See Appendix A in the * <a href= * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA"> * Java Cryptography Architecture Reference Guide</a> * for information about standard Cipher algorithm names. * @param encryptedData encrypted data. The contents of * <code>encrypedData</code> are copied to protect against subsequent * modification when constructing this object. * @exception NullPointerException if <code>algName</code> or * <code>encryptedData</code> is null. * @exception IllegalArgumentException if <code>encryptedData</code> * is empty, i.e. 0-length. * @exception NoSuchAlgorithmException if the specified algName is * not supported. */
public EncryptedPrivateKeyInfo(String algName, byte[] encryptedData) throws NoSuchAlgorithmException { if (algName == null) throw new NullPointerException("the algName parameter " + "must be non-null"); this.algid = AlgorithmId.get(algName); if (encryptedData == null) { throw new NullPointerException("the encryptedData " + "parameter must be non-null"); } else if (encryptedData.length == 0) { throw new IllegalArgumentException("the encryptedData " + "parameter must not be empty"); } else { this.encryptedData = encryptedData.clone(); } // delay the generation of ASN.1 encoding until // getEncoded() is called this.encoded = null; }
Constructs an EncryptedPrivateKeyInfo from the encryption algorithm parameters and the encrypted data.
Params:
  • algParams – the algorithm parameters for the encryption algorithm. algParams.getEncoded() should return the ASN.1 encoded bytes of the parameters field of the AlgorithmIdentifer component of the EncryptedPrivateKeyInfo type.
  • encryptedData – encrypted data. The contents of encrypedData are copied to protect against subsequent modification when constructing this object.
Throws:
/** * Constructs an <code>EncryptedPrivateKeyInfo</code> from the * encryption algorithm parameters and the encrypted data. * * @param algParams the algorithm parameters for the encryption * algorithm. <code>algParams.getEncoded()</code> should return * the ASN.1 encoded bytes of the <code>parameters</code> field * of the <code>AlgorithmIdentifer</code> component of the * <code>EncryptedPrivateKeyInfo</code> type. * @param encryptedData encrypted data. The contents of * <code>encrypedData</code> are copied to protect against * subsequent modification when constructing this object. * @exception NullPointerException if <code>algParams</code> or * <code>encryptedData</code> is null. * @exception IllegalArgumentException if <code>encryptedData</code> * is empty, i.e. 0-length. * @exception NoSuchAlgorithmException if the specified algName of * the specified <code>algParams</code> parameter is not supported. */
public EncryptedPrivateKeyInfo(AlgorithmParameters algParams, byte[] encryptedData) throws NoSuchAlgorithmException { if (algParams == null) { throw new NullPointerException("algParams must be non-null"); } this.algid = AlgorithmId.get(algParams); if (encryptedData == null) { throw new NullPointerException("encryptedData must be non-null"); } else if (encryptedData.length == 0) { throw new IllegalArgumentException("the encryptedData " + "parameter must not be empty"); } else { this.encryptedData = encryptedData.clone(); } // delay the generation of ASN.1 encoding until // getEncoded() is called this.encoded = null; }
Returns the encryption algorithm.

Note: Standard name is returned instead of the specified one in the constructor when such mapping is available. See Appendix A in the Java Cryptography Architecture Reference Guide for information about standard Cipher algorithm names.

Returns:the encryption algorithm name.
/** * Returns the encryption algorithm. * <p>Note: Standard name is returned instead of the specified one * in the constructor when such mapping is available. * See Appendix A in the * <a href= * "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA"> * Java Cryptography Architecture Reference Guide</a> * for information about standard Cipher algorithm names. * * @return the encryption algorithm name. */
public String getAlgName() { return this.algid.getName(); }
Returns the algorithm parameters used by the encryption algorithm.
Returns:the algorithm parameters.
/** * Returns the algorithm parameters used by the encryption algorithm. * @return the algorithm parameters. */
public AlgorithmParameters getAlgParameters() { return this.algid.getParameters(); }
Returns the encrypted data.
Returns:the encrypted data. Returns a new array each time this method is called.
/** * Returns the encrypted data. * @return the encrypted data. Returns a new array * each time this method is called. */
public byte[] getEncryptedData() { return this.encryptedData.clone(); }
Extract the enclosed PKCS8EncodedKeySpec object from the encrypted data and return it.
Note: In order to successfully retrieve the enclosed PKCS8EncodedKeySpec object, cipher needs to be initialized to either Cipher.DECRYPT_MODE or Cipher.UNWRAP_MODE, with the same key and parameters used for generating the encrypted data.
Params:
  • cipher – the initialized cipher object which will be used for decrypting the encrypted data.
Throws:
Returns:the PKCS8EncodedKeySpec object.
/** * Extract the enclosed PKCS8EncodedKeySpec object from the * encrypted data and return it. * <br>Note: In order to successfully retrieve the enclosed * PKCS8EncodedKeySpec object, <code>cipher</code> needs * to be initialized to either Cipher.DECRYPT_MODE or * Cipher.UNWRAP_MODE, with the same key and parameters used * for generating the encrypted data. * * @param cipher the initialized cipher object which will be * used for decrypting the encrypted data. * @return the PKCS8EncodedKeySpec object. * @exception NullPointerException if <code>cipher</code> * is null. * @exception InvalidKeySpecException if the given cipher is * inappropriate for the encrypted data or the encrypted * data is corrupted and cannot be decrypted. */
public PKCS8EncodedKeySpec getKeySpec(Cipher cipher) throws InvalidKeySpecException { byte[] encoded = null; try { encoded = cipher.doFinal(encryptedData); checkPKCS8Encoding(encoded); } catch (GeneralSecurityException ex) { throw new InvalidKeySpecException( "Cannot retrieve the PKCS8EncodedKeySpec", ex); } catch (IOException ex) { throw new InvalidKeySpecException( "Cannot retrieve the PKCS8EncodedKeySpec", ex); } catch (IllegalStateException ex) { throw new InvalidKeySpecException( "Cannot retrieve the PKCS8EncodedKeySpec", ex); } return new PKCS8EncodedKeySpec(encoded); } private PKCS8EncodedKeySpec getKeySpecImpl(Key decryptKey, Provider provider) throws NoSuchAlgorithmException, InvalidKeyException { byte[] encoded = null; Cipher c; try { if (provider == null) { // use the most preferred one c = Cipher.getInstance(algid.getName()); } else { c = Cipher.getInstance(algid.getName(), provider); } c.init(Cipher.DECRYPT_MODE, decryptKey, algid.getParameters()); encoded = c.doFinal(encryptedData); checkPKCS8Encoding(encoded); } catch (NoSuchAlgorithmException nsae) { // rethrow throw nsae; } catch (GeneralSecurityException ex) { throw new InvalidKeyException( "Cannot retrieve the PKCS8EncodedKeySpec", ex); } catch (IOException ex) { throw new InvalidKeyException( "Cannot retrieve the PKCS8EncodedKeySpec", ex); } return new PKCS8EncodedKeySpec(encoded); }
Extract the enclosed PKCS8EncodedKeySpec object from the encrypted data and return it.
Params:
  • decryptKey – key used for decrypting the encrypted data.
Throws:
Returns:the PKCS8EncodedKeySpec object.
Since:1.5
/** * Extract the enclosed PKCS8EncodedKeySpec object from the * encrypted data and return it. * @param decryptKey key used for decrypting the encrypted data. * @return the PKCS8EncodedKeySpec object. * @exception NullPointerException if <code>decryptKey</code> * is null. * @exception NoSuchAlgorithmException if cannot find appropriate * cipher to decrypt the encrypted data. * @exception InvalidKeyException if <code>decryptKey</code> * cannot be used to decrypt the encrypted data or the decryption * result is not a valid PKCS8KeySpec. * * @since 1.5 */
public PKCS8EncodedKeySpec getKeySpec(Key decryptKey) throws NoSuchAlgorithmException, InvalidKeyException { if (decryptKey == null) { throw new NullPointerException("decryptKey is null"); } return getKeySpecImpl(decryptKey, null); }
Extract the enclosed PKCS8EncodedKeySpec object from the encrypted data and return it.
Params:
  • decryptKey – key used for decrypting the encrypted data.
  • providerName – the name of provider whose Cipher implementation will be used.
Throws:
Returns:the PKCS8EncodedKeySpec object.
Since:1.5
/** * Extract the enclosed PKCS8EncodedKeySpec object from the * encrypted data and return it. * @param decryptKey key used for decrypting the encrypted data. * @param providerName the name of provider whose Cipher * implementation will be used. * @return the PKCS8EncodedKeySpec object. * @exception NullPointerException if <code>decryptKey</code> * or <code>providerName</code> is null. * @exception NoSuchProviderException if no provider * <code>providerName</code> is registered. * @exception NoSuchAlgorithmException if cannot find appropriate * cipher to decrypt the encrypted data. * @exception InvalidKeyException if <code>decryptKey</code> * cannot be used to decrypt the encrypted data or the decryption * result is not a valid PKCS8KeySpec. * * @since 1.5 */
public PKCS8EncodedKeySpec getKeySpec(Key decryptKey, String providerName) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException { if (decryptKey == null) { throw new NullPointerException("decryptKey is null"); } if (providerName == null) { throw new NullPointerException("provider is null"); } Provider provider = Security.getProvider(providerName); if (provider == null) { throw new NoSuchProviderException("provider " + providerName + " not found"); } return getKeySpecImpl(decryptKey, provider); }
Extract the enclosed PKCS8EncodedKeySpec object from the encrypted data and return it.
Params:
  • decryptKey – key used for decrypting the encrypted data.
  • provider – the name of provider whose Cipher implementation will be used.
Throws:
Returns:the PKCS8EncodedKeySpec object.
Since:1.5
/** * Extract the enclosed PKCS8EncodedKeySpec object from the * encrypted data and return it. * @param decryptKey key used for decrypting the encrypted data. * @param provider the name of provider whose Cipher implementation * will be used. * @return the PKCS8EncodedKeySpec object. * @exception NullPointerException if <code>decryptKey</code> * or <code>provider</code> is null. * @exception NoSuchAlgorithmException if cannot find appropriate * cipher to decrypt the encrypted data in <code>provider</code>. * @exception InvalidKeyException if <code>decryptKey</code> * cannot be used to decrypt the encrypted data or the decryption * result is not a valid PKCS8KeySpec. * * @since 1.5 */
public PKCS8EncodedKeySpec getKeySpec(Key decryptKey, Provider provider) throws NoSuchAlgorithmException, InvalidKeyException { if (decryptKey == null) { throw new NullPointerException("decryptKey is null"); } if (provider == null) { throw new NullPointerException("provider is null"); } return getKeySpecImpl(decryptKey, provider); }
Returns the ASN.1 encoding of this object.
Throws:
  • IOException – if error occurs when constructing its ASN.1 encoding.
Returns:the ASN.1 encoding. Returns a new array each time this method is called.
/** * Returns the ASN.1 encoding of this object. * @return the ASN.1 encoding. Returns a new array * each time this method is called. * @exception IOException if error occurs when constructing its * ASN.1 encoding. */
public byte[] getEncoded() throws IOException { if (this.encoded == null) { DerOutputStream out = new DerOutputStream(); DerOutputStream tmp = new DerOutputStream(); // encode encryption algorithm algid.encode(tmp); // encode encrypted data tmp.putOctetString(encryptedData); // wrap everything into a SEQUENCE out.write(DerValue.tag_Sequence, tmp); this.encoded = out.toByteArray(); } return this.encoded.clone(); } private static void checkTag(DerValue val, byte tag, String valName) throws IOException { if (val.getTag() != tag) { throw new IOException("invalid key encoding - wrong tag for " + valName); } } @SuppressWarnings("fallthrough") private static void checkPKCS8Encoding(byte[] encodedKey) throws IOException { DerInputStream in = new DerInputStream(encodedKey); DerValue[] values = in.getSequence(3); switch (values.length) { case 4: checkTag(values[3], DerValue.TAG_CONTEXT, "attributes"); /* fall through */ case 3: checkTag(values[0], DerValue.tag_Integer, "version"); DerInputStream algid = values[1].toDerInputStream(); algid.getOID(); if (algid.available() != 0) { algid.getDerValue(); } checkTag(values[2], DerValue.tag_OctetString, "privateKey"); break; default: throw new IOException("invalid key encoding"); } } }