Frames | No Frames |
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 name. */ 96: private String algName; 97: 98: /** The encryption algorithm's parameters. */ 99: private AlgorithmParameters params; 100: 101: /** The encoded ASN.1 algorithm parameters. */ 102: private byte[] encodedParams; 103: 104: // Constructors. 105: // ------------------------------------------------------------------------ 106: 107: /** 108: * Create a new <code>EncryptedPrivateKeyInfo</code> object from raw 109: * encrypted data and the parameters used for encryption. 110: * 111: * <p>The <code>encryptedData</code> array is cloned. 112: * 113: * @param params The encryption algorithm parameters. 114: * @param encryptedData The encrypted key data. 115: * @throws java.lang.IllegalArgumentException If the 116: * <code>encryptedData</code> array is empty (zero-length). 117: * @throws java.security.NoSuchAlgorithmException If the algorithm 118: * specified in the parameters is not supported. 119: * @throws java.lang.NullPointerException If <code>encryptedData</code> 120: * is null. 121: */ 122: public EncryptedPrivateKeyInfo(AlgorithmParameters params, 123: byte[] encryptedData) 124: throws IllegalArgumentException, NoSuchAlgorithmException 125: { 126: if (encryptedData.length == 0) 127: { 128: throw new IllegalArgumentException("0-length encryptedData"); 129: } 130: this.params = params; 131: algName = params.getAlgorithm (); 132: algOid = getOid (algName); 133: this.encryptedData = (byte[]) encryptedData.clone(); 134: } 135: 136: /** 137: * Create a new <code>EncryptedPrivateKeyInfo</code> from an encoded 138: * representation, parsing the ASN.1 sequence. 139: * 140: * @param encoded The encoded info. 141: * @throws java.io.IOException If parsing the encoded data fails. 142: * @throws java.lang.NullPointerException If <code>encoded</code> is 143: * null. 144: */ 145: public EncryptedPrivateKeyInfo(byte[] encoded) 146: throws IOException 147: { 148: this.encoded = (byte[]) encoded.clone(); 149: decode(); 150: } 151: 152: /** 153: * Create a new <code>EncryptedPrivateKeyInfo</code> from the cipher 154: * name and the encrytpedData. 155: * 156: * <p>The <code>encryptedData</code> array is cloned. 157: * 158: * @param algName The name of the algorithm (as an object identifier). 159: * @param encryptedData The encrypted key data. 160: * @throws java.lang.IllegalArgumentException If the 161: * <code>encryptedData</code> array is empty (zero-length). 162: * @throws java.security.NoSuchAlgorithmException If algName is not 163: * the name of a supported algorithm. 164: * @throws java.lang.NullPointerException If <code>encryptedData</code> 165: * is null. 166: */ 167: public EncryptedPrivateKeyInfo(String algName, byte[] encryptedData) 168: throws IllegalArgumentException, NoSuchAlgorithmException, 169: NullPointerException 170: { 171: if (encryptedData.length == 0) 172: { 173: throw new IllegalArgumentException("0-length encryptedData"); 174: } 175: this.algName = algName.toString (); // do NP check 176: this.algOid = getOid (algName); 177: this.encryptedData = (byte[]) encryptedData.clone(); 178: } 179: 180: /** 181: * Return the OID for the given cipher name. 182: * 183: * @param str The string. 184: * @throws NoSuchAlgorithmException If the OID is not known. 185: */ 186: private static OID getOid (final String str) 187: throws NoSuchAlgorithmException 188: { 189: if (str.equalsIgnoreCase ("DSA")) 190: { 191: return new OID ("1.2.840.10040.4.3"); 192: } 193: // FIXME add more 194: 195: try 196: { 197: return new OID (str); 198: } 199: catch (Throwable t) 200: { 201: } 202: throw new NoSuchAlgorithmException ("cannot determine OID for '" + str + "'"); 203: } 204: 205: // Instance methods. 206: // ------------------------------------------------------------------------ 207: 208: /** 209: * Return the name of the cipher used to encrypt this key. 210: * 211: * @return The algorithm name. 212: */ 213: public String getAlgName() 214: { 215: return algOid.toString(); 216: } 217: 218: public AlgorithmParameters getAlgParameters() 219: { 220: if (params == null && encodedParams != null) 221: { 222: try 223: { 224: params = AlgorithmParameters.getInstance(getAlgName()); 225: params.init(encodedParams); 226: } 227: catch (NoSuchAlgorithmException ignore) 228: { 229: // FIXME throw exception? 230: } 231: catch (IOException ignore) 232: { 233: } 234: } 235: return params; 236: } 237: 238: public synchronized byte[] getEncoded() throws IOException 239: { 240: if (encoded == null) encode(); 241: return (byte[]) encoded.clone(); 242: } 243: 244: public byte[] getEncryptedData() 245: { 246: return encryptedData; 247: } 248: 249: public PKCS8EncodedKeySpec getKeySpec(Cipher cipher) 250: throws InvalidKeySpecException 251: { 252: try 253: { 254: return new PKCS8EncodedKeySpec(cipher.doFinal(encryptedData)); 255: } 256: catch (Exception x) 257: { 258: throw new InvalidKeySpecException(x.toString()); 259: } 260: } 261: 262: // Own methods. 263: // ------------------------------------------------------------------------- 264: 265: private void decode() throws IOException 266: { 267: DERReader der = new DERReader(encoded); 268: DERValue val = der.read(); 269: if (val.getTag() != DER.SEQUENCE) 270: throw new IOException("malformed EncryptedPrivateKeyInfo"); 271: val = der.read(); 272: if (val.getTag() != DER.SEQUENCE) 273: throw new IOException("malformed AlgorithmIdentifier"); 274: int algpLen = val.getLength(); 275: DERValue oid = der.read(); 276: if (oid.getTag() != DER.OBJECT_IDENTIFIER) 277: throw new IOException("malformed AlgorithmIdentifier"); 278: algOid = (OID) oid.getValue(); 279: if (algpLen == 0) 280: { 281: val = der.read(); 282: if (val.getTag() != 0) 283: { 284: encodedParams = val.getEncoded(); 285: der.read(); 286: } 287: } 288: else if (oid.getEncodedLength() < val.getLength()) 289: { 290: val = der.read(); 291: encodedParams = val.getEncoded(); 292: } 293: val = der.read(); 294: if (val.getTag() != DER.OCTET_STRING) 295: throw new IOException("malformed AlgorithmIdentifier"); 296: encryptedData = (byte[]) val.getValue(); 297: } 298: 299: private void encode() throws IOException 300: { 301: List algId = new ArrayList(2); 302: algId.add(new DERValue(DER.OBJECT_IDENTIFIER, algOid)); 303: getAlgParameters(); 304: if (params != null) 305: { 306: algId.add (DERReader.read (params.getEncoded())); 307: } 308: else 309: { 310: algId.add (new DERValue (DER.NULL, null)); 311: } 312: List epki = new ArrayList(2); 313: epki.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, algId)); 314: epki.add(new DERValue(DER.OCTET_STRING, encryptedData)); 315: encoded = new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, epki).getEncoded(); 316: } 317: }