/** * Assigns the given key (that has already been protected) to the given alias. * * <p>If the protected key is of type <code>java.security.PrivateKey</code>, it must be * accompanied by a certificate chain certifying the corresponding public key. If the underlying * keystore implementation is of type <code>jks</code>, <code>key</code> must be encoded as an * <code>EncryptedPrivateKeyInfo</code> as defined in the PKCS #8 standard. * * <p>If the given alias already exists, the keystore information associated with it is overridden * by the given key (and possibly certificate chain). * * @param alias the alias name * @param key the key (in protected format) to be associated with the alias * @param chain the certificate chain for the corresponding public key (only useful if the * protected key is of type <code>java.security.PrivateKey</code>). * @exception KeyStoreException if this operation fails. */ public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException { permissionCheck(); synchronized (entries) { // key must be encoded as EncryptedPrivateKeyInfo as defined in // PKCS#8 KeyEntry entry = new KeyEntry(); try { EncryptedPrivateKeyInfo privateKey = new EncryptedPrivateKeyInfo(key); entry.protectedPrivKey = privateKey.getEncoded(); } catch (IOException ioe) { throw new KeyStoreException("key is not encoded as " + "EncryptedPrivateKeyInfo"); } entry.date = new Date(); if ((chain != null) && (chain.length != 0)) { entry.chain = chain.clone(); entry.chainRefs = new long[entry.chain.length]; } String lowerAlias = alias.toLowerCase(); if (entries.get(lowerAlias) != null) { deletedEntries.put(lowerAlias, entries.get(alias)); } entries.put(lowerAlias, entry); addedEntries.put(lowerAlias, entry); } }
/* * Encrypt private key using Password-based encryption (PBE) * as defined in PKCS#5. * * NOTE: Currently pbeWithSHAAnd3-KeyTripleDES-CBC algorithmID is * used to derive the key and IV. * * @return encrypted private key encoded as EncryptedPrivateKeyInfo */ private byte[] encryptPrivateKey(byte[] data, char[] password) throws IOException, NoSuchAlgorithmException, UnrecoverableKeyException { byte[] key = null; try { // create AlgorithmParameters AlgorithmParameters algParams = getAlgorithmParameters("PBEWithSHA1AndDESede"); // Use JCE SecretKey skey = getPBEKey(password); Cipher cipher = Cipher.getInstance("PBEWithSHA1AndDESede"); cipher.init(Cipher.ENCRYPT_MODE, skey, algParams); byte[] encryptedKey = cipher.doFinal(data); // wrap encrypted private key in EncryptedPrivateKeyInfo // as defined in PKCS#8 AlgorithmId algid = new AlgorithmId(pbeWithSHAAnd3KeyTripleDESCBC_OID, algParams); EncryptedPrivateKeyInfo encrInfo = new EncryptedPrivateKeyInfo(algid, encryptedKey); key = encrInfo.getEncoded(); } catch (Exception e) { UnrecoverableKeyException uke = new UnrecoverableKeyException("Encrypt Private Key failed: " + e.getMessage()); uke.initCause(e); throw uke; } return key; }
/** * Returns the key associated with the given alias, using the given password to recover it. * * @param alias the alias name * @param password the password for recovering the key. This password is used internally as the * key is exported in a PKCS12 format. * @return the requested key, or null if the given alias does not exist or does not identify a * <i>key entry</i>. * @exception NoSuchAlgorithmException if the algorithm for recovering the key cannot be found * @exception UnrecoverableKeyException if the key cannot be recovered (e.g., the given password * is wrong). */ public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException { permissionCheck(); // An empty password is rejected by MacOS API, no private key data // is exported. If no password is passed (as is the case when // this implementation is used as browser keystore in various // deployment scenarios like Webstart, JFX and applets), create // a dummy password so MacOS API is happy. if (password == null || password.length == 0) { // Must not be a char array with only a 0, as this is an empty // string. if (random == null) { random = new SecureRandom(); } password = Long.toString(random.nextLong()).toCharArray(); } Object entry = entries.get(alias.toLowerCase()); if (entry == null || !(entry instanceof KeyEntry)) { return null; } // This call gives us a PKCS12 bag, with the key inside it. byte[] exportedKeyInfo = _getEncodedKeyData(((KeyEntry) entry).keyRef, password); if (exportedKeyInfo == null) { return null; } PrivateKey returnValue = null; try { byte[] pkcs8KeyData = fetchPrivateKeyFromBag(exportedKeyInfo); byte[] encryptedKey; AlgorithmParameters algParams; ObjectIdentifier algOid; try { // get the encrypted private key EncryptedPrivateKeyInfo encrInfo = new EncryptedPrivateKeyInfo(pkcs8KeyData); encryptedKey = encrInfo.getEncryptedData(); // parse Algorithm parameters DerValue val = new DerValue(encrInfo.getAlgorithm().encode()); DerInputStream in = val.toDerInputStream(); algOid = in.getOID(); algParams = parseAlgParameters(in); } catch (IOException ioe) { UnrecoverableKeyException uke = new UnrecoverableKeyException( "Private key not stored as " + "PKCS#8 EncryptedPrivateKeyInfo: " + ioe); uke.initCause(ioe); throw uke; } // Use JCE to decrypt the data using the supplied password. SecretKey skey = getPBEKey(password); Cipher cipher = Cipher.getInstance(algOid.toString()); cipher.init(Cipher.DECRYPT_MODE, skey, algParams); byte[] decryptedPrivateKey = cipher.doFinal(encryptedKey); PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(decryptedPrivateKey); // Parse the key algorithm and then use a JCA key factory to create the private key. DerValue val = new DerValue(decryptedPrivateKey); DerInputStream in = val.toDerInputStream(); // Ignore this -- version should be 0. int i = in.getInteger(); // Get the Algorithm ID next DerValue[] value = in.getSequence(2); AlgorithmId algId = new AlgorithmId(value[0].getOID()); String algName = algId.getName(); // Get a key factory for this algorithm. It's likely to be 'RSA'. KeyFactory kfac = KeyFactory.getInstance(algName); returnValue = kfac.generatePrivate(kspec); } catch (Exception e) { UnrecoverableKeyException uke = new UnrecoverableKeyException("Get Key failed: " + e.getMessage()); uke.initCause(e); throw uke; } return returnValue; }