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