--- /dev/null 2015-04-01 04:18:40.040238864 -0700 +++ new/test/javax/crypto/SecretKeyFactory/PBKDF2TranslateTest.java 2015-04-08 20:14:04.048395409 -0700 @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2003, 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.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; +import java.util.Random; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.interfaces.PBEKey; +import javax.crypto.spec.PBEKeySpec; +import javax.security.auth.DestroyFailedException; + +import static java.lang.System.out; + +/* + * @test + * @bug 8048820 + * @summary The test verifies if the SecretKeyFactory.translateKey() method + * works as expected for the PBKDF2 algorithms. + */ + +public class PBKDF2TranslateTest { + + private static final String PASS_PHRASE = "some hidden string"; + private static final int ITERATION_COUNT = 1000; + private static final int KEY_SIZE = 128; + private static final String[] TEST_ALGOS = { "PBKDF2WithHmacSHA1", + "PBKDF2WithHmacSHA224", "PBKDF2WithHmacSHA256", + "PBKDF2WithHmacSHA384", "PBKDF2WithHmacSHA512" }; + private final String algoForTest; + + public static void main(String[] args) throws Exception { + for (String algo : TEST_ALGOS) { + PBKDF2TranslateTest theTest = new PBKDF2TranslateTest(algo); + byte[] salt = new byte[8]; + new Random().nextBytes(salt); + theTest.testMyOwnSecretKey(salt); + theTest.generateAndTranslateKey(salt); + theTest.translateSpoiledKey(salt); + } + } + + public PBKDF2TranslateTest(String algo) { + algoForTest = algo; + } + + /** + * The test case scenario implemented in the method: - derive PBKDF2 key + * using the given algorithm; - translate the key - check if the translated + * and original keys have the same key value. + * + */ + public void generateAndTranslateKey(byte[] salt) + throws NoSuchAlgorithmException, InvalidKeySpecException, + InvalidKeyException { + // derive PBKDF2 key + SecretKey key1 = getSecretKeyForPBKDF2(algoForTest, salt); + + // translate key + SecretKeyFactory skf = SecretKeyFactory.getInstance(algoForTest); + SecretKey key2 = skf.translateKey(key1); + + // Check if it still the same after translation + if (!Arrays.equals(key1.getEncoded(), key2.getEncoded())) { + System.out.println("Key1=" + new String(key1.getEncoded()) + + " key2=" + new String(key2.getEncoded()) + " salt=" + + new String(salt)); + throw new RuntimeException( + "generateAndTranslateKey test case failed: the key1 and" + + " key2 values in its primary encoding format are" + + " not the same for " + algoForTest + + " algorithm."); + } + } + + /** + * The test case scenario implemented in the method: - derive Key1 for the + * given PBKDF2 algorithm - create my own secret Key2 as an instance of a + * class implements PBEKey - translate Key2 - check if the key value of the + * translated key and Key1 are the same. + */ + private void testMyOwnSecretKey(byte[] salt) + throws NoSuchAlgorithmException, InvalidKeySpecException, + InvalidKeyException { + SecretKey key1 = getSecretKeyForPBKDF2(algoForTest, salt); + SecretKey key2 = getMyOwnSecretKey(salt); + + // Is it actually the same? + if (!Arrays.equals(key1.getEncoded(), key2.getEncoded())) { + throw new RuntimeException( + "We shouldn't be here. The key1 and key2 values in its" + + " primary encoding format have to be the same!"); + } + + // translate key + SecretKeyFactory skf = SecretKeyFactory.getInstance(algoForTest); + SecretKey key3 = skf.translateKey(key2); + + // Check if it still the same after translation + if (!Arrays.equals(key1.getEncoded(), key3.getEncoded())) { + System.out.println("Key1=" + new String(key1.getEncoded()) + + " key3=" + new String(key3.getEncoded()) + " salt=" + + new String(salt)); + throw new RuntimeException( + "testMyOwnSecretKey test case failed: the key1 and key3" + + " values in its primary encoding format are not" + + " the same for " + algoForTest + " algorithm."); + } + + } + + /** + * The test case scenario implemented in the method: - create my own secret + * Key2 as an instance of a class implements PBEKey - spoil the key (set + * iteration count to 0, for example) - try to translate key - + * InvalidKeyException is expected. + */ + public void translateSpoiledKey(byte[] salt) + throws NoSuchAlgorithmException, InvalidKeySpecException { + // derive the key + SecretKey key1 = getMyOwnSecretKey(salt); + + // spoil the key + ((MyPBKDF2SecretKey) key1).spoil(); + + // translate key + SecretKeyFactory skf = SecretKeyFactory.getInstance(algoForTest); + try { + skf.translateKey(key1); + throw new RuntimeException( + "translateSpoiledKey test case failed, should throw" + + " InvalidKeyException when spoil the key"); + } catch (InvalidKeyException ike) { + out.println("Expected exception when spoil the key"); + } + + } + + /** + * Generate a PBKDF2 secret key using given algorithm. + */ + private SecretKey getSecretKeyForPBKDF2(String algoDeriveKey, byte[] salt) + throws NoSuchAlgorithmException, InvalidKeySpecException { + + SecretKeyFactory skf = SecretKeyFactory.getInstance(algoDeriveKey); + PBEKeySpec spec = new PBEKeySpec(PASS_PHRASE.toCharArray(), salt, + ITERATION_COUNT, KEY_SIZE); + + return skf.generateSecret(spec); + } + + /** + * Generate a secrete key as an instance of a class implements PBEKey. + */ + private SecretKey getMyOwnSecretKey(byte[] salt) + throws InvalidKeySpecException, NoSuchAlgorithmException { + return new MyPBKDF2SecretKey(PASS_PHRASE, algoForTest, salt, + ITERATION_COUNT, KEY_SIZE); + } + + /** + * An utility class to check the SecretKeyFactory.translateKey() method. + */ + class MyPBKDF2SecretKey implements PBEKey { + private final byte[] key; + private final byte[] salt; + private final String algorithm; + private final int keyLength; + private final String pass; + private int itereationCount; + + /** + * The key is generating by SecretKeyFactory and its value just copying + * in the key field of MySecretKey class. So, this is real key derived + * using the given algo. + */ + public MyPBKDF2SecretKey(String passPhrase, String algo, byte[] salt1, + int iterationCount, int keySize) + throws InvalidKeySpecException, NoSuchAlgorithmException { + algorithm = algo; + salt = salt1; + itereationCount = iterationCount; + pass = passPhrase; + + PBEKeySpec spec = new PBEKeySpec(passPhrase.toCharArray(), salt, + iterationCount, keySize); + + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algo); + + SecretKey realKey = keyFactory.generateSecret(spec); + + keyLength = realKey.getEncoded().length; + + key = new byte[keyLength]; + System.arraycopy(realKey.getEncoded(), 0, key, 0, keyLength); + } + + @Override + public String getAlgorithm() { + return algorithm; + } + + @Override + public String getFormat() { + return "RAW"; + } + + @Override + public byte[] getEncoded() { + byte[] copy = new byte[keyLength]; + System.arraycopy(key, 0, copy, 0, keyLength); + return copy; + } + + @Override + public int getIterationCount() { + return itereationCount; + } + + @Override + public byte[] getSalt() { + return salt; + } + + @Override + public char[] getPassword() { + return pass.toCharArray(); + } + + /** + * Spoil the generated key (before translation) to cause an + * InvalidKeyException + */ + public void spoil() { + itereationCount = -1; + } + + @Override + public void destroy() throws DestroyFailedException { + } + + @Override + public boolean isDestroyed() { + return false; + } + + } +} \ No newline at end of file --- /dev/null 2015-04-01 04:18:40.040238864 -0700 +++ new/test/javax/crypto/SecretKeyFactory/SecKFTranslateTest.java 2015-04-08 20:14:05.418395280 -0700 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2003, 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.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; +import java.util.Random; + +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; +import javax.security.auth.DestroyFailedException; + +/* + * @test + * @bug 8048820 + * @summary The test verifies SecretKey values should remain the same after + * translation with SecretKeyFactory.translateKey(). + */ + +public class SecKFTranslateTest { + private static final String SUN_JCE = "SunJCE"; + + public static void main(String[] args) throws Exception { + + SecKFTranslateTest test = new SecKFTranslateTest(); + test.run(); + } + + private void run() throws Exception { + + for (Algorithm algorithm : Algorithm.values()) { + runTest(algorithm); + } + } + + private void runTest(Algorithm algo) throws NoSuchAlgorithmException, + NoSuchProviderException, InvalidKeyException, + InvalidKeySpecException, NoSuchPaddingException, + InvalidAlgorithmParameterException, ShortBufferException, + IllegalBlockSizeException, BadPaddingException { + AlgorithmParameterSpec[] aps = new AlgorithmParameterSpec[1]; + byte[] plainText = new byte[800]; + + SecretKey key1 = algo.intSecurityKey(aps); + Random random = new Random(); + // Initialization + SecretKeyFactory skf = SecretKeyFactory.getInstance(algo.toString(), + SUN_JCE); + + random.nextBytes(plainText); + Cipher ci = Cipher.getInstance(algo.toString(), SUN_JCE); + // Encryption + ci.init(Cipher.ENCRYPT_MODE, key1, aps[0]); + byte[] cipherText = new byte[ci.getOutputSize(plainText.length)]; + int offset = ci.update(plainText, 0, plainText.length, cipherText, 0); + ci.doFinal(cipherText, offset); + // translate key + SecretKey key2 = skf.translateKey(key1); + + // Decryption + ci.init(Cipher.DECRYPT_MODE, key2, aps[0]); + byte[] recoveredText = new byte[ci.getOutputSize(plainText.length)]; + ci.doFinal(cipherText, 0, cipherText.length, recoveredText); + + // Comparison + if (!Arrays.equals(plainText, recoveredText)) { + System.out.println("Key1:" + new String(key1.getEncoded()) + + " Key2:" + new String(key2.getEncoded())); + throw new RuntimeException("Testing translate key failed with " + + algo); + } + + } +} + +class MyOwnSecKey implements SecretKey { + + private static final String DEFAULT_ALGO = "PBEWithMD5AndDES"; + private final byte[] key; + private final String algorithm; + private final int keySize; + + public MyOwnSecKey(byte[] key1, int offset, String algo) + throws InvalidKeyException { + algorithm = algo; + if (algo.equalsIgnoreCase("DES")) { + keySize = 8; + } else if (algo.equalsIgnoreCase("DESede")) { + keySize = 24; + } else { + throw new InvalidKeyException( + "Inappropriate key format and algorithm"); + } + + if (key1 == null || key1.length - offset < keySize) { + throw new InvalidKeyException("Wrong key size"); + } + key = new byte[keySize]; + System.arraycopy(key, offset, key, 0, keySize); + } + + public MyOwnSecKey(PBEKeySpec ks) throws InvalidKeySpecException { + algorithm = DEFAULT_ALGO; + key = new String(ks.getPassword()).getBytes(); + keySize = key.length; + } + + @Override + public String getAlgorithm() { + return algorithm; + } + + @Override + public String getFormat() { + return "RAW"; + } + + @Override + public byte[] getEncoded() { + byte[] copy = new byte[keySize]; + System.arraycopy(key, 0, copy, 0, keySize); + return copy; + } + + @Override + public void destroy() throws DestroyFailedException { + } + + @Override + public boolean isDestroyed() { + return false; + } +} + +enum Algorithm { + DES { + @Override + SecretKey intSecurityKey(AlgorithmParameterSpec[] spec) + throws InvalidKeyException { + int keyLength = 8; + byte[] keyVal = new byte[keyLength]; + new SecureRandom().nextBytes(keyVal); + SecretKey key1 = new MyOwnSecKey(keyVal, 0, this.toString()); + return key1; + } + }, + DESEDE { + @Override + SecretKey intSecurityKey(AlgorithmParameterSpec[] spec) + throws InvalidKeyException { + int keyLength = 24; + byte[] keyVal = new byte[keyLength]; + new SecureRandom().nextBytes(keyVal); + SecretKey key1 = new MyOwnSecKey(keyVal, 0, this.toString()); + return key1; + } + }, + PBEWithMD5ANDdes { + @Override + SecretKey intSecurityKey(AlgorithmParameterSpec[] spec) + throws InvalidKeySpecException { + byte[] salt = new byte[8]; + int iterCnt = 6; + new Random().nextBytes(salt); + spec[0] = new PBEParameterSpec(salt, iterCnt); + PBEKeySpec pbeKS = new PBEKeySpec( + new String("So far so good").toCharArray()); + SecretKey key1 = new MyOwnSecKey(pbeKS); + return key1; + } + }; + abstract SecretKey intSecurityKey(AlgorithmParameterSpec[] spec) + throws InvalidKeyException, InvalidKeySpecException; +}