Source for javax.crypto.EncryptedPrivateKeyInfo

   1: /* EncryptedPrivateKeyInfo.java -- As in PKCS #8.
   2:    Copyright (C) 2004  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.crypto;
  40: 
  41: import gnu.java.security.OID;
  42: import gnu.java.security.der.DER;
  43: import gnu.java.security.der.DERReader;
  44: import gnu.java.security.der.DERValue;
  45: 
  46: import java.io.IOException;
  47: import java.security.AlgorithmParameters;
  48: import java.security.NoSuchAlgorithmException;
  49: import java.security.spec.InvalidKeySpecException;
  50: import java.security.spec.PKCS8EncodedKeySpec;
  51: import java.util.ArrayList;
  52: import java.util.List;
  53: 
  54: /**
  55:  * An implementation of the <code>EncryptedPrivateKeyInfo</code> ASN.1
  56:  * type as specified in <a
  57:  * href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-8/">PKCS #8 -
  58:  * Private-Key Information Syntax Standard</a>.
  59:  *
  60:  * <p>The ASN.1 type <code>EncryptedPrivateKeyInfo</code> is:
  61:  *
  62:  * <blockquote>
  63:  * <pre>EncryptedPrivateKeyInfo ::= SEQUENCE {
  64:  *   encryptionAlgorithm EncryptionAlgorithmIdentifier,
  65:  *   encryptedData EncryptedData }
  66:  *
  67:  * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
  68:  *
  69:  * EncrytpedData ::= OCTET STRING
  70:  *
  71:  * AlgorithmIdentifier ::= SEQUENCE {
  72:  *   algorithm  OBJECT IDENTIFIER,
  73:  *   parameters ANY DEFINED BY algorithm OPTIONAL }</pre>
  74:  * </blockquote>
  75:  *
  76:  * @author Casey Marshall (csm@gnu.org)
  77:  * @since 1.4
  78:  * @see java.security.spec.PKCS8EncodedKeySpec
  79:  */
  80: public class EncryptedPrivateKeyInfo
  81: {
  82: 
  83:   // Fields.
  84:   // ------------------------------------------------------------------------
  85: 
  86:   /** The encrypted data. */
  87:   private byte[] encryptedData;
  88: 
  89:   /** The encoded, encrypted key. */
  90:   private byte[] encoded;
  91: 
  92:   /** The OID of the encryption algorithm. */
  93:   private OID algOid;
  94: 
  95:   /** The encryption algorithm's parameters. */
  96:   private AlgorithmParameters params;
  97: 
  98:   /** The encoded ASN.1 algorithm parameters. */
  99:   private byte[] encodedParams;
 100: 
 101:   // Constructors.
 102:   // ------------------------------------------------------------------------
 103: 
 104:   /**
 105:    * Create a new <code>EncryptedPrivateKeyInfo</code> object from raw
 106:    * encrypted data and the parameters used for encryption.
 107:    *
 108:    * <p>The <code>encryptedData</code> array is cloned.
 109:    *
 110:    * @param params        The encryption algorithm parameters.
 111:    * @param encryptedData The encrypted key data.
 112:    * @throws java.lang.IllegalArgumentException If the
 113:    *         <code>encryptedData</code> array is empty (zero-length).
 114:    * @throws java.security.NoSuchAlgorithmException If the algorithm
 115:    *         specified in the parameters is not supported.
 116:    * @throws java.lang.NullPointerException If <code>encryptedData</code>
 117:    *         is null.
 118:    */
 119:   public EncryptedPrivateKeyInfo(AlgorithmParameters params,
 120:                                  byte[] encryptedData)
 121:     throws IllegalArgumentException, NoSuchAlgorithmException
 122:   {
 123:     if (encryptedData.length == 0)
 124:       {
 125:         throw new IllegalArgumentException("0-length encryptedData");
 126:       }
 127:     this.params = params;
 128:     algOid = new OID(params.getAlgorithm());
 129:     this.encryptedData = (byte[]) encryptedData.clone();
 130:   }
 131: 
 132:   /**
 133:    * Create a new <code>EncryptedPrivateKeyInfo</code> from an encoded
 134:    * representation, parsing the ASN.1 sequence.
 135:    *
 136:    * @param encoded The encoded info.
 137:    * @throws java.io.IOException If parsing the encoded data fails.
 138:    * @throws java.lang.NullPointerException If <code>encoded</code> is
 139:    *         null.
 140:    */
 141:   public EncryptedPrivateKeyInfo(byte[] encoded)
 142:     throws IOException
 143:   {
 144:     this.encoded = (byte[]) encoded.clone();
 145:     decode();
 146:   }
 147: 
 148:   /**
 149:    * Create a new <code>EncryptedPrivateKeyInfo</code> from the cipher
 150:    * name and the encrytpedData.
 151:    *
 152:    * <p>The <code>encryptedData</code> array is cloned.
 153:    *
 154:    * @param algName       The name of the algorithm (as an object identifier).
 155:    * @param encryptedData The encrypted key data.
 156:    * @throws java.lang.IllegalArgumentException If the
 157:    *         <code>encryptedData</code> array is empty (zero-length).
 158:    * @throws java.security.NoSuchAlgorithmException If algName is not
 159:    *         the name of a supported algorithm.
 160:    * @throws java.lang.NullPointerException If <code>encryptedData</code>
 161:    *         is null.
 162:    */
 163:   public EncryptedPrivateKeyInfo(String algName, byte[] encryptedData)
 164:     throws IllegalArgumentException, NoSuchAlgorithmException,
 165:            NullPointerException
 166:   {
 167:     if (encryptedData.length == 0)
 168:       {
 169:         throw new IllegalArgumentException("0-length encryptedData");
 170:       }
 171:     this.algOid = new OID(algName);
 172:     this.encryptedData = (byte[]) encryptedData.clone();
 173:   }
 174: 
 175:   // Instance methods.
 176:   // ------------------------------------------------------------------------
 177: 
 178:   /**
 179:    * Return the name of the cipher used to encrypt this key.
 180:    *
 181:    * @return The algorithm name.
 182:    */
 183:   public String getAlgName()
 184:   {
 185:     return algOid.toString();
 186:   }
 187: 
 188:   public AlgorithmParameters getAlgParameters()
 189:   {
 190:     if (params == null && encodedParams != null)
 191:       {
 192:         try
 193:           {
 194:             params = AlgorithmParameters.getInstance(getAlgName());
 195:             params.init(encodedParams);
 196:           }
 197:         catch (NoSuchAlgorithmException ignore)
 198:           {
 199:           }
 200:         catch (IOException ignore)
 201:           {
 202:           }
 203:       }
 204:     return params;
 205:   }
 206: 
 207:   public synchronized byte[] getEncoded() throws IOException
 208:   {
 209:     if (encoded == null) encode();
 210:     return (byte[]) encoded.clone();
 211:   }
 212: 
 213:   public byte[] getEncryptedData()
 214:   {
 215:     return encryptedData;
 216:   }
 217: 
 218:   public PKCS8EncodedKeySpec getKeySpec(Cipher cipher)
 219:     throws InvalidKeySpecException
 220:   {
 221:     try
 222:       {
 223:         return new PKCS8EncodedKeySpec(cipher.doFinal(encryptedData));
 224:       }
 225:     catch (Exception x)
 226:       {
 227:         throw new InvalidKeySpecException(x.toString());
 228:       }
 229:   }
 230: 
 231:   // Own methods.
 232:   // -------------------------------------------------------------------------
 233: 
 234:   private void decode() throws IOException
 235:   {
 236:     DERReader der = new DERReader(encoded);
 237:     DERValue val = der.read();
 238:     if (val.getTag() != DER.SEQUENCE)
 239:       throw new IOException("malformed EncryptedPrivateKeyInfo");
 240:     val = der.read();
 241:     if (val.getTag() != DER.SEQUENCE)
 242:       throw new IOException("malformed AlgorithmIdentifier");
 243:     int algpLen = val.getLength();
 244:     DERValue oid = der.read();
 245:     if (oid.getTag() != DER.OBJECT_IDENTIFIER)
 246:       throw new IOException("malformed AlgorithmIdentifier");
 247:     algOid = (OID) oid.getValue();
 248:     if (algpLen == 0)
 249:       {
 250:         val = der.read();
 251:         if (val.getTag() != 0)
 252:           {
 253:             encodedParams = val.getEncoded();
 254:             der.read();
 255:           }
 256:       }
 257:     else if (oid.getEncodedLength() < val.getLength())
 258:       {
 259:         val = der.read();
 260:         encodedParams = val.getEncoded();
 261:       }
 262:     val = der.read();
 263:     if (val.getTag() != DER.OCTET_STRING)
 264:       throw new IOException("malformed AlgorithmIdentifier");
 265:     encryptedData = (byte[]) val.getValue();
 266:   }
 267: 
 268:   private void encode() throws IOException
 269:   {
 270:     List algId = new ArrayList(2);
 271:     algId.add(new DERValue(DER.OBJECT_IDENTIFIER, algOid));
 272:     getAlgParameters();
 273:     if (params != null)
 274:       {
 275:         algId.add(DERReader.read(params.getEncoded()));
 276:       }
 277:     List epki = new ArrayList(2);
 278:     epki.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, algId));
 279:     epki.add(new DERValue(DER.OCTET_STRING, encryptedData));
 280:     encoded = new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, epki).getEncoded();
 281:   }
 282: }