changeset 6082:519f4c9ebf8d

6383200: PBE: need new algorithm support in password based encryption Reviewed-by: valeriep
author vinnie
date Mon, 05 Nov 2012 20:18:05 +0000
parents 510cb3671f14
children 798292c71419
files src/share/classes/com/sun/crypto/provider/PBEKeyFactory.java src/share/classes/com/sun/crypto/provider/PBEParameters.java src/share/classes/com/sun/crypto/provider/PBES1Core.java src/share/classes/com/sun/crypto/provider/PBES2Core.java src/share/classes/com/sun/crypto/provider/PBES2Parameters.java src/share/classes/com/sun/crypto/provider/PBEWithMD5AndDESCipher.java src/share/classes/com/sun/crypto/provider/PBEWithMD5AndTripleDESCipher.java src/share/classes/com/sun/crypto/provider/PBKDF2Core.java src/share/classes/com/sun/crypto/provider/PBMAC1Core.java src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java src/share/classes/com/sun/crypto/provider/SunJCE.java src/share/classes/javax/crypto/spec/PBEParameterSpec.java test/com/sun/crypto/provider/Cipher/PBE/PBEInvalidParamsTest.java test/com/sun/crypto/provider/Cipher/PBE/PBEKeysAlgorithmNames.java test/com/sun/crypto/provider/Cipher/PBE/PBEParametersTest.java test/com/sun/crypto/provider/Cipher/PBE/PBES2Test.java test/com/sun/crypto/provider/Cipher/PBE/PKCS12Cipher.java test/com/sun/crypto/provider/Cipher/PBE/PKCS12Oid.java test/com/sun/crypto/provider/Mac/HmacPBESHA1.java test/com/sun/crypto/provider/Mac/HmacSaltLengths.java
diffstat 20 files changed, 2821 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/crypto/provider/PBEKeyFactory.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/src/share/classes/com/sun/crypto/provider/PBEKeyFactory.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, 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
@@ -55,12 +55,25 @@
     }
 
     static {
-        validTypes = new HashSet<String>(4);
+        validTypes = new HashSet<String>(17);
         validTypes.add("PBEWithMD5AndDES".toUpperCase());
         validTypes.add("PBEWithSHA1AndDESede".toUpperCase());
         validTypes.add("PBEWithSHA1AndRC2_40".toUpperCase());
+        validTypes.add("PBEWithSHA1AndRC2_128".toUpperCase());
+        validTypes.add("PBEWithSHA1AndRC4_40".toUpperCase());
+        validTypes.add("PBEWithSHA1AndRC4_128".toUpperCase());
         // Proprietary algorithm.
         validTypes.add("PBEWithMD5AndTripleDES".toUpperCase());
+        validTypes.add("PBEWithHmacSHA1AndAES_128".toUpperCase());
+        validTypes.add("PBEWithHmacSHA224AndAES_128".toUpperCase());
+        validTypes.add("PBEWithHmacSHA256AndAES_128".toUpperCase());
+        validTypes.add("PBEWithHmacSHA384AndAES_128".toUpperCase());
+        validTypes.add("PBEWithHmacSHA512AndAES_128".toUpperCase());
+        validTypes.add("PBEWithHmacSHA1AndAES_256".toUpperCase());
+        validTypes.add("PBEWithHmacSHA224AndAES_256".toUpperCase());
+        validTypes.add("PBEWithHmacSHA256AndAES_256".toUpperCase());
+        validTypes.add("PBEWithHmacSHA384AndAES_256".toUpperCase());
+        validTypes.add("PBEWithHmacSHA512AndAES_256".toUpperCase());
     }
 
     public static final class PBEWithMD5AndDES
@@ -84,6 +97,27 @@
         }
     }
 
+    public static final class PBEWithSHA1AndRC2_128
+            extends PBEKeyFactory {
+        public PBEWithSHA1AndRC2_128()  {
+            super("PBEWithSHA1AndRC2_128");
+        }
+    }
+
+    public static final class PBEWithSHA1AndRC4_40
+            extends PBEKeyFactory {
+        public PBEWithSHA1AndRC4_40()  {
+            super("PBEWithSHA1AndRC4_40");
+        }
+    }
+
+    public static final class PBEWithSHA1AndRC4_128
+            extends PBEKeyFactory {
+        public PBEWithSHA1AndRC4_128()  {
+            super("PBEWithSHA1AndRC4_128");
+        }
+    }
+
     /*
      * Private proprietary algorithm for supporting JCEKS.
      */
@@ -94,6 +128,75 @@
         }
     }
 
