changeset 11856:8680c7ebabf7

8048601: Tests for JCE crypto ciphers (part 1) Reviewed-by: valeriep
author rhalade
date Fri, 28 Aug 2015 13:35:54 -0700
parents b760ad429561
children df3c11e837ba
files test/com/sun/crypto/provider/Cipher/Blowfish/TestCipherBlowfish.java test/com/sun/crypto/provider/Cipher/DES/TestCipherDES.java test/com/sun/crypto/provider/Cipher/DES/TestCipherDESede.java test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBE.java test/com/sun/crypto/provider/Cipher/TestCipher.java test/com/sun/crypto/provider/Cipher/TextLength/DESCipherWrapper.java test/com/sun/crypto/provider/Cipher/TextLength/PBECipherWrapper.java test/com/sun/crypto/provider/Cipher/TextLength/TestCipherTextLength.java
diffstat 8 files changed, 1061 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/crypto/provider/Cipher/Blowfish/TestCipherBlowfish.java	Fri Aug 28 13:35:54 2015 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import java.security.NoSuchAlgorithmException;
+
+/*
+ * @test
+ * @bug 8048601
+ * @library ../
+ * @summary Test Blowfish cipher with different MODES and padding
+ */
+
+public class TestCipherBlowfish extends TestCipher {
+
+    TestCipherBlowfish() throws NoSuchAlgorithmException {
+        super("Blowfish",
+                new String[]{"CBC", "CTR", "CTS", "ECB", "PCBC",
+                    //CFBx
+                    "CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40", "CFB48", "CFB56",
+                    "CFB64",
+                    //OFBx
+                    "OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40", "OFB48", "OFB56",
+                    "OFB64"},
+                new String[]{"NoPaDDing", "PKCS5Padding"},
+                true);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new TestCipherBlowfish().runAll();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/crypto/provider/Cipher/DES/TestCipherDES.java	Fri Aug 28 13:35:54 2015 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 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 8048601
+ * @library ../
+ * @summary Test DES/DESede cipher with different MODES and padding
+ */
+
+public class TestCipherDES extends TestCipher {
+
+    TestCipherDES() {
+        super("DES",
+                new String[]{"CBC", "CTR", "CTS", "ECB", "PCBC",
+                    //CFBx
+                    "CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40", "CFB48", "CFB56",
+                    "CFB64",
+                    //OFBx
+                    "OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40", "OFB48", "OFB56",
+                    "OFB64"},
+                new String[]{"NoPaDDing", "PKCS5Padding"});
+    }
+
+    public static void main(String[] args) throws Exception {
+        new TestCipherDES().runAll();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/crypto/provider/Cipher/DES/TestCipherDESede.java	Fri Aug 28 13:35:54 2015 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 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 8048601
+ * @library ../
+ * @summary Test DES/DESede cipher with different MODES and padding
+ */
+
+public class TestCipherDESede extends TestCipher {
+
+    TestCipherDESede() {
+        super("DESede",
+                new String[]{"CBC", "CTR", "CTS", "ECB", "PCBC",
+                    //CFBx
+                    "CFB", "CFB8", "CFB16", "CFB24", "CFB32", "CFB40", "CFB48", "CFB56",
+                    "CFB64",
+                    //OFBx
+                    "OFB", "OFB8", "OFB16", "OFB24", "OFB32", "OFB40", "OFB48", "OFB56",
+                    "OFB64"},
+                new String[]{"NoPaDDing", "PKCS5Padding"});
+    }
+
+    public static void main(String[] args) throws Exception {
+        new TestCipherDESede().runAll();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBE.java	Fri Aug 28 13:35:54 2015 -0700
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import static java.lang.System.out;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+/*
+ * @test
+ * @bug 8048601
+ * @summary Tests for PBE ciphers
+ */
+public class TestCipherPBE {
+
+    private static final String[] ALGORITHMS = {"PBEWithMD5AndDES",
+        "PBEWithMD5AndDES/CBC/PKCS5Padding", "PBEWithMD5AndTripleDES",
+        "PBEWithMD5AndTripleDES/CBC/PKCS5Padding"};
+
+    private static final String KEY_ALGO = "pbeWithMD5ANDdes";
+    private final byte[] SALT;
+    private final byte[] PLAIN_TEXT;
+
+    public TestCipherPBE() {
+        SALT = generateBytes(8);
+        PLAIN_TEXT = generateBytes(200);
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        new TestCipherPBE().runAll();
+    }
+
+    private void runAll() throws Exception {
+        for (String algorithm : ALGORITHMS) {
+            runTest(algorithm);
+        }
+    }
+
+    private void runTest(String algorithm)
+            throws InvalidKeySpecException, NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException, ShortBufferException,
+            NoSuchPaddingException, IllegalBlockSizeException,
+            BadPaddingException, InvalidKeyException {
+
+        out.println("=> Testing: " + algorithm);
+
+        try {
+            // Initialization
+            AlgorithmParameterSpec algoParamSpec
+                    = new PBEParameterSpec(SALT, 6);
+
+            SecretKey secretKey
+                    = SecretKeyFactory.getInstance(KEY_ALGO).generateSecret(
+                    new PBEKeySpec(("Secret Key Value").toCharArray()));
+
+            Cipher ci = Cipher.getInstance(algorithm);
+            ci.init(Cipher.ENCRYPT_MODE, secretKey, algoParamSpec);
+
+            // Encryption
+            byte[] cipherText = ci.doFinal(PLAIN_TEXT);
+
+            // Decryption
+            ci.init(Cipher.DECRYPT_MODE, secretKey, algoParamSpec);
+            byte[] recoveredText = ci.doFinal(cipherText);
+
+            if (algorithm.contains("TripleDES")) {
+                throw new RuntimeException(
+                        "Expected InvalidKeyException exception uncaugh");
+            }
+
+            // Comparison
+            if (!Arrays.equals(PLAIN_TEXT, recoveredText)) {
+                throw new RuntimeException(
+                        "Test failed: plainText is not equal to recoveredText");
+            }
+            out.println("Test Passed.");
+        } catch (InvalidKeyException ex) {
+            if (algorithm.contains("TripleDES")) {
+                out.println("Expected InvalidKeyException raised");
+            } else {
+                throw new RuntimeException(ex);
+            }
+        }
+    }
+
+    public static byte[] generateBytes(int length) {
+        byte[] bytes = new byte[length];
+        for (int i = 0; i < length; i++) {
+            bytes[i] = (byte) (i & 0xff);
+        }
+        return bytes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/crypto/provider/Cipher/TestCipher.java	Fri Aug 28 13:35:54 2015 -0700
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import static java.lang.System.out;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * This is a abstract class used to test various ciphers
+ */
+public abstract class TestCipher {
+
+    private final String SUNJCE = "SunJCE";
+    private final String ALGORITHM;
+    private final String[] MODES;
+    private final String[] PADDINGS;
+
+    /* Used to test cipher with different key strengths
+       Key size tested is increment of KEYCUTTER from MINIMUM_KEY_SIZE to
+       maximum allowed keysize.
+       DES/DESede/Blowfish work with currently selected key sizes.
+    */
+    private final int variousKeySize;
+    private final int KEYCUTTER = 8;
+    private final int MINIMUM_KEY_SIZE = 32;
+
+    // Used to assert that Encryption/Decryption works with same buffer
+    // TEXT_LEN is multiple of blocks in order to work against ciphers w/ NoPadding
+    private final int TEXT_LEN = 800;
+    private final int ENC_OFFSET = 6;
+    private final int STORAGE_OFFSET = 3;
+    private final int PAD_BYTES = 16;
+
+    private final byte[] IV;
+    private final byte[] INPUT_TEXT;
+
+    TestCipher(String algo, String[] modes, String[] paddings,
+            boolean keyStrength) throws NoSuchAlgorithmException {
+        ALGORITHM = algo;
+        MODES = modes;
+        PADDINGS = paddings;
+        this.variousKeySize
+                = keyStrength ? Cipher.getMaxAllowedKeyLength(ALGORITHM) : 0;
+
+        IV = generateBytes(8);
+        INPUT_TEXT = generateBytes(TEXT_LEN + PAD_BYTES + ENC_OFFSET);
+    }
+
+    TestCipher(String algo, String[] modes, String[] paddings) {
+        ALGORITHM = algo;
+        MODES = modes;
+        PADDINGS = paddings;
+        variousKeySize = 0;
+
+        IV = generateBytes(8);
+        INPUT_TEXT = generateBytes(TEXT_LEN + PAD_BYTES + ENC_OFFSET);
+    }
+
+    private static byte[] generateBytes(int length) {
+        byte[] bytes = new byte[length];
+        for (int i = 0; i < length; i++) {
+            bytes[i] = (byte) (i & 0xff);
+        }
+        return bytes;
+    }
+
+    private boolean isKeyStrenthSupported() {
+        return (variousKeySize != 0);
+    }
+
+    public void runAll() throws InvalidKeyException,
+            NoSuchPaddingException, InvalidAlgorithmParameterException,
+            ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException, NoSuchAlgorithmException,
+            NoSuchProviderException {
+
+        for (String mode : MODES) {
+            for (String padding : PADDINGS) {
+                if (!isKeyStrenthSupported()) {
+                    runTest(mode, padding, 0);
+                } else {
+                    int keySize = variousKeySize;
+                    while (keySize >= MINIMUM_KEY_SIZE) {
+                        out.println("With Key Strength: " + keySize);
+                        runTest(mode, padding, keySize);
+                        keySize -= KEYCUTTER;
+                    }
+                }
+            }
+        }
+    }
+
+    private void runTest(String mo, String pad, int keySize)
+            throws NoSuchPaddingException, BadPaddingException,
+            ShortBufferException, IllegalBlockSizeException,
+            InvalidAlgorithmParameterException, InvalidKeyException,
+            NoSuchAlgorithmException, NoSuchProviderException {
+
+        String TRANSFORMATION = ALGORITHM + "/" + mo + "/" + pad;
+        out.println("Testing: " + TRANSFORMATION);
+
+        // Initialization
+        Cipher ci = Cipher.getInstance(TRANSFORMATION, SUNJCE);
+        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM, SUNJCE);
+        if (keySize != 0) {
+            kg.init(keySize);
+        }
+        SecretKey key = kg.generateKey();
+        SecretKeySpec skeySpec = new SecretKeySpec(key.getEncoded(), ALGORITHM);
+
+        AlgorithmParameterSpec aps = new IvParameterSpec(IV);
+        if (mo.equalsIgnoreCase("ECB")) {
+            ci.init(Cipher.ENCRYPT_MODE, key);
+        } else {
+            ci.init(Cipher.ENCRYPT_MODE, key, aps);
+        }
+
+        // Encryption
+        int PAD_LEN = 0;
+        if (pad.equalsIgnoreCase("PKCS5Padding")) {
+            // Need to consider pad bytes
+            PAD_LEN = 8;
+        }
+
+        byte[] plainText = INPUT_TEXT.clone();
+
+        // Generate cipher and save to separate buffer
+        byte[] cipherText = ci.doFinal(INPUT_TEXT, ENC_OFFSET, TEXT_LEN);
+
+        // Generate cipher and save to same buffer
+        int offset = ci.update(
+                INPUT_TEXT, ENC_OFFSET, TEXT_LEN, INPUT_TEXT, STORAGE_OFFSET);
+        ci.doFinal(INPUT_TEXT, offset + STORAGE_OFFSET);
+
+        if (!equalsBlock(
+                INPUT_TEXT, STORAGE_OFFSET, cipherText, 0, cipherText.length)) {
+            throw new RuntimeException(
+                    "Different ciphers generated with same buffer");
+        }
+
+        // Decryption
+        if (mo.equalsIgnoreCase("ECB")) {
+            ci.init(Cipher.DECRYPT_MODE, skeySpec);
+        } else {
+            ci.init(Cipher.DECRYPT_MODE, skeySpec, aps);
+        }
+
+        // Recover text from cipher and save to separate buffer
+        byte[] recoveredText = ci.doFinal(cipherText, 0, cipherText.length);
+
+        if (!equalsBlock(
+                plainText, ENC_OFFSET, recoveredText, 0,
+                recoveredText.length)) {
+            throw new RuntimeException(
+                    "Recovered text not same as plain text");
+        } else {
+            out.println("Recovered and plain text are same");
+        }
+
+        // Recover text from cipher and save to same buffer
+        ci.update(INPUT_TEXT, STORAGE_OFFSET, TEXT_LEN + PAD_LEN, INPUT_TEXT,
+                ENC_OFFSET);
+        ci.doFinal(INPUT_TEXT, ENC_OFFSET);
+
+        if (!equalsBlock(
+                plainText, ENC_OFFSET, recoveredText, 0,
+                recoveredText.length)) {
+            throw new RuntimeException(
+                    "Recovered text not same as plain text with same buffer");
+        } else {
+            out.println("Recovered and plain text are same with same buffer");
+        }
+
+        out.println("Test Passed.");
+    }
+
+    private static boolean equalsBlock(byte[] b1, int off1, byte[] b2, int off2,
+            int len) {
+        for (int i = off1, j = off2, k = 0; k < len; i++, j++, k++) {
+            if (b1[i] != b2[j]) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/crypto/provider/Cipher/TextLength/DESCipherWrapper.java	Fri Aug 28 13:35:54 2015 -0700
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import static java.lang.System.out;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * Wrapper class to test a given DES algorithm.
+ */
+public class DESCipherWrapper {
+
+    private final Cipher ci;
+    private final byte[] iv;
+    private final SecretKey key;
+    private final String algo;
+    private final String mode;
+    private final String pad;
+    private final int keyStrength;
+    private byte[] resultText = null;
+
+    public DESCipherWrapper(String algo, String mode, String pad)
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+        ci = Cipher.getInstance(algo + "/" + mode + "/" + pad);
+
+        iv = new byte[8];
+        for (int i = 0; i < 8; i++) {
+            iv[i] = (byte) (i & 0xff);
+        }
+
+        KeyGenerator kg = KeyGenerator.getInstance(algo);
+        key = kg.generateKey();
+        keyStrength = algo.equalsIgnoreCase("DESede") ? 112
+                : key.getEncoded().length * 8;
+
+        this.algo = algo;
+        this.mode = mode;
+        this.pad = pad;
+    }
+
+    public byte[] getResult() {
+        return resultText.clone();
+    }
+
+    public void execute(int edMode, byte[] inputText)
+            throws InvalidKeyException, InvalidAlgorithmParameterException,
+            IllegalBlockSizeException, BadPaddingException,
+            ShortBufferException, NoSuchAlgorithmException {
+        AlgorithmParameterSpec aps = null;
+
+        try {
+            if (!mode.equalsIgnoreCase("ECB")) {
+                aps = new IvParameterSpec(iv);
+            }
+            ci.init(edMode, key, aps);
+
+            // Generate a resultText using a single-part enc/dec
+            resultText = ci.doFinal(inputText);
+
+            // Generate outputText for each multi-part en/de-cryption
+            /* Combination #1:
+            update(byte[], int, int)
+            doFinal(byte[], int, int)
+             */
+            byte[] part11 = ci.update(inputText, 0, inputText.length);
+            byte[] part12 = ci.doFinal();
+            byte[] outputText1 = new byte[part11.length + part12.length];
+            System.arraycopy(part11, 0, outputText1, 0, part11.length);
+            System.arraycopy(part12, 0, outputText1, part11.length,
+                    part12.length);
+
+            List<byte[]> outputTexts = new ArrayList<>(4);
+            outputTexts.add(outputText1);
+
+            /* Combination #2:
+            update(byte[], int, int)
+            doFinal(byte[], int, int, byte[], int)
+             */
+            byte[] part21 = ci.update(inputText, 0, inputText.length - 5);
+            byte[] part22 = new byte[ci.getOutputSize(inputText.length)];
+            int len2 = ci
+                    .doFinal(inputText, inputText.length - 5, 5, part22, 0);
+            byte[] outputText2 = new byte[part21.length + len2];
+            System.arraycopy(part21, 0, outputText2, 0, part21.length);
+            System.arraycopy(part22, 0, outputText2, part21.length, len2);
+
+            outputTexts.add(outputText2);
+
+            /* Combination #3:
+            update(byte[], int, int, byte[], int)
+            doFinal(byte[], int, int)
+             */
+            byte[] part31 = new byte[ci.getOutputSize(inputText.length)];
+            int len3 = ci.update(inputText, 0, inputText.length - 8, part31, 0);
+            byte[] part32 = ci.doFinal(inputText, inputText.length - 8, 8);
+            byte[] outputText3 = new byte[len3 + part32.length];
+            System.arraycopy(part31, 0, outputText3, 0, len3);
+            System.arraycopy(part32, 0, outputText3, len3, part32.length);
+
+            outputTexts.add(outputText3);
+
+            /* Combination #4:
+            update(byte[], int, int, byte[], int)
+            doFinal(byte[], int, int, byte[], int)
+             */
+            byte[] part41 = new byte[ci.getOutputSize(inputText.length)];
+            int len4 = ci.update(inputText, 0, inputText.length - 8, part41, 0);
+            int rest4 = ci.doFinal(inputText, inputText.length - 8, 8, part41,
+                    len4);
+            byte[] outputText4 = new byte[len4 + rest4];
+            System.arraycopy(part41, 0, outputText4, 0, outputText4.length);
+
+            outputTexts.add(outputText4);
+
+            // Compare results
+            for (int k = 0; k < outputTexts.size(); k++) {
+                if (!Arrays.equals(resultText, outputTexts.get(k))) {
+                    out.println(" Testing: " + algo + "/" + mode + "/" + pad);
+                    throw new RuntimeException(
+                            "Compare value of resultText and combination " + k
+                            + " are not same. Test failed.");
+                }
+            }
+            if (keyStrength > Cipher.getMaxAllowedKeyLength(algo)) {
+                throw new RuntimeException(
+                        "Expected exception uncaught, keyStrength "
+                        + keyStrength);
+            }
+        } catch (InvalidKeyException ex) {
+            if (keyStrength <= Cipher.getMaxAllowedKeyLength(algo)) {
+                out.println("Unexpected exception in " + algo + "/" + mode
+                        + "/" + pad + " ,  KeySize " + keyStrength);
+                throw ex;
+            }
+            out.println("Caught InvalidKeyException as expected");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/crypto/provider/Cipher/TextLength/PBECipherWrapper.java	Fri Aug 28 13:35:54 2015 -0700
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * PBECipherWrapper is the abstract class for all concrete PBE Cipher wrappers.
+ */
+public abstract class PBECipherWrapper {
+
+    public static final int ITERATION_COUNT = 1000;
+    private final String algorithm;
+    private final byte[] salt;
+    protected SecretKey key;
+    protected Cipher ci;
+    protected String baseAlgo;
+    protected byte[] resultText = null;
+    protected AlgorithmParameterSpec aps = null;
+
+    public PBECipherWrapper(String algorithm, int saltSize) {
+        this.algorithm = algorithm;
+        baseAlgo = algorithm.split("/")[0].toUpperCase();
+        salt = generateSalt(saltSize);
+    }
+
+    protected abstract void initCipher(int mode) throws InvalidKeyException,
+            InvalidAlgorithmParameterException, InvalidParameterSpecException;
+
+    public void execute(int edMode, byte[] inputText)
+            throws InvalidAlgorithmParameterException,
+            InvalidParameterSpecException, IllegalBlockSizeException,
+            BadPaddingException, ShortBufferException, InvalidKeyException {
+        // Initialize
+        initCipher(edMode);
+
+        // Generate a resultText using a single-part enc/dec
+        resultText = ci.doFinal(inputText);
+
+        // Generate outputText for each multi-part en/de-cryption
+        /* Combination #1:
+        update(byte[], int, int)
+        doFinal(byte[], int, int)
+         */
+        byte[] part11 = ci.update(inputText, 0, inputText.length);
+        byte[] part12 = ci.doFinal();
+        byte[] outputText1 = new byte[part11.length + part12.length];
+        System.arraycopy(part11, 0, outputText1, 0, part11.length);
+        System.arraycopy(part12, 0, outputText1, part11.length, part12.length);
+
+        List<byte[]> outputTexts = new ArrayList<>(4);
+        outputTexts.add(outputText1);
+
+        /* Combination #2:
+        update(byte[], int, int)
+        doFinal(byte[], int, int, byte[], int)
+         */
+        byte[] part21 = ci.update(inputText, 0, inputText.length - 5);
+        byte[] part22 = new byte[ci.getOutputSize(inputText.length)];
+        int len2 = ci.doFinal(inputText, inputText.length - 5, 5, part22, 0);
+        byte[] outputText2 = new byte[part21.length + len2];
+        System.arraycopy(part21, 0, outputText2, 0, part21.length);
+        System.arraycopy(part22, 0, outputText2, part21.length, len2);
+
+        outputTexts.add(outputText2);
+
+        /* Combination #3:
+        update(byte[], int, int, byte[], int)
+        doFinal(byte[], int, int)
+         */
+        byte[] part31 = new byte[ci.getOutputSize(inputText.length)];
+        int len3 = ci.update(inputText, 0, inputText.length - 8, part31, 0);
+        byte[] part32 = ci.doFinal(inputText, inputText.length - 8, 8);
+        byte[] outputText3 = new byte[len3 + part32.length];
+        System.arraycopy(part31, 0, outputText3, 0, len3);
+        System.arraycopy(part32, 0, outputText3, len3, part32.length);
+
+        outputTexts.add(outputText3);
+
+        /* Combination #4:
+        update(byte[], int, int, byte[], int)
+        doFinal(byte[], int, int, byte[], int)
+         */
+        byte[] part41 = new byte[ci.getOutputSize(inputText.length)];
+        int len4 = ci.update(inputText, 0, inputText.length - 8, part41, 0);
+        int rest4 = ci
+                .doFinal(inputText, inputText.length - 8, 8, part41, len4);
+        byte[] outputText4 = new byte[len4 + rest4];
+        System.arraycopy(part41, 0, outputText4, 0, outputText4.length);
+
+        outputTexts.add(outputText4);
+
+        // Compare results
+        for (int k = 0; k < outputTexts.size(); k++) {
+            if (!Arrays.equals(resultText, outputTexts.get(k))) {
+                throw new RuntimeException(
+                        "Compare value of resultText and combination " + k
+                        + " are not same. Test failed.");
+            }
+        }
+
+    }
+
+    public final byte[] generateSalt(int numberOfBytes) {
+        byte[] aSalt = new byte[numberOfBytes];
+        for (int i = 0; i < numberOfBytes; i++) {
+            aSalt[i] = (byte) (i & 0xff);
+        }
+        return aSalt;
+    }
+
+    public byte[] getResult() {
+        return resultText;
+    }
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    public byte[] getSalt() {
+        return salt;
+    }
+
+    /**
+     * Wrapper class to test a given SecretKeyFactory.PBKDF2 algorithm.
+     */
+    public static class PBKDF2 extends PBECipherWrapper {
+
+        private static final int PBKDF2_SALT_SIZE = 64;
+        private static final int CIPHER_KEY_SIZE = 128;
+        private static final String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding";
+        private static final String KEY_ALGORITHM = "AES";
+        private byte[] iv = null;
+
+        public PBKDF2(String algo, String passwd)
+                throws InvalidKeySpecException, NoSuchAlgorithmException,
+                NoSuchPaddingException {
+            super(algo, PBKDF2_SALT_SIZE);
+
+            ci = Cipher.getInstance(CIPHER_TRANSFORMATION);
+
+            PBEKeySpec pbeKeySpec = new PBEKeySpec(passwd.toCharArray(), getSalt(),
+                    ITERATION_COUNT, CIPHER_KEY_SIZE);
+            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algo);
+            key = keyFactory.generateSecret(pbeKeySpec);
+        }
+
+        @Override
+        protected void initCipher(int mode) throws InvalidKeyException,
+                InvalidAlgorithmParameterException, InvalidParameterSpecException {
+            if (Cipher.ENCRYPT_MODE == mode) {
+                ci.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getEncoded(),
+                        KEY_ALGORITHM));
+                iv = ci.getParameters().getParameterSpec(IvParameterSpec.class)
+                        .getIV();
+            } else {
+                ci.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getEncoded(),
+                        KEY_ALGORITHM), new IvParameterSpec(iv));
+            }
+        }
+    }
+
+    /**
+     * Wrapper class to test a given AES-based PBE algorithm.
+     */
+    public static class AES extends PBECipherWrapper {
+
+        private AlgorithmParameters pbeParams;
+
+        public AES(String algo, String passwd)
+                throws NoSuchAlgorithmException, NoSuchPaddingException,
+                InvalidKeySpecException {
+            super(algo, 0);
+
+            ci = Cipher.getInstance(algo);
+
+            SecretKeyFactory skf = SecretKeyFactory.getInstance(algo);
+            key = skf.generateSecret(new PBEKeySpec(passwd.toCharArray()));
+        }
+
+        @Override
+        protected void initCipher(int mode) throws InvalidKeyException,
+                InvalidAlgorithmParameterException, InvalidParameterSpecException {
+            if (Cipher.ENCRYPT_MODE == mode) {
+                ci.init(Cipher.ENCRYPT_MODE, key);
+                pbeParams = ci.getParameters();
+            } else {
+                ci.init(Cipher.DECRYPT_MODE, key, pbeParams);
+            }
+        }
+    }
+
+    /**
+     * Wrapper class to test a given PBE algorithm.
+     */
+    public static class Legacy extends PBECipherWrapper {
+
+        private static final int PBE_SALT_SIZE = 8;
+
+        public Legacy(String algo, String passwd)
+                throws NoSuchAlgorithmException, NoSuchPaddingException,
+                InvalidKeySpecException {
+            super(algo, PBE_SALT_SIZE);
+
+            SecretKeyFactory skf = SecretKeyFactory.getInstance(algo.split("/")[0]);
+            key = skf.generateSecret(new PBEKeySpec(passwd.toCharArray()));
+
+            aps = new PBEParameterSpec(getSalt(), ITERATION_COUNT);
+
+            ci = Cipher.getInstance(algo);
+        }
+
+        @Override
+        protected void initCipher(int mode) throws InvalidKeyException,
+                InvalidAlgorithmParameterException, InvalidParameterSpecException {
+            ci.init(mode, key, aps);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/com/sun/crypto/provider/Cipher/TextLength/TestCipherTextLength.java	Fri Aug 28 13:35:54 2015 -0700
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+import static java.lang.System.out;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+
+/*
+ * @test
+ * @bug 8048601
+ * @summary Performs multiple-part encryption/decryption depending on the
+ *  specified encryption mode and check if the results obtained by
+ *  different ways are the same.
+ */
+public class TestCipherTextLength {
+
+    /* Algorithms tested by DESCipherWrapper */
+    private static final String[] DES_ALGORITHMS = {"DES", "DESede",
+        "Blowfish"};
+    private static final String[] DES_MODES = {"ECB", "CBC", "PCBC"};
+    private static final String[] DES_PADDING = {"PKCS5Padding"};
+
+    /* Algorithms tested by PBECipherWrapper */
+    private static final String[] PBE_ALGORITHMS = {"PBEWithMD5AndDES",
+        "PBEWithMD5AndDES/CBC/PKCS5Padding", "PBEWithMD5ANDTripleDES",
+        "PBEWithMD5AndTripleDES/CBC/PKCS5Padding", "PBEwithSHA1AndDESede",
+        "PBEwithSHA1AndDESede/CBC/PKCS5Padding", "PBEwithSHA1AndRC2_40",
+        "PBEwithSHA1Andrc2_40/CBC/PKCS5Padding", "PBEWithSHA1AndRC2_128",
+        "PBEWithSHA1andRC2_128/CBC/PKCS5Padding", "PBEWithSHA1AndRC4_40",
+        "PBEWithsha1AndRC4_40/ECB/NoPadding", "PBEWithSHA1AndRC4_128",
+        "PBEWithSHA1AndRC4_128/ECB/NoPadding", "PBEWithHmacSHA1AndAES_128",
+        "PBEWithHmacSHA224AndAES_128", "PBEWithHmacSHA256AndAES_128",
+        "PBEWithHmacSHA384AndAES_128", "PBEWithHmacSHA512AndAES_128",
+        "PBEWithHmacSHA1AndAES_256", "PBEWithHmacSHA224AndAES_256",
+        "PBEWithHmacSHA256AndAES_256", "PBEWithHmacSHA384AndAES_256",
+        "PBEWithHmacSHA512AndAES_256", "PBKDF2WithHmacSHA1",
+        "PBKDF2WithHmacSHA224", "PBKDF2WithHmacSHA256",
+        "PBKDF2WithHmacSHA384", "PBKDF2WithHmacSHA512"};
+    private static final String PBE_PASSWORD = "Hush, it's a secret!!";
+
+    // Algorithm tested by PBKDF2Wrappter
+    private static final String PBKDF2 = "PBKDF2";
+
+    // Algorithm tested by AESPBEWrapper
+    private static final String AES = "AES";
+
+    public static void main(String[] args) throws Exception {
+        byte[] plainText = new byte[64];
+        for (int i = 0; i < 64; i++) {
+            plainText[i] = (byte) (i & 0xff);
+        }
+
+        new TestCipherTextLength().runAll(plainText);
+    }
+
+    public void runAll(byte[] plainText) throws Exception {
+
+        // Testing DES/Blowfish Cipher
+        for (String algorithm : DES_ALGORITHMS) {
+            for (String desMode : DES_MODES) {
+                for (String padding : DES_PADDING) {
+                    out.println("=>Testing: " + algorithm + "/" + desMode
+                            + "/" + padding);
+                    DESCipherWrapper desCi = new DESCipherWrapper(algorithm,
+                            desMode, padding);
+                    desCi.execute(Cipher.ENCRYPT_MODE, plainText);
+                    desCi.execute(Cipher.DECRYPT_MODE, desCi.getResult());
+                    if (!Arrays.equals(plainText, desCi.getResult())) {
+                        throw new RuntimeException(
+                                "Plain and recovered texts are not same for:"
+                                + algorithm + "/" + desMode + "/"
+                                + padding);
+                    }
+                }
+            }
+        }
+
+        // Testing PBE Cipher
+        for (String algorithm : PBE_ALGORITHMS) {
+            int maxKeyLen = Cipher.getMaxAllowedKeyLength(algorithm);
+            boolean isUnlimited = maxKeyLen == Integer.MAX_VALUE;
+            if (!isUnlimited
+                    && (algorithm.contains("TripleDES") || algorithm
+                    .contains("AES_256"))) {
+                out.println("Test " + algorithm + " will be ignored");
+                continue;
+            }
+
+            out.println("=>Testing: " + algorithm);
+            PBECipherWrapper pbeCi = createWrapper(algorithm, PBE_PASSWORD);
+            pbeCi.execute(Cipher.ENCRYPT_MODE, plainText);
+            pbeCi.execute(Cipher.DECRYPT_MODE, pbeCi.getResult());
+            if (!Arrays.equals(plainText, pbeCi.getResult())) {
+                throw new RuntimeException(
+                        "Plain and recovered texts are not same for:"
+                        + algorithm);
+            }
+        }
+    }
+
+    private PBECipherWrapper createWrapper(String algo, String passwd)
+            throws InvalidKeySpecException, NoSuchAlgorithmException,
+            NoSuchPaddingException {
+        if (algo.contains(PBKDF2)) {
+            return new PBECipherWrapper.PBKDF2(algo, passwd);
+        } else if (algo.contains(AES)) {
+            return new PBECipherWrapper.AES(algo, passwd);
+        } else {
+            return new PBECipherWrapper.Legacy(algo, passwd);
+        }
+    }
+}