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 // keyLength INTEGER (1..MAX) OPTIONAL, 316 if (pBKDF2_params.data.available() > 0) { 317 DerValue keyLength = pBKDF2_params.data.getDerValue(); 318 if (keyLength.tag == DerValue.tag_Integer) { 319 keysize = keyLength.getInteger() * 8; // keysize (in bits) 320 } 321 } 322 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 323 String kdfAlgo = "HmacSHA1"; 324 if (pBKDF2_params.data.available() > 0) { 325 if (pBKDF2_params.tag == DerValue.tag_Sequence) { 326 DerValue prf = pBKDF2_params.data.getDerValue(); 327 kdfAlgo_OID = prf.data.getOID(); 328 if (hmacWithSHA1_OID.equals(kdfAlgo_OID)) { 329 kdfAlgo = "HmacSHA1"; 330 } else if (hmacWithSHA224_OID.equals(kdfAlgo_OID)) { 331 kdfAlgo = "HmacSHA224"; 332 } else if (hmacWithSHA256_OID.equals(kdfAlgo_OID)) { 333 kdfAlgo = "HmacSHA256"; 334 } else if (hmacWithSHA384_OID.equals(kdfAlgo_OID)) { 335 kdfAlgo = "HmacSHA384"; 336 } else if (hmacWithSHA512_OID.equals(kdfAlgo_OID)) { 337 kdfAlgo = "HmacSHA512"; 338 } else { 339 throw new IOException("PBE parameter parsing error: " 340 + "expecting the object identifier for a HmacSHA key " 341 + "derivation function"); 342 } 343 if (prf.data.available() != 0) { 344 // parameter is 'NULL' for all HmacSHA KDFs 345 DerValue parameter = prf.data.getDerValue(); 346 if (parameter.tag != DerValue.tag_Null) { 347 throw new IOException("PBE parameter parsing error: " 348 + "not an ASN.1 NULL tag"); 349 } 350 } 351 } 352 } 353 354 return kdfAlgo; 355 } 356 357 private String parseES(DerValue encryptionScheme) throws IOException { 358 String cipherAlgo = null; 359 360 cipherAlgo_OID = encryptionScheme.data.getOID(); 361 if (aes128CBC_OID.equals(cipherAlgo_OID)) { 362 cipherAlgo = "AES_128"; 363 // parameter is AES-IV 'OCTET STRING (SIZE(16))' 364 cipherParam = 365 new IvParameterSpec(encryptionScheme.data.getOctetString()); 366 keysize = 128; 367 } else if (aes256CBC_OID.equals(cipherAlgo_OID)) { 368 cipherAlgo = "AES_256"; 369 // parameter is AES-IV 'OCTET STRING (SIZE(16))' 370 cipherParam = 371 new IvParameterSpec(encryptionScheme.data.getOctetString()); 372 keysize = 256; 373 } else { 374 throw new IOException("PBE parameter parsing error: " 375 + "expecting the object identifier for AES cipher"); 376 } 377 378 return cipherAlgo; 379 } 380 381 protected void engineInit(byte[] encoded, String decodingMethod) 382 throws IOException 383 { 384 engineInit(encoded); 385 } 386 387 protected <T extends AlgorithmParameterSpec> 388 T engineGetParameterSpec(Class<T> paramSpec) 389 throws InvalidParameterSpecException 390 { 391 if (PBEParameterSpec.class.isAssignableFrom(paramSpec)) { 392 return paramSpec.cast( 393 new PBEParameterSpec(this.salt, this.iCount, this.cipherParam)); 394 } else { 395 throw new InvalidParameterSpecException 396 ("Inappropriate parameter specification"); 397 } 398 } 399 400 protected byte[] engineGetEncoded() throws IOException { 401 DerOutputStream out = new DerOutputStream(); 402 403 DerOutputStream pBES2_params = new DerOutputStream(); 404 405 DerOutputStream keyDerivationFunc = new DerOutputStream(); 406 keyDerivationFunc.putOID(pkcs5PBKDF2_OID); 407 408 DerOutputStream pBKDF2_params = new DerOutputStream(); 409 pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING' 410 pBKDF2_params.putInteger(iCount); 411 412 if (keysize > 0) { 413 pBKDF2_params.putInteger(keysize / 8); // derived key length (in octets) 414 } 415 416 DerOutputStream prf = new DerOutputStream(); 417 // algorithm is id-hmacWithSHA1/SHA224/SHA256/SHA384/SHA512 418 prf.putOID(kdfAlgo_OID); 419 // parameters is 'NULL' 420 prf.putNull(); 421 pBKDF2_params.write(DerValue.tag_Sequence, prf); 422 423 keyDerivationFunc.write(DerValue.tag_Sequence, pBKDF2_params); 424 pBES2_params.write(DerValue.tag_Sequence, keyDerivationFunc); 425 426 DerOutputStream encryptionScheme = new DerOutputStream(); 427 // algorithm is id-aes128-CBC or id-aes256-CBC 428 encryptionScheme.putOID(cipherAlgo_OID); 429 // parameters is 'AES-IV ::= OCTET STRING (SIZE(16))' 430 if (cipherParam != null && cipherParam instanceof IvParameterSpec) { 431 encryptionScheme.putOctetString( 432 ((IvParameterSpec)cipherParam).getIV()); 433 } else { 434 throw new IOException("Wrong parameter type: IV expected"); 435 } 436 pBES2_params.write(DerValue.tag_Sequence, encryptionScheme); 437 438 out.write(DerValue.tag_Sequence, pBES2_params); 439 440 return out.toByteArray(); 441 } 442 443 protected byte[] engineGetEncoded(String encodingMethod) 444 throws IOException 445 { 446 return engineGetEncoded(); 447 } 448 449 /* 450 * Returns a formatted string describing the parameters. 451 * 452 * The algorithn name pattern is: "PBEWith<prf>And<encryption>" 453 * where <prf> is one of: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, 454 * or HmacSHA512, and <encryption> is AES with a keysize suffix. 455 */ 456 protected String engineToString() { 457 return pbes2AlgorithmName; 458 } 459 460 public static final class General extends PBES2Parameters { 461 public General() throws NoSuchAlgorithmException { 462 super(); 463 } 464 } 465 466 public static final class HmacSHA1AndAES_128 extends PBES2Parameters { 467 public HmacSHA1AndAES_128() throws NoSuchAlgorithmException { 468 super("PBEWithHmacSHA1AndAES_128"); 469 } 470 } 471 472 public static final class HmacSHA224AndAES_128 extends PBES2Parameters { 473 public HmacSHA224AndAES_128() throws NoSuchAlgorithmException { 474 super("PBEWithHmacSHA224AndAES_128"); 475 } 476 } 477 478 public static final class HmacSHA256AndAES_128 extends PBES2Parameters { 479 public HmacSHA256AndAES_128() throws NoSuchAlgorithmException { 480 super("PBEWithHmacSHA256AndAES_128"); 481 } 482 } 483 484 public static final class HmacSHA384AndAES_128 extends PBES2Parameters { 485 public HmacSHA384AndAES_128() throws NoSuchAlgorithmException { 486 super("PBEWithHmacSHA384AndAES_128"); 487 } 488 } 489 490 public static final class HmacSHA512AndAES_128 extends PBES2Parameters { 491 public HmacSHA512AndAES_128() throws NoSuchAlgorithmException { 492 super("PBEWithHmacSHA512AndAES_128"); 493 } 494 } 495 496 public static final class HmacSHA1AndAES_256 extends PBES2Parameters { 497 public HmacSHA1AndAES_256() throws NoSuchAlgorithmException { 498 super("PBEWithHmacSHA1AndAES_256"); 499 } 500 } 501 502 public static final class HmacSHA224AndAES_256 extends PBES2Parameters { 503 public HmacSHA224AndAES_256() throws NoSuchAlgorithmException { 504 super("PBEWithHmacSHA224AndAES_256"); 505 } 506 } 507 508 public static final class HmacSHA256AndAES_256 extends PBES2Parameters { 509 public HmacSHA256AndAES_256() throws NoSuchAlgorithmException { 510 super("PBEWithHmacSHA256AndAES_256"); 511 } 512 } 513 514 public static final class HmacSHA384AndAES_256 extends PBES2Parameters { 515 public HmacSHA384AndAES_256() throws NoSuchAlgorithmException { 516 super("PBEWithHmacSHA384AndAES_256"); 517 } 518 } 519 520 public static final class HmacSHA512AndAES_256 extends PBES2Parameters { 521 public HmacSHA512AndAES_256() throws NoSuchAlgorithmException { 522 super("PBEWithHmacSHA512AndAES_256"); 523 } 524 } 525 }