+    public static final class PBEWithHmacSHA1AndAES_128
+            extends PBEKeyFactory {
+        public PBEWithHmacSHA1AndAES_128()  {
+            super("PBEWithHmacSHA1AndAES_128");
+        }
+    }
+
+    public static final class PBEWithHmacSHA224AndAES_128
+            extends PBEKeyFactory {
+        public PBEWithHmacSHA224AndAES_128()  {
+            super("PBEWithHmacSHA224AndAES_128");
+        }
+    }
+
+    public static final class PBEWithHmacSHA256AndAES_128
+            extends PBEKeyFactory {
+        public PBEWithHmacSHA256AndAES_128()  {
+            super("PBEWithHmacSHA256AndAES_128");
+        }
+    }
+
+    public static final class PBEWithHmacSHA384AndAES_128
+            extends PBEKeyFactory {
+        public PBEWithHmacSHA384AndAES_128()  {
+            super("PBEWithHmacSHA384AndAES_128");
+        }
+    }
+
+    public static final class PBEWithHmacSHA512AndAES_128
+            extends PBEKeyFactory {
+        public PBEWithHmacSHA512AndAES_128()  {
+            super("PBEWithHmacSHA512AndAES_128");
+        }
+    }
+
+    public static final class PBEWithHmacSHA1AndAES_256
+            extends PBEKeyFactory {
+        public PBEWithHmacSHA1AndAES_256()  {
+            super("PBEWithHmacSHA1AndAES_256");
+        }
+    }
+
+    public static final class PBEWithHmacSHA224AndAES_256
+            extends PBEKeyFactory {
+        public PBEWithHmacSHA224AndAES_256()  {
+            super("PBEWithHmacSHA224AndAES_256");
+        }
+    }
+
+    public static final class PBEWithHmacSHA256AndAES_256
+            extends PBEKeyFactory {
+        public PBEWithHmacSHA256AndAES_256()  {
+            super("PBEWithHmacSHA256AndAES_256");
+        }
+    }
+
+    public static final class PBEWithHmacSHA384AndAES_256
+            extends PBEKeyFactory {
+        public PBEWithHmacSHA384AndAES_256()  {
+            super("PBEWithHmacSHA384AndAES_256");
+        }
+    }
+
+    public static final class PBEWithHmacSHA512AndAES_256
+            extends PBEKeyFactory {
+        public PBEWithHmacSHA512AndAES_256()  {
+            super("PBEWithHmacSHA512AndAES_256");
+        }
+    }
 
     /**
      * Generates a <code>SecretKey</code> object from the provided key
--- a/src/share/classes/com/sun/crypto/provider/PBEParameters.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/src/share/classes/com/sun/crypto/provider/PBEParameters.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, 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
@@ -57,6 +57,9 @@
     // the iteration count
     private int iCount = 0;
 
+    // the cipher parameter
+    private AlgorithmParameterSpec cipherParam = null;
+
     protected void engineInit(AlgorithmParameterSpec paramSpec)
         throws InvalidParameterSpecException
    {
@@ -66,6 +69,7 @@
        }
        this.salt = ((PBEParameterSpec)paramSpec).getSalt().clone();
        this.iCount = ((PBEParameterSpec)paramSpec).getIterationCount();
+       this.cipherParam = ((PBEParameterSpec)paramSpec).getParameterSpec();
     }
 
     protected void engineInit(byte[] encoded)
@@ -102,7 +106,8 @@
         throws InvalidParameterSpecException
     {
         if (PBEParameterSpec.class.isAssignableFrom(paramSpec)) {
-            return paramSpec.cast(new PBEParameterSpec(this.salt, this.iCount));
+            return paramSpec.cast(
+                new PBEParameterSpec(this.salt, this.iCount, this.cipherParam));
         } else {
             throw new InvalidParameterSpecException
                 ("Inappropriate parameter specification");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/crypto/provider/PBES1Core.java	Mon Nov 05 20:18:05 2012 +0000
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 2002, 2012, 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 com.sun.crypto.provider;
+
+import java.security.*;
+import java.security.spec.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+/**
+ * This class represents password-based encryption as defined by the PKCS #5
+ * standard.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see javax.crypto.Cipher
+ */
+final class PBES1Core {
+
+    // the encapsulated DES cipher
+    private CipherCore cipher;
+    private MessageDigest md;
+    private int blkSize;
+    private String algo = null;
+    private byte[] salt = null;
+    private int iCount = 10;
+
+    /**
+     * Creates an instance of PBE Cipher using the specified CipherSpi
+     * instance.
+     *
+     */
+    PBES1Core(String cipherAlg) throws NoSuchAlgorithmException,
+        NoSuchPaddingException {
+        algo = cipherAlg;
+        if (algo.equals("DES")) {
+            cipher = new CipherCore(new DESCrypt(),
+                                    DESConstants.DES_BLOCK_SIZE);
+        } else if (algo.equals("DESede")) {
+
+            cipher = new CipherCore(new DESedeCrypt(),
+                                    DESConstants.DES_BLOCK_SIZE);
+        } else {
+            throw new NoSuchAlgorithmException("No Cipher implementation " +
+                                               "for PBEWithMD5And" + algo);
+        }
+        cipher.setMode("CBC");
+        cipher.setPadding("PKCS5Padding");
+        // get instance of MD5
+        md = MessageDigest.getInstance("MD5");
+    }
+
+    /**
+     * Sets the mode of this cipher. This algorithm can only be run in CBC
+     * mode.
+     *
+     * @param mode the cipher mode
+     *
+     * @exception NoSuchAlgorithmException if the requested cipher mode is
+     * invalid
+     */
+    void setMode(String mode) throws NoSuchAlgorithmException {
+        cipher.setMode(mode);
+    }
+
+     /**
+     * Sets the padding mechanism of this cipher. This algorithm only uses
+     * PKCS #5 padding.
+     *
+     * @param padding the padding mechanism
+     *
+     * @exception NoSuchPaddingException if the requested padding mechanism
+     * is invalid
+     */
+    void setPadding(String paddingScheme) throws NoSuchPaddingException {
+        cipher.setPadding(paddingScheme);
+    }
+
+    /**
+     * Returns the block size (in bytes).
+     *
+     * @return the block size (in bytes)
+     */
+    int getBlockSize() {
+        return DESConstants.DES_BLOCK_SIZE;
+    }
+
+    /**
+     * Returns the length in bytes that an output buffer would need to be in
+     * order to hold the result of the next <code>update</code> or
+     * <code>doFinal</code> operation, given the input length
+     * <code>inputLen</code> (in bytes).
+     *
+     * <p>This call takes into account any unprocessed (buffered) data from a
+     * previous <code>update</code> call, and padding.
+     *
+     * <p>The actual output length of the next <code>update</code> or
+     * <code>doFinal</code> call may be smaller than the length returned by
+     * this method.
+     *
+     * @param inputLen the input length (in bytes)
+     *
+     * @return the required output buffer size (in bytes)
+     *
+     */
+    int getOutputSize(int inputLen) {
+        return cipher.getOutputSize(inputLen);
+    }
+
+    /**
+     * Returns the initialization vector (IV) in a new buffer.
+     *
+     * <p> This is useful in the case where a random IV has been created
+     * (see <a href = "#init">init</a>),
+     * or in the context of password-based encryption or
+     * decryption, where the IV is derived from a user-supplied password.
+     *
+     * @return the initialization vector in a new buffer, or null if the
+     * underlying algorithm does not use an IV, or if the IV has not yet
+     * been set.
+     */
+    byte[] getIV() {
+        return cipher.getIV();
+    }
+
+    /**
+     * Returns the parameters used with this cipher.
+     *
+     * <p>The returned parameters may be the same that were used to initialize
+     * this cipher, or may contain the default set of parameters or a set of
+     * randomly generated parameters used by the underlying cipher
+     * implementation (provided that the underlying cipher implementation
+     * uses a default set of parameters or creates new parameters if it needs
+     * parameters but was not initialized with any).
+     *
+     * @return the parameters used with this cipher, or null if this cipher
+     * does not use any parameters.
+     */
+    AlgorithmParameters getParameters() {
+        AlgorithmParameters params = null;
+        if (salt == null) {
+            salt = new byte[8];
+            SunJCE.RANDOM.nextBytes(salt);
+        }
+        PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount);
+        try {
+            params = AlgorithmParameters.getInstance("PBEWithMD5And" +
+                (algo.equalsIgnoreCase("DES")? "DES":"TripleDES"), "SunJCE");
+        } catch (NoSuchAlgorithmException nsae) {
+            // should never happen
+            throw new RuntimeException("SunJCE called, but not configured");
+        } catch (NoSuchProviderException nspe) {
+            // should never happen
+            throw new RuntimeException("SunJCE called, but not configured");
+        }
+        try {
+            params.init(pbeSpec);
+        } catch (InvalidParameterSpecException ipse) {
+            // should never happen
+            throw new RuntimeException("PBEParameterSpec not supported");
+        }
+        return params;
+    }
+
+    /**
+     * Initializes this cipher with a key, a set of
+     * algorithm parameters, and a source of randomness.
+     * The cipher is initialized for one of the following four operations:
+     * encryption, decryption, key wrapping or key unwrapping, depending on
+     * the value of <code>opmode</code>.
+     *
+     * <p>If this cipher (including its underlying feedback or padding scheme)
+     * requires any random bytes, it will get them from <code>random</code>.
+     *
+     * @param opmode the operation mode of this cipher (this is one of
+     * the following:
+     * <code>ENCRYPT_MODE</code>, <code>DECRYPT_MODE</code>),
+     * <code>WRAP_MODE</code> or <code>UNWRAP_MODE</code>)
+     * @param key the encryption key
+     * @param params the algorithm parameters
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this cipher
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this cipher
+     */
+    void init(int opmode, Key key, AlgorithmParameterSpec params,
+              SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException {
+        if (((opmode == Cipher.DECRYPT_MODE) ||
+             (opmode == Cipher.UNWRAP_MODE)) && (params == null)) {
+            throw new InvalidAlgorithmParameterException("Parameters "
+                                                         + "missing");
+        }
+        if ((key == null) ||
+            (key.getEncoded() == null) ||
+            !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {
+            throw new InvalidKeyException("Missing password");
+        }
+
+        if (params == null) {
+            // create random salt and use default iteration count
+            salt = new byte[8];
+            random.nextBytes(salt);
+        } else {
+            if (!(params instanceof PBEParameterSpec)) {
+                throw new InvalidAlgorithmParameterException
+                    ("Wrong parameter type: PBE expected");
+            }
+            salt = ((PBEParameterSpec) params).getSalt();
+            // salt must be 8 bytes long (by definition)
+            if (salt.length != 8) {
+                throw new InvalidAlgorithmParameterException
+                    ("Salt must be 8 bytes long");
+            }
+            iCount = ((PBEParameterSpec) params).getIterationCount();
+            if (iCount <= 0) {
+                throw new InvalidAlgorithmParameterException
+                    ("IterationCount must be a positive number");
+            }
+        }
+
+        byte[] derivedKey = deriveCipherKey(key);
+        // use all but the last 8 bytes as the key value
+        SecretKeySpec cipherKey = new SecretKeySpec(derivedKey, 0,
+                                                    derivedKey.length-8, algo);
+        // use the last 8 bytes as the IV
+        IvParameterSpec ivSpec = new IvParameterSpec(derivedKey,
+                                                     derivedKey.length-8,
+                                                     8);
+        // initialize the underlying cipher
+        cipher.init(opmode, cipherKey, ivSpec, random);
+    }
+
+    private byte[] deriveCipherKey(Key key) {
+
+        byte[] result = null;
+        byte[] passwdBytes = key.getEncoded();
+
+        if (algo.equals("DES")) {
+            // P || S (password concatenated with salt)
+            byte[] concat = new byte[passwdBytes.length + salt.length];
+            System.arraycopy(passwdBytes, 0, concat, 0, passwdBytes.length);
+            java.util.Arrays.fill(passwdBytes, (byte)0x00);
+            System.arraycopy(salt, 0, concat, passwdBytes.length, salt.length);
+
+            // digest P || S with c iterations
+            byte[] toBeHashed = concat;
+            for (int i = 0; i < iCount; i++) {
+                md.update(toBeHashed);
+                toBeHashed = md.digest(); // this resets the digest
+            }
+            java.util.Arrays.fill(concat, (byte)0x00);
+            result = toBeHashed;
+        } else if (algo.equals("DESede")) {
+            // if the 2 salt halves are the same, invert one of them
+            int i;
+            for (i=0; i<4; i++) {
+                if (salt[i] != salt[i+4])
+                    break;
+            }
+            if (i==4) { // same, invert 1st half
+                for (i=0; i<2; i++) {
+                    byte tmp = salt[i];
+                    salt[i] = salt[3-i];
+                    salt[3-1] = tmp;
+                }
+            }
+
+            // Now digest each half (concatenated with password). For each
+            // half, go through the loop as many times as specified by the
+            // iteration count parameter (inner for loop).
+            // Concatenate the output from each digest round with the
+            // password, and use the result as the input to the next digest
+            // operation.
+            byte[] kBytes = null;
+            IvParameterSpec iv = null;
+            byte[] toBeHashed = null;
+            result = new byte[DESedeKeySpec.DES_EDE_KEY_LEN +
+                              DESConstants.DES_BLOCK_SIZE];
+            for (i = 0; i < 2; i++) {
+                toBeHashed = new byte[salt.length/2];
+                System.arraycopy(salt, i*(salt.length/2), toBeHashed, 0,
+                                 toBeHashed.length);
+                for (int j=0; j < iCount; j++) {
+                    md.update(toBeHashed);
+                    md.update(passwdBytes);
+                    toBeHashed = md.digest(); // this resets the digest
+                }
+                System.arraycopy(toBeHashed, 0, result, i*16,
+                                 toBeHashed.length);
+            }
+        }
+        return result;
+    }
+
+    void init(int opmode, Key key, AlgorithmParameters params,
+              SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException {
+        PBEParameterSpec pbeSpec = null;
+        if (params != null) {
+            try {
+                pbeSpec = params.getParameterSpec(PBEParameterSpec.class);
+            } catch (InvalidParameterSpecException ipse) {
+                throw new InvalidAlgorithmParameterException("Wrong parameter "
+                                                             + "type: PBE "
+                                                             + "expected");
+            }
+        }
+        init(opmode, key, pbeSpec, random);
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code>, are processed, and the
+     * result is stored in a new buffer.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     *
+     * @return the new buffer with the result
+     *
+     */
+    byte[] update(byte[] input, int inputOffset, int inputLen) {
+        return cipher.update(input, inputOffset, inputLen);
+    }
+
+    /**
+     * Continues a multiple-part encryption or decryption operation
+     * (depending on how this cipher was initialized), processing another data
+     * part.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code>, are processed, and the
+     * result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code>.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     */
+    int update(byte[] input, int inputOffset, int inputLen,
+               byte[] output, int outputOffset)
+        throws ShortBufferException {
+        return cipher.update(input, inputOffset, inputLen,
+                             output, outputOffset);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation,
+     * or finishes a multiple-part operation.
+     * The data is encrypted or decrypted, depending on how this cipher was
+     * initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code>, and any input bytes that
+     * may have been buffered during a previous <code>update</code> operation,
+     * are processed, with padding (if requested) being applied.
+     * The result is stored in a new buffer.
+     *
+     * <p>The cipher is reset to its initial state (uninitialized) after this
+     * call.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     *
+     * @return the new buffer with the result
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size
+     * @exception BadPaddingException if decrypting and padding is choosen,
+     * but the last input data does not have proper padding bytes.
+     */
+    byte[] doFinal(byte[] input, int inputOffset, int inputLen)
+        throws IllegalBlockSizeException, BadPaddingException {
+        return cipher.doFinal(input, inputOffset, inputLen);
+    }
+
+    /**
+     * Encrypts or decrypts data in a single-part operation,
+     * or finishes a multiple-part operation.
+     * The data is encrypted or decrypted, depending on how this cipher was
+     * initialized.
+     *
+     * <p>The first <code>inputLen</code> bytes in the <code>input</code>
+     * buffer, starting at <code>inputOffset</code>, and any input bytes that
+     * may have been buffered during a previous <code>update</code> operation,
+     * are processed, with padding (if requested) being applied.
+     * The result is stored in the <code>output</code> buffer, starting at
+     * <code>outputOffset</code>.
+     *
+     * <p>The cipher is reset to its initial state (uninitialized) after this
+     * call.
+     *
+     * @param input the input buffer
+     * @param inputOffset the offset in <code>input</code> where the input
+     * starts
+     * @param inputLen the input length
+     * @param output the buffer for the result
+     * @param outputOffset the offset in <code>output</code> where the result
+     * is stored
+     *
+     * @return the number of bytes stored in <code>output</code>
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block cipher,
+     * no padding has been requested (only in encryption mode), and the total
+     * input length of the data processed by this cipher is not a multiple of
+     * block size
+     * @exception ShortBufferException if the given output buffer is too small
+     * to hold the result
+     * @exception BadPaddingException if decrypting and padding is choosen,
+     * but the last input data does not have proper padding bytes.
+     */
+    int doFinal(byte[] input, int inputOffset, int inputLen,
+                byte[] output, int outputOffset)
+        throws ShortBufferException, IllegalBlockSizeException,
+               BadPaddingException {
+        return cipher.doFinal(input, inputOffset, inputLen,
+                                    output, outputOffset);
+    }
+
+    /**
+     * Wrap a key.
+     *
+     * @param key the key to be wrapped.
+     *
+     * @return the wrapped key.
+     *
+     * @exception IllegalBlockSizeException if this cipher is a block
+     * cipher, no padding has been requested, and the length of the
+     * encoding of the key to be wrapped is not a
+     * multiple of the block size.
+     *
+     * @exception InvalidKeyException if it is impossible or unsafe to
+     * wrap the key with this cipher (e.g., a hardware protected key is
+     * being passed to a software only cipher).
+     */
+    byte[] wrap(Key key)
+        throws IllegalBlockSizeException, InvalidKeyException {
+        byte[] result = null;
+
+        try {
+            byte[] encodedKey = key.getEncoded();
+            if ((encodedKey == null) || (encodedKey.length == 0)) {
+                throw new InvalidKeyException("Cannot get an encoding of " +
+                                              "the key to be wrapped");
+            }
+
+            result = doFinal(encodedKey, 0, encodedKey.length);
+        } catch (BadPaddingException e) {
+            // Should never happen
+        }
+
+        return result;
+    }
+
+    /**
+     * Unwrap a previously wrapped key.
+     *
+     * @param wrappedKey the key to be unwrapped.
+     *
+     * @param wrappedKeyAlgorithm the algorithm the wrapped key is for.
+     *
+     * @param wrappedKeyType the type of the wrapped key.
+     * This is one of <code>Cipher.SECRET_KEY</code>,
+     * <code>Cipher.PRIVATE_KEY</code>, or <code>Cipher.PUBLIC_KEY</code>.
+     *
+     * @return the unwrapped key.
+     *
+     * @exception NoSuchAlgorithmException if no installed providers
+     * can create keys of type <code>wrappedKeyType</code> for the
+     * <code>wrappedKeyAlgorithm</code>.
+     *
+     * @exception InvalidKeyException if <code>wrappedKey</code> does not
+     * represent a wrapped key of type <code>wrappedKeyType</code> for
+     * the <code>wrappedKeyAlgorithm</code>.
+     */
+    Key unwrap(byte[] wrappedKey,
+               String wrappedKeyAlgorithm,
+               int wrappedKeyType)
+        throws InvalidKeyException, NoSuchAlgorithmException {
+        byte[] encodedKey;
+        try {
+            encodedKey = doFinal(wrappedKey, 0, wrappedKey.length);
+        } catch (BadPaddingException ePadding) {
+            throw new InvalidKeyException("The wrapped key is not padded " +
+                                          "correctly");
+        } catch (IllegalBlockSizeException eBlockSize) {
+            throw new InvalidKeyException("The wrapped key does not have " +
+                                          "the correct length");
+        }
+        return ConstructKeys.constructKey(encodedKey, wrappedKeyAlgorithm,
+                                          wrappedKeyType);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/crypto/provider/PBES2Core.java	Mon Nov 05 20:18:05 2012 +0000
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2012, 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 com.sun.crypto.provider;
+
+import java.io.UnsupportedEncodingException;
+import java.security.*;
+import java.security.spec.*;
+import javax.crypto.*;
+import javax.crypto.interfaces.*;
+import javax.crypto.spec.*;
+
+/**
+ * This class represents password-based encryption as defined by the PKCS #5
+ * standard.
+ * These algorithms implement PBE with HmacSHA1/HmacSHA2-family and AES-CBC.
+ * Padding is done as described in PKCS #5.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see javax.crypto.Cipher
+ */
+abstract class PBES2Core extends CipherSpi {
+
+    private static final int DEFAULT_SALT_LENGTH = 20;
+    private static final int DEFAULT_COUNT = 4096;
+
+    // the encapsulated cipher
+    private final CipherCore cipher;
+    private final int keyLength; // in bits
+    private final int blkSize; // in bits
+    private final PBKDF2Core kdf;
+    private final String pbeAlgo;
+    private final String cipherAlgo;
+    private int iCount = DEFAULT_COUNT;
+    private byte[] salt = null;
+    private IvParameterSpec ivSpec = null;
+
+    /**
+     * Creates an instance of PBE Scheme 2 according to the selected
+     * password-based key derivation function and encryption scheme.
+     */
+    PBES2Core(String kdfAlgo, String cipherAlgo, int keySize)
+        throws NoSuchAlgorithmException, NoSuchPaddingException {
+
+        this.cipherAlgo = cipherAlgo;
+        keyLength = keySize * 8;
+        pbeAlgo = "PBEWith" + kdfAlgo + "And" + cipherAlgo + "_" + keyLength;
+
+        if (cipherAlgo.equals("AES")) {
+            blkSize = AESConstants.AES_BLOCK_SIZE;
+            cipher = new CipherCore(new AESCrypt(), blkSize);
+
+            switch(kdfAlgo) {
+            case "HmacSHA1":
+                kdf = new PBKDF2Core.HmacSHA1();
+                break;
+            case "HmacSHA224":
+                kdf = new PBKDF2Core.HmacSHA224();
+                break;
+            case "HmacSHA256":
+                kdf = new PBKDF2Core.HmacSHA256();
+                break;
+            case "HmacSHA384":
+                kdf = new PBKDF2Core.HmacSHA384();
+                break;
+            case "HmacSHA512":
+                kdf = new PBKDF2Core.HmacSHA512();
+                break;
+            default:
+                throw new NoSuchAlgorithmException(
+                    "No Cipher implementation for " + kdfAlgo);
+            }
+        } else {
+            throw new NoSuchAlgorithmException("No Cipher implementation for " +
+                                               pbeAlgo);
+        }
+        cipher.setMode("CBC");
+        cipher.setPadding("PKCS5Padding");
+    }
+
+    protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+        if ((mode != null) && (!mode.equalsIgnoreCase("CBC"))) {
+            throw new NoSuchAlgorithmException("Invalid cipher mode: " + mode);
+        }
+    }
+
+    protected void engineSetPadding(String paddingScheme)
+        throws NoSuchPaddingException {
+        if ((paddingScheme != null) &&
+            (!paddingScheme.equalsIgnoreCase("PKCS5Padding"))) {
+            throw new NoSuchPaddingException("Invalid padding scheme: " +
+                                             paddingScheme);
+        }
+    }
+
+    protected int engineGetBlockSize() {
+        return blkSize;
+    }
+
+    protected int engineGetOutputSize(int inputLen) {
+        return cipher.getOutputSize(inputLen);
+    }
+
+    protected byte[] engineGetIV() {
+        return cipher.getIV();
+    }
+
+    protected AlgorithmParameters engineGetParameters() {
+        AlgorithmParameters params = null;
+        if (salt == null) {
+            // generate random salt and use default iteration count
+            salt = new byte[DEFAULT_SALT_LENGTH];
+            SunJCE.RANDOM.nextBytes(salt);
+            iCount = DEFAULT_COUNT;
+        }
+        if (ivSpec == null) {
+            // generate random IV
+            byte[] ivBytes = new byte[blkSize];
+            SunJCE.RANDOM.nextBytes(ivBytes);
+            ivSpec = new IvParameterSpec(ivBytes);
+        }
+        PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount, ivSpec);
+        try {
+            params = AlgorithmParameters.getInstance(pbeAlgo, "SunJCE");
+        } catch (NoSuchAlgorithmException nsae) {
+            // should never happen
+            throw new RuntimeException("SunJCE called, but not configured");
+        } catch (NoSuchProviderException nspe) {
+            // should never happen
+            throw new RuntimeException("SunJCE called, but not configured");
+        }
+        try {
+            params.init(pbeSpec);
+        } catch (InvalidParameterSpecException ipse) {
+            // should never happen
+            throw new RuntimeException("PBEParameterSpec not supported");
+        }
+        return params;
+    }
+
+    protected void engineInit(int opmode, Key key, SecureRandom random)
+        throws InvalidKeyException {
+        try {
+            engineInit(opmode, key, (AlgorithmParameterSpec) null, random);
+        } catch (InvalidAlgorithmParameterException ie) {
+            InvalidKeyException ike =
+                new InvalidKeyException("requires PBE parameters");
+            ike.initCause(ie);
+            throw ike;
+        }
+    }
+
+    protected void engineInit(int opmode, Key key,
+                              AlgorithmParameterSpec params,
+                              SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException {
+
+        if ((key == null) ||
+            (key.getEncoded() == null) ||
+            !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {
+            throw new InvalidKeyException("Missing password");
+        }
+
+        // TBD: consolidate the salt, ic and IV parameter checks below
+
+        // Extract salt and iteration count from the key, if present
+        if (key instanceof javax.crypto.interfaces.PBEKey) {
+            salt = ((javax.crypto.interfaces.PBEKey)key).getSalt();
+            if (salt != null && salt.length < 8) {
+                throw new InvalidAlgorithmParameterException(
+                    "Salt must be at least 8 bytes long");
+            }
+            iCount = ((javax.crypto.interfaces.PBEKey)key).getIterationCount();
+            if (iCount == 0) {
+                iCount = DEFAULT_COUNT;
+            } else if (iCount < 0) {
+                throw new InvalidAlgorithmParameterException(
+                    "Iteration count must be a positive number");
+            }
+        }
+
+        // Extract salt, iteration count and IV from the params, if present
+        if (params == null) {
+            if (salt == null) {
+                // generate random salt and use default iteration count
+                salt = new byte[DEFAULT_SALT_LENGTH];
+                random.nextBytes(salt);
+                iCount = DEFAULT_COUNT;
+            }
+            if ((opmode == Cipher.ENCRYPT_MODE) ||
+                        (opmode == Cipher.WRAP_MODE)) {
+                // generate random IV
+                byte[] ivBytes = new byte[blkSize];
+                random.nextBytes(ivBytes);
+                ivSpec = new IvParameterSpec(ivBytes);
+            }
+        } else {
+            if (!(params instanceof PBEParameterSpec)) {
+                throw new InvalidAlgorithmParameterException
+                    ("Wrong parameter type: PBE expected");
+            }
+            // salt and iteration count from the params take precedence
+            byte[] specSalt = ((PBEParameterSpec) params).getSalt();
+            if (specSalt != null && specSalt.length < 8) {
+                throw new InvalidAlgorithmParameterException(
+                    "Salt must be at least 8 bytes long");
+            }
+            salt = specSalt;
+            int specICount = ((PBEParameterSpec) params).getIterationCount();
+            if (specICount == 0) {
+                specICount = DEFAULT_COUNT;
+            } else if (specICount < 0) {
+                throw new InvalidAlgorithmParameterException(
+                    "Iteration count must be a positive number");
+            }
+            iCount = specICount;
+
+            AlgorithmParameterSpec specParams =
+                ((PBEParameterSpec) params).getParameterSpec();
+            if (specParams != null) {
+                if (specParams instanceof IvParameterSpec) {
+                    ivSpec = (IvParameterSpec)specParams;
+                } else {
+                    throw new InvalidAlgorithmParameterException(
+                        "Wrong parameter type: IV expected");
+                }
+            } else if ((opmode == Cipher.ENCRYPT_MODE) ||
+                        (opmode == Cipher.WRAP_MODE)) {
+                // generate random IV
+                byte[] ivBytes = new byte[blkSize];
+                random.nextBytes(ivBytes);
+                ivSpec = new IvParameterSpec(ivBytes);
+            } else {
+                throw new InvalidAlgorithmParameterException(
+                    "Missing parameter type: IV expected");
+            }
+        }
+
+        SecretKeySpec cipherKey = null;
+        byte[] derivedKey = null;
+        byte[] passwdBytes = key.getEncoded();
+        char[] passwdChars = new char[passwdBytes.length];
+
+        for (int i=0; i<passwdChars.length; i++)
+            passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
+
+        PBEKeySpec pbeSpec =
+            new PBEKeySpec(passwdChars, salt, iCount, blkSize * 8);
+            // password char[] was cloned in PBEKeySpec constructor,
+            // so we can zero it out here
+        java.util.Arrays.fill(passwdChars, ' ');
+        java.util.Arrays.fill(passwdBytes, (byte)0x00);
+
+        SecretKey s = null;
+
+        try {
+            s = kdf.engineGenerateSecret(pbeSpec);
+
+        } catch (InvalidKeySpecException ikse) {
+            InvalidKeyException ike =
+                new InvalidKeyException("Cannot construct PBE key");
+            ike.initCause(ikse);
+            throw ike;
+        }
+        derivedKey = s.getEncoded();
+        cipherKey = new SecretKeySpec(derivedKey, cipherAlgo);
+
+        // initialize the underlying cipher
+        cipher.init(opmode, cipherKey, ivSpec, random);
+    }
+
+    protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+                              SecureRandom random)
+        throws InvalidKeyException, InvalidAlgorithmParameterException {
+        AlgorithmParameterSpec pbeSpec = null;
+        if (params != null) {
+            try {
+                pbeSpec = params.getParameterSpec(PBEParameterSpec.class);
+            } catch (InvalidParameterSpecException ipse) {
+                throw new InvalidAlgorithmParameterException(
+                    "Wrong parameter type: PBE expected");
+            }
+        }
+        engineInit(opmode, key, pbeSpec, random);
+    }
+
+    protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
+        return cipher.update(input, inputOffset, inputLen);
+    }
+
+    protected int engineUpdate(byte[] input, int inputOffset, int inputLen,
+                               byte[] output, int outputOffset)
+        throws ShortBufferException {
+        return cipher.update(input, inputOffset, inputLen,
+                             output, outputOffset);
+    }
+
+    protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
+        throws IllegalBlockSizeException, BadPaddingException {
+        return cipher.doFinal(input, inputOffset, inputLen);
+    }
+
+    protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,
+                                byte[] output, int outputOffset)
+        throws ShortBufferException, IllegalBlockSizeException,
+               BadPaddingException {
+        return cipher.doFinal(input, inputOffset, inputLen,
+                              output, outputOffset);
+    }
+
+    protected int engineGetKeySize(Key key) throws InvalidKeyException {
+        return keyLength;
+    }
+
+    protected byte[] engineWrap(Key key)
+        throws IllegalBlockSizeException, InvalidKeyException {
+        return cipher.wrap(key);
+    }
+
+    protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
+                               int wrappedKeyType)
+        throws InvalidKeyException, NoSuchAlgorithmException {
+        byte[] encodedKey;
+        return cipher.unwrap(wrappedKey, wrappedKeyAlgorithm,
+                             wrappedKeyType);
+    }
+
+    public static final class HmacSHA1AndAES_128 extends PBES2Core {
+        public HmacSHA1AndAES_128()
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super("HmacSHA1", "AES", 16);
+        }
+    }
+
+    public static final class HmacSHA224AndAES_128 extends PBES2Core {
+        public HmacSHA224AndAES_128()
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super("HmacSHA224", "AES", 16);
+        }
+    }
+
+    public static final class HmacSHA256AndAES_128 extends PBES2Core {
+        public HmacSHA256AndAES_128()
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super("HmacSHA256", "AES", 16);
+        }
+    }
+
+    public static final class HmacSHA384AndAES_128 extends PBES2Core {
+        public HmacSHA384AndAES_128()
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super("HmacSHA384", "AES", 16);
+        }
+    }
+
+    public static final class HmacSHA512AndAES_128 extends PBES2Core {
+        public HmacSHA512AndAES_128()
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super("HmacSHA512", "AES", 16);
+        }
+    }
+
+    public static final class HmacSHA1AndAES_256 extends PBES2Core {
+        public HmacSHA1AndAES_256()
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super("HmacSHA1", "AES", 32);
+        }
+    }
+
+    public static final class HmacSHA224AndAES_256 extends PBES2Core {
+        public HmacSHA224AndAES_256()
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super("HmacSHA224", "AES", 32);
+        }
+    }
+
+    public static final class HmacSHA256AndAES_256 extends PBES2Core {
+        public HmacSHA256AndAES_256()
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super("HmacSHA256", "AES", 32);
+        }
+    }
+
+    public static final class HmacSHA384AndAES_256 extends PBES2Core {
+        public HmacSHA384AndAES_256()
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super("HmacSHA384", "AES", 32);
+        }
+    }
+
+    public static final class HmacSHA512AndAES_256 extends PBES2Core {
+        public HmacSHA512AndAES_256()
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+            super("HmacSHA512", "AES", 32);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/crypto/provider/PBES2Parameters.java	Mon Nov 05 20:18:05 2012 +0000
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2012, 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 com.sun.crypto.provider;
+
+import java.io.*;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import sun.misc.HexDumpEncoder;
+import sun.security.util.*;
+
+/**
+ * This class implements the parameter set used with password-based
+ * encryption scheme 2 (PBES2), which is defined in PKCS#5 as follows:
+ *
+ * <pre>
+ * -- PBES2
+ *
+ * PBES2Algorithms ALGORITHM-IDENTIFIER ::=
+ *   { {PBES2-params IDENTIFIED BY id-PBES2}, ...}
+ *
+ * id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13}
+ *
+ * PBES2-params ::= SEQUENCE {
+ *   keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+ *   encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
+ *
+ * PBES2-KDFs ALGORITHM-IDENTIFIER ::=
+ *   { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
+ *
+ * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... }
+ *
+ * -- PBKDF2
+ *
+ * PBKDF2Algorithms ALGORITHM-IDENTIFIER ::=
+ *   { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...}
+ *
+ * id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
+ *
+ * PBKDF2-params ::= SEQUENCE {
+ *     salt CHOICE {
+ *       specified OCTET STRING,
+ *       otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+ *     },
+ *     iterationCount INTEGER (1..MAX),
+ *     keyLength INTEGER (1..MAX) OPTIONAL,
+ *     prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
+ * }
+ *
+ * PBKDF2-SaltSources ALGORITHM-IDENTIFIER ::= { ... }
+ *
+ * PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= {
+ *     {NULL IDENTIFIED BY id-hmacWithSHA1} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA224} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA256} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA384} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA512}, ... }
+ *
+ * algid-hmacWithSHA1 AlgorithmIdentifier {{PBKDF2-PRFs}} ::=
+ *     {algorithm id-hmacWithSHA1, parameters NULL : NULL}
+ *
+ * id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7}
+ *
+ * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... }
+ *
+ * </pre>
+ */
+
+abstract class PBES2Parameters extends AlgorithmParametersSpi {
+
+    private static final int pkcs5PBKDF2[] =
+                                        {1, 2, 840, 113549, 1, 5, 12};
+    private static final int pkcs5PBES2[] =
+                                        {1, 2, 840, 113549, 1, 5, 13};
+    private static final int hmacWithSHA1[] =
+                                        {1, 2, 840, 113549, 2, 7};
+    private static final int hmacWithSHA224[] =
+                                        {1, 2, 840, 113549, 2, 8};
+    private static final int hmacWithSHA256[] =
+                                        {1, 2, 840, 113549, 2, 9};
+    private static final int hmacWithSHA384[] =
+                                        {1, 2, 840, 113549, 2, 10};
+    private static final int hmacWithSHA512[] =
+                                        {1, 2, 840, 113549, 2, 11};
+    private static final int aes128CBC[] =
+                                        {2, 16, 840, 1, 101, 3, 4, 1, 2};
+    private static final int aes192CBC[] =
+                                        {2, 16, 840, 1, 101, 3, 4, 1, 22};
+    private static final int aes256CBC[] =
+                                        {2, 16, 840, 1, 101, 3, 4, 1, 42};
+
+    private static ObjectIdentifier pkcs5PBKDF2_OID;
+    private static ObjectIdentifier pkcs5PBES2_OID;
+    private static ObjectIdentifier hmacWithSHA1_OID;
+    private static ObjectIdentifier hmacWithSHA224_OID;
+    private static ObjectIdentifier hmacWithSHA256_OID;
+    private static ObjectIdentifier hmacWithSHA384_OID;
+    private static ObjectIdentifier hmacWithSHA512_OID;
+    private static ObjectIdentifier aes128CBC_OID;
+    private static ObjectIdentifier aes192CBC_OID;
+    private static ObjectIdentifier aes256CBC_OID;
+
+    static {
+        try {
+            pkcs5PBKDF2_OID = new ObjectIdentifier(pkcs5PBKDF2);
+            pkcs5PBES2_OID = new ObjectIdentifier(pkcs5PBES2);
+            hmacWithSHA1_OID = new ObjectIdentifier(hmacWithSHA1);
+            hmacWithSHA224_OID = new ObjectIdentifier(hmacWithSHA224);
+            hmacWithSHA256_OID = new ObjectIdentifier(hmacWithSHA256);
+            hmacWithSHA384_OID = new ObjectIdentifier(hmacWithSHA384);
+            hmacWithSHA512_OID = new ObjectIdentifier(hmacWithSHA512);
+            aes128CBC_OID = new ObjectIdentifier(aes128CBC);
+            aes192CBC_OID = new ObjectIdentifier(aes192CBC);
+            aes256CBC_OID = new ObjectIdentifier(aes256CBC);
+        } catch (IOException ioe) {
+            // should not happen
+        }
+    }
+
+    // the PBES2 algorithm name
+    private String pbes2AlgorithmName = null;
+
+    // the salt
+    private byte[] salt = null;
+
+    // the iteration count
+    private int iCount = 0;
+
+    // the cipher parameter
+    private AlgorithmParameterSpec cipherParam = null;
+
+    // the key derivation function (default is HmacSHA1)
+    private ObjectIdentifier kdfAlgo_OID = hmacWithSHA1_OID;
+
+    // the encryption function
+    private ObjectIdentifier cipherAlgo_OID = null;
+
+    // the cipher keysize (in bits)
+    private int keysize = -1;
+
+    PBES2Parameters() {
+        // KDF, encryption & keysize values are set later, in engineInit(byte[])
+    }
+
+    PBES2Parameters(String pbes2AlgorithmName) throws NoSuchAlgorithmException {
+        int and;
+        String kdfAlgo = null;
+        String cipherAlgo = null;
+
+        // Extract the KDF and encryption algorithm names
+        this.pbes2AlgorithmName = pbes2AlgorithmName;
+        if (pbes2AlgorithmName.startsWith("PBEWith") &&
+            (and = pbes2AlgorithmName.indexOf("And", 7 + 1)) > 0) {
+            kdfAlgo = pbes2AlgorithmName.substring(7, and);
+            cipherAlgo = pbes2AlgorithmName.substring(and + 3);
+
+            // Check for keysize
+            int underscore;
+            if ((underscore = cipherAlgo.indexOf('_')) > 0) {
+                int slash;
+                if ((slash = cipherAlgo.indexOf('/', underscore + 1)) > 0) {
+                    keysize =
+                        Integer.parseInt(cipherAlgo.substring(underscore + 1,
+                            slash));
+                } else {
+                    keysize =
+                        Integer.parseInt(cipherAlgo.substring(underscore + 1));
+                }
+                cipherAlgo = cipherAlgo.substring(0, underscore);
+            }
+        } else {
+            throw new NoSuchAlgorithmException("No crypto implementation for " +
+                pbes2AlgorithmName);
+        }
+
+        switch (kdfAlgo) {
+        case "HmacSHA1":
+            kdfAlgo_OID = hmacWithSHA1_OID;
+            break;
+        case "HmacSHA224":
+            kdfAlgo_OID = hmacWithSHA224_OID;
+            break;
+        case "HmacSHA256":
+            kdfAlgo_OID = hmacWithSHA256_OID;
+            break;
+        case "HmacSHA384":
+            kdfAlgo_OID = hmacWithSHA384_OID;
+            break;
+        case "HmacSHA512":
+            kdfAlgo_OID = hmacWithSHA512_OID;
+            break;
+        default:
+            throw new NoSuchAlgorithmException(
+                "No crypto implementation for " + kdfAlgo);
+        }
+
+        if (cipherAlgo.equals("AES")) {
+            this.keysize = keysize;
+            switch (keysize) {
+            case 128:
+                cipherAlgo_OID = aes128CBC_OID;
+                break;
+            case 256:
+                cipherAlgo_OID = aes256CBC_OID;
+                break;
+            default:
+                throw new NoSuchAlgorithmException(
+                    "No Cipher implementation for " + keysize + "-bit " +
+                        cipherAlgo);
+            }
+        } else {
+            throw new NoSuchAlgorithmException("No Cipher implementation for " +
+                cipherAlgo);
+        }
+    }
+
+    protected void engineInit(AlgorithmParameterSpec paramSpec)
+        throws InvalidParameterSpecException
+    {
+       if (!(paramSpec instanceof PBEParameterSpec)) {
+           throw new InvalidParameterSpecException
+               ("Inappropriate parameter specification");
+       }
+       this.salt = ((PBEParameterSpec)paramSpec).getSalt().clone();
+       this.iCount = ((PBEParameterSpec)paramSpec).getIterationCount();
+       this.cipherParam = ((PBEParameterSpec)paramSpec).getParameterSpec();
+    }
+
+    protected void engineInit(byte[] encoded)
+        throws IOException
+    {
+        String kdfAlgo = null;
+        String cipherAlgo = null;
+
+        DerValue pBES2Algorithms = new DerValue(encoded);
+        if (pBES2Algorithms.tag != DerValue.tag_Sequence) {
+            throw new IOException("PBE parameter parsing error: "
+                                  + "not an ASN.1 SEQUENCE tag");
+        }
+        if (!pkcs5PBES2_OID.equals(pBES2Algorithms.data.getOID())) {
+            throw new IOException("PBE parameter parsing error: "
+                + "expecting the object identifier for PBES2");
+        }
+        if (pBES2Algorithms.tag != DerValue.tag_Sequence) {
+            throw new IOException("PBE parameter parsing error: "
+                + "not an ASN.1 SEQUENCE tag");
+        }
+
+        DerValue pBES2_params = pBES2Algorithms.data.getDerValue();
+        if (pBES2_params.tag != DerValue.tag_Sequence) {
+            throw new IOException("PBE parameter parsing error: "
+                + "not an ASN.1 SEQUENCE tag");
+        }
+        kdfAlgo = parseKDF(pBES2_params.data.getDerValue());
+
+        if (pBES2_params.tag != DerValue.tag_Sequence) {
+            throw new IOException("PBE parameter parsing error: "
+                + "not an ASN.1 SEQUENCE tag");
+        }
+        cipherAlgo = parseES(pBES2_params.data.getDerValue());
+
+        pbes2AlgorithmName = new StringBuilder().append("PBEWith")
+            .append(kdfAlgo).append("And").append(cipherAlgo).toString();
+    }
+
+    private String parseKDF(DerValue keyDerivationFunc) throws IOException {
+        String kdfAlgo = null;
+
+        if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) {
+            throw new IOException("PBE parameter parsing error: "
+                + "expecting the object identifier for PBKDF2");
+        }
+        if (keyDerivationFunc.tag != DerValue.tag_Sequence) {
+            throw new IOException("PBE parameter parsing error: "
+                + "not an ASN.1 SEQUENCE tag");
+        }
+        DerValue pBKDF2_params = keyDerivationFunc.data.getDerValue();
+        if (pBKDF2_params.tag != DerValue.tag_Sequence) {
+            throw new IOException("PBE parameter parsing error: "
+                + "not an ASN.1 SEQUENCE tag");
+        }
+        DerValue specified = pBKDF2_params.data.getDerValue();
+        // the 'specified' ASN.1 CHOICE for 'salt' is supported
+        if (specified.tag == DerValue.tag_OctetString) {
+            salt = specified.getOctetString();
+        } else {
+            // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported
+            throw new IOException("PBE parameter parsing error: "
+                + "not an ASN.1 OCTET STRING tag");
+        }
+        iCount = pBKDF2_params.data.getInteger();
+        DerValue keyLength = pBKDF2_params.data.getDerValue();
+        if (keyLength.tag == DerValue.tag_Integer) {
+            keysize = keyLength.getInteger() * 8; // keysize (in bits)
+        }
+        if (pBKDF2_params.tag == DerValue.tag_Sequence) {
+            DerValue prf = pBKDF2_params.data.getDerValue();
+            kdfAlgo_OID = prf.data.getOID();
+            if (hmacWithSHA1_OID.equals(kdfAlgo_OID)) {
+                kdfAlgo = "HmacSHA1";
+            } else if (hmacWithSHA224_OID.equals(kdfAlgo_OID)) {
+                kdfAlgo = "HmacSHA224";
+            } else if (hmacWithSHA256_OID.equals(kdfAlgo_OID)) {
+                kdfAlgo = "HmacSHA256";
+            } else if (hmacWithSHA384_OID.equals(kdfAlgo_OID)) {
+                kdfAlgo = "HmacSHA384";
+            } else if (hmacWithSHA512_OID.equals(kdfAlgo_OID)) {
+                kdfAlgo = "HmacSHA512";
+            } else {
+                throw new IOException("PBE parameter parsing error: "
+                    + "expecting the object identifier for a HmacSHA key "
+                    + "derivation function");
+            }
+            if (prf.data.available() != 0) {
+                // parameter is 'NULL' for all HmacSHA KDFs
+                DerValue parameter = prf.data.getDerValue();
+                if (parameter.tag != DerValue.tag_Null) {
+                    throw new IOException("PBE parameter parsing error: "
+                        + "not an ASN.1 NULL tag");
+                }
+            }
+        }
+
+        return kdfAlgo;
+    }
+
+    private String parseES(DerValue encryptionScheme) throws IOException {
+        String cipherAlgo = null;
+
+        cipherAlgo_OID = encryptionScheme.data.getOID();
+        if (aes128CBC_OID.equals(cipherAlgo_OID)) {
+            cipherAlgo = "AES_128";
+            // parameter is AES-IV 'OCTET STRING (SIZE(16))'
+            cipherParam =
+                new IvParameterSpec(encryptionScheme.data.getOctetString());
+            keysize = 128;
+        } else if (aes256CBC_OID.equals(cipherAlgo_OID)) {
+            cipherAlgo = "AES_256";
+            // parameter is AES-IV 'OCTET STRING (SIZE(16))'
+            cipherParam =
+                new IvParameterSpec(encryptionScheme.data.getOctetString());
+            keysize = 256;
+        } else {
+            throw new IOException("PBE parameter parsing error: "
+                + "expecting the object identifier for AES cipher");
+        }
+
+        return cipherAlgo;
+    }
+
+    protected void engineInit(byte[] encoded, String decodingMethod)
+        throws IOException
+    {
+        engineInit(encoded);
+    }
+
+    protected <T extends AlgorithmParameterSpec>
+            T engineGetParameterSpec(Class<T> paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (PBEParameterSpec.class.isAssignableFrom(paramSpec)) {
+            return paramSpec.cast(
+                new PBEParameterSpec(this.salt, this.iCount, this.cipherParam));
+        } else {
+            throw new InvalidParameterSpecException
+                ("Inappropriate parameter specification");
+        }
+    }
+
+    protected byte[] engineGetEncoded() throws IOException {
+        DerOutputStream out = new DerOutputStream();
+        DerOutputStream pBES2Algorithms = new DerOutputStream();
+        pBES2Algorithms.putOID(pkcs5PBES2_OID);
+
+        DerOutputStream pBES2_params = new DerOutputStream();
+
+        DerOutputStream keyDerivationFunc = new DerOutputStream();
+        keyDerivationFunc.putOID(pkcs5PBKDF2_OID);
+
+        DerOutputStream pBKDF2_params = new DerOutputStream();
+        pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING'
+        pBKDF2_params.putInteger(iCount);
+        pBKDF2_params.putInteger(keysize / 8); // derived key length (in octets)
+
+        DerOutputStream prf = new DerOutputStream();
+        // algorithm is id-hmacWithSHA1/SHA224/SHA256/SHA384/SHA512
+        prf.putOID(kdfAlgo_OID);
+        // parameters is 'NULL'
+        prf.putNull();
+        pBKDF2_params.write(DerValue.tag_Sequence, prf);
+
+        keyDerivationFunc.write(DerValue.tag_Sequence, pBKDF2_params);
+        pBES2_params.write(DerValue.tag_Sequence, keyDerivationFunc);
+
+        DerOutputStream encryptionScheme = new DerOutputStream();
+        // algorithm is id-aes128-CBC or id-aes256-CBC
+        encryptionScheme.putOID(cipherAlgo_OID);
+        // parameters is 'AES-IV ::= OCTET STRING (SIZE(16))'
+        if (cipherParam != null && cipherParam instanceof IvParameterSpec) {
+            encryptionScheme.putOctetString(
+                ((IvParameterSpec)cipherParam).getIV());
+        } else {
+            throw new IOException("Wrong parameter type: IV expected");
+        }
+        pBES2_params.write(DerValue.tag_Sequence, encryptionScheme);
+
+        pBES2Algorithms.write(DerValue.tag_Sequence, pBES2_params);
+        out.write(DerValue.tag_Sequence, pBES2Algorithms);
+
+        return out.toByteArray();
+    }
+
+    protected byte[] engineGetEncoded(String encodingMethod)
+        throws IOException
+    {
+        return engineGetEncoded();
+    }
+
+    /*
+     * Returns a formatted string describing the parameters.
+     *
+     * The algorithn name pattern is: "PBEWith<prf>And<encryption>"
+     * where <prf> is one of: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384,
+     * or HmacSHA512, and <encryption> is AES with a keysize suffix.
+     */
+    protected String engineToString() {
+        return pbes2AlgorithmName;
+    }
+
+    public static final class General extends PBES2Parameters {
+        public General() throws NoSuchAlgorithmException {
+            super();
+        }
+    }
+
+    public static final class HmacSHA1AndAES_128 extends PBES2Parameters {
+        public HmacSHA1AndAES_128() throws NoSuchAlgorithmException {
+            super("PBEWithHmacSHA1AndAES_128");
+        }
+    }
+
+    public static final class HmacSHA224AndAES_128 extends PBES2Parameters {
+        public HmacSHA224AndAES_128() throws NoSuchAlgorithmException {
+            super("PBEWithHmacSHA224AndAES_128");
+        }
+    }
+
+    public static final class HmacSHA256AndAES_128 extends PBES2Parameters {
+        public HmacSHA256AndAES_128() throws NoSuchAlgorithmException {
+            super("PBEWithHmacSHA256AndAES_128");
+        }
+    }
+
+    public static final class HmacSHA384AndAES_128 extends PBES2Parameters {
+        public HmacSHA384AndAES_128() throws NoSuchAlgorithmException {
+            super("PBEWithHmacSHA384AndAES_128");
+        }
+    }
+
+    public static final class HmacSHA512AndAES_128 extends PBES2Parameters {
+        public HmacSHA512AndAES_128() throws NoSuchAlgorithmException {
+            super("PBEWithHmacSHA512AndAES_128");
+        }
+    }
+
+    public static final class HmacSHA1AndAES_256 extends PBES2Parameters {
+        public HmacSHA1AndAES_256() throws NoSuchAlgorithmException {
+            super("PBEWithHmacSHA1AndAES_256");
+        }
+    }
+
+    public static final class HmacSHA224AndAES_256 extends PBES2Parameters {
+        public HmacSHA224AndAES_256() throws NoSuchAlgorithmException {
+            super("PBEWithHmacSHA224AndAES_256");
+        }
+    }
+
+    public static final class HmacSHA256AndAES_256 extends PBES2Parameters {
+        public HmacSHA256AndAES_256() throws NoSuchAlgorithmException {
+            super("PBEWithHmacSHA256AndAES_256");
+        }
+    }
+
+    public static final class HmacSHA384AndAES_256 extends PBES2Parameters {
+        public HmacSHA384AndAES_256() throws NoSuchAlgorithmException {
+            super("PBEWithHmacSHA384AndAES_256");
+        }
+    }
+
+    public static final class HmacSHA512AndAES_256 extends PBES2Parameters {
+        public HmacSHA512AndAES_256() throws NoSuchAlgorithmException {
+            super("PBEWithHmacSHA512AndAES_256");
+        }
+    }
+}
--- a/src/share/classes/com/sun/crypto/provider/PBEWithMD5AndDESCipher.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/src/share/classes/com/sun/crypto/provider/PBEWithMD5AndDESCipher.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, 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
@@ -45,7 +45,7 @@
 public final class PBEWithMD5AndDESCipher extends CipherSpi {
 
     // the encapsulated DES cipher
-    private PBECipherCore core;
+    private PBES1Core core;
 
     /**
      * Creates an instance of this cipher, and initializes its mode (CBC) and
@@ -58,7 +58,7 @@
      */
     public PBEWithMD5AndDESCipher()
         throws NoSuchAlgorithmException, NoSuchPaddingException {
-        core = new PBECipherCore("DES");
+        core = new PBES1Core("DES");
     }
 
     /**
--- a/src/share/classes/com/sun/crypto/provider/PBEWithMD5AndTripleDESCipher.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/src/share/classes/com/sun/crypto/provider/PBEWithMD5AndTripleDESCipher.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, 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
@@ -55,7 +55,7 @@
  */
 public final class PBEWithMD5AndTripleDESCipher extends CipherSpi {
 
-    private PBECipherCore core;
+    private PBES1Core core;
 
     /**
      * Creates an instance of this cipher, and initializes its mode (CBC) and
@@ -70,7 +70,7 @@
         throws NoSuchAlgorithmException, NoSuchPaddingException
     {
         // set the encapsulated cipher to do triple DES
-        core = new PBECipherCore("DESede");
+        core = new PBES1Core("DESede");
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/crypto/provider/PBKDF2Core.java	Mon Nov 05 20:18:05 2012 +0000
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2005, 2012, 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 com.sun.crypto.provider;
+
+import java.security.InvalidKeyException;
+import java.security.spec.KeySpec;
+import java.security.spec.InvalidKeySpecException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.PBEKeySpec;
+
+/**
+ * This class implements a key factory for PBE keys derived using
+ * PBKDF2 with HmacSHA1/HmacSHA224/HmacSHA256/HmacSHA384/HmacSHA512
+ * pseudo random function (PRF) as defined in PKCS#5 v2.1.
+ *
+ * @author Valerie Peng
+ *
+ */
+abstract class PBKDF2Core extends SecretKeyFactorySpi {
+
+    private final String prfAlgo;
+
+    PBKDF2Core(String prfAlgo) {
+        this.prfAlgo = prfAlgo;
+    }
+
+    /**
+     * Generates a <code>SecretKey</code> object from the provided key
+     * specification (key material).
+     *
+     * @param keySpec the specification (key material) of the secret key
+     *
+     * @return the secret key
+     *
+     * @exception InvalidKeySpecException if the given key specification
+     * is inappropriate for this key factory to produce a public key.
+     */
+    protected SecretKey engineGenerateSecret(KeySpec keySpec)
+        throws InvalidKeySpecException
+    {
+        if (!(keySpec instanceof PBEKeySpec)) {
+            throw new InvalidKeySpecException("Invalid key spec");
+        }
+        PBEKeySpec ks = (PBEKeySpec) keySpec;
+        return new PBKDF2KeyImpl(ks, prfAlgo);
+    }
+
+    /**
+     * Returns a specification (key material) of the given key
+     * in the requested format.
+     *
+     * @param key the key
+     *
+     * @param keySpec the requested format in which the key material shall be
+     * returned
+     *
+     * @return the underlying key specification (key material) in the
+     * requested format
+     *
+     * @exception InvalidKeySpecException if the requested key
+     * specification is inappropriate for the given key, or the
+     * given key cannot be processed (e.g., the given key has an
+     * unrecognized algorithm or format).
+     */
+    protected KeySpec engineGetKeySpec(SecretKey key, Class<?> keySpecCl)
+        throws InvalidKeySpecException {
+        if (key instanceof javax.crypto.interfaces.PBEKey) {
+            // Check if requested key spec is amongst the valid ones
+            if ((keySpecCl != null)
+                && PBEKeySpec.class.isAssignableFrom(keySpecCl)) {
+                javax.crypto.interfaces.PBEKey pKey =
+                    (javax.crypto.interfaces.PBEKey) key;
+                return new PBEKeySpec
+                    (pKey.getPassword(), pKey.getSalt(),
+                     pKey.getIterationCount(), pKey.getEncoded().length*8);
+            } else {
+                throw new InvalidKeySpecException("Invalid key spec");
+            }
+        } else {
+            throw new InvalidKeySpecException("Invalid key " +
+                                               "format/algorithm");
+        }
+    }
+
+    /**
+     * Translates a <code>SecretKey</code> object, whose provider may be
+     * unknown or potentially untrusted, into a corresponding
+     * <code>SecretKey</code> object of this key factory.
+     *
+     * @param key the key whose provider is unknown or untrusted
+     *
+     * @return the translated key
+     *
+     * @exception InvalidKeyException if the given key cannot be processed by
+     * this key factory.
+     */
+    protected SecretKey engineTranslateKey(SecretKey key)
+        throws InvalidKeyException {
+        if ((key != null) &&
+            (key.getAlgorithm().equalsIgnoreCase("PBKDF2With" + prfAlgo)) &&
+            (key.getFormat().equalsIgnoreCase("RAW"))) {
+
+            // Check if key originates from this factory
+            if (key instanceof com.sun.crypto.provider.PBKDF2KeyImpl) {
+                return key;
+            }
+            // Check if key implements the PBEKey
+            if (key instanceof javax.crypto.interfaces.PBEKey) {
+                javax.crypto.interfaces.PBEKey pKey =
+                    (javax.crypto.interfaces.PBEKey) key;
+                try {
+                    PBEKeySpec spec =
+                        new PBEKeySpec(pKey.getPassword(),
+                                       pKey.getSalt(),
+                                       pKey.getIterationCount(),
+                                       pKey.getEncoded().length*8);
+                    return new PBKDF2KeyImpl(spec, prfAlgo);
+                } catch (InvalidKeySpecException re) {
+                    InvalidKeyException ike = new InvalidKeyException
+                        ("Invalid key component(s)");
+                    ike.initCause(re);
+                    throw ike;
+                }
+            }
+        }
+        throw new InvalidKeyException("Invalid key format/algorithm");
+    }
+
+    public static final class HmacSHA1 extends PBKDF2Core {
+        public HmacSHA1() {
+            super("HmacSHA1");
+        }
+    }
+
+    public static final class HmacSHA224 extends PBKDF2Core {
+        public HmacSHA224() {
+            super("HmacSHA224");
+        }
+    }
+
+    public static final class HmacSHA256 extends PBKDF2Core {
+        public HmacSHA256() {
+            super("HmacSHA256");
+        }
+    }
+
+    public static final class HmacSHA384 extends PBKDF2Core {
+        public HmacSHA384() {
+            super("HmacSHA384");
+        }
+    }
+
+    public static final class HmacSHA512 extends PBKDF2Core {
+        public HmacSHA512() {
+            super("HmacSHA512");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/crypto/provider/PBMAC1Core.java	Mon Nov 05 20:18:05 2012 +0000
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2003, 2012, 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 com.sun.crypto.provider;
+
+import java.util.Arrays;
+import java.nio.ByteBuffer;
+
+import javax.crypto.MacSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+import java.security.*;
+import java.security.spec.*;
+
+/**
+ * This is an implementation of the PBMAC1 algorithms as defined
+ * in PKCS#5 v2.1 standard.
+ */
+abstract class PBMAC1Core extends HmacCore {
+
+    private static final int DEFAULT_SALT_LENGTH = 20;
+    private static final int DEFAULT_COUNT = 4096;
+
+    private final String kdfAlgo;
+    private final String hashAlgo;
+    private final PBKDF2Core kdf;
+    private final int blockLength; // in octets
+
+    /**
+     * Creates an instance of PBMAC1 according to the selected
+     * password-based key derivation function.
+     */
+    PBMAC1Core(String kdfAlgo, String hashAlgo, int blockLength)
+        throws NoSuchAlgorithmException {
+
+        super(hashAlgo, blockLength);
+        this.kdfAlgo = kdfAlgo;
+        this.hashAlgo = hashAlgo;
+        this.blockLength = blockLength;
+
+        switch(kdfAlgo) {
+        case "HmacSHA1":
+                kdf = new PBKDF2Core.HmacSHA1();
+                break;
+        case "HmacSHA224":
+                kdf = new PBKDF2Core.HmacSHA224();
+                break;
+        case "HmacSHA256":
+                kdf = new PBKDF2Core.HmacSHA256();
+                break;
+        case "HmacSHA384":
+                kdf = new PBKDF2Core.HmacSHA384();
+                break;
+        case "HmacSHA512":
+                kdf = new PBKDF2Core.HmacSHA512();
+                break;
+        default:
+                throw new NoSuchAlgorithmException(
+                    "No MAC implementation for " + kdfAlgo);
+        }
+    }
+
+    /**
+     * Initializes the HMAC with the given secret key and algorithm parameters.
+     *
+     * @param key the secret key.
+     * @param params the algorithm parameters.
+     *
+     * @exception InvalidKeyException if the given key is inappropriate for
+     * initializing this MAC.
+     * @exception InvalidAlgorithmParameterException if the given algorithm
+     * parameters are inappropriate for this MAC.
+     */
+    protected void engineInit(Key key, AlgorithmParameterSpec params)
+        throws InvalidKeyException, InvalidAlgorithmParameterException {
+        char[] passwdChars;
+        byte[] salt = null;
+        int iCount = 0;
+        if (key instanceof javax.crypto.interfaces.PBEKey) {
+            javax.crypto.interfaces.PBEKey pbeKey =
+                (javax.crypto.interfaces.PBEKey) key;
+            passwdChars = pbeKey.getPassword();
+            salt = pbeKey.getSalt(); // maybe null if unspecified
+            iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified
+        } else if (key instanceof SecretKey) {
+            byte[] passwdBytes = key.getEncoded();
+            if ((passwdBytes == null) ||
+                !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {
+                throw new InvalidKeyException("Missing password");
+            }
+            passwdChars = new char[passwdBytes.length];
+            for (int i=0; i<passwdChars.length; i++) {
+                passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
+            }
+        } else {
+            throw new InvalidKeyException("SecretKey of PBE type required");
+        }
+        if (params == null) {
+            // generate default for salt and iteration count if necessary
+            if (salt == null) {
+                salt = new byte[DEFAULT_SALT_LENGTH];
+                SunJCE.RANDOM.nextBytes(salt);
+            }
+            if (iCount == 0) iCount = DEFAULT_COUNT;
+        } else if (!(params instanceof PBEParameterSpec)) {
+            throw new InvalidAlgorithmParameterException
+                ("PBEParameterSpec type required");
+        } else {
+            PBEParameterSpec pbeParams = (PBEParameterSpec) params;
+            // make sure the parameter values are consistent
+            if (salt != null) {
+                if (!Arrays.equals(salt, pbeParams.getSalt())) {
+                    throw new InvalidAlgorithmParameterException
+                        ("Inconsistent value of salt between key and params");
+                }
+            } else {
+                salt = pbeParams.getSalt();
+            }
+            if (iCount != 0) {
+                if (iCount != pbeParams.getIterationCount()) {
+                    throw new InvalidAlgorithmParameterException
+                        ("Different iteration count between key and params");
+                }
+            } else {
+                iCount = pbeParams.getIterationCount();
+            }
+        }
+        // For security purpose, we need to enforce a minimum length
+        // for salt; just require the minimum salt length to be 8-byte
+        // which is what PKCS#5 recommends and openssl does.
+        if (salt.length < 8) {
+            throw new InvalidAlgorithmParameterException
+                ("Salt must be at least 8 bytes long");
+        }
+        if (iCount <= 0) {
+            throw new InvalidAlgorithmParameterException
+                ("IterationCount must be a positive number");
+        }
+
+        PBEKeySpec pbeSpec =
+            new PBEKeySpec(passwdChars, salt, iCount, blockLength);
+            // password char[] was cloned in PBEKeySpec constructor,
+            // so we can zero it out here
+        java.util.Arrays.fill(passwdChars, ' ');
+
+        SecretKey s = null;
+
+        try {
+            s = kdf.engineGenerateSecret(pbeSpec);
+
+        } catch (InvalidKeySpecException ikse) {
+            InvalidKeyException ike =
+                new InvalidKeyException("Cannot construct PBE key");
+            ike.initCause(ikse);
+            throw ike;
+        }
+        byte[] derivedKey = s.getEncoded();
+        SecretKey cipherKey = new SecretKeySpec(derivedKey, kdfAlgo);
+
+        super.engineInit(cipherKey, null);
+    }
+
+    public static final class HmacSHA1 extends PBMAC1Core {
+        public HmacSHA1() throws NoSuchAlgorithmException {
+            super("HmacSHA1", "SHA1", 64);
+        }
+    }
+
+    public static final class HmacSHA224 extends PBMAC1Core {
+        public HmacSHA224() throws NoSuchAlgorithmException {
+            super("HmacSHA224", "SHA-224", 64);
+        }
+    }
+
+    public static final class HmacSHA256 extends PBMAC1Core {
+        public HmacSHA256() throws NoSuchAlgorithmException {
+            super("HmacSHA256", "SHA-256", 64);
+        }
+    }
+
+    public static final class HmacSHA384 extends PBMAC1Core {
+        public HmacSHA384() throws NoSuchAlgorithmException {
+            super("HmacSHA384", "SHA-384", 128);
+        }
+    }
+
+    public static final class HmacSHA512 extends PBMAC1Core {
+        public HmacSHA512() throws NoSuchAlgorithmException {
+            super("HmacSHA512", "SHA-512", 128);
+        }
+    }
+}
--- a/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java	Mon Nov 05 20:18:05 2012 +0000
@@ -35,19 +35,24 @@
 
 /**
  * This class implements password-base encryption algorithm with
- * SHA1 digest and the following Ciphers in CBC mode
+ * SHA1 digest and the following Ciphers (in CBC mode, where applicable):
  * - DESede cipher and
- * - RC2 Cipher with 40-bit effective key length
+ * - RC2 Cipher with 40-bit or 128-bit effective key length and
+ * - RC4 Cipher with 40-bit or 128-bit effective key length
  * as defined by PKCS #12 version 1.0 standard.
  *
  * @author Valerie Peng
  * @see javax.crypto.CipherSpi
  */
 final class PKCS12PBECipherCore {
+
+    // TBD: replace CipherCore with a CipherSpi object to simplify maintenance
+
     private CipherCore cipher;
     private int blockSize;
     private int keySize;
     private String algo = null;
+    private String pbeAlgo = null;
     private byte[] salt = null;
     private int iCount = 0;
 
@@ -58,8 +63,16 @@
     static final int CIPHER_IV = 2;
     static final int MAC_KEY = 3;
 
+    // Uses default hash algorithm (SHA-1)
     static byte[] derive(char[] chars, byte[] salt,
                          int ic, int n, int type) {
+        return derive(chars, salt, ic, n, type, "SHA-1", 64);
+    }
+
+    // Uses supplied hash algorithm
+    static byte[] derive(char[] chars, byte[] salt, int ic, int n, int type,
+        String hashAlgo, int blockLength) {
+
         // Add in trailing NULL terminator.  Special case:
         // no terminator if password is "\0".
         int length = chars.length*2;
@@ -75,21 +88,23 @@
             passwd[j] = (byte) ((chars[i] >>> 8) & 0xFF);
             passwd[j+1] = (byte) (chars[i] & 0xFF);
         }
-        int v = 512 / 8;
-        int u = 160 / 8;
-        int c = roundup(n, u) / u;
-        byte[] D = new byte[v];
-        int s = roundup(salt.length, v);
-        int p = roundup(passwd.length, v);
-        byte[] I = new byte[s + p];
         byte[] key = new byte[n];
 
-        Arrays.fill(D, (byte)type);
-        concat(salt, I, 0, s);
-        concat(passwd, I, s, p);
+        try {
+            MessageDigest sha = MessageDigest.getInstance(hashAlgo);
 
-        try {
-            MessageDigest sha = MessageDigest.getInstance("SHA1");
+            int v = blockLength;
+            int u = sha.getDigestLength();
+            int c = roundup(n, u) / u;
+            byte[] D = new byte[v];
+            int s = roundup(salt.length, v);
+            int p = roundup(passwd.length, v);
+            byte[] I = new byte[s + p];
+
+            Arrays.fill(D, (byte)type);
+            concat(salt, I, 0, s);
+            concat(passwd, I, s, p);
+
             byte[] Ai;
             byte[] B = new byte[v];
             byte[] tmp = new byte[v];
@@ -150,23 +165,30 @@
 
     PKCS12PBECipherCore(String symmCipherAlg, int defKeySize)
         throws NoSuchAlgorithmException {
+
         algo = symmCipherAlg;
-        SymmetricCipher symmCipher = null;
-        if (algo.equals("DESede")) {
-            symmCipher = new DESedeCrypt();
-        } else if (algo.equals("RC2")) {
-            symmCipher = new RC2Crypt();
+        if (algo.equals("RC4")) {
+            pbeAlgo = "PBEWithSHA1AndRC4_" + defKeySize * 8;
         } else {
-            throw new NoSuchAlgorithmException("No Cipher implementation " +
+            SymmetricCipher symmCipher = null;
+            if (algo.equals("DESede")) {
+                symmCipher = new DESedeCrypt();
+                pbeAlgo = "PBEWithSHA1AndDESede";
+            } else if (algo.equals("RC2")) {
+                symmCipher = new RC2Crypt();
+                pbeAlgo = "PBEWithSHA1AndRC2_" + defKeySize * 8;
+            } else {
+                throw new NoSuchAlgorithmException("No Cipher implementation " +
                        "for PBEWithSHA1And" + algo);
-        }
-        blockSize = symmCipher.getBlockSize();
-        cipher = new CipherCore(symmCipher, blockSize);
-        cipher.setMode("CBC");
-        try {
-            cipher.setPadding("PKCS5Padding");
-        } catch (NoSuchPaddingException nspe) {
-            // should not happen
+            }
+            blockSize = symmCipher.getBlockSize();
+            cipher = new CipherCore(symmCipher, blockSize);
+            cipher.setMode("CBC");
+            try {
+                cipher.setPadding("PKCS5Padding");
+            } catch (NoSuchPaddingException nspe) {
+                // should not happen
+            }
         }
         keySize = defKeySize;
     }
@@ -210,8 +232,7 @@
         }
         PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount);
         try {
-            params = AlgorithmParameters.getInstance("PBEWithSHA1And" +
-                (algo.equalsIgnoreCase("RC2")?"RC2_40":algo), "SunJCE");
+            params = AlgorithmParameters.getInstance(pbeAlgo, "SunJCE");
         } catch (GeneralSecurityException gse) {
             // should never happen
             throw new RuntimeException(
@@ -229,6 +250,13 @@
     void implInit(int opmode, Key key, AlgorithmParameterSpec params,
                   SecureRandom random) throws InvalidKeyException,
         InvalidAlgorithmParameterException {
+        implInit(opmode, key, params, random, null);
+    }
+
+    void implInit(int opmode, Key key, AlgorithmParameterSpec params,
+                  SecureRandom random, CipherSpi cipherImpl)
+                      throws InvalidKeyException,
+        InvalidAlgorithmParameterException {
         char[] passwdChars = null;
         salt = null;
         iCount = 0;
@@ -309,17 +337,29 @@
         byte[] derivedKey = derive(passwdChars, salt, iCount,
                                    keySize, CIPHER_KEY);
         SecretKey cipherKey = new SecretKeySpec(derivedKey, algo);
-        byte[] derivedIv = derive(passwdChars, salt, iCount, 8,
+
+        if (cipherImpl != null && cipherImpl instanceof ARCFOURCipher) {
+            ((ARCFOURCipher)cipherImpl).engineInit(opmode, cipherKey, random);
+
+        } else {
+            byte[] derivedIv = derive(passwdChars, salt, iCount, 8,
                                   CIPHER_IV);
-        IvParameterSpec ivSpec = new IvParameterSpec(derivedIv, 0, 8);
+            IvParameterSpec ivSpec = new IvParameterSpec(derivedIv, 0, 8);
 
-        // initialize the underlying cipher
-        cipher.init(opmode, cipherKey, ivSpec, random);
+            // initialize the underlying cipher
+            cipher.init(opmode, cipherKey, ivSpec, random);
+        }
     }
 
     void implInit(int opmode, Key key, AlgorithmParameters params,
                   SecureRandom random)
         throws InvalidKeyException, InvalidAlgorithmParameterException {
+        implInit(opmode, key, params, random, null);
+    }
+
+    void implInit(int opmode, Key key, AlgorithmParameters params,
+                  SecureRandom random, CipherSpi cipherImpl)
+        throws InvalidKeyException, InvalidAlgorithmParameterException {
         AlgorithmParameterSpec paramSpec = null;
         if (params != null) {
             try {
@@ -329,13 +369,19 @@
                     "requires PBE parameters");
             }
         }
-        implInit(opmode, key, paramSpec, random);
+        implInit(opmode, key, paramSpec, random, cipherImpl);
     }
 
     void implInit(int opmode, Key key, SecureRandom random)
         throws InvalidKeyException {
+        implInit(opmode, key, random, null);
+    }
+
+    void implInit(int opmode, Key key, SecureRandom random,
+        CipherSpi cipherImpl) throws InvalidKeyException {
         try {
-            implInit(opmode, key, (AlgorithmParameterSpec) null, random);
+            implInit(opmode, key, (AlgorithmParameterSpec) null, random,
+                cipherImpl);
         } catch (InvalidAlgorithmParameterException iape) {
             throw new InvalidKeyException("requires PBE parameters");
         }
@@ -526,4 +572,245 @@
             return core.implWrap(key);
         }
     }
+
+    public static final class PBEWithSHA1AndRC2_128 extends CipherSpi {
+        private final PKCS12PBECipherCore core;
+        public PBEWithSHA1AndRC2_128() throws NoSuchAlgorithmException {
+            core = new PKCS12PBECipherCore("RC2", 16);
+        }
+        protected byte[] engineDoFinal(byte[] in, int inOff, int inLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+            return core.implDoFinal(in, inOff, inLen);
+        }
+        protected int engineDoFinal(byte[] in, int inOff, int inLen,
+                                    byte[] out, int outOff)
+            throws ShortBufferException, IllegalBlockSizeException,
+                   BadPaddingException {
+            return core.implDoFinal(in, inOff, inLen, out, outOff);
+        }
+        protected int engineGetBlockSize() {
+            return core.implGetBlockSize();
+        }
+        protected byte[] engineGetIV() {
+            return core.implGetIV();
+        }
+        protected int engineGetKeySize(Key key) throws InvalidKeyException {
+            return core.implGetKeySize(key);
+        }
+        protected int engineGetOutputSize(int inLen) {
+            return core.implGetOutputSize(inLen);
+        }
+        protected AlgorithmParameters engineGetParameters() {
+            return core.implGetParameters();
+        }
+        protected void engineInit(int opmode, Key key,
+                                  AlgorithmParameterSpec params,
+                                  SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+            core.implInit(opmode, key, params, random);
+        }
+        protected void engineInit(int opmode, Key key,
+                                  AlgorithmParameters params,
+                                  SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+            core.implInit(opmode, key, params, random);
+        }
+        protected void engineInit(int opmode, Key key, SecureRandom random)
+            throws InvalidKeyException {
+            core.implInit(opmode, key, random);
+        }
+        protected void engineSetMode(String mode)
+            throws NoSuchAlgorithmException {
+            core.implSetMode(mode);
+        }
+        protected void engineSetPadding(String paddingScheme)
+            throws NoSuchPaddingException {
+            core.implSetPadding(paddingScheme);
+        }
+        protected Key engineUnwrap(byte[] wrappedKey,
+                                   String wrappedKeyAlgorithm,
+                                   int wrappedKeyType)
+            throws InvalidKeyException, NoSuchAlgorithmException {
+            return core.implUnwrap(wrappedKey, wrappedKeyAlgorithm,
+                                   wrappedKeyType);
+        }
+        protected byte[] engineUpdate(byte[] in, int inOff, int inLen) {
+            return core.implUpdate(in, inOff, inLen);
+        }
+        protected int engineUpdate(byte[] in, int inOff, int inLen,
+                                   byte[] out, int outOff)
+            throws ShortBufferException {
+            return core.implUpdate(in, inOff, inLen, out, outOff);
+        }
+        protected byte[] engineWrap(Key key)
+            throws IllegalBlockSizeException, InvalidKeyException {
+            return core.implWrap(key);
+        }
+    }
+
+    public static final class PBEWithSHA1AndRC4_40 extends CipherSpi {
+        private static final int RC4_KEYSIZE = 5;
+        private final PKCS12PBECipherCore core;
+        private final ARCFOURCipher cipher;
+
+        public PBEWithSHA1AndRC4_40() throws NoSuchAlgorithmException {
+            core = new PKCS12PBECipherCore("RC4", RC4_KEYSIZE);
+            cipher = new ARCFOURCipher();
+        }
+        protected byte[] engineDoFinal(byte[] in, int inOff, int inLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+            return cipher.engineDoFinal(in, inOff, inLen);
+        }
+        protected int engineDoFinal(byte[] in, int inOff, int inLen,
+                                    byte[] out, int outOff)
+            throws ShortBufferException, IllegalBlockSizeException,
+                   BadPaddingException {
+            return cipher.engineDoFinal(in, inOff, inLen, out, outOff);
+        }
+        protected int engineGetBlockSize() {
+            return cipher.engineGetBlockSize();
+        }
+        protected byte[] engineGetIV() {
+            return cipher.engineGetIV();
+        }
+        protected int engineGetKeySize(Key key) throws InvalidKeyException {
+            return RC4_KEYSIZE;
+        }
+        protected int engineGetOutputSize(int inLen) {
+            return cipher.engineGetOutputSize(inLen);
+        }
+        protected AlgorithmParameters engineGetParameters() {
+            return core.implGetParameters();
+        }
+        protected void engineInit(int opmode, Key key,
+                                  AlgorithmParameterSpec params,
+                                  SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+            core.implInit(opmode, key, params, random, cipher);
+        }
+        protected void engineInit(int opmode, Key key,
+                                  AlgorithmParameters params,
+                                  SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+            core.implInit(opmode, key, params, random, cipher);
+        }
+        protected void engineInit(int opmode, Key key, SecureRandom random)
+            throws InvalidKeyException {
+            core.implInit(opmode, key, random, cipher);
+        }
+        protected void engineSetMode(String mode)
+            throws NoSuchAlgorithmException {
+            if (mode.equalsIgnoreCase("ECB") == false) {
+                throw new NoSuchAlgorithmException("Unsupported mode " + mode);
+            }
+        }
+        protected void engineSetPadding(String paddingScheme)
+            throws NoSuchPaddingException {
+            if (paddingScheme.equalsIgnoreCase("NoPadding") == false) {
+                throw new NoSuchPaddingException("Padding must be NoPadding");
+            }
+        }
+        protected Key engineUnwrap(byte[] wrappedKey,
+                                   String wrappedKeyAlgorithm,
+                                   int wrappedKeyType)
+            throws InvalidKeyException, NoSuchAlgorithmException {
+            return cipher.engineUnwrap(wrappedKey, wrappedKeyAlgorithm,
+                                   wrappedKeyType);
+        }
+        protected byte[] engineUpdate(byte[] in, int inOff, int inLen) {
+            return cipher.engineUpdate(in, inOff, inLen);
+        }
+        protected int engineUpdate(byte[] in, int inOff, int inLen,
+                                   byte[] out, int outOff)
+            throws ShortBufferException {
+            return cipher.engineUpdate(in, inOff, inLen, out, outOff);
+        }
+        protected byte[] engineWrap(Key key)
+            throws IllegalBlockSizeException, InvalidKeyException {
+            return cipher.engineWrap(key);
+        }
+    }
+
+    public static final class PBEWithSHA1AndRC4_128 extends CipherSpi {
+        private static final int RC4_KEYSIZE = 16;
+        private final PKCS12PBECipherCore core;
+        private final ARCFOURCipher cipher;
+
+        public PBEWithSHA1AndRC4_128() throws NoSuchAlgorithmException {
+            core = new PKCS12PBECipherCore("RC4", RC4_KEYSIZE);
+            cipher = new ARCFOURCipher();
+        }
+        protected byte[] engineDoFinal(byte[] in, int inOff, int inLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+            return cipher.engineDoFinal(in, inOff, inLen);
+        }
+        protected int engineDoFinal(byte[] in, int inOff, int inLen,
+                                    byte[] out, int outOff)
+            throws ShortBufferException, IllegalBlockSizeException,
+                   BadPaddingException {
+            return cipher.engineDoFinal(in, inOff, inLen, out, outOff);
+        }
+        protected int engineGetBlockSize() {
+            return cipher.engineGetBlockSize();
+        }
+        protected byte[] engineGetIV() {
+            return cipher.engineGetIV();
+        }
+        protected int engineGetKeySize(Key key) throws InvalidKeyException {
+            return RC4_KEYSIZE;
+        }
+        protected int engineGetOutputSize(int inLen) {
+            return cipher.engineGetOutputSize(inLen);
+        }
+        protected AlgorithmParameters engineGetParameters() {
+            return core.implGetParameters();
+        }
+        protected void engineInit(int opmode, Key key,
+                                  AlgorithmParameterSpec params,
+                                  SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+            core.implInit(opmode, key, params, random, cipher);
+        }
+        protected void engineInit(int opmode, Key key,
+                                  AlgorithmParameters params,
+                                  SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+            core.implInit(opmode, key, params, random, cipher);
+        }
+        protected void engineInit(int opmode, Key key, SecureRandom random)
+            throws InvalidKeyException {
+            core.implInit(opmode, key, random, cipher);
+        }
+        protected void engineSetMode(String mode)
+            throws NoSuchAlgorithmException {
+            if (mode.equalsIgnoreCase("ECB") == false) {
+                throw new NoSuchAlgorithmException("Unsupported mode " + mode);
+            }
+        }
+        protected void engineSetPadding(String paddingScheme)
+            throws NoSuchPaddingException {
+            if (paddingScheme.equalsIgnoreCase("NoPadding") == false) {
+                throw new NoSuchPaddingException("Padding must be NoPadding");
+            }
+        }
+        protected Key engineUnwrap(byte[] wrappedKey,
+                                   String wrappedKeyAlgorithm,
+                                   int wrappedKeyType)
+            throws InvalidKeyException, NoSuchAlgorithmException {
+            return cipher.engineUnwrap(wrappedKey, wrappedKeyAlgorithm,
+                                   wrappedKeyType);
+        }
+        protected byte[] engineUpdate(byte[] in, int inOff, int inLen) {
+            return cipher.engineUpdate(in, inOff, inLen);
+        }
+        protected int engineUpdate(byte[] in, int inOff, int inLen,
+                                   byte[] out, int outOff)
+            throws ShortBufferException {
+            return cipher.engineUpdate(in, inOff, inLen, out, outOff);
+        }
+        protected byte[] engineWrap(Key key)
+            throws IllegalBlockSizeException, InvalidKeyException {
+            return cipher.engineWrap(key);
+        }
+    }
 }
--- a/src/share/classes/com/sun/crypto/provider/SunJCE.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/src/share/classes/com/sun/crypto/provider/SunJCE.java	Mon Nov 05 20:18:05 2012 +0000
@@ -77,10 +77,14 @@
     "(implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, "
     + "Diffie-Hellman, HMAC)";
 
+    private static final String OID_PKCS12_RC4_128 = "1.2.840.113549.1.12.1.1";
+    private static final String OID_PKCS12_RC4_40 = "1.2.840.113549.1.12.1.2";
+    private static final String OID_PKCS12_DESede = "1.2.840.113549.1.12.1.3";
+    private static final String OID_PKCS12_RC2_128 = "1.2.840.113549.1.12.1.5";
     private static final String OID_PKCS12_RC2_40 = "1.2.840.113549.1.12.1.6";
-    private static final String OID_PKCS12_DESede = "1.2.840.113549.1.12.1.3";
     private static final String OID_PKCS5_MD5_DES = "1.2.840.113549.1.5.3";
     private static final String OID_PKCS5_PBKDF2 = "1.2.840.113549.1.5.12";
+    private static final String OID_PKCS5_PBES2 = "1.2.840.113549.1.5.13";
     private static final String OID_PKCS3 = "1.2.840.113549.1.3.1";
 
     /* Are we debugging? -- for developers */
@@ -138,14 +142,26 @@
                     put("Cipher.DESedeWrap SupportedPaddings", "NOPADDING");
                     put("Cipher.DESedeWrap SupportedKeyFormats", "RAW");
 
+                    // PBES1
+
                     put("Cipher.PBEWithMD5AndDES",
                         "com.sun.crypto.provider.PBEWithMD5AndDESCipher");
                     put("Alg.Alias.Cipher.OID."+OID_PKCS5_MD5_DES,
                         "PBEWithMD5AndDES");
                     put("Alg.Alias.Cipher."+OID_PKCS5_MD5_DES,
                         "PBEWithMD5AndDES");
+
                     put("Cipher.PBEWithMD5AndTripleDES",
                         "com.sun.crypto.provider.PBEWithMD5AndTripleDESCipher");
+
+                    put("Cipher.PBEWithSHA1AndDESede",
+                        "com.sun.crypto.provider.PKCS12PBECipherCore$" +
+                        "PBEWithSHA1AndDESede");
+                    put("Alg.Alias.Cipher.OID." + OID_PKCS12_DESede,
+                        "PBEWithSHA1AndDESede");
+                    put("Alg.Alias.Cipher." + OID_PKCS12_DESede,
+                        "PBEWithSHA1AndDESede");
+
                     put("Cipher.PBEWithSHA1AndRC2_40",
                         "com.sun.crypto.provider.PKCS12PBECipherCore$" +
                         "PBEWithSHA1AndRC2_40");
@@ -153,13 +169,70 @@
                         "PBEWithSHA1AndRC2_40");
                     put("Alg.Alias.Cipher." + OID_PKCS12_RC2_40,
                         "PBEWithSHA1AndRC2_40");
-                    put("Cipher.PBEWithSHA1AndDESede",
+
+                    put("Cipher.PBEWithSHA1AndRC2_128",
                         "com.sun.crypto.provider.PKCS12PBECipherCore$" +
-                        "PBEWithSHA1AndDESede");
-                    put("Alg.Alias.Cipher.OID." + OID_PKCS12_DESede,
-                        "PBEWithSHA1AndDESede");
-                    put("Alg.Alias.Cipher." + OID_PKCS12_DESede,
-                        "PBEWithSHA1AndDESede");
+                        "PBEWithSHA1AndRC2_128");
+                    put("Alg.Alias.Cipher.OID." + OID_PKCS12_RC2_128,
+                        "PBEWithSHA1AndRC2_128");
+                    put("Alg.Alias.Cipher." + OID_PKCS12_RC2_128,
+                        "PBEWithSHA1AndRC2_128");
+
+                    put("Cipher.PBEWithSHA1AndRC4_40",
+                        "com.sun.crypto.provider.PKCS12PBECipherCore$" +
+                        "PBEWithSHA1AndRC4_40");
+                    put("Alg.Alias.Cipher.OID." + OID_PKCS12_RC4_40,
+                        "PBEWithSHA1AndRC4_40");
+                    put("Alg.Alias.Cipher." + OID_PKCS12_RC4_40,
+                        "PBEWithSHA1AndRC4_40");
+
+                    put("Cipher.PBEWithSHA1AndRC4_128",
+                        "com.sun.crypto.provider.PKCS12PBECipherCore$" +
+                        "PBEWithSHA1AndRC4_128");
+                    put("Alg.Alias.Cipher.OID." + OID_PKCS12_RC4_128,
+                        "PBEWithSHA1AndRC4_128");
+                    put("Alg.Alias.Cipher." + OID_PKCS12_RC4_128,
+                        "PBEWithSHA1AndRC4_128");
+
+                    //PBES2
+
+                    put("Cipher.PBEWithHmacSHA1AndAES_128",
+                        "com.sun.crypto.provider.PBES2Core$HmacSHA1AndAES_128");
+
+                    put("Cipher.PBEWithHmacSHA224AndAES_128",
+                        "com.sun.crypto.provider.PBES2Core$" +
+                            "HmacSHA224AndAES_128");
+
+                    put("Cipher.PBEWithHmacSHA256AndAES_128",
+                        "com.sun.crypto.provider.PBES2Core$" +
+                            "HmacSHA256AndAES_128");
+
+                    put("Cipher.PBEWithHmacSHA384AndAES_128",
+                        "com.sun.crypto.provider.PBES2Core$" +
+                            "HmacSHA384AndAES_128");
+
+                    put("Cipher.PBEWithHmacSHA512AndAES_128",
+                        "com.sun.crypto.provider.PBES2Core$" +
+                            "HmacSHA512AndAES_128");
+
+                    put("Cipher.PBEWithHmacSHA1AndAES_256",
+                        "com.sun.crypto.provider.PBES2Core$HmacSHA1AndAES_256");
+
+                    put("Cipher.PBEWithHmacSHA224AndAES_256",
+                        "com.sun.crypto.provider.PBES2Core$" +
+                            "HmacSHA224AndAES_256");
+
+                    put("Cipher.PBEWithHmacSHA256AndAES_256",
+                        "com.sun.crypto.provider.PBES2Core$" +
+                            "HmacSHA256AndAES_256");
+
+                    put("Cipher.PBEWithHmacSHA384AndAES_256",
+                        "com.sun.crypto.provider.PBES2Core$" +
+                            "HmacSHA384AndAES_256");
+
+                    put("Cipher.PBEWithHmacSHA512AndAES_256",
+                        "com.sun.crypto.provider.PBES2Core$" +
+                            "HmacSHA512AndAES_256");
 
                     put("Cipher.Blowfish",
                         "com.sun.crypto.provider.BlowfishCipher");
@@ -301,6 +374,7 @@
                         "DiffieHellman");
                     put("Alg.Alias.KeyPairGenerator."+OID_PKCS3,
                         "DiffieHellman");
+
                     /*
                      * Algorithm parameter generation engines
                      */
@@ -371,6 +445,64 @@
                     put("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC2_40,
                         "PBEWithSHA1AndRC2_40");
 
+                    put("AlgorithmParameters.PBEWithSHA1AndRC2_128",
+                        "com.sun.crypto.provider.PBEParameters");
+                    put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS12_RC2_128,
+                        "PBEWithSHA1AndRC2_128");
+                    put("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC2_128,
+                        "PBEWithSHA1AndRC2_128");
+
+                    put("AlgorithmParameters.PBEWithSHA1AndRC4_40",
+                        "com.sun.crypto.provider.PBEParameters");
+                    put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS12_RC4_40,
+                        "PBEWithSHA1AndRC4_40");
+                    put("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC4_40,
+                        "PBEWithSHA1AndRC4_40");
+
+                    put("AlgorithmParameters.PBEWithSHA1AndRC4_128",
+                        "com.sun.crypto.provider.PBEParameters");
+                    put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS12_RC4_128,
+                        "PBEWithSHA1AndRC4_128");
+                    put("Alg.Alias.AlgorithmParameters." + OID_PKCS12_RC4_128,
+                        "PBEWithSHA1AndRC4_128");
+
+                    put("AlgorithmParameters.PBES2",
+                        "com.sun.crypto.provider.PBES2Parameters$General");
+                    put("Alg.Alias.AlgorithmParameters.OID."+OID_PKCS5_PBES2,
+                        "PBES2");
+                    put("Alg.Alias.AlgorithmParameters." + OID_PKCS5_PBES2,
+                        "PBES2");
+
+                    put("AlgorithmParameters.PBEWithHmacSHA1AndAES_128",
+                        "com.sun.crypto.provider.PBES2Parameters$HmacSHA1AndAES_128");
+
+                    put("AlgorithmParameters.PBEWithHmacSHA224AndAES_128",
+                        "com.sun.crypto.provider.PBES2Parameters$HmacSHA224AndAES_128");
+
+                    put("AlgorithmParameters.PBEWithHmacSHA256AndAES_128",
+                        "com.sun.crypto.provider.PBES2Parameters$HmacSHA256AndAES_128");
+
+                    put("AlgorithmParameters.PBEWithHmacSHA384AndAES_128",
+                        "com.sun.crypto.provider.PBES2Parameters$HmacSHA384AndAES_128");
+
+                    put("AlgorithmParameters.PBEWithHmacSHA512AndAES_128",
+                        "com.sun.crypto.provider.PBES2Parameters$HmacSHA512AndAES_128");
+
+                    put("AlgorithmParameters.PBEWithHmacSHA1AndAES_256",
+                        "com.sun.crypto.provider.PBES2Parameters$HmacSHA1AndAES_256");
+
+                    put("AlgorithmParameters.PBEWithHmacSHA224AndAES_256",
+                        "com.sun.crypto.provider.PBES2Parameters$HmacSHA224AndAES_256");
+
+                    put("AlgorithmParameters.PBEWithHmacSHA256AndAES_256",
+                        "com.sun.crypto.provider.PBES2Parameters$HmacSHA256AndAES_256");
+
+                    put("AlgorithmParameters.PBEWithHmacSHA384AndAES_256",
+                        "com.sun.crypto.provider.PBES2Parameters$HmacSHA384AndAES_256");
+
+                    put("AlgorithmParameters.PBEWithHmacSHA512AndAES_256",
+                        "com.sun.crypto.provider.PBES2Parameters$HmacSHA512AndAES_256");
+
                     put("AlgorithmParameters.Blowfish",
                         "com.sun.crypto.provider.BlowfishParameters");
 
@@ -378,6 +510,7 @@
                         "com.sun.crypto.provider.AESParameters");
                     put("Alg.Alias.AlgorithmParameters.Rijndael", "AES");
 
+
                     put("AlgorithmParameters.RC2",
                         "com.sun.crypto.provider.RC2Parameters");
 
@@ -393,6 +526,7 @@
                     put("Alg.Alias.KeyFactory.OID."+OID_PKCS3,
                         "DiffieHellman");
                     put("Alg.Alias.KeyFactory."+OID_PKCS3, "DiffieHellman");
+
                     /*
                      * Secret-key factories
                      */
@@ -441,13 +575,90 @@
                     put("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC2_40,
                         "PBEWithSHA1AndRC2_40");
 
+                    put("SecretKeyFactory.PBEWithSHA1AndRC2_128",
+                        "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC2_128"
+                        );
+                    put("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_RC2_128,
+                        "PBEWithSHA1AndRC2_128");
+                    put("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC2_128,
+                        "PBEWithSHA1AndRC2_128");
+
+                    put("SecretKeyFactory.PBEWithSHA1AndRC4_40",
+                        "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC4_40"
+                        );
+
+                    put("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_RC4_40,
+                        "PBEWithSHA1AndRC4_40");
+                    put("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC4_40,
+                        "PBEWithSHA1AndRC4_40");
+
+                    put("SecretKeyFactory.PBEWithSHA1AndRC4_128",
+                        "com.sun.crypto.provider.PBEKeyFactory$PBEWithSHA1AndRC4_128"
+                        );
+
+                    put("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS12_RC4_128,
+                        "PBEWithSHA1AndRC4_128");
+                    put("Alg.Alias.SecretKeyFactory." + OID_PKCS12_RC4_128,
+                        "PBEWithSHA1AndRC4_128");
+
+                    put("SecretKeyFactory.PBEWithHmacSHA1AndAES_128",
+                        "com.sun.crypto.provider.PBEKeyFactory$" +
+                        "PBEWithHmacSHA1AndAES_128");
+
+                    put("SecretKeyFactory.PBEWithHmacSHA224AndAES_128",
+                        "com.sun.crypto.provider.PBEKeyFactory$" +
+                        "PBEWithHmacSHA224AndAES_128");
+
+                    put("SecretKeyFactory.PBEWithHmacSHA256AndAES_128",
+                        "com.sun.crypto.provider.PBEKeyFactory$" +
+                        "PBEWithHmacSHA256AndAES_128");
+
+                    put("SecretKeyFactory.PBEWithHmacSHA384AndAES_128",
+                        "com.sun.crypto.provider.PBEKeyFactory$" +
+                        "PBEWithHmacSHA384AndAES_128");
+
+                    put("SecretKeyFactory.PBEWithHmacSHA512AndAES_128",
+                        "com.sun.crypto.provider.PBEKeyFactory$" +
+                        "PBEWithHmacSHA512AndAES_128");
+
+                    put("SecretKeyFactory.PBEWithHmacSHA1AndAES_256",
+                        "com.sun.crypto.provider.PBEKeyFactory$" +
+                        "PBEWithHmacSHA1AndAES_256");
+
+                    put("SecretKeyFactory.PBEWithHmacSHA224AndAES_256",
+                        "com.sun.crypto.provider.PBEKeyFactory$" +
+                        "PBEWithHmacSHA224AndAES_256");
+
+                    put("SecretKeyFactory.PBEWithHmacSHA256AndAES_256",
+                        "com.sun.crypto.provider.PBEKeyFactory$" +
+                        "PBEWithHmacSHA256AndAES_256");
+
+                    put("SecretKeyFactory.PBEWithHmacSHA384AndAES_256",
+                        "com.sun.crypto.provider.PBEKeyFactory$" +
+                        "PBEWithHmacSHA384AndAES_256");
+
+                    put("SecretKeyFactory.PBEWithHmacSHA512AndAES_256",
+                        "com.sun.crypto.provider.PBEKeyFactory$" +
+                        "PBEWithHmacSHA512AndAES_256");
+
+                    // PBKDF2
+
                     put("SecretKeyFactory.PBKDF2WithHmacSHA1",
-                        "com.sun.crypto.provider.PBKDF2HmacSHA1Factory");
+                        "com.sun.crypto.provider.PBKDF2Core$HmacSHA1");
                     put("Alg.Alias.SecretKeyFactory.OID." + OID_PKCS5_PBKDF2,
                         "PBKDF2WithHmacSHA1");
                     put("Alg.Alias.SecretKeyFactory." + OID_PKCS5_PBKDF2,
                         "PBKDF2WithHmacSHA1");
 
+                    put("SecretKeyFactory.PBKDF2WithHmacSHA224",
+                        "com.sun.crypto.provider.PBKDF2Core$HmacSHA224");
+                    put("SecretKeyFactory.PBKDF2WithHmacSHA256",
+                        "com.sun.crypto.provider.PBKDF2Core$HmacSHA256");
+                    put("SecretKeyFactory.PBKDF2WithHmacSHA384",
+                        "com.sun.crypto.provider.PBKDF2Core$HmacSHA384");
+                    put("SecretKeyFactory.PBKDF2WithHmacSHA512",
+                        "com.sun.crypto.provider.PBKDF2Core$HmacSHA512");
+
                     /*
                      * MAC
                      */
@@ -475,6 +686,19 @@
                     put("Mac.HmacPBESHA1",
                         "com.sun.crypto.provider.HmacPKCS12PBESHA1");
 
+                    // PBMAC1
+
+                    put("Mac.PBEWithHmacSHA1",
+                        "com.sun.crypto.provider.PBMAC1Core$HmacSHA1");
+                    put("Mac.PBEWithHmacSHA224",
+                        "com.sun.crypto.provider.PBMAC1Core$HmacSHA224");
+                    put("Mac.PBEWithHmacSHA256",
+                        "com.sun.crypto.provider.PBMAC1Core$HmacSHA256");
+                    put("Mac.PBEWithHmacSHA384",
+                        "com.sun.crypto.provider.PBMAC1Core$HmacSHA384");
+                    put("Mac.PBEWithHmacSHA512",
+                        "com.sun.crypto.provider.PBMAC1Core$HmacSHA512");
+
                     put("Mac.SslMacMD5",
                         "com.sun.crypto.provider.SslMacCore$SslMacMD5");
                     put("Mac.SslMacSHA1",
@@ -487,6 +711,10 @@
                     put("Mac.HmacSHA384 SupportedKeyFormats", "RAW");
                     put("Mac.HmacSHA512 SupportedKeyFormats", "RAW");
                     put("Mac.HmacPBESHA1 SupportedKeyFormats", "RAW");
+                    put("Mac.HmacPBESHA224 SupportedKeyFormats", "RAW");
+                    put("Mac.HmacPBESHA256 SupportedKeyFormats", "RAW");
+                    put("Mac.HmacPBESHA384 SupportedKeyFormats", "RAW");
+                    put("Mac.HmacPBESHA512 SupportedKeyFormats", "RAW");
                     put("Mac.SslMacMD5 SupportedKeyFormats", "RAW");
                     put("Mac.SslMacSHA1 SupportedKeyFormats", "RAW");
 
--- a/src/share/classes/javax/crypto/spec/PBEParameterSpec.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/src/share/classes/javax/crypto/spec/PBEParameterSpec.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, 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
@@ -41,6 +41,7 @@
 
     private byte[] salt;
     private int iterationCount;
+    private AlgorithmParameterSpec paramSpec = null;
 
     /**
      * Constructs a parameter set for password-based encryption as defined in
@@ -57,6 +58,25 @@
     }
 
     /**
+     * Constructs a parameter set for password-based encryption as defined in
+     * the PKCS #5 standard.
+     *
+     * @param salt the salt. The contents of <code>salt</code> are copied
+     * to protect against subsequent modification.
+     * @param iterationCount the iteration count.
+     * @param paramSpec the cipher algorithm parameter specification.
+     * @exception NullPointerException if <code>salt</code> is null.
+     *
+     * @since 1.8
+     */
+    public PBEParameterSpec(byte[] salt, int iterationCount,
+            AlgorithmParameterSpec paramSpec) {
+        this.salt = salt.clone();
+        this.iterationCount = iterationCount;
+        this.paramSpec = paramSpec;
+    }
+
+    /**
      * Returns the salt.
      *
      * @return the salt. Returns a new array
@@ -74,4 +94,15 @@
     public int getIterationCount() {
         return this.iterationCount;
     }
+
+    /**
+     * Returns the cipher algorithm parameter specification.
+     *
+     * @return the parameter specification, or null if none was set.
+     *
+     * @since 1.8
+     */
+    public AlgorithmParameterSpec getParameterSpec() {
+        return this.paramSpec;
+    }
 }
--- a/test/com/sun/crypto/provider/Cipher/PBE/PBEInvalidParamsTest.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/test/com/sun/crypto/provider/Cipher/PBE/PBEInvalidParamsTest.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2012, 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
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 6209660
+ * @bug 6209660 6383200
  * @summary Ensure that InvalidAlgorithmParameterException is
  * thrown as javadoc specified when parameters of the wrong
  * type are used.
@@ -38,9 +38,21 @@
 
     private static final char[] PASSWORD = { 'p', 'a', 's', 's' };
     private static final String[] PBE_ALGOS = {
-        "PBEWithMD5AndDES", "PBEWithSHA1AndDESede", "PBEWithSHA1AndRC2_40"
+        "PBEWithMD5AndDES",
+        "PBEWithSHA1AndDESede",
+        "PBEWithSHA1AndRC2_40",
+        "PBEWithSHA1AndRC2_128",
+        "PBEWithSHA1AndRC4_40",
+        "PBEWithSHA1AndRC4_128",
         // skip "PBEWithMD5AndTripleDES" since it requires Unlimited
         // version of JCE jurisdiction policy files.
+        "PBEWithHmacSHA1AndAES_128",
+        "PBEWithHmacSHA224AndAES_128",
+        "PBEWithHmacSHA256AndAES_128",
+        "PBEWithHmacSHA384AndAES_128",
+        "PBEWithHmacSHA512AndAES_128"
+        // skip "PBEWithHmacSHAxxxAndAES_256" since they require Unlimited
+        // version of JCE jurisdiction policy files.
     };
 
     private static final IvParameterSpec INVALID_PARAMS =
--- a/test/com/sun/crypto/provider/Cipher/PBE/PBEKeysAlgorithmNames.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/test/com/sun/crypto/provider/Cipher/PBE/PBEKeysAlgorithmNames.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2012, 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
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 6341599
+ * @bug 6341599 6383200
  * @summary JCE Reference Guide has recommendations, not requirements,
  * for algorithm names
  * @author Brad R. Wetmore
@@ -38,8 +38,15 @@
         "PBEWithMD5AndDES",
         "PBEWithSHA1AndDESede",
         "PBEWithSHA1AndRC2_40",
+        "PBEWithSHA1AndRC2_128",
+        "PBEWithMD5AndTripleDES",
+        "PBEWithSHA1AndRC4_40",
+        "PBEWithSHA1AndRC4_128",
         "PBKDF2WithHmacSHA1",
-        "PBEWithMD5AndTripleDES"
+        "PBKDF2WithHmacSHA224",
+        "PBKDF2WithHmacSHA256",
+        "PBKDF2WithHmacSHA384",
+        "PBKDF2WithHmacSHA512"
     };
 
     public static void main(String[] argv) throws Exception {
--- a/test/com/sun/crypto/provider/Cipher/PBE/PBEParametersTest.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/test/com/sun/crypto/provider/Cipher/PBE/PBEParametersTest.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 4944783
+ * @bug 4944783 6383200
  * @summary ensure that the AlgorithmParameters object returned by
  * PBE ciphers have the matching algorithm name.
  * @author Valerie Peng
@@ -37,9 +37,21 @@
 
     private static final char[] PASSWORD = { 'p', 'a', 's', 's' };
     private static final String[] PBE_ALGOS = {
-        "PBEWithMD5AndDES", "PBEWithSHA1AndDESede", "PBEWithSHA1AndRC2_40"
+        "PBEWithMD5AndDES",
+        "PBEWithSHA1AndDESede",
+        "PBEWithSHA1AndRC2_40",
+        "PBEWithSHA1AndRC2_128",
+        "PBEWithSHA1AndRC4_40",
+        "PBEWithSHA1AndRC4_128",
         // skip "PBEWithMD5AndTripleDES" since it requires Unlimited
         // version of JCE jurisdiction policy files.
+        "PBEWithHmacSHA1AndAES_128",
+        "PBEWithHmacSHA224AndAES_128",
+        "PBEWithHmacSHA256AndAES_128",
+        "PBEWithHmacSHA384AndAES_128",
+        "PBEWithHmacSHA512AndAES_128"
+        // skip "PBEWithHmacSHAxxxAndAES_256" since they require Unlimited
+        // version of JCE jurisdiction policy files.
     };
     public static void main(String[] args) throws Exception {
         PBEKeySpec ks = new PBEKeySpec(PASSWORD);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/crypto/provider/Cipher/PBE/PBES2Test.java	Mon Nov 05 20:18:05 2012 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 6383200
+ * @summary PBE: need new algorithm support in password based encryption
+ */
+import java.security.*;
+import java.util.Arrays;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class PBES2Test {
+
+    private static final String[] algos = {
+        "PBEWithHmacSHA1AndAES_128",
+        "PBEWithHmacSHA224AndAES_128",
+        "PBEWithHmacSHA256AndAES_128",
+        "PBEWithHmacSHA384AndAES_128",
+        "PBEWithHmacSHA512AndAES_128"
+    };
+    private static final byte[] ivBytes = {
+        0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
+        0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,
+    };
+
+    public static final void main(String[] args) throws Exception {
+        for (String algo : algos) {
+            test(algo, true);  // salt, ic, IV supplied by the application
+            test(algo, false); // salt, ic, IV generated by the implementation
+        }
+    }
+
+    private static final void test(String algo, boolean suppliedParams)
+        throws Exception {
+
+        System.out.println("***********************************************");
+        System.out.println(algo +
+            (suppliedParams ? "  [algorithm parameters are supplied]\n"
+                            : "  [algorithm parameters are generated]\n"));
+        int iterationCount = 1000;
+        byte[] salt = new byte[]{ 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 };
+
+        // Create PBE key
+        PBEKeySpec pbeKeySpec = new PBEKeySpec("mypassword".toCharArray());
+        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algo);
+        SecretKey pbeKey = keyFactory.generateSecret(pbeKeySpec);
+        byte[] pbeKeyBytes = pbeKey.getEncoded();
+        System.out.println("   key[" + pbeKeyBytes.length + "]: " +
+            String.format("0x%0" + (pbeKeyBytes.length * 2) + "x",
+                new java.math.BigInteger(1, pbeKeyBytes)));
+
+        // Create PBE cipher
+        System.out.println("Encrypting...");
+        Cipher pbeCipher = Cipher.getInstance(algo);
+        if (suppliedParams) {
+            pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey,
+                new PBEParameterSpec(salt, iterationCount,
+                    new IvParameterSpec(ivBytes)));
+        } else {
+            pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey);
+        }
+
+        // Encrypt
+        byte[] cleartext = "This is just an example".getBytes();
+        System.out.println("  text[" + cleartext.length + "]: " +
+            String.format("0x%0" + (cleartext.length * 2) + "x",
+                new java.math.BigInteger(1, cleartext)));
+
+        byte[] ciphertext = pbeCipher.doFinal(cleartext);
+        System.out.println("c'text[" + ciphertext.length + "]: " +
+            String.format("0x%0" + (ciphertext.length * 2) + "x",
+                new java.math.BigInteger(1, ciphertext)));
+
+        AlgorithmParameters aps = pbeCipher.getParameters();
+
+        byte[] iv;
+        if (suppliedParams) {
+            iv = ivBytes;
+        } else {
+            PBEParameterSpec pbeSpec =
+                aps.getParameterSpec(PBEParameterSpec.class);
+            salt = pbeSpec.getSalt();
+            iterationCount = pbeSpec.getIterationCount();
+            IvParameterSpec ivSpec =
+                (IvParameterSpec) pbeSpec.getParameterSpec();
+            iv = ivSpec.getIV();
+        }
+        System.out.println("  salt[" + salt.length + "]: " +
+            String.format("0x%0" + (salt.length * 2) + "x",
+                new java.math.BigInteger(1, salt)));
+        System.out.println("iterationCount=" + iterationCount);
+        System.out.println("    iv[" + iv.length + "]: " +
+            String.format("0x%0" + (iv.length * 2) + "x",
+                new java.math.BigInteger(1, iv)));
+
+        // Decrypt
+        System.out.println("Decrypting...");
+        Cipher pbeCipher2 = Cipher.getInstance(algo);
+        pbeCipher2.init(Cipher.DECRYPT_MODE, pbeKey, aps);
+        byte[] cleartext2 = pbeCipher2.doFinal(ciphertext);
+        System.out.println("  text[" + cleartext2.length + "]: " +
+            String.format("0x%0" + (cleartext2.length * 2) + "x",
+                new java.math.BigInteger(1, cleartext2)));
+
+        if (Arrays.equals(cleartext, cleartext2)) {
+            System.out.println(
+                "\nPass: decrypted ciphertext matches the original text\n");
+        } else {
+            throw new Exception(
+                "Fail: decrypted ciphertext does NOT match the original text");
+        }
+    }
+}
--- a/test/com/sun/crypto/provider/Cipher/PBE/PKCS12Cipher.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/test/com/sun/crypto/provider/Cipher/PBE/PKCS12Cipher.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -23,9 +23,9 @@
 
 /**
  * @test
- * @bug 4893959
- * @summary basic test for PBEWithSHA1AndDESede and
- * PBEWithSHA1AndRC2_40
+ * @bug 4893959 6383200
+ * @summary basic test for PBEWithSHA1AndDESede, PBEWithSHA1AndRC2_40/128
+ *          and PBEWithSHA1AndRC4_40/128
  * @author Valerie Peng
  */
 
