--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/crypto/provider/CICO/CICOSkipTest.java Wed Sep 23 21:28:14 2015 +0000
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2007, 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.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Security;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+/*
+ * @test
+ * @bug 8048604
+ * @summary This test verifies the assertion "The skip feature of Filter
+ * streams should be supported." for feature
+ * CipherInputStream and CipherOutputStream
+ */
+public class CICOSkipTest {
+ /**
+ * Block length.
+ */
+ private static final int BLOCK = 50;
+
+ /**
+ * Saving bytes length.
+ */
+ private static final int SAVE = 45;
+
+ /**
+ * Plain text length.
+ */
+ private static final int PLAIN_TEXT_LENGTH = 800;
+
+ /**
+ * Skip reading byte size. This should be same to BLOCK - SAVE
+ */
+ private static final int DISCARD = BLOCK - SAVE;
+
+ private static final String[] ALGOS = {"DES", "DESede", "Blowfish"};
+ private static final String[] MODES = {"ECB", "CBC", "CFB", "CFB32",
+ "OFB", "OFB64", "PCBC"};
+ private static final String[] PADDINGS = {"NoPadding", "Pkcs5Padding"};
+ private static final String[] PBE_ALGOS = {"PBEWithMD5AndDES",
+ "PBEWithMD5AndDES/CBC/PKCS5Padding"};
+
+ public static void main(String[] args) throws Exception {
+ // how many kinds of padding mode such as PKCS5padding and NoPadding
+ for (String algo : ALGOS) {
+ for (String mode : MODES) {
+ int padKinds = 1;
+ if (mode.equalsIgnoreCase("ECB")
+ || mode.equalsIgnoreCase("PCBC")
+ || mode.equalsIgnoreCase("CBC")) {
+ padKinds = PADDINGS.length;
+ }
+ // PKCS5padding is meaningful only for ECB, CBC, PCBC
+ for (int k = 0; k < padKinds; k++) {
+ String info = algo + "/" + mode + "/" + PADDINGS[k];
+ try {
+ CipherGenerator cg = new CipherGenerator(algo, mode,
+ PADDINGS[k]);
+ for (ReadMethod model : ReadMethod.values()) {
+ runTest(cg.getPair(), info, model);
+ }
+ } catch (LengthLimitException exp) {
+ // skip this if this key length is larger than what's
+ // configured in the jce jurisdiction policy files
+ out.println(exp.getMessage() + " is expected.");
+ }
+ }
+ }
+ }
+ for (String pbeAlgo : PBE_ALGOS) {
+ for (ReadMethod model : ReadMethod.values()) {
+ System.out.println("Testing Algorithm : " + pbeAlgo
+ + " ReadMethod : " + model);
+ runTest(new CipherGenerator(pbeAlgo).getPair(), pbeAlgo, model);
+ }
+ }
+ }
+
+ private static void runTest(Cipher[] pair, String info, ReadMethod whichRead)
+ throws IOException {
+ byte[] plainText = TestUtilities.generateBytes(PLAIN_TEXT_LENGTH);
+ out.println("Testing: " + info + "/" + whichRead);
+ try (ByteArrayInputStream baInput = new ByteArrayInputStream(plainText);
+ CipherInputStream ciInput1 = new CipherInputStream(baInput,
+ pair[0]);
+ CipherInputStream ciInput2 = new CipherInputStream(ciInput1,
+ pair[1]);) {
+ // Skip 5 bytes after read 45 bytes and repeat until finish
+ // (Read from the input and write to the output using 2 types
+ // of buffering : byte[] and int)
+ // So output has size:
+ // (OVERALL/BLOCK)* SAVE = (800 / 50) * 45 = 720 bytes
+ int numOfBlocks = plainText.length / BLOCK;
+
+ // Output buffer.
+ byte[] outputText = new byte[numOfBlocks * SAVE];
+ int index = 0;
+ for (int i = 0; i < numOfBlocks; i++) {
+ index = whichRead.readByte(ciInput2, outputText, SAVE, index);
+ // If available is more than expected discard byte size. Skip
+ // discard bytes, otherwise try to read discard bytes by read.
+ if (ciInput2.available() >= DISCARD) {
+ ciInput2.skip(DISCARD);
+ } else {
+ for (int k = 0; k < DISCARD; k++) {
+ ciInput2.read();
+ }
+ }
+ }
+ // Verify output is same as input
+ if (!TestUtilities
+ .equalsBlockPartial(plainText, outputText, BLOCK, SAVE)) {
+ throw new RuntimeException("Test failed with compare fail");
+ }
+ }
+ }
+}
+
+class CipherGenerator {
+ /**
+ * Initialization vector length.
+ */
+ private static final int IV_LENGTH = 8;
+
+ private static final String PASSWD = "Sesame!(@#$%^&*)";
+
+ private final Cipher[] pair = new Cipher[2];
+
+ // For DES/DESede ciphers
+ CipherGenerator(String algo, String mo, String pad)
+ throws NoSuchAlgorithmException,
+ InvalidAlgorithmParameterException, InvalidKeyException,
+ NoSuchPaddingException, SecurityException, LengthLimitException {
+ // Do initialization
+ KeyGenerator kg = KeyGenerator.getInstance(algo);
+ SecretKey key = kg.generateKey();
+ if (key.getEncoded().length * 8 > Cipher.getMaxAllowedKeyLength(algo)) {
+ // skip this if this key length is larger than what's
+ // configured in the jce jurisdiction policy files
+ throw new LengthLimitException(
+ "Skip this test if key length is larger than what's"
+ + "configured in the jce jurisdiction policy files");
+ }
+ AlgorithmParameterSpec aps = null;
+ if (!mo.equalsIgnoreCase("ECB")) {
+ byte[] iv = TestUtilities.generateBytes(IV_LENGTH);
+ aps = new IvParameterSpec(iv);
+ }
+ initCiphers(algo + "/" + mo + "/" + pad, key, aps);
+ }
+
+ // For PBE ciphers
+ CipherGenerator(String algo) throws NoSuchAlgorithmException,
+ InvalidAlgorithmParameterException, InvalidKeyException,
+ NoSuchPaddingException, InvalidKeySpecException {
+ // Do initialization
+ byte[] salt = TestUtilities.generateBytes(IV_LENGTH);
+ int iterCnt = 6;
+ SecretKeyFactory skf = SecretKeyFactory.getInstance(algo.split("/")[0]);
+ SecretKey key = skf
+ .generateSecret(new PBEKeySpec(PASSWD.toCharArray()));
+ AlgorithmParameterSpec aps = new PBEParameterSpec(salt, iterCnt);
+ initCiphers(algo, key, aps);
+ }
+
+ private void initCiphers(String algo, SecretKey key,
+ AlgorithmParameterSpec aps) throws NoSuchAlgorithmException,
+ NoSuchPaddingException, InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ Provider provider = Security.getProvider("SunJCE");
+ if (provider == null) {
+ throw new RuntimeException("SunJCE provider does not exist.");
+ }
+ Cipher ci1 = Cipher.getInstance(algo, provider);
+ ci1.init(Cipher.ENCRYPT_MODE, key, aps);
+ pair[0] = ci1;
+ Cipher ci2 = Cipher.getInstance(algo, provider);
+ ci2.init(Cipher.DECRYPT_MODE, key, aps);
+ pair[1] = ci2;
+ }
+
+ Cipher[] getPair() {
+ return pair;
+ }
+}
+
+enum ReadMethod {
+ // read one byte at a time for save times
+ READ_ONE_BYTE {
+ @Override
+ int readByte(CipherInputStream ciIn2, byte[] outputText, int save,
+ int index) throws IOException {
+ for (int j = 0; j < save; j++, index++) {
+ int buffer0 = ciIn2.read();
+ if (buffer0 != -1) {
+ outputText[index] = (byte) buffer0;
+ } else {
+ break;
+ }
+ }
+ return index;
+ }
+ },
+ // read a chunk of save bytes if possible
+ READ_BLOCK {
+ @Override
+ int readByte(CipherInputStream ciIn2, byte[] outputText, int save,
+ int index) throws IOException {
+ int len1 = ciIn2.read(outputText, index, save);
+ out.println("Init: index=" + index + ",len=" + len1);
+ // read more until save bytes
+ index += len1;
+ int len2 = 0;
+ while (len1 != save && len2 != -1) {
+ len2 = ciIn2.read(outputText, index, save - len1);
+ out.println("Cont: index=" + index + ",len=" + len2);
+ len1 += len2;
+ index += len2;
+ }
+ return index;
+ }
+ };
+
+ abstract int readByte(CipherInputStream ciIn2, byte[] outputText, int save,
+ int index) throws IOException;
+};
+
+class LengthLimitException extends Exception {
+
+ public LengthLimitException(String string) {
+ super(string);
+ }
+}