1 /* 2 * Copyright (c) 2012, 2020, 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.IOException; 29 import java.security.AlgorithmParameters; 30 import java.security.AlgorithmParametersSpi; 31 import java.security.NoSuchAlgorithmException; 32 import java.security.NoSuchProviderException; 33 import java.security.spec.AlgorithmParameterSpec; 34 import java.security.spec.InvalidParameterSpecException; 35 import javax.crypto.spec.IvParameterSpec; 36 import javax.crypto.spec.PBEParameterSpec; 37 import javax.crypto.spec.RC2ParameterSpec; 38 import javax.crypto.spec.RC5ParameterSpec; 39 import sun.security.util.DerOutputStream; 40 import sun.security.util.DerValue; 41 import sun.security.util.ObjectIdentifier; 42 import sun.security.x509.AlgorithmId; 43 44 /** 45 * This class implements the parameter set used with password-based 46 * encryption scheme 2 (PBES2), which is defined in PKCS#5 as follows: 47 * 48 * <pre> 49 * -- PBES2 50 * 51 * PBES2Algorithms ALGORITHM-IDENTIFIER ::= 52 * { {PBES2-params IDENTIFIED BY id-PBES2}, ...} 53 * 54 * id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} 55 * 56 * PBES2-params ::= SEQUENCE { 57 * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, 58 * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } 59 * 60 * PBES2-KDFs ALGORITHM-IDENTIFIER ::= 61 * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... } 62 * 63 * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... } 64 * 65 * -- PBKDF2 66 * 67 * PBKDF2Algorithms ALGORITHM-IDENTIFIER ::= 68 * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...} 69 * 70 * id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} 71 * 72 * PBKDF2-params ::= SEQUENCE { 73 * salt CHOICE { 74 * specified OCTET STRING, 75 * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} 76 * }, 77 * iterationCount INTEGER (1..MAX), 78 * keyLength INTEGER (1..MAX) OPTIONAL, 79 * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 80 * } 81 * 82 * PBKDF2-SaltSources ALGORITHM-IDENTIFIER ::= { ... } 83 * 84 * PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= { 85 * {NULL IDENTIFIED BY id-hmacWithSHA1} | 86 * {NULL IDENTIFIED BY id-hmacWithSHA224} | 87 * {NULL IDENTIFIED BY id-hmacWithSHA256} | 88 * {NULL IDENTIFIED BY id-hmacWithSHA384} | 89 * {NULL IDENTIFIED BY id-hmacWithSHA512}, ... } 90 * 91 * algid-hmacWithSHA1 AlgorithmIdentifier {{PBKDF2-PRFs}} ::= 92 * {algorithm id-hmacWithSHA1, parameters NULL : NULL} 93 * 94 * id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7} 95 * 96 * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... } 97 * 98 * </pre> 99 */ 100 abstract class PBES2Parameters extends AlgorithmParametersSpi { 101 102 // PKCS#5/8 AlgorithmIdentifier OIDs 103 private static final ObjectIdentifier pkcs5PBKDF2_OID = 104 ObjectIdentifier.of("1.2.840.113549.1.5.12"); 105 private static final ObjectIdentifier pkcs5PBES2_OID = 106 ObjectIdentifier.of("1.2.840.113549.1.5.13"); 107 108 // PBKDF2 PRF OIDs 109 private static final ObjectIdentifier hmacWithSHA1_OID = 110 ObjectIdentifier.of("1.2.840.113549.2.7"); 111 private static final ObjectIdentifier hmacWithSHA224_OID = 112 ObjectIdentifier.of("1.2.840.113549.2.8"); 113 private static final ObjectIdentifier hmacWithSHA256_OID = 114 ObjectIdentifier.of("1.2.840.113549.2.9"); 115 private static final ObjectIdentifier hmacWithSHA384_OID = 116 ObjectIdentifier.of("1.2.840.113549.2.10"); 117 private static final ObjectIdentifier hmacWithSHA512_OID = 118 ObjectIdentifier.of("1.2.840.113549.2.11"); 119 private static final ObjectIdentifier hmacWithSHA512_224_OID = 120 ObjectIdentifier.of("1.2.840.113549.2.12"); 121 private static final ObjectIdentifier hmacWithSHA512_256_OID = 122 ObjectIdentifier.of("1.2.840.113549.2.13"); 123 124 // Encryption Scheme OIDs 125 private static final ObjectIdentifier aes128CBC_OID = 126 ObjectIdentifier.of("2.16.840.1.101.3.4.1.2"); 127 private static final ObjectIdentifier aes192CBC_OID = 128 ObjectIdentifier.of("2.16.840.1.101.3.4.1.22"); 129 private static final ObjectIdentifier aes256CBC_OID = 130 ObjectIdentifier.of("2.16.840.1.101.3.4.1.42"); 131 private static final ObjectIdentifier desCBC_OID = 132 ObjectIdentifier.of("1.3.14.3.2.7"); 133 private static final ObjectIdentifier desEDE3CBC_OID = 134 ObjectIdentifier.of("1.2.840.113549.3.7"); 135 private static final ObjectIdentifier rc2CBC_OID = 136 ObjectIdentifier.of("1.2.840.113549.3.2"); 137 private static final ObjectIdentifier rc5CBC_OID = 138 ObjectIdentifier.of("1.2.840.113549.3.9"); 139 140 // Other PRF and Encryption Scheme constants 141 private static final int AES_IVLEN = 16; 142 private static final int DES_IVLEN = 8; 143 private static final int RC2_IVLEN = 8; 144 private static final int RC5_IVLEN_64 = 8; 145 private static final int RC5_IVLEN_128 = 16; 146 147 // Used to indicate both variable length or an unspecified length 148 private static final int KEYLEN_UNSPEC = -1; 149 150 // the PBES2 algorithm name 151 private String pbes2AlgorithmName = "PBES2"; 152 153 // the salt 154 private byte[] salt = null; 155 156 // the iteration count 157 private int iCount = 0; 158 159 // the cipher parameter 160 private AlgorithmParameterSpec cipherParam = null; 161 162 // the key derivation function (default is HmacSHA1) 163 private PrfType kdfType = null; 164 165 // the encryption function 166 private EncType encryptionType = null; 167 168 // the cipher keysize (in bits) 169 private int keysize = KEYLEN_UNSPEC; 170 171 /** 172 * Define the basic characteristics of the PRFs that we are able to 173 * process. 174 */ 175 enum PrfType { 176 HMAC_SHA1(hmacWithSHA1_OID, "HmacSHA1"), 177 HMAC_SHA224(hmacWithSHA224_OID, "HmacSHA224"), 178 HMAC_SHA256(hmacWithSHA256_OID, "HmacSHA256"), 179 HMAC_SHA384(hmacWithSHA384_OID, "HmacSHA384"), 180 HMAC_SHA512(hmacWithSHA512_OID, "HmacSHA512"), 181 HMAC_SHA512_224(hmacWithSHA512_224_OID, "HmacSHA512/224"), 182 HMAC_SHA512_256(hmacWithSHA512_256_OID, "HmacSHA512/256"); 183 184 final ObjectIdentifier schemeOid; 185 final String schemeName; 186 187 private PrfType(ObjectIdentifier oid, String cName) { 188 this.schemeOid = oid; 189 this.schemeName = cName; 190 } 191 192 static PrfType getByName(String name) { 193 for (PrfType prf : PrfType.values()) { 194 if (prf.schemeName.equalsIgnoreCase(name)) { 195 return prf; 196 } 197 } 198 return null; 199 } 200 201 static PrfType getByOid(ObjectIdentifier oid) { 202 for (PrfType prf : PrfType.values()) { 203 if (prf.schemeOid.equals(oid)) { 204 return prf; 205 } 206 } 207 return null; 208 } 209 } 210 211 enum EncType { 212 AES_128_CBC("AES", true, 128, aes128CBC_OID, IvParameterSpec.class), 213 AES_192_CBC("AES", true, 192, aes192CBC_OID, IvParameterSpec.class), 214 AES_256_CBC("AES", true, 256, aes256CBC_OID, IvParameterSpec.class), 215 DES_CBC("DES", true, 64, desCBC_OID, IvParameterSpec.class), 216 DES_EDE3_CBC("DESede", true, 192, desEDE3CBC_OID, 217 IvParameterSpec.class), 218 RC2_CBC("RC2", false, KEYLEN_UNSPEC, rc2CBC_OID, RC2ParameterSpec.class), 219 RC5_CBC("RC5", false, KEYLEN_UNSPEC, rc5CBC_OID, RC5ParameterSpec.class); 220 221 final String schemeName; 222 final boolean fixedKeySize; 223 final int keyLen; 224 final ObjectIdentifier oid; 225 final Class<? extends AlgorithmParameterSpec> specClass; 226 227 private EncType(String name, boolean fixed, int keyLen, 228 ObjectIdentifier oid, 229 Class<? extends AlgorithmParameterSpec> clazz) { 230 schemeName = name; 231 fixedKeySize = fixed; 232 this.keyLen = keyLen; 233 this.oid = oid; 234 specClass = clazz; 235 } 236 237 static EncType getByOid(ObjectIdentifier oid) { 238 for (EncType enc : EncType.values()) { 239 if (enc.oid.equals(oid)) { 240 return enc; 241 } 242 } 243 return null; 244 } 245 246 static EncType getByName(String algName, int keylen) { 247 for (EncType enc : EncType.values()) { 248 if (enc.schemeName.equalsIgnoreCase(algName)) { 249 if (enc.fixedKeySize) { 250 if (enc.keyLen == keylen || 251 enc.keyLen == KEYLEN_UNSPEC) { 252 // This case is for schemes where the key size 253 // is fixed either by OID (e.g. AES-128/192/256)\ 254 // or where it is always the same for an algorithm 255 // and therefore not specified by name (DES/DESede). 256 return enc; 257 } 258 } else { 259 // For a variable length key a single enc scheme 260 // will handle all values and they will be verified 261 // later if specified in DER. 262 return enc; 263 } 264 } 265 } 266 return null; 267 } 268 } 269 270 protected PBES2Parameters() { 271 // KDF, encryption & keysize values are set later, in engineInit(byte[]) 272 } 273 274 protected PBES2Parameters(String pbes2AlgorithmName) 275 throws NoSuchAlgorithmException { 276 int and; 277 String kdfAlgo = null; 278 String cipherAlgo = null; 279 280 // Extract the KDF and encryption algorithm names 281 this.pbes2AlgorithmName = pbes2AlgorithmName; 282 if (pbes2AlgorithmName.startsWith("PBEWith") && 283 (and = pbes2AlgorithmName.indexOf("And", 7 + 1)) > 0) { 284 kdfAlgo = pbes2AlgorithmName.substring(7, and); 285 cipherAlgo = pbes2AlgorithmName.substring(and + 3); 286 287 // Check for keysize 288 int underscore; 289 if ((underscore = cipherAlgo.indexOf('_')) > 0) { 290 int slash; 291 if ((slash = cipherAlgo.indexOf('/', underscore + 1)) > 0) { 292 keysize = 293 Integer.parseInt(cipherAlgo.substring(underscore + 1, 294 slash)); 295 } else { 296 keysize = 297 Integer.parseInt(cipherAlgo.substring(underscore + 1)); 298 } 299 cipherAlgo = cipherAlgo.substring(0, underscore); 300 } 301 } else { 302 throw new NoSuchAlgorithmException("No crypto implementation for " + 303 pbes2AlgorithmName); 304 } 305 306 kdfType = PrfType.getByName(kdfAlgo); 307 if (kdfType == null) { 308 throw new NoSuchAlgorithmException("Unsupported KDF: " + kdfAlgo); 309 } 310 encryptionType = EncType.getByName(cipherAlgo, keysize); 311 if (encryptionType == null) { 312 throw new NoSuchAlgorithmException( 313 "Unsupported Encryption Scheme: " + cipherAlgo); 314 } 315 } 316 317 @Override 318 protected void engineInit(AlgorithmParameterSpec paramSpec) 319 throws InvalidParameterSpecException { 320 if (!(paramSpec instanceof PBEParameterSpec)) { 321 throw new InvalidParameterSpecException 322 ("Inappropriate parameter specification"); 323 } 324 this.salt = ((PBEParameterSpec)paramSpec).getSalt().clone(); 325 this.iCount = ((PBEParameterSpec)paramSpec).getIterationCount(); 326 this.cipherParam = ((PBEParameterSpec)paramSpec).getParameterSpec(); 327 328 // In this form of initialization, if the kdfType has not 329 // been set by the constructor, we will set it to the default 330 // HMAC-SHA1. 331 if (kdfType == null) { 332 kdfType = PrfType.HMAC_SHA1; 333 } 334 335 // Perform a sanity check to make sure that the supplied 336 // cipher AlgorithmParameterSpec is the correct type for the selected 337 // encryption scheme that was chosen at instantiation time. 338 if (encryptionType != null) { 339 validateEncParams(); 340 try { 341 pbes2AlgorithmName = String.format("PBEWith%sAnd%s", 342 kdfType.schemeName, getEncSchemeName()); 343 } catch (NoSuchAlgorithmException nsae) { 344 throw (InvalidParameterSpecException) 345 new InvalidParameterSpecException().initCause(nsae); 346 } 347 } else { 348 // This branch will be walked if the generic form of the 349 // PBES2Parameters is created. Use of this form of init with 350 // PBES2Parameters.General is disallowed. This is because in some 351 // cases there is no way to know from the submitted cipher 352 // AlgorithmParameterSpec which encryption scheme has been 353 // selected (i.e. multiple CBC-based ciphers all use 354 // IvParameterSpec) 355 throw new InvalidParameterSpecException("Invalid initialization " + 356 "method when no encryption scheme explicitly selected."); 357 } 358 } 359 360 @Override 361 protected void engineInit(byte[] encoded, String decodingMethod) 362 throws IOException { 363 engineInit(encoded); 364 } 365 366 @Override 367 protected void engineInit(byte[] encoded) throws IOException { 368 DerValue pBES2_params = new DerValue(encoded); 369 if (pBES2_params.tag != DerValue.tag_Sequence) { 370 throw new IOException("PBE parameter parsing error: " 371 + "not an ASN.1 SEQUENCE tag"); 372 } 373 DerValue kdf = pBES2_params.data.getDerValue(); 374 375 // Before JDK-8202837, PBES2-params was mistakenly encoded like 376 // an AlgorithmId which is a sequence of its own OID and the real 377 // PBES2-params. If the first DerValue is an OID instead of a 378 // PBES2-KDFs (which should be a SEQUENCE), we are likely to be 379 // dealing with this buggy encoding. Skip the OID and treat the 380 // next DerValue as the real PBES2-params. 381 if (kdf.getTag() == DerValue.tag_ObjectId) { 382 pBES2_params = pBES2_params.data.getDerValue(); 383 kdf = pBES2_params.data.getDerValue(); 384 } 385 386 parseKDF(kdf); 387 388 parseES(pBES2_params.data.getDerValue()); 389 390 try { 391 validateEncParams(); 392 pbes2AlgorithmName = String.format("PBEWith%sAnd%s", 393 kdfType.schemeName, getEncSchemeName()); 394 } catch (InvalidParameterSpecException | NoSuchAlgorithmException exc) { 395 throw new IOException(exc); 396 } 397 } 398 399 /** 400 * Parse the PBES2-KDFs portion of the PBES2 parameters structure: 401 * 402 * PBES2-KDFs ALGORITHM-IDENTIFIER ::= 403 * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... } 404 * 405 * PBKDF2-params ::= SEQUENCE { 406 * salt CHOICE { 407 * specified OCTET STRING, 408 * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} 409 * }, 410 * iterationCount INTEGER (1..MAX), 411 * keyLength INTEGER (1..MAX) OPTIONAL, 412 * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 413 * } 414 * 415 * @param keyDerivationFunc a DerValue built from the outer SEQUENCE 416 * that begins the PBES2-KDFs structure. 417 * 418 * @throws IOException if any processing failures occur or the values 419 * read sit outside acceptable ranges. 420 */ 421 private void parseKDF(DerValue keyDerivationFunc) throws IOException { 422 // The incoming keyDerivationFunc is an AlgorithmID. Ensure that 423 // the DerValue is a SEQUENCE with the first element being the correct 424 // PBKDF2 OID. 425 if (keyDerivationFunc.tag != DerValue.tag_Sequence) { 426 throw new IOException("PBES2-KDFs DerValue is not a SEQUENCE"); 427 } else if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { 428 throw new IOException("PBE parameter parsing error: " 429 + "expecting the object identifier for PBKDF2"); 430 } 431 432 // Pull out all the elements out of the PBKDF2-params structure 433 DerValue[] pk2Params = keyDerivationFunc.data.getSequence(4); 434 int idx = 0; 435 if (pk2Params.length < 2 || pk2Params.length > 4) { 436 throw new IOException("Invalid number of PBKDF2-params elements " + 437 "(2 <= X <= 4), got " + pk2Params.length); 438 } 439 440 DerValue curParam = pk2Params[idx++]; 441 // salt: specified OCTET STRING 442 // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported 443 salt = curParam.getOctetString(); 444 445 // iterationCount INTEGER (1..MAX) 446 iCount = pk2Params[idx++].getInteger(); 447 if (iCount < 1) { 448 throw new IOException("Illegal non-positive iteration count: " + 449 iCount); 450 } 451 452 // keyLength INTEGER (1..MAX) OPTIONAL 453 if (idx < pk2Params.length) { 454 curParam = pk2Params[idx]; 455 if (curParam.tag == DerValue.tag_Integer) { 456 int keysizeBytes = curParam.getInteger(); 457 if (keysizeBytes < 1) { 458 throw new IOException("Illegal non-positive key length: " + 459 keysizeBytes); 460 } else { 461 // If keyLength is specified, it should be consistent 462 // with the declared key length (if any). 463 int derKeyBits = keysizeBytes * 8; 464 if (keysize >= 0) { 465 if (keysize != derKeyBits) { 466 throw new IOException("PBKDF2-param keyLength " + 467 "mismatch: expected " + keysize + 468 ", received " + derKeyBits); 469 } 470 } else { 471 keysize = derKeyBits; 472 } 473 idx++; 474 } 475 } 476 } 477 478 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 479 PrfType receivedKdf; 480 if (idx < pk2Params.length) { 481 curParam = pk2Params[idx]; 482 // The AlgorithmIdentifier will have an OID and optionally 483 // parameters. Currently the parameters for all the PRFs we 484 // support are either ASN.1 NULL or are omitted entirely. 485 ObjectIdentifier providedKdfOid = curParam.data.getOID(); 486 receivedKdf = PrfType.getByOid(providedKdfOid); 487 if (receivedKdf != null) { 488 // AlgorithmIdentifiers have the parameters section defined 489 // in RFC 5280 as ANY DEFINED BY algorithm OPTIONAL. Since 490 // all the current KDF algs we use are HMAC-SHA* they have 491 // no parameters. We will accept an ASN.1 NULL or a complete 492 // omission of the AlgId parameters segment. 493 if (curParam.data.available() > 0) { 494 curParam.data.getNull(); 495 } 496 } else { 497 throw new IOException("PBE parameter parsing error: " + 498 "Unsupported PRF OID: " + providedKdfOid); 499 } 500 } else { 501 receivedKdf = PrfType.HMAC_SHA1; 502 } 503 504 // Lastly, if a KDF type has already been set as a result of 505 // instantiation by the complete PBES2 name 506 // (e.g. PBEWith<prf>And<encryption>), and the KDF 507 // OID indicated by the DER encoding does not match, then this is 508 // an error. 509 if (kdfType != null && kdfType != receivedKdf) { 510 throw new IOException("Requested instance KDF does not match " + 511 "received KDF type, inst: " + kdfType.schemeOid + 512 ", received: " + receivedKdf.schemeOid); 513 } else { 514 // Instantiated via the PBES2Parameters.General, the DER determines 515 // the KDF OID. 516 kdfType = receivedKdf; 517 } 518 } 519 520 /** 521 * Parse the PBES2-Encs portion of the PBES2 parameters structure: 522 * 523 * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... } 524 * 525 * where the definitions of the encryption scheme parameters are found 526 * in the AlgIdParams implementations for each encryption scheme. 527 * 528 * @param encryptionScheme a DerValue built from the outer SEQUENCE 529 * that begins the PBES2-Encss structure. 530 * 531 * @throws IOException if any processing failures occur or the values 532 * read sit outside acceptable ranges. 533 */ 534 private void parseES(DerValue encryptionScheme) throws IOException { 535 AlgorithmId encAlgId = AlgorithmId.parse(encryptionScheme); 536 ObjectIdentifier esOid = encAlgId.getOID(); 537 EncType receivedEncType = EncType.getByOid(esOid); 538 if (receivedEncType == null) { 539 throw new IOException("Unsupported encryption scheme for OID " + 540 esOid); 541 } 542 543 // Compare any pre-set encryptionType against what we found in the DER. 544 if (encryptionType != null && encryptionType != receivedEncType) { 545 throw new IOException("Requested instance encryption scheme does " + 546 "not match the received encryption scheme type. " + 547 "Inst: " + encryptionType.oid + 548 ", received: " + receivedEncType.oid); 549 } else { 550 // Instantiated via the PBES2Parameters.General, the DER 551 // determines the EncType. 552 encryptionType = receivedEncType; 553 } 554 555 // Pull the data out as an AlgorithmParameterSpec and assign it 556 // to the main PBES2 object 557 AlgorithmParameters encrParams = encAlgId.getParameters(); 558 try { 559 cipherParam = (encrParams != null) ? 560 encrParams.getParameterSpec(encryptionType.specClass) : 561 null; 562 } catch (InvalidParameterSpecException ipse) { 563 throw new IOException(ipse); 564 } 565 } 566 567 @Override 568 protected <T extends AlgorithmParameterSpec> 569 T engineGetParameterSpec(Class<T> paramSpec) 570 throws InvalidParameterSpecException { 571 if (PBEParameterSpec.class.isAssignableFrom(paramSpec)) { 572 return paramSpec.cast(new PBEParameterSpec(this.salt, 573 this.iCount, this.cipherParam)); 574 } else { 575 throw new InvalidParameterSpecException 576 ("Inappropriate parameter specification"); 577 } 578 } 579 580 @Override 581 protected byte[] engineGetEncoded() throws IOException { 582 DerOutputStream out = new DerOutputStream(); 583 584 DerOutputStream pBES2_params = new DerOutputStream(); 585 586 DerOutputStream keyDerivationFunc = new DerOutputStream(); 587 keyDerivationFunc.putOID(pkcs5PBKDF2_OID); 588 589 DerOutputStream pBKDF2_params = new DerOutputStream(); 590 pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING' 591 pBKDF2_params.putInteger(iCount); 592 593 // derived key length (in octets) 594 // keyLength INTEGER (1..MAX) OPTIONAL 595 // This only needs to be asserted for OIDs that have variable 596 // key lengths associated with it. 597 if (!encryptionType.fixedKeySize && keysize != KEYLEN_UNSPEC) { 598 pBKDF2_params.putInteger(keysize / 8); 599 } 600 601 DerOutputStream prf = new DerOutputStream(); 602 prf.putOID(kdfType.schemeOid); 603 // Note: we do not use an ASN.1 NULL tag for the parameters for any 604 // of the HMAC-SHA* KDF algs we use. 605 pBKDF2_params.write(DerValue.tag_Sequence, prf); 606 607 keyDerivationFunc.write(DerValue.tag_Sequence, pBKDF2_params); 608 pBES2_params.write(DerValue.tag_Sequence, keyDerivationFunc); 609 610 DerOutputStream encryptionScheme = new DerOutputStream(); 611 encryptionScheme.putOID(encryptionType.oid); 612 if (cipherParam != null) { 613 try { 614 AlgorithmParameters encParams = AlgorithmParameters.getInstance( 615 encryptionType.schemeName, "SunJCE"); 616 encParams.init(cipherParam); 617 byte[] encrData = encParams.getEncoded(); 618 encryptionScheme.write(encrData); 619 } catch (NoSuchAlgorithmException | NoSuchProviderException | 620 InvalidParameterSpecException exc) { 621 throw new IOException(exc); 622 } 623 } else { 624 throw new IOException("Missing encryption scheme parameters: " + 625 "expected " + encryptionType.specClass.getName()); 626 } 627 pBES2_params.write(DerValue.tag_Sequence, encryptionScheme); 628 629 out.write(DerValue.tag_Sequence, pBES2_params); 630 631 return out.toByteArray(); 632 } 633 634 @Override 635 protected byte[] engineGetEncoded(String encodingMethod) 636 throws IOException { 637 return engineGetEncoded(); 638 } 639 640 private void validateEncParams() throws InvalidParameterSpecException { 641 if (this.cipherParam == null) { 642 // No encryption scheme AlgorithmParameterSpec was provided 643 // at init time. 644 return; 645 } 646 647 if (encryptionType.specClass != null) { 648 if (!encryptionType.specClass.isAssignableFrom( 649 this.cipherParam.getClass())) { 650 throw new InvalidParameterSpecException( 651 "Illegal parameter spec for encryption OID " + 652 encryptionType.oid + ". Submitted " + 653 this.cipherParam.getClass().getName() + 654 ", expected " + encryptionType.specClass.getName() + 655 " (or subclass)"); 656 } 657 } 658 659 switch (encryptionType) { 660 case AES_128_CBC: 661 case AES_192_CBC: 662 case AES_256_CBC: 663 validateIvPS(AES_IVLEN); 664 break; 665 case DES_CBC: 666 case DES_EDE3_CBC: 667 validateIvPS(DES_IVLEN); 668 break; 669 case RC2_CBC: 670 validateRC2PS(); 671 break; 672 case RC5_CBC: 673 validateRC5PS(); 674 break; 675 default: 676 throw new InvalidParameterSpecException( 677 "Unsupported encryption type"); 678 } 679 680 // Finally perform any key size consistency checks. 681 // If fixed, the key size should only be checked if it had ever been 682 // asserted. If variable, the key size must have been defined 683 // somehow prior to this, either by name, by encoding, or a default. 684 if (encryptionType.fixedKeySize) { 685 if (keysize != KEYLEN_UNSPEC && keysize != encryptionType.keyLen) { 686 throw new InvalidParameterSpecException("Key size mismatch. " + 687 "Expected: " + encryptionType.keyLen + ", actual: " + 688 keysize); 689 } 690 } else { 691 if (keysize == KEYLEN_UNSPEC) { 692 throw new InvalidParameterSpecException("Variable length " + 693 "encryption scheme has no key size defined"); 694 } 695 } 696 } 697 698 private void validateIvPS(int ivReqLen) 699 throws InvalidParameterSpecException { 700 IvParameterSpec ivSpec = (IvParameterSpec)cipherParam; 701 byte[] ivBytes = ivSpec.getIV(); 702 if (ivBytes.length != ivReqLen) { 703 throw new InvalidParameterSpecException( 704 "Incorrect IV length, expected " + ivReqLen + 705 " bytes, received " + ivBytes.length); 706 } 707 } 708 709 private void validateRC2PS() throws InvalidParameterSpecException { 710 RC2ParameterSpec rc2Spec = (RC2ParameterSpec)cipherParam; 711 712 // If an IV has been set, make sure it is of the correct length 713 byte[] ivBytes = rc2Spec.getIV(); 714 if (ivBytes.length != RC2_IVLEN) { 715 throw new InvalidParameterSpecException( 716 "Incorrect IV length, expected " + RC2_IVLEN + 717 " bytes, received " + ivBytes.length); 718 } 719 720 // It is possible that key length is still unset if initialized by 721 // DER encoding with no key length called out in the PBKDF2-Params. 722 // If the key length is unset, then set it based on the effective 723 // key bits from this AlgorithmParameterSpec. If already set either 724 // by virtue of the AlgorithmParameters name or from the PBKDF2-Params 725 // then this value should be consistent with it. 726 int psKeyLen = rc2Spec.getEffectiveKeyBits(); 727 if (keysize <= 0) { 728 keysize = psKeyLen; 729 } else { 730 if (keysize != psKeyLen) { 731 throw new InvalidParameterSpecException("Effective key length" + 732 " mismatch: expected " + keysize + ", received: " + 733 psKeyLen); 734 } 735 } 736 } 737 738 private void validateRC5PS() throws InvalidParameterSpecException { 739 // Some of these checks will be redundant if the AlgorithmParameterSpec 740 // is constructed via DER decoding, but if provided via the engineInit 741 // method it may have values inconsistent with the ranges in the 742 // ASN.1 from RFC 8018. 743 RC5ParameterSpec rc5Spec = (RC5ParameterSpec)cipherParam; 744 int rounds = rc5Spec.getRounds(); 745 if (rounds < 8 || rounds > 127) { 746 throw new InvalidParameterSpecException("Rounds must be in the " + 747 "range 8..127, received " + rounds); 748 } 749 750 int wordSize = rc5Spec.getWordSize(); 751 if (wordSize != 32 && wordSize != 64) { 752 throw new InvalidParameterSpecException("Word size must be " + 753 "either 32 or 64 bits, received " + wordSize); 754 } 755 756 // If we get to this point and for some reason the RC5 PBES2 block 757 // hasn't specified a key length either in the PBKDF2 block or via 758 // the name during construction, assign it a default of 128-bit. 759 if (keysize == KEYLEN_UNSPEC) { 760 keysize = 128; 761 } 762 763 // No need to check word size against IV length, as RC5ParameterSpec 764 // already performs this check upon construction when an IV is provided. 765 } 766 767 private String getEncSchemeName() throws NoSuchAlgorithmException { 768 switch (encryptionType) { 769 case AES_128_CBC: 770 case AES_192_CBC: 771 case AES_256_CBC: 772 return (encryptionType.schemeName + "_" + 773 encryptionType.keyLen); 774 case DES_CBC: 775 case DES_EDE3_CBC: 776 return encryptionType.schemeName; 777 case RC2_CBC: 778 case RC5_CBC: 779 return (encryptionType.schemeName + "_" + keysize); 780 default: 781 // Should never happen 782 throw new NoSuchAlgorithmException( 783 "Unsupported encryption type: " + 784 encryptionType.name()); 785 } 786 } 787 788 /* 789 * Returns a formatted string describing the parameters. 790 * 791 * The algorithn name pattern is: "PBEWith<prf>And<encryption>" 792 * where <prf> is one of: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, 793 * or HmacSHA512, and <encryption> is AES with a keysize suffix. 794 */ 795 @Override 796 protected String engineToString() { 797 return pbes2AlgorithmName; 798 } 799 800 public static final class General extends PBES2Parameters { 801 public General() throws NoSuchAlgorithmException { 802 super(); 803 } 804 } 805 806 public static final class HmacSHA1AndAES_128 extends PBES2Parameters { 807 public HmacSHA1AndAES_128() throws NoSuchAlgorithmException { 808 super("PBEWithHmacSHA1AndAES_128"); 809 } 810 } 811 812 public static final class HmacSHA224AndAES_128 extends PBES2Parameters { 813 public HmacSHA224AndAES_128() throws NoSuchAlgorithmException { 814 super("PBEWithHmacSHA224AndAES_128"); 815 } 816 } 817 818 public static final class HmacSHA256AndAES_128 extends PBES2Parameters { 819 public HmacSHA256AndAES_128() throws NoSuchAlgorithmException { 820 super("PBEWithHmacSHA256AndAES_128"); 821 } 822 } 823 824 public static final class HmacSHA384AndAES_128 extends PBES2Parameters { 825 public HmacSHA384AndAES_128() throws NoSuchAlgorithmException { 826 super("PBEWithHmacSHA384AndAES_128"); 827 } 828 } 829 830 public static final class HmacSHA512AndAES_128 extends PBES2Parameters { 831 public HmacSHA512AndAES_128() throws NoSuchAlgorithmException { 832 super("PBEWithHmacSHA512AndAES_128"); 833 } 834 } 835 836 public static final class HmacSHA1AndAES_256 extends PBES2Parameters { 837 public HmacSHA1AndAES_256() throws NoSuchAlgorithmException { 838 super("PBEWithHmacSHA1AndAES_256"); 839 } 840 } 841 842 public static final class HmacSHA224AndAES_256 extends PBES2Parameters { 843 public HmacSHA224AndAES_256() throws NoSuchAlgorithmException { 844 super("PBEWithHmacSHA224AndAES_256"); 845 } 846 } 847 848 public static final class HmacSHA256AndAES_256 extends PBES2Parameters { 849 public HmacSHA256AndAES_256() throws NoSuchAlgorithmException { 850 super("PBEWithHmacSHA256AndAES_256"); 851 } 852 } 853 854 public static final class HmacSHA384AndAES_256 extends PBES2Parameters { 855 public HmacSHA384AndAES_256() throws NoSuchAlgorithmException { 856 super("PBEWithHmacSHA384AndAES_256"); 857 } 858 } 859 860 public static final class HmacSHA512AndAES_256 extends PBES2Parameters { 861 public HmacSHA512AndAES_256() throws NoSuchAlgorithmException { 862 super("PBEWithHmacSHA512AndAES_256"); 863 } 864 } 865 }