@@ -87,6 +87,9 @@
         System.out.println("Testing provider " + p.getName() + "...");
         runTest("PBEWithSHA1AndDESede", input, PASSWD, p);
         runTest("PBEWithSHA1AndRC2_40", input, PASSWD, p);
+        runTest("PBEWithSHA1AndRC2_128", input, PASSWD, p);
+        runTest("PBEWithSHA1AndRC4_40", input, PASSWD, p);
+        runTest("PBEWithSHA1AndRC4_128", input, PASSWD, p);
         System.out.println("All tests passed");
         long stop = System.currentTimeMillis();
         System.out.println("Done (" + (stop - start) + " ms).");
--- a/test/com/sun/crypto/provider/Cipher/PBE/PKCS12Oid.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/test/com/sun/crypto/provider/Cipher/PBE/PKCS12Oid.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -23,9 +23,9 @@
 
 /**
  * @test
- * @bug 4898810
- * @summary ensure PBEWithSHA1AndDESede and PBEWithSHA1AndRC2_40
- * is registered under correct OID.
+ * @bug 4898810 6383200
+ * @summary ensure PBEWithSHA1AndDESede, PBEWithSHA1AndRC2_40/128
+ *          and PBEWithSHA1AndRC4_40/128 are registered under correct OID.
  * @author Valerie Peng
  */
 
