1 /* 2 * Copyright (c) 2012, 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 com.sun.crypto.provider; 27 28 import java.io.*; 29 import java.math.BigInteger; 30 import java.security.NoSuchAlgorithmException; 31 import java.security.AlgorithmParametersSpi; 32 import java.security.spec.AlgorithmParameterSpec; 33 import java.security.spec.InvalidParameterSpecException; 34 import javax.crypto.spec.IvParameterSpec; 35 import javax.crypto.spec.PBEParameterSpec; 36 import sun.misc.HexDumpEncoder; 37 import sun.security.util.*; 38 39 /** 40 * This class implements the parameter set used with password-based 41 * encryption scheme 2 (PBES2), which is defined in PKCS#5 as follows: 42 * 43 * <pre> 44 * -- PBES2 45 * 46 * PBES2Algorithms ALGORITHM-IDENTIFIER ::= 47 * { {PBES2-params IDENTIFIED BY id-PBES2}, ...} 48 * 49 * id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} 50 * 51 * PBES2-params ::= SEQUENCE { 52 * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, 53 * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } 54 * 55 * PBES2-KDFs ALGORITHM-IDENTIFIER ::= 56 * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... } 57 * 58 * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... } 59 * 60 * -- PBKDF2 61 * 62 * PBKDF2Algorithms ALGORITHM-IDENTIFIER ::= 63 * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...} 64 * 65 * id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} 66 * 67 * PBKDF2-params ::= SEQUENCE { 68 * salt CHOICE { 69 * specified OCTET STRING, 70 * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} 71 * }, 72 * iterationCount INTEGER (1..MAX), 73 * keyLength INTEGER (1..MAX) OPTIONAL, 74 * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 75 * } 76 * 77 * PBKDF2-SaltSources ALGORITHM-IDENTIFIER ::= { ... } 78 * 79 * PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= { 80 * {NULL IDENTIFIED BY id-hmacWithSHA1} | 81 * {NULL IDENTIFIED BY id-hmacWithSHA224} | 82 * {NULL IDENTIFIED BY id-hmacWithSHA256} | 83 * {NULL IDENTIFIED BY id-hmacWithSHA384} | 84 * {NULL IDENTIFIED BY id-hmacWithSHA512}, ... } 85 * 86 * algid-hmacWithSHA1 AlgorithmIdentifier {{PBKDF2-PRFs}} ::= 87 * {algorithm id-hmacWithSHA1, parameters NULL : NULL} 88 * 89 * id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7} 90 * 91 * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... } 92 * 93 * </pre> 94 */ 95 96 abstract class PBES2Parameters extends AlgorithmParametersSpi { 97 98 private static final int pkcs5PBKDF2[] = 99 {1, 2, 840, 113549, 1, 5, 12}; 100 private static final int pkcs5PBES2[] = 101 {1, 2, 840, 113549, 1, 5, 13}; 102 private static final int hmacWithSHA1[] = 103 {1, 2, 840, 113549, 2, 7}; 104 private static final int hmacWithSHA224[] = 105 {1, 2, 840, 113549, 2, 8}; 106 private static final int hmacWithSHA256[] = 107 {1, 2, 840, 113549, 2, 9}; 108 private static final int hmacWithSHA384[] = 109 {1, 2, 840, 113549, 2, 10}; 110 private static final int hmacWithSHA512[] = 111 {1, 2, 840, 113549, 2, 11}; 112 private static final int aes128CBC[] = 113 {2, 16, 840, 1, 101, 3, 4, 1, 2}; 114 private static final int aes192CBC[] = 115 {2, 16, 840, 1, 101, 3, 4, 1, 22}; 116 private static final int aes256CBC[] = 117 {2, 16, 840, 1, 101, 3, 4, 1, 42}; 118 119 private static ObjectIdentifier pkcs5PBKDF2_OID; 120 private static ObjectIdentifier pkcs5PBES2_OID; 121 private static ObjectIdentifier hmacWithSHA1_OID; 122 private static ObjectIdentifier hmacWithSHA224_OID; 123 private static ObjectIdentifier hmacWithSHA256_OID; 124 private static ObjectIdentifier hmacWithSHA384_OID; 125 private static ObjectIdentifier hmacWithSHA512_OID; 126 private static ObjectIdentifier aes128CBC_OID; 127 private static ObjectIdentifier aes192CBC_OID; 128 private static ObjectIdentifier aes256CBC_OID; 129 130 static { 131 try { 132 pkcs5PBKDF2_OID = new ObjectIdentifier(pkcs5PBKDF2); 133 pkcs5PBES2_OID = new ObjectIdentifier(pkcs5PBES2); 134 hmacWithSHA1_OID = new ObjectIdentifier(hmacWithSHA1); 135 hmacWithSHA224_OID = new ObjectIdentifier(hmacWithSHA224); 136 hmacWithSHA256_OID = new ObjectIdentifier(hmacWithSHA256); 137 hmacWithSHA384_OID = new ObjectIdentifier(hmacWithSHA384); 138 hmacWithSHA512_OID = new ObjectIdentifier(hmacWithSHA512); 139 aes128CBC_OID = new ObjectIdentifier(aes128CBC); 140 aes192CBC_OID = new ObjectIdentifier(aes192CBC); 141 aes256CBC_OID = new ObjectIdentifier(aes256CBC); 142 } catch (IOException ioe) { 143 // should not happen 144 } 145 } 146 147 // the PBES2 algorithm name 148 private String pbes2AlgorithmName = null; 149 150 // the salt 151 private byte[] salt = null; 152 153 // the iteration count 154 private int iCount = 0; 155 156 // the cipher parameter 157 private AlgorithmParameterSpec cipherParam = null; 158 159 // the key derivation function (default is HmacSHA1) 160 private ObjectIdentifier kdfAlgo_OID = hmacWithSHA1_OID; 161 162 // the encryption function 163 private ObjectIdentifier cipherAlgo_OID = null; 164 165 // the cipher keysize (in bits) 166 private int keysize = -1; 167 168 PBES2Parameters() { 169 // KDF, encryption & keysize values are set later, in engineInit(byte[]) 170 } 171 172 PBES2Parameters(String pbes2AlgorithmName) throws NoSuchAlgorithmException { 173 int and; 174 String kdfAlgo = null; 175 String cipherAlgo = null; 176 177 // Extract the KDF and encryption algorithm names 178 this.pbes2AlgorithmName = pbes2AlgorithmName; 179 if (pbes2AlgorithmName.startsWith("PBEWith") && 180 (and = pbes2AlgorithmName.indexOf("And", 7 + 1)) > 0) { 181 kdfAlgo = pbes2AlgorithmName.substring(7, and); 182 cipherAlgo = pbes2AlgorithmName.substring(and + 3); 183 184 // Check for keysize 185 int underscore; 186 if ((underscore = cipherAlgo.indexOf('_')) > 0) { 187 int slash; 188 if ((slash = cipherAlgo.indexOf('/', underscore + 1)) > 0) { 189 keysize = 190 Integer.parseInt(cipherAlgo.substring(underscore + 1, 191 slash)); 192 } else { 193 keysize = 194 Integer.parseInt(cipherAlgo.substring(underscore + 1)); 195 } 196 cipherAlgo = cipherAlgo.substring(0, underscore); 197 } 198 } else { 199 throw new NoSuchAlgorithmException("No crypto implementation for " + 200 pbes2AlgorithmName); 201 } 202 203 switch (kdfAlgo) { 204 case "HmacSHA1": 205 kdfAlgo_OID = hmacWithSHA1_OID; 206 break; 207 case "HmacSHA224": 208 kdfAlgo_OID = hmacWithSHA224_OID; 209 break; 210 case "HmacSHA256": 211 kdfAlgo_OID = hmacWithSHA256_OID; 212 break; 213 case "HmacSHA384": 214 kdfAlgo_OID = hmacWithSHA384_OID; 215 break; 216 case "HmacSHA512": 217 kdfAlgo_OID = hmacWithSHA512_OID; 218 break; 219 default: 220 throw new NoSuchAlgorithmException( 221 "No crypto implementation for " + kdfAlgo); 222 } 223 224 if (cipherAlgo.equals("AES")) { 225 this.keysize = keysize; 226 switch (keysize) { 227 case 128: 228 cipherAlgo_OID = aes128CBC_OID; 229 break; 230 case 256: 231 cipherAlgo_OID = aes256CBC_OID; 232 break; 233 default: 234 throw new NoSuchAlgorithmException( 235 "No Cipher implementation for " + keysize + "-bit " + 236 cipherAlgo); 237 } 238 } else { 239 throw new NoSuchAlgorithmException("No Cipher implementation for " + 240 cipherAlgo); 241 } 242 } 243 244 protected void engineInit(AlgorithmParameterSpec paramSpec) 245 throws InvalidParameterSpecException 246 { 247 if (!(paramSpec instanceof PBEParameterSpec)) { 248 throw new InvalidParameterSpecException 249 ("Inappropriate parameter specification"); 250 } 251 this.salt = ((PBEParameterSpec)paramSpec).getSalt().clone(); 252 this.iCount = ((PBEParameterSpec)paramSpec).getIterationCount(); 253 this.cipherParam = ((PBEParameterSpec)paramSpec).getParameterSpec(); 254 } 255 256 protected void engineInit(byte[] encoded) 257 throws IOException 258 { 259 String kdfAlgo = null; 260 String cipherAlgo = null; 261 262 DerValue pBES2Algorithms = new DerValue(encoded); 263 if (pBES2Algorithms.tag != DerValue.tag_Sequence) { 264 throw new IOException("PBE parameter parsing error: " 265 + "not an ASN.1 SEQUENCE tag"); 266 } 267 if (!pkcs5PBES2_OID.equals(pBES2Algorithms.data.getOID())) { 268 throw new IOException("PBE parameter parsing error: " 269 + "expecting the object identifier for PBES2"); 270 } 271 if (pBES2Algorithms.tag != DerValue.tag_Sequence) { 272 throw new IOException("PBE parameter parsing error: " 273 + "not an ASN.1 SEQUENCE tag"); 274 } 275 276 DerValue pBES2_params = pBES2Algorithms.data.getDerValue(); 277 if (pBES2_params.tag != DerValue.tag_Sequence) { 278 throw new IOException("PBE parameter parsing error: " 279 + "not an ASN.1 SEQUENCE tag"); 280 } 281 kdfAlgo = parseKDF(pBES2_params.data.getDerValue()); 282 283 if (pBES2_params.tag != DerValue.tag_Sequence) { 284 throw new IOException("PBE parameter parsing error: " 285 + "not an ASN.1 SEQUENCE tag"); 286 } 287 cipherAlgo = parseES(pBES2_params.data.getDerValue()); 288 289 pbes2AlgorithmName = new StringBuilder().append("PBEWith") 290 .append(kdfAlgo).append("And").append(cipherAlgo).toString(); 291 } 292 293 private String parseKDF(DerValue keyDerivationFunc) throws IOException { 294 String kdfAlgo = null; 295 296 if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { 297 throw new IOException("PBE parameter parsing error: " 298 + "expecting the object identifier for PBKDF2"); 299 } 300 if (keyDerivationFunc.tag != DerValue.tag_Sequence) { 301 throw new IOException("PBE parameter parsing error: " 302 + "not an ASN.1 SEQUENCE tag"); 303 } 304 DerValue pBKDF2_params = keyDerivationFunc.data.getDerValue(); 305 if (pBKDF2_params.tag != DerValue.tag_Sequence) { 306 throw new IOException("PBE parameter parsing error: " 307 + "not an ASN.1 SEQUENCE tag"); 308 } 309 DerValue specified = pBKDF2_params.data.getDerValue(); 310 // the 'specified' ASN.1 CHOICE for 'salt' is supported 311 if (specified.tag == DerValue.tag_OctetString) { 312 salt = specified.getOctetString(); 313 } else { 314 // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported 315 throw new IOException("PBE parameter parsing error: " 316 + "not an ASN.1 OCTET STRING tag"); 317 } 318 iCount = pBKDF2_params.data.getInteger(); 319 DerValue keyLength = pBKDF2_params.data.getDerValue(); 320 if (keyLength.tag == DerValue.tag_Integer) { 321 keysize = keyLength.getInteger() * 8; // keysize (in bits) 322 } 323 if (pBKDF2_params.tag == DerValue.tag_Sequence) { 324 DerValue prf = pBKDF2_params.data.getDerValue(); 325 kdfAlgo_OID = prf.data.getOID(); 326 if (hmacWithSHA1_OID.equals(kdfAlgo_OID)) { 327 kdfAlgo = "HmacSHA1"; 328 } else if (hmacWithSHA224_OID.equals(kdfAlgo_OID)) { 329 kdfAlgo = "HmacSHA224"; 330 } else if (hmacWithSHA256_OID.equals(kdfAlgo_OID)) { 331 kdfAlgo = "HmacSHA256"; 332 } else if (hmacWithSHA384_OID.equals(kdfAlgo_OID)) { 333 kdfAlgo = "HmacSHA384"; 334 } else if (hmacWithSHA512_OID.equals(kdfAlgo_OID)) { 335 kdfAlgo = "HmacSHA512"; 336 } else { 337 throw new IOException("PBE parameter parsing error: " 338 + "expecting the object identifier for a HmacSHA key " 339 + "derivation function"); 340 } 341 if (prf.data.available() != 0) { 342 // parameter is 'NULL' for all HmacSHA KDFs 343 DerValue parameter = prf.data.getDerValue(); 344 if (parameter.tag != DerValue.tag_Null) { 345 throw new IOException("PBE parameter parsing error: " 346 + "not an ASN.1 NULL tag"); 347 } 348 } 349 } 350 351 return kdfAlgo; 352 } 353 354 private String parseES(DerValue encryptionScheme) throws IOException { 355 String cipherAlgo = null; 356 357 cipherAlgo_OID = encryptionScheme.data.getOID(); 358 if (aes128CBC_OID.equals(cipherAlgo_OID)) { 359 cipherAlgo = "AES_128"; 360 // parameter is AES-IV 'OCTET STRING (SIZE(16))' 361 cipherParam = 362 new IvParameterSpec(encryptionScheme.data.getOctetString()); 363 keysize = 128; 364 } else if (aes256CBC_OID.equals(cipherAlgo_OID)) { 365 cipherAlgo = "AES_256"; 366 // parameter is AES-IV 'OCTET STRING (SIZE(16))' 367 cipherParam = 368 new IvParameterSpec(encryptionScheme.data.getOctetString()); 369 keysize = 256; 370 } else { 371 throw new IOException("PBE parameter parsing error: " 372 + "expecting the object identifier for AES cipher"); 373 } 374 375 return cipherAlgo; 376 } 377 378 protected void engineInit(byte[] encoded, String decodingMethod) 379 throws IOException 380 { 381 engineInit(encoded); 382 } 383 384 protected <T extends AlgorithmParameterSpec> 385 T engineGetParameterSpec(Class<T> paramSpec) 386 throws InvalidParameterSpecException 387 { 388 if (PBEParameterSpec.class.isAssignableFrom(paramSpec)) { 389 return paramSpec.cast( 390 new PBEParameterSpec(this.salt, this.iCount, this.cipherParam)); 391 } else { 392 throw new InvalidParameterSpecException 393 ("Inappropriate parameter specification"); 394 } 395 } 396 397 protected byte[] engineGetEncoded() throws IOException { 398 DerOutputStream out = new DerOutputStream(); 399 DerOutputStream pBES2Algorithms = new DerOutputStream(); 400 pBES2Algorithms.putOID(pkcs5PBES2_OID); 401 402 DerOutputStream pBES2_params = new DerOutputStream(); 403 404 DerOutputStream keyDerivationFunc = new DerOutputStream(); 405 keyDerivationFunc.putOID(pkcs5PBKDF2_OID); 406 407 DerOutputStream pBKDF2_params = new DerOutputStream(); 408 pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING' 409 pBKDF2_params.putInteger(iCount); 410 pBKDF2_params.putInteger(keysize / 8); // derived key length (in octets) 411 412 DerOutputStream prf = new DerOutputStream(); 413 // algorithm is id-hmacWithSHA1/SHA224/SHA256/SHA384/SHA512 414 prf.putOID(kdfAlgo_OID); 415 // parameters is 'NULL' 416 prf.putNull(); 417 pBKDF2_params.write(DerValue.tag_Sequence, prf); 418 419 keyDerivationFunc.write(DerValue.tag_Sequence, pBKDF2_params); 420 pBES2_params.write(DerValue.tag_Sequence, keyDerivationFunc); 421 422 DerOutputStream encryptionScheme = new DerOutputStream(); 423 // algorithm is id-aes128-CBC or id-aes256-CBC 424 encryptionScheme.putOID(cipherAlgo_OID); 425 // parameters is 'AES-IV ::= OCTET STRING (SIZE(16))' 426 if (cipherParam != null && cipherParam instanceof IvParameterSpec) { 427 encryptionScheme.putOctetString( 428 ((IvParameterSpec)cipherParam).getIV()); 429 } else { 430 throw new IOException("Wrong parameter type: IV expected"); 431 } 432 pBES2_params.write(DerValue.tag_Sequence, encryptionScheme); 433 434 pBES2Algorithms.write(DerValue.tag_Sequence, pBES2_params); 435 out.write(DerValue.tag_Sequence, pBES2Algorithms); 436 437 return out.toByteArray(); 438 } 439 440 protected byte[] engineGetEncoded(String encodingMethod) 441 throws IOException 442 { 443 return engineGetEncoded(); 444 } 445 446 /* 447 * Returns a formatted string describing the parameters. 448 * 449 * The algorithn name pattern is: "PBEWith<prf>And<encryption>" 450 * where <prf> is one of: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, 451 * or HmacSHA512, and <encryption> is AES with a keysize suffix. 452 */ 453 protected String engineToString() { 454 return pbes2AlgorithmName; 455 } 456 457 public static final class General extends PBES2Parameters { 458 public General() throws NoSuchAlgorithmException { 459 super(); 460 } 461 } 462 463 public static final class HmacSHA1AndAES_128 extends PBES2Parameters { 464 public HmacSHA1AndAES_128() throws NoSuchAlgorithmException { 465 super("PBEWithHmacSHA1AndAES_128"); 466 } 467 } 468 469 public static final class HmacSHA224AndAES_128 extends PBES2Parameters { 470 public HmacSHA224AndAES_128() throws NoSuchAlgorithmException { 471 super("PBEWithHmacSHA224AndAES_128"); 472 } 473 } 474 475 public static final class HmacSHA256AndAES_128 extends PBES2Parameters { 476 public HmacSHA256AndAES_128() throws NoSuchAlgorithmException { 477 super("PBEWithHmacSHA256AndAES_128"); 478 } 479 } 480 481 public static final class HmacSHA384AndAES_128 extends PBES2Parameters { 482 public HmacSHA384AndAES_128() throws NoSuchAlgorithmException { 483 super("PBEWithHmacSHA384AndAES_128"); 484 } 485 } 486 487 public static final class HmacSHA512AndAES_128 extends PBES2Parameters { 488 public HmacSHA512AndAES_128() throws NoSuchAlgorithmException { 489 super("PBEWithHmacSHA512AndAES_128"); 490 } 491 } 492 493 public static final class HmacSHA1AndAES_256 extends PBES2Parameters { 494 public HmacSHA1AndAES_256() throws NoSuchAlgorithmException { 495 super("PBEWithHmacSHA1AndAES_256"); 496 } 497 } 498 499 public static final class HmacSHA224AndAES_256 extends PBES2Parameters { 500 public HmacSHA224AndAES_256() throws NoSuchAlgorithmException { 501 super("PBEWithHmacSHA224AndAES_256"); 502 } 503 } 504 505 public static final class HmacSHA256AndAES_256 extends PBES2Parameters { 506 public HmacSHA256AndAES_256() throws NoSuchAlgorithmException { 507 super("PBEWithHmacSHA256AndAES_256"); 508 } 509 } 510 511 public static final class HmacSHA384AndAES_256 extends PBES2Parameters { 512 public HmacSHA384AndAES_256() throws NoSuchAlgorithmException { 513 super("PBEWithHmacSHA384AndAES_256"); 514 } 515 } 516 517 public static final class HmacSHA512AndAES_256 extends PBES2Parameters { 518 public HmacSHA512AndAES_256() throws NoSuchAlgorithmException { 519 super("PBEWithHmacSHA512AndAES_256"); 520 } 521 } 522 }