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 166 PBES2Parameters() { 167 // KDF, encryption & keysize values are set later, in engineInit(byte[]) 168 } 169 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 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 protected void engineInit(byte[] encoded) 255 throws IOException 256 { 257 String kdfAlgo = null; 258 String cipherAlgo = null; 259 260 DerValue pBES2_params = new DerValue(encoded); 261 if (pBES2_params.tag != DerValue.tag_Sequence) { 262 throw new IOException("PBE parameter parsing error: " 263 + "not an ASN.1 SEQUENCE tag"); 264 } 265 DerValue kdf = pBES2_params.data.getDerValue(); 266 267 // Before JDK-8202837, PBES2-params was mistakenly encoded like 268 // an AlgorithmId which is a sequence of its own OID and the real 269 // PBES2-params. If the first DerValue is an OID instead of a 270 // PBES2-KDFs (which should be a SEQUENCE), we are likely to be 271 // dealing with this buggy encoding. Skip the OID and treat the 272 // next DerValue as the real PBES2-params. 273 if (kdf.getTag() == DerValue.tag_ObjectId) { 274 pBES2_params = pBES2_params.data.getDerValue(); 275 kdf = pBES2_params.data.getDerValue(); 276 } 277 278 kdfAlgo = parseKDF(kdf); 279 280 if (pBES2_params.tag != DerValue.tag_Sequence) { 281 throw new IOException("PBE parameter parsing error: " 282 + "not an ASN.1 SEQUENCE tag"); 283 } 284 cipherAlgo = parseES(pBES2_params.data.getDerValue()); 285 286 pbes2AlgorithmName = new StringBuilder().append("PBEWith") 287 .append(kdfAlgo).append("And").append(cipherAlgo).toString(); 288 } 289 290 private String parseKDF(DerValue keyDerivationFunc) throws IOException { 291 292 if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { 293 throw new IOException("PBE parameter parsing error: " 294 + "expecting the object identifier for PBKDF2"); 295 } 296 if (keyDerivationFunc.tag != DerValue.tag_Sequence) { 297 throw new IOException("PBE parameter parsing error: " 298 + "not an ASN.1 SEQUENCE tag"); 299 } 300 DerValue pBKDF2_params = keyDerivationFunc.data.getDerValue(); 301 if (pBKDF2_params.tag != DerValue.tag_Sequence) { 302 throw new IOException("PBE parameter parsing error: " 303 + "not an ASN.1 SEQUENCE tag"); 304 } 305 DerValue specified = pBKDF2_params.data.getDerValue(); 306 // the 'specified' ASN.1 CHOICE for 'salt' is supported 307 if (specified.tag == DerValue.tag_OctetString) { 308 salt = specified.getOctetString(); 309 } else { 310 // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported 311 throw new IOException("PBE parameter parsing error: " 312 + "not an ASN.1 OCTET STRING tag"); 313 } 314 iCount = pBKDF2_params.data.getInteger(); 315 316 DerValue prf = null; 317 // keyLength INTEGER (1..MAX) OPTIONAL, 318 if (pBKDF2_params.data.available() > 0) { 319 DerValue keyLength = pBKDF2_params.data.getDerValue(); 320 if (keyLength.tag == DerValue.tag_Integer) { 321 keysize = keyLength.getInteger() * 8; // keysize (in bits) 322 } else { 323 // Should be the prf 324 prf = keyLength; 325 } 326 } 327 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 328 String kdfAlgo = "HmacSHA1"; 329 if (prf == null) { 330 if (pBKDF2_params.data.available() > 0) { 331 prf = pBKDF2_params.data.getDerValue(); 332 } 333 } 334 if (prf != null) { 335 kdfAlgo_OID = prf.data.getOID(); 336 if (hmacWithSHA1_OID.equals(kdfAlgo_OID)) { 337 kdfAlgo = "HmacSHA1"; 338 } else if (hmacWithSHA224_OID.equals(kdfAlgo_OID)) { 339 kdfAlgo = "HmacSHA224"; 340 } else if (hmacWithSHA256_OID.equals(kdfAlgo_OID)) { 341 kdfAlgo = "HmacSHA256"; 342 } else if (hmacWithSHA384_OID.equals(kdfAlgo_OID)) { 343 kdfAlgo = "HmacSHA384"; 344 } else if (hmacWithSHA512_OID.equals(kdfAlgo_OID)) { 345 kdfAlgo = "HmacSHA512"; 346 } else { 347 throw new IOException("PBE parameter parsing error: " 348 + "expecting the object identifier for a HmacSHA key " 349 + "derivation function"); 350 } 351 if (prf.data.available() != 0) { 352 // parameter is 'NULL' for all HmacSHA KDFs 353 DerValue parameter = prf.data.getDerValue(); 354 if (parameter.tag != DerValue.tag_Null) { 355 throw new IOException("PBE parameter parsing error: " 356 + "not an ASN.1 NULL tag"); 357 } 358 } 359 } 360 361 return kdfAlgo; 362 } 363 364 private String parseES(DerValue encryptionScheme) throws IOException { 365 String cipherAlgo = null; 366 367 cipherAlgo_OID = encryptionScheme.data.getOID(); 368 if (aes128CBC_OID.equals(cipherAlgo_OID)) { 369 cipherAlgo = "AES_128"; 370 // parameter is AES-IV 'OCTET STRING (SIZE(16))' 371 cipherParam = 372 new IvParameterSpec(encryptionScheme.data.getOctetString()); 373 keysize = 128; 374 } else if (aes256CBC_OID.equals(cipherAlgo_OID)) { 375 cipherAlgo = "AES_256"; 376 // parameter is AES-IV 'OCTET STRING (SIZE(16))' 377 cipherParam = 378 new IvParameterSpec(encryptionScheme.data.getOctetString()); 379 keysize = 256; 380 } else { 381 throw new IOException("PBE parameter parsing error: " 382 + "expecting the object identifier for AES cipher"); 383 } 384 385 return cipherAlgo; 386 } 387 388 protected void engineInit(byte[] encoded, String decodingMethod) 389 throws IOException 390 { 391 engineInit(encoded); 392 } 393 394 protected <T extends AlgorithmParameterSpec> 395 T engineGetParameterSpec(Class<T> paramSpec) 396 throws InvalidParameterSpecException 397 { 398 if (PBEParameterSpec.class.isAssignableFrom(paramSpec)) { 399 return paramSpec.cast( 400 new PBEParameterSpec(this.salt, this.iCount, this.cipherParam)); 401 } else { 402 throw new InvalidParameterSpecException 403 ("Inappropriate parameter specification"); 404 } 405 } 406 407 protected byte[] engineGetEncoded() throws IOException { 408 DerOutputStream out = new DerOutputStream(); 409 410 DerOutputStream pBES2_params = new DerOutputStream(); 411 412 DerOutputStream keyDerivationFunc = new DerOutputStream(); 413 keyDerivationFunc.putOID(pkcs5PBKDF2_OID); 414 415 DerOutputStream pBKDF2_params = new DerOutputStream(); 416 pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING' 417 pBKDF2_params.putInteger(iCount); 418 419 if (keysize > 0) { 420 pBKDF2_params.putInteger(keysize / 8); // derived key length (in octets) 421 } 422 423 DerOutputStream prf = new DerOutputStream(); 424 // algorithm is id-hmacWithSHA1/SHA224/SHA256/SHA384/SHA512 425 prf.putOID(kdfAlgo_OID); 426 // parameters is 'NULL' 427 prf.putNull(); 428 pBKDF2_params.write(DerValue.tag_Sequence, prf); 429 430 keyDerivationFunc.write(DerValue.tag_Sequence, pBKDF2_params); 431 pBES2_params.write(DerValue.tag_Sequence, keyDerivationFunc); 432 433 DerOutputStream encryptionScheme = new DerOutputStream(); 434 // algorithm is id-aes128-CBC or id-aes256-CBC 435 encryptionScheme.putOID(cipherAlgo_OID); 436 // parameters is 'AES-IV ::= OCTET STRING (SIZE(16))' 437 if (cipherParam != null && cipherParam instanceof IvParameterSpec) { 438 encryptionScheme.putOctetString( 439 ((IvParameterSpec)cipherParam).getIV()); 440 } else { 441 throw new IOException("Wrong parameter type: IV expected"); 442 } 443 pBES2_params.write(DerValue.tag_Sequence, encryptionScheme); 444 445 out.write(DerValue.tag_Sequence, pBES2_params); 446 447 return out.toByteArray(); 448 } 449 450 protected byte[] engineGetEncoded(String encodingMethod) 451 throws IOException 452 { 453 return engineGetEncoded(); 454 } 455 456 /* 457 * Returns a formatted string describing the parameters. 458 * 459 * The algorithn name pattern is: "PBEWith<prf>And<encryption>" 460 * where <prf> is one of: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, 461 * or HmacSHA512, and <encryption> is AES with a keysize suffix. 462 */ 463 protected String engineToString() { 464 return pbes2AlgorithmName; 465 } 466 467 public static final class General extends PBES2Parameters { 468 public General() throws NoSuchAlgorithmException { 469 super(); 470 } 471 } 472 473 public static final class HmacSHA1AndAES_128 extends PBES2Parameters { 474 public HmacSHA1AndAES_128() throws NoSuchAlgorithmException { 475 super("PBEWithHmacSHA1AndAES_128"); 476 } 477 } 478 479 public static final class HmacSHA224AndAES_128 extends PBES2Parameters { 480 public HmacSHA224AndAES_128() throws NoSuchAlgorithmException { 481 super("PBEWithHmacSHA224AndAES_128"); 482 } 483 } 484 485 public static final class HmacSHA256AndAES_128 extends PBES2Parameters { 486 public HmacSHA256AndAES_128() throws NoSuchAlgorithmException { 487 super("PBEWithHmacSHA256AndAES_128"); 488 } 489 } 490 491 public static final class HmacSHA384AndAES_128 extends PBES2Parameters { 492 public HmacSHA384AndAES_128() throws NoSuchAlgorithmException { 493 super("PBEWithHmacSHA384AndAES_128"); 494 } 495 } 496 497 public static final class HmacSHA512AndAES_128 extends PBES2Parameters { 498 public HmacSHA512AndAES_128() throws NoSuchAlgorithmException { 499 super("PBEWithHmacSHA512AndAES_128"); 500 } 501 } 502 503 public static final class HmacSHA1AndAES_256 extends PBES2Parameters { 504 public HmacSHA1AndAES_256() throws NoSuchAlgorithmException { 505 super("PBEWithHmacSHA1AndAES_256"); 506 } 507 } 508 509 public static final class HmacSHA224AndAES_256 extends PBES2Parameters { 510 public HmacSHA224AndAES_256() throws NoSuchAlgorithmException { 511 super("PBEWithHmacSHA224AndAES_256"); 512 } 513 } 514 515 public static final class HmacSHA256AndAES_256 extends PBES2Parameters { 516 public HmacSHA256AndAES_256() throws NoSuchAlgorithmException { 517 super("PBEWithHmacSHA256AndAES_256"); 518 } 519 } 520 521 public static final class HmacSHA384AndAES_256 extends PBES2Parameters { 522 public HmacSHA384AndAES_256() throws NoSuchAlgorithmException { 523 super("PBEWithHmacSHA384AndAES_256"); 524 } 525 } 526 527 public static final class HmacSHA512AndAES_256 extends PBES2Parameters { 528 public HmacSHA512AndAES_256() throws NoSuchAlgorithmException { 529 super("PBEWithHmacSHA512AndAES_256"); 530 } 531 } 532 }