@@ -37,12 +37,20 @@
 import javax.crypto.interfaces.PBEKey;
 
 public class PKCS12Oid {
-    private static String OID_PBEWithSHAAnd40BitRC2CBC = "1.2.840.113549.1.12.1.6";
-    private static String OID_PBEWithSHAAnd3KeyTripleDESCBC = "1.2.840.113549.1.12.1.3";
+    private static String OID_PKCS12 = "1.2.840.113549.1.12.1.";
+    private static String OID_PBEWithSHAAnd128BitRC4 = OID_PKCS12 + "1";
+    private static String OID_PBEWithSHAAnd40BitRC4 = OID_PKCS12 + "2";
+    private static String OID_PBEWithSHAAnd3KeyTripleDESCBC = OID_PKCS12 + "3";
+    private static String OID_PBEWithSHAAnd128BitRC2CBC = OID_PKCS12 + "5";
+    private static String OID_PBEWithSHAAnd40BitRC2CBC = OID_PKCS12 + "6";
 
     public static void main(String[] argv) throws Exception {
         Cipher c = Cipher.getInstance(OID_PBEWithSHAAnd40BitRC2CBC, "SunJCE");
         c = Cipher.getInstance(OID_PBEWithSHAAnd3KeyTripleDESCBC, "SunJCE");
+
+        c = Cipher.getInstance(OID_PBEWithSHAAnd128BitRC4, "SunJCE");
+        c = Cipher.getInstance(OID_PBEWithSHAAnd40BitRC4, "SunJCE");
+        c = Cipher.getInstance(OID_PBEWithSHAAnd128BitRC2CBC, "SunJCE");
         System.out.println("All tests passed");
     }
 }
