1 /* 2 * Copyright (c) 2003, 2011, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.pkcs11; 27 28 import java.util.*; 29 30 import java.security.*; 31 import java.security.spec.*; 32 33 import javax.crypto.*; 34 import javax.crypto.spec.*; 35 36 import static sun.security.pkcs11.TemplateManager.*; 37 import sun.security.pkcs11.wrapper.*; 38 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 39 40 /** 41 * SecretKeyFactory implementation class. This class currently supports 42 * DES, DESede, AES, ARCFOUR, and Blowfish. 43 * 44 * @author Andreas Sterbenz 45 * @since 1.5 46 */ 47 final class P11SecretKeyFactory extends SecretKeyFactorySpi { 48 49 // token instance 50 private final Token token; 51 52 // algorithm name 53 private final String algorithm; 54 55 P11SecretKeyFactory(Token token, String algorithm) { 56 super(); 57 this.token = token; 58 this.algorithm = algorithm; 59 } 60 61 private static final Map<String,Long> keyTypes; 62 63 static { 64 keyTypes = new HashMap<String,Long>(); 65 addKeyType("RC4", CKK_RC4); 66 addKeyType("ARCFOUR", CKK_RC4); 67 addKeyType("DES", CKK_DES); 68 addKeyType("DESede", CKK_DES3); 69 addKeyType("AES", CKK_AES); 70 addKeyType("Blowfish", CKK_BLOWFISH); 71 72 // we don't implement RC2 or IDEA, but we want to be able to generate 73 // keys for those SSL/TLS ciphersuites. 74 addKeyType("RC2", CKK_RC2); 75 addKeyType("IDEA", CKK_IDEA); 76 77 addKeyType("TlsPremasterSecret", PCKK_TLSPREMASTER); 78 addKeyType("TlsRsaPremasterSecret", PCKK_TLSRSAPREMASTER); 79 addKeyType("TlsMasterSecret", PCKK_TLSMASTER); 80 addKeyType("Generic", CKK_GENERIC_SECRET); 81 } 82 83 private static void addKeyType(String name, long id) { 84 Long l = Long.valueOf(id); 85 keyTypes.put(name, l); 86 keyTypes.put(name.toUpperCase(Locale.ENGLISH), l); 87 } 88 89 static long getKeyType(String algorithm) { 90 Long l = keyTypes.get(algorithm); 91 if (l == null) { 92 algorithm = algorithm.toUpperCase(Locale.ENGLISH); 93 l = keyTypes.get(algorithm); 94 if (l == null) { 95 if (algorithm.startsWith("HMAC")) { 96 return PCKK_HMAC; 97 } else if (algorithm.startsWith("SSLMAC")) { 98 return PCKK_SSLMAC; 99 } 100 } 101 } 102 return (l != null) ? l.longValue() : -1; 103 } 104 105 /** 106 * Convert an arbitrary key of algorithm into a P11Key of provider. 107 * Used in engineTranslateKey(), P11Cipher.init(), and P11Mac.init(). 108 */ 109 static P11Key convertKey(Token token, Key key, String algo) 110 throws InvalidKeyException { 111 return convertKey(token, key, algo, null); 112 } 113 114 /** 115 * Convert an arbitrary key of algorithm w/ custom attributes into a 116 * P11Key of provider. 117 * Used in P11KeyStore.storeSkey. 118 */ 119 static P11Key convertKey(Token token, Key key, String algo, 120 CK_ATTRIBUTE[] extraAttrs) 121 throws InvalidKeyException { 122 token.ensureValid(); 123 if (key == null) { 124 throw new InvalidKeyException("Key must not be null"); 125 } 126 if (key instanceof SecretKey == false) { 127 throw new InvalidKeyException("Key must be a SecretKey"); 128 } 129 long algoType; 130 if (algo == null) { 131 algo = key.getAlgorithm(); 132 algoType = getKeyType(algo); 133 } else { 134 algoType = getKeyType(algo); 135 long keyAlgorithmType = getKeyType(key.getAlgorithm()); 136 if (algoType != keyAlgorithmType) { 137 if ((algoType == PCKK_HMAC) || (algoType == PCKK_SSLMAC)) { 138 // ignore key algorithm for MACs 139 } else { 140 throw new InvalidKeyException 141 ("Key algorithm must be " + algo); 142 } 143 } 144 } 145 if (key instanceof P11Key) { 146 P11Key p11Key = (P11Key)key; 147 if (p11Key.token == token) { 148 if (extraAttrs != null) { 149 Session session = null; 150 try { 151 session = token.getObjSession(); 152 p11Key.incNativeKeyRef(); 153 long newKeyID; 154 try { 155 newKeyID = token.p11.C_CopyObject(session.id(), 156 p11Key.keyID, extraAttrs); 157 } finally { 158 p11Key.decNativeKeyRef(); 159 } 160 p11Key = (P11Key) (P11Key.secretKey(session, 161 newKeyID, p11Key.algorithm, p11Key.keyLength, 162 extraAttrs, true)); 163 } catch (PKCS11Exception p11e) { 164 throw new InvalidKeyException 165 ("Cannot duplicate the PKCS11 key", p11e); 166 } finally { 167 token.releaseSession(session); 168 } 169 } 170 return p11Key; 171 } 172 } 173 P11Key p11Key = token.secretCache.get(key); 174 if (p11Key != null) { 175 return p11Key; 176 } 177 if ("RAW".equalsIgnoreCase(key.getFormat()) == false) { 178 throw new InvalidKeyException("Encoded format must be RAW"); 179 } 180 byte[] encoded = key.getEncoded(); 181 p11Key = createKey(token, encoded, algo, algoType, extraAttrs); 182 token.secretCache.put(key, p11Key); 183 return p11Key; 184 } 185 186 static void fixDESParity(byte[] key, int offset) { 187 for (int i = 0; i < 8; i++) { 188 int b = key[offset] & 0xfe; 189 b |= (Integer.bitCount(b) & 1) ^ 1; 190 key[offset++] = (byte)b; 191 } 192 } 193 194 private static P11Key createKey(Token token, byte[] encoded, 195 String algorithm, long keyType, CK_ATTRIBUTE[] extraAttrs) 196 throws InvalidKeyException { 197 int n = encoded.length << 3; 198 int keyLength = n; 199 try { 200 switch ((int)keyType) { 201 case (int)CKK_DES: 202 keyLength = 203 P11KeyGenerator.checkKeySize(CKM_DES_KEY_GEN, n, token); 204 fixDESParity(encoded, 0); 205 break; 206 case (int)CKK_DES3: 207 keyLength = 208 P11KeyGenerator.checkKeySize(CKM_DES3_KEY_GEN, n, token); 209 fixDESParity(encoded, 0); 210 fixDESParity(encoded, 8); 211 if (keyLength == 112) { 212 keyType = CKK_DES2; 213 } else { 214 keyType = CKK_DES3; 215 fixDESParity(encoded, 16); 216 } 217 break; 218 case (int)CKK_AES: 219 keyLength = 220 P11KeyGenerator.checkKeySize(CKM_AES_KEY_GEN, n, token); 221 break; 222 case (int)CKK_RC4: 223 keyLength = 224 P11KeyGenerator.checkKeySize(CKM_RC4_KEY_GEN, n, token); 225 break; 226 case (int)CKK_BLOWFISH: 227 keyLength = 228 P11KeyGenerator.checkKeySize(CKM_BLOWFISH_KEY_GEN, n, 229 token); 230 break; 231 case (int)CKK_GENERIC_SECRET: 232 case (int)PCKK_TLSPREMASTER: 233 case (int)PCKK_TLSRSAPREMASTER: 234 case (int)PCKK_TLSMASTER: 235 keyType = CKK_GENERIC_SECRET; 236 break; 237 case (int)PCKK_SSLMAC: 238 case (int)PCKK_HMAC: 239 if (n == 0) { 240 throw new InvalidKeyException 241 ("MAC keys must not be empty"); 242 } 243 keyType = CKK_GENERIC_SECRET; 244 break; 245 default: 246 throw new InvalidKeyException("Unknown algorithm " + 247 algorithm); 248 } 249 } catch (InvalidAlgorithmParameterException iape) { 250 throw new InvalidKeyException("Invalid key for " + algorithm, 251 iape); 252 } catch (ProviderException pe) { 253 throw new InvalidKeyException("Could not create key", pe); 254 } 255 Session session = null; 256 try { 257 CK_ATTRIBUTE[] attributes; 258 if (extraAttrs != null) { 259 attributes = new CK_ATTRIBUTE[3 + extraAttrs.length]; 260 System.arraycopy(extraAttrs, 0, attributes, 3, 261 extraAttrs.length); 262 } else { 263 attributes = new CK_ATTRIBUTE[3]; 264 } 265 attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY); 266 attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType); 267 attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded); 268 attributes = token.getAttributes 269 (O_IMPORT, CKO_SECRET_KEY, keyType, attributes); 270 session = token.getObjSession(); 271 long keyID = token.p11.C_CreateObject(session.id(), attributes); 272 P11Key p11Key = (P11Key)P11Key.secretKey 273 (session, keyID, algorithm, keyLength, attributes, true); 274 return p11Key; 275 } catch (PKCS11Exception e) { 276 throw new InvalidKeyException("Could not create key", e); 277 } finally { 278 token.releaseSession(session); 279 } 280 } 281 282 // see JCE spec 283 protected SecretKey engineGenerateSecret(KeySpec keySpec) 284 throws InvalidKeySpecException { 285 token.ensureValid(); 286 if (keySpec == null) { 287 throw new InvalidKeySpecException("KeySpec must not be null"); 288 } 289 if (keySpec instanceof SecretKeySpec) { 290 try { 291 Key key = convertKey(token, (SecretKey)keySpec, algorithm); 292 return (SecretKey)key; 293 } catch (InvalidKeyException e) { 294 throw new InvalidKeySpecException(e); 295 } 296 } else if (algorithm.equalsIgnoreCase("DES")) { 297 if (keySpec instanceof DESKeySpec) { 298 byte[] keyBytes = ((DESKeySpec)keySpec).getKey(); 299 keySpec = new SecretKeySpec(keyBytes, "DES"); 300 return engineGenerateSecret(keySpec); 301 } 302 } else if (algorithm.equalsIgnoreCase("DESede")) { 303 if (keySpec instanceof DESedeKeySpec) { 304 byte[] keyBytes = ((DESedeKeySpec)keySpec).getKey(); 305 keySpec = new SecretKeySpec(keyBytes, "DESede"); 306 return engineGenerateSecret(keySpec); 307 } 308 } 309 throw new InvalidKeySpecException 310 ("Unsupported spec: " + keySpec.getClass().getName()); 311 } 312 313 private byte[] getKeyBytes(SecretKey key) throws InvalidKeySpecException { 314 try { 315 key = engineTranslateKey(key); 316 if ("RAW".equalsIgnoreCase(key.getFormat()) == false) { 317 throw new InvalidKeySpecException 318 ("Could not obtain key bytes"); 319 } 320 byte[] k = key.getEncoded(); 321 return k; 322 } catch (InvalidKeyException e) { 323 throw new InvalidKeySpecException(e); 324 } 325 } 326 327 // see JCE spec 328 protected KeySpec engineGetKeySpec(SecretKey key, Class<?> keySpec) 329 throws InvalidKeySpecException { 330 token.ensureValid(); 331 if ((key == null) || (keySpec == null)) { 332 throw new InvalidKeySpecException 333 ("key and keySpec must not be null"); 334 } 335 if (SecretKeySpec.class.isAssignableFrom(keySpec)) { 336 return new SecretKeySpec(getKeyBytes(key), algorithm); 337 } else if (algorithm.equalsIgnoreCase("DES")) { 338 try { 339 if (DESKeySpec.class.isAssignableFrom(keySpec)) { 340 return new DESKeySpec(getKeyBytes(key)); 341 } 342 } catch (InvalidKeyException e) { 343 throw new InvalidKeySpecException(e); 344 } 345 } else if (algorithm.equalsIgnoreCase("DESede")) { 346 try { 347 if (DESedeKeySpec.class.isAssignableFrom(keySpec)) { 348 return new DESedeKeySpec(getKeyBytes(key)); 349 } 350 } catch (InvalidKeyException e) { 351 throw new InvalidKeySpecException(e); 352 } 353 } 354 throw new InvalidKeySpecException 355 ("Unsupported spec: " + keySpec.getName()); 356 } 357 358 // see JCE spec 359 protected SecretKey engineTranslateKey(SecretKey key) 360 throws InvalidKeyException { 361 return (SecretKey)convertKey(token, key, algorithm); 362 } 363 364 }