1/* 2 * Copyright (c) 2015, 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 24import static java.lang.System.out; 25 26import java.lang.Integer; 27import java.lang.String; 28import java.lang.System; 29import java.security.AlgorithmParameters; 30import java.security.InvalidAlgorithmParameterException; 31import java.security.InvalidKeyException; 32import java.security.Key; 33import java.security.KeyPair; 34import java.security.NoSuchAlgorithmException; 35import java.security.KeyPairGenerator; 36import java.security.Provider; 37import java.security.Security; 38import java.security.spec.AlgorithmParameterSpec; 39import java.security.spec.InvalidKeySpecException; 40import java.util.Arrays; 41import java.util.HashMap; 42import java.util.Map; 43import java.util.Random; 44 45import javax.crypto.IllegalBlockSizeException; 46import javax.crypto.NoSuchPaddingException; 47import javax.crypto.SecretKey; 48import javax.crypto.Cipher; 49import javax.crypto.KeyGenerator; 50import javax.crypto.SecretKeyFactory; 51import javax.crypto.spec.PBEKeySpec; 52import javax.crypto.spec.PBEParameterSpec; 53 54/* 55 * @test 56 * @bug 8048599 57 * @summary Tests for key wrap and unwrap operations 58 */ 59 60public class TestCipherKeyWrapperTest { 61 private static final String SUN_JCE = "SunJCE"; 62 // Blowfish Variable key length: 32 bits to 448 bits 63 private static final int BLOWFISH_MIN_KEYSIZE = 32; 64 private static final int BLOWFISH_MAX_KEYSIZE = 448; 65 private static final int LINIMITED_KEYSIZE = 128; 66 private static final String NOPADDING = "NoPaDDing"; 67 private static final String[] PBE_ALGORITHM_AR = { "pbeWithMD5ANDdes", 68 "PBEWithMD5AndDES/CBC/PKCS5Padding", "PBEWithMD5AndTripleDES", 69 "PBEWithMD5AndTripleDES/CBC/PKCS5Padding", "PBEwithSHA1AndDESede", 70 "PBEwithSHA1AndDESede/CBC/PKCS5Padding", "PBEwithSHA1AndRC2_40", 71 "PBEwithSHA1Andrc2_40/CBC/PKCS5Padding", "PBEWithSHA1AndRC2_128", 72 "PBEWithSHA1andRC2_128/CBC/PKCS5Padding", "PBEWithSHA1AndRC4_40", 73 "PBEWithsha1AndRC4_40/ECB/NoPadding", "PBEWithSHA1AndRC4_128", 74 "pbeWithSHA1AndRC4_128/ECB/NoPadding", "PBEWithHmacSHA1AndAES_128", 75 "PBEWithHmacSHA224AndAES_128", "PBEWithHmacSHA256AndAES_128", 76 "PBEWithHmacSHA384AndAES_128", "PBEWithHmacSHA512AndAES_128", 77 "PBEWithHmacSHA1AndAES_256", "PBEWithHmacSHA224AndAES_256", 78 "PBEWithHmacSHA256AndAES_256", "PBEWithHmacSHA384AndAES_256", 79 "PBEWithHmacSHA512AndAES_256" }; 80 private static final String[] MODEL_AR = { "ECb", "pCbC", "cbC", "cFB", 81 "cFB24", "cFB40", "OfB48", "OFB64" }; 82 private static final String[] PADDING_AR = { NOPADDING, "PKCS5Padding" }; 83 84 private enum AlgorithmWrapper { 85 AESWrap("AES", "AESWrap", -1), 86 AESWrap_128("AES", "AESWrap_128", 128), 87 AESWrap_192("AES", "AESWrap_192", 192), 88 AESWrap_256("AES", "AESWrap_256", 256), 89 DESedeWrap("desede", "DESedeWrap", -1), 90 NegtiveWrap("AES", "DESedeWrap", -1); 91 92 private final String algorithm; 93 private final String wrapper; 94 private final int keySize; 95 96 private AlgorithmWrapper(String algorithm, String wrapper, int kSize) { 97 this.algorithm = algorithm; 98 this.wrapper = wrapper; 99 this.keySize = kSize; 100 } 101 102 public String getAlgorithm() { 103 return algorithm; 104 } 105 106 public String getWrapper() { 107 return wrapper; 108 } 109 110 public int getKeySize() { 111 return keySize; 112 } 113 114 }; 115 116 public static void main(String[] args) throws Exception { 117 118 TestCipherKeyWrapperTest test = new TestCipherKeyWrapperTest(); 119 // AESWrap and DESedeWrap test 120 for (AlgorithmWrapper algoWrapper : AlgorithmWrapper.values()) { 121 String algo = algoWrapper.getAlgorithm(); 122 String wrapper = algoWrapper.getWrapper(); 123 try { 124 int keySize = algoWrapper.getKeySize(); 125 // only run the tests on longer key lengths if unlimited 126 // version of JCE jurisdiction policy files are installed 127 if (!(Cipher.getMaxAllowedKeyLength(algo) == Integer.MAX_VALUE) 128 && keySize > LINIMITED_KEYSIZE) { 129 out.println(algo + " will not run if unlimited version of" 130 + " JCE jurisdiction policy files are installed"); 131 continue; 132 } 133 test.wrapperAesDESedeKeyTest(algo, wrapper, keySize); 134 if (algoWrapper == AlgorithmWrapper.NegtiveWrap) { 135 throw new RuntimeException("Expected not throw when algo" 136 + " and wrapAlgo are not match:" + algo); 137 } 138 } catch (InvalidKeyException e) { 139 if (algoWrapper == AlgorithmWrapper.NegtiveWrap) { 140 out.println("Expepted exception when algo" 141 + " and wrapAlgo are not match:" + algo); 142 } else { 143 throw e; 144 } 145 } 146 } 147 test.wrapperBlowfishKeyTest(); 148 // PBE and public wrapper test. 149 String[] publicPrivateAlgos = new String[] { "DiffieHellman", "DSA", 150 "RSA" }; 151 Provider provider = Security.getProvider(SUN_JCE); 152 if (provider == null) { 153 throw new RuntimeException("SUN_JCE provider not exist"); 154 } 155 156 test.wrapperPBEKeyTest(provider); 157 // Public and private key wrap test 158 test.wrapperPublicPriviteKeyTest(provider, publicPrivateAlgos); 159 } 160 161 private void wrapperAesDESedeKeyTest(String algo, String wrapAlgo, 162 int keySize) throws InvalidKeyException, NoSuchAlgorithmException, 163 NoSuchPaddingException, IllegalBlockSizeException, 164 InvalidAlgorithmParameterException { 165 // Initialization 166 KeyGenerator kg = KeyGenerator.getInstance(algo); 167 if (keySize != -1) { 168 kg.init(keySize); 169 } 170 SecretKey key = kg.generateKey(); 171 wrapTest(algo, wrapAlgo, key, key, Cipher.SECRET_KEY, false); 172 } 173 174 private void wrapperBlowfishKeyTest() throws InvalidKeyException, 175 NoSuchAlgorithmException, NoSuchPaddingException, 176 IllegalBlockSizeException, InvalidAlgorithmParameterException { 177 // how many kinds of padding mode 178 int padKinds; 179 // Keysize should be multiple of 8 bytes. 180 int KeyCutter = 8; 181 int kSize = BLOWFISH_MIN_KEYSIZE; 182 String algorithm = "Blowfish"; 183 int maxAllowKeyLength = Cipher.getMaxAllowedKeyLength(algorithm); 184 boolean unLimitPolicy = maxAllowKeyLength == Integer.MAX_VALUE; 185 SecretKey key = null; 186 while (kSize <= BLOWFISH_MAX_KEYSIZE) { 187 for (String mode : MODEL_AR) { 188 // PKCS5padding is meaningful only for ECB, CBC, PCBC 189 if (mode.equalsIgnoreCase(MODEL_AR[0]) 190 || mode.equalsIgnoreCase(MODEL_AR[1]) 191 || mode.equalsIgnoreCase(MODEL_AR[2])) { 192 padKinds = PADDING_AR.length; 193 } else { 194 padKinds = 1; 195 } 196 // Initialization 197 KeyGenerator kg = KeyGenerator.getInstance(algorithm); 198 for (int k = 0; k < padKinds; k++) { 199 String transformation = algorithm + "/" + mode + "/" 200 + PADDING_AR[k]; 201 if (NOPADDING.equals(PADDING_AR[k]) && kSize % 64 != 0) { 202 out.println(transformation 203 + " will not run if input length not multiple" 204 + " of 8 bytes when padding is " + NOPADDING); 205 continue; 206 } 207 kg.init(kSize); 208 key = kg.generateKey(); 209 // only run the tests on longer key lengths if unlimited 210 // version of JCE jurisdiction policy files are installed 211 if (!unLimitPolicy && kSize > LINIMITED_KEYSIZE) { 212 out.println("keyStrength > 128 within " + algorithm 213 + " will not run under global policy"); 214 } else { 215 wrapTest(transformation, transformation, key, key, 216 Cipher.SECRET_KEY, false); 217 } 218 } 219 } 220 if (kSize <= LINIMITED_KEYSIZE) { 221 KeyCutter = 8; 222 } else { 223 KeyCutter = 48; 224 } 225 kSize += KeyCutter; 226 } 227 } 228 229 private void wrapperPBEKeyTest(Provider p) throws InvalidKeySpecException, 230 InvalidKeyException, NoSuchPaddingException, 231 IllegalBlockSizeException, InvalidAlgorithmParameterException, 232 NoSuchAlgorithmException { 233 for (String alg : PBE_ALGORITHM_AR) { 234 String baseAlgo = alg.split("/")[0].toUpperCase(); 235 // only run the tests on longer key lengths if unlimited version 236 // of JCE jurisdiction policy files are installed 237 238 if (Cipher.getMaxAllowedKeyLength(alg) < Integer.MAX_VALUE 239 && (baseAlgo.endsWith("TRIPLEDES") || alg 240 .endsWith("AES_256"))) { 241 out.println("keyStrength > 128 within " + alg 242 + " will not run under global policy"); 243 continue; 244 } 245 SecretKeyFactory skf = SecretKeyFactory.getInstance(baseAlgo, p); 246 SecretKey key = skf.generateSecret(new PBEKeySpec("Secret Lover" 247 .toCharArray())); 248 wrapTest(alg, alg, key, key, Cipher.SECRET_KEY, true); 249 } 250 } 251 252 private void wrapperPublicPriviteKeyTest(Provider p, String[] algorithms) 253 throws NoSuchAlgorithmException, InvalidKeyException, 254 NoSuchPaddingException, IllegalBlockSizeException, 255 InvalidAlgorithmParameterException { 256 for (String algo : algorithms) { 257 // Key pair generated 258 System.out.println("Generate key pair (algorithm: " + algo 259 + ", provider: " + p.getName() + ")"); 260 KeyPairGenerator kpg = KeyPairGenerator.getInstance(algo); 261 kpg.initialize(512); 262 KeyPair kp = kpg.genKeyPair(); 263 // key generated 264 String algoWrap = "DES"; 265 KeyGenerator kg = KeyGenerator.getInstance(algoWrap, p); 266 Key key = kg.generateKey(); 267 wrapTest(algo, algoWrap, key, kp.getPrivate(), Cipher.PRIVATE_KEY, 268 false); 269 wrapTest(algo, algoWrap, key, kp.getPublic(), Cipher.PUBLIC_KEY, 270 false); 271 } 272 } 273 274 private void wrapTest(String transformation, String wrapAlgo, Key initKey, 275 Key wrapKey, int keyType, boolean isPBE) 276 throws NoSuchAlgorithmException, NoSuchPaddingException, 277 InvalidKeyException, IllegalBlockSizeException, 278 InvalidAlgorithmParameterException { 279 String algo = transformation.split("/")[0]; 280 boolean isAESBlowfish = algo.indexOf("AES") != -1 281 || algo.indexOf("Blowfish") != -1; 282 AlgorithmParameters aps = null; 283 AlgorithmParameterSpec pbeParams = null; 284 if (isPBE) { 285 byte[] salt = new byte[8]; 286 int iterCnt = 1000; 287 new Random().nextBytes(salt); 288 pbeParams = new PBEParameterSpec(salt, iterCnt); 289 } 290 // Wrap & UnWrap operation 291 Cipher wrapCI = Cipher.getInstance(wrapAlgo); 292 if (isPBE && !isAESBlowfish) { 293 wrapCI.init(Cipher.WRAP_MODE, initKey, pbeParams); 294 } else if (isAESBlowfish) { 295 wrapCI.init(Cipher.WRAP_MODE, initKey); 296 aps = wrapCI.getParameters(); 297 } else { 298 wrapCI.init(Cipher.WRAP_MODE, initKey); 299 } 300 out.println("keysize : " + wrapKey.getEncoded().length); 301 byte[] keyWrapper = wrapCI.wrap(wrapKey); 302 if (isPBE && !isAESBlowfish) { 303 wrapCI.init(Cipher.UNWRAP_MODE, initKey, pbeParams); 304 } else if (isAESBlowfish) { 305 wrapCI.init(Cipher.UNWRAP_MODE, initKey, aps); 306 } else { 307 wrapCI.init(Cipher.UNWRAP_MODE, initKey); 308 } 309 Key unwrappedKey = wrapCI.unwrap(keyWrapper, algo, keyType); 310 // Comparison 311 if (!Arrays.equals(wrapKey.getEncoded(), unwrappedKey.getEncoded())) { 312 throw new RuntimeException("Comparation failed testing " 313 + transformation + ":" + wrapAlgo + ":" + keyType); 314 } 315 } 316} 317