--- a/test/com/sun/crypto/provider/Mac/HmacPBESHA1.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/test/com/sun/crypto/provider/Mac/HmacPBESHA1.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -36,34 +36,45 @@
 import javax.crypto.spec.*;
 
 public class HmacPBESHA1 {
-    private static final String MAC_ALGO = "HmacPBESHA1";
+    private static final String[] MAC_ALGOS = {
+        "HmacPBESHA1",
+        "PBEWithHmacSHA1",
+        "PBEWithHmacSHA224",
+        "PBEWithHmacSHA256",
+        "PBEWithHmacSHA384",
+        "PBEWithHmacSHA512"
+    };
+    private static final int[] MAC_LENGTHS = { 20, 20, 28, 32, 48, 64 };
     private static final String KEY_ALGO = "PBE";
     private static final String PROVIDER = "SunJCE";
 
-    private SecretKey key = null;
+    private static SecretKey key = null;
 
     public static void main(String argv[]) throws Exception {
-        HmacPBESHA1 test = new HmacPBESHA1();
-        test.run();
-        System.out.println("Test Passed");
+        for (int i = 0; i < MAC_ALGOS.length; i++) {
+            runtest(MAC_ALGOS[i], MAC_LENGTHS[i]);
+        }
+        System.out.println("\nTest Passed");
     }
 
-    public void run() throws Exception {
+    private static void runtest(String algo, int length) throws Exception {
+        System.out.println("Testing: " + algo);
         if (key == null) {
             char[] password = { 't', 'e', 's', 't' };
             PBEKeySpec keySpec = new PBEKeySpec(password);
-            SecretKeyFactory kf = SecretKeyFactory.getInstance(KEY_ALGO, PROVIDER);
+            SecretKeyFactory kf =
+                SecretKeyFactory.getInstance(KEY_ALGO, PROVIDER);
             key = kf.generateSecret(keySpec);
         }
-        Mac mac = Mac.getInstance(MAC_ALGO, PROVIDER);
+        Mac mac = Mac.getInstance(algo, PROVIDER);
         byte[] plainText = new byte[30];
 
         mac.init(key);
         mac.update(plainText);
         byte[] value1 = mac.doFinal();
-        if (value1.length != 20) {
-            throw new Exception("incorrect MAC output length, " +
-                                "expected 20, got " + value1.length);
+        if (value1.length != length) {
+            throw new Exception("incorrect MAC output length, expected " +
+                length + ", got " + value1.length);
         }
         mac.update(plainText);
         byte[] value2 = mac.doFinal();
--- a/test/com/sun/crypto/provider/Mac/HmacSaltLengths.java	Mon Nov 05 12:08:04 2012 -0500
+++ b/test/com/sun/crypto/provider/Mac/HmacSaltLengths.java	Mon Nov 05 20:18:05 2012 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
@@ -38,6 +38,15 @@
 
 public class HmacSaltLengths {
 
+    private static final String[] ALGOS = {
+        "HmacPBESHA1",
+        "PBEWithHmacSHA1",
+        "PBEWithHmacSHA224",
+        "PBEWithHmacSHA256",
+        "PBEWithHmacSHA384",
+        "PBEWithHmacSHA512"
+    };
+
     private static void runTest(String alg, byte[] plaintext,
                                 char[] password, Provider p)
         throws Exception {
@@ -81,7 +90,9 @@
         long start = System.currentTimeMillis();
         Provider p = Security.getProvider("SunJCE");
         System.out.println("Testing provider " + p.getName() + "...");
-        runTest("HmacPBESHA1", input, PASSWD, p);
+        for (String algo : ALGOS) {
+            runTest(algo, input, PASSWD, p);
+        }
         System.out.println("All tests passed");
         long stop = System.currentTimeMillis();
         System.out.println("Done (" + (stop - start) + " ms).");