1/* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 8006591 27 * @summary Protect keystore entries using stronger PBE algorithms 28 */ 29 30import java.io.*; 31import java.security.*; 32import javax.crypto.*; 33import javax.crypto.spec.*; 34 35// Retrieve a keystore entry, protected by the default encryption algorithm. 36// Set the keystore entry, protected by a stronger encryption algorithm. 37 38public class PBETest { 39 private final static String DIR = System.getProperty("test.src", "."); 40 private final static String KEY_PROTECTION_PROPERTY = 41 "keystore.PKCS12.keyProtectionAlgorithm"; 42 private static final String[] PBE_ALGOS = { 43 "PBEWithSHA1AndDESede", 44 "PBEWithHmacSHA1AndAES_128", 45 "PBEWithHmacSHA224AndAES_128", 46 "PBEWithHmacSHA256AndAES_128", 47 "PBEWithHmacSHA384AndAES_128", 48 "PBEWithHmacSHA512AndAES_128" 49 }; 50 private static final char[] PASSWORD = "passphrase".toCharArray(); 51 private static final String KEYSTORE_TYPE = "JKS"; 52 private static final String KEYSTORE = DIR + "/keystore.jks"; 53 private static final String NEW_KEYSTORE_TYPE = "PKCS12"; 54 private static final String ALIAS = "vajra"; 55 56 private static final byte[] IV = { 57 0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, 58 0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20 59 }; 60 private static final byte[] SALT = { 61 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 62 }; 63 private static final int ITERATION_COUNT = 1024; 64 65 public static void main(String[] args) throws Exception { 66 for (String algo : PBE_ALGOS) { 67 String filename = algo + ".p12"; 68 main0(algo, filename, true); 69 main0(algo, filename, false); 70 Security.setProperty(KEY_PROTECTION_PROPERTY, algo); 71 main0(null, "PBE.p12", false); 72 Security.setProperty(KEY_PROTECTION_PROPERTY, ""); 73 } 74 main0(null, "default.p12", false); // default algorithm 75 } 76 77 private static void main0(String algo, String filename, boolean useParams) 78 throws Exception { 79 80 KeyStore keystore = load(KEYSTORE_TYPE, KEYSTORE, PASSWORD); 81 KeyStore.Entry entry = 82 keystore.getEntry(ALIAS, 83 new KeyStore.PasswordProtection(PASSWORD)); 84 System.out.println("Retrieved key entry named '" + ALIAS + "'"); 85 Key originalKey = null; 86 if (entry instanceof KeyStore.PrivateKeyEntry) { 87 originalKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey(); 88 } else if (entry instanceof KeyStore.SecretKeyEntry) { 89 originalKey = ((KeyStore.SecretKeyEntry) entry).getSecretKey(); 90 } 91 92 // Set entry 93 KeyStore keystore2 = load(NEW_KEYSTORE_TYPE, null, null); 94 if (useParams) { 95 keystore2.setEntry(ALIAS, entry, 96 new KeyStore.PasswordProtection(PASSWORD, algo, 97 new PBEParameterSpec(SALT, ITERATION_COUNT, 98 new IvParameterSpec(IV)))); 99 System.out.println("Encrypted key entry using: " + algo + 100 " (with PBE parameters)"); 101 } else if (algo != null) { 102 keystore2.setEntry(ALIAS, entry, 103 new KeyStore.PasswordProtection(PASSWORD, algo, null)); 104 System.out.println("Encrypted key entry using: " + algo + 105 " (without PBE parameters)"); 106 } else { 107 keystore2.setEntry(ALIAS, entry, 108 new KeyStore.PasswordProtection(PASSWORD)); 109 String prop = Security.getProperty(KEY_PROTECTION_PROPERTY); 110 if (prop == null || prop.isEmpty()) { 111 System.out.println("Encrypted key entry using: " + 112 "default PKCS12 key protection algorithm"); 113 } else { 114 System.out.println("Encrypted key entry using: " + 115 "keyProtectionAlgorithm=" + prop); 116 } 117 } 118 119 try (FileOutputStream outStream = new FileOutputStream(filename)) { 120 System.out.println("Storing keystore to: " + filename); 121 keystore2.store(outStream, PASSWORD); 122 } 123 124 try { 125 keystore2 = load(NEW_KEYSTORE_TYPE, filename, PASSWORD); 126 entry = keystore2.getEntry(ALIAS, 127 new KeyStore.PasswordProtection(PASSWORD)); 128 Key key; 129 if (entry instanceof KeyStore.PrivateKeyEntry) { 130 key = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey(); 131 } else if (entry instanceof KeyStore.SecretKeyEntry) { 132 key = ((KeyStore.SecretKeyEntry) entry).getSecretKey(); 133 } else { 134 throw new Exception("Failed to retrieve key entry"); 135 } 136 if (originalKey.equals(key)) { 137 System.out.println("Retrieved key entry named '" + ALIAS + "'"); 138 System.out.println(); 139 } else { 140 throw new Exception( 141 "Failed: recovered key does not match the original key"); 142 } 143 144 } finally { 145 new File(filename).delete(); 146 } 147 } 148 149 private static KeyStore load(String type, String path, char[] password) 150 throws Exception { 151 KeyStore keystore = KeyStore.getInstance(type); 152 153 if (path != null) { 154 155 try (FileInputStream inStream = new FileInputStream(path)) { 156 System.out.println("Loading keystore from: " + path); 157 keystore.load(inStream, password); 158 System.out.println("Loaded keystore with " + keystore.size() + 159 " entries"); 160 } 161 } else { 162 keystore.load(null, null); 163 } 164 165 return keystore; 166 } 167} 168