1/* 2 * Copyright (c) 2003, 2016, 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 26package com.sun.crypto.provider; 27 28import java.math.BigInteger; 29import java.security.*; 30import java.security.spec.*; 31import java.util.Arrays; 32import javax.crypto.*; 33import javax.crypto.spec.*; 34 35/** 36 * This class implements password-base encryption algorithm with 37 * SHA1 digest and the following Ciphers (in CBC mode, where applicable): 38 * - DESede cipher and 39 * - RC2 Cipher with 40-bit or 128-bit effective key length and 40 * - RC4 Cipher with 40-bit or 128-bit effective key length 41 * as defined by PKCS #12 version 1.0 standard. 42 * 43 * @author Valerie Peng 44 * @see javax.crypto.CipherSpi 45 */ 46final class PKCS12PBECipherCore { 47 48 // TBD: replace CipherCore with a CipherSpi object to simplify maintenance 49 50 private CipherCore cipher; 51 private int blockSize; 52 private int keySize; 53 private int keyLength; // in bits 54 private String algo = null; 55 private String pbeAlgo = null; 56 private byte[] salt = null; 57 private int iCount = 0; 58 59 private static final int DEFAULT_SALT_LENGTH = 20; 60 private static final int DEFAULT_COUNT = 1024; 61 62 static final int CIPHER_KEY = 1; 63 static final int CIPHER_IV = 2; 64 static final int MAC_KEY = 3; 65 66 // Uses default hash algorithm (SHA-1) 67 static byte[] derive(char[] chars, byte[] salt, 68 int ic, int n, int type) { 69 return derive(chars, salt, ic, n, type, "SHA-1", 64); 70 } 71 72 // Uses supplied hash algorithm 73 static byte[] derive(char[] chars, byte[] salt, int ic, int n, int type, 74 String hashAlgo, int blockLength) { 75 76 // Add in trailing NULL terminator. Special case: 77 // no terminator if password is "\0". 78 int length = chars.length*2; 79 if (length == 2 && chars[0] == 0) { 80 chars = new char[0]; 81 length = 0; 82 } else { 83 length += 2; 84 } 85 86 byte[] passwd = new byte[length]; 87 for (int i = 0, j = 0; i < chars.length; i++, j+=2) { 88 passwd[j] = (byte) ((chars[i] >>> 8) & 0xFF); 89 passwd[j+1] = (byte) (chars[i] & 0xFF); 90 } 91 byte[] key = new byte[n]; 92 93 try { 94 MessageDigest sha = MessageDigest.getInstance(hashAlgo); 95 96 int v = blockLength; 97 int u = sha.getDigestLength(); 98 int c = roundup(n, u) / u; 99 byte[] D = new byte[v]; 100 int s = roundup(salt.length, v); 101 int p = roundup(passwd.length, v); 102 byte[] I = new byte[s + p]; 103 104 Arrays.fill(D, (byte)type); 105 concat(salt, I, 0, s); 106 concat(passwd, I, s, p); 107 108 byte[] Ai; 109 byte[] B = new byte[v]; 110 byte[] tmp = new byte[v]; 111 112 int i = 0; 113 for (; ; i++, n -= u) { 114 sha.update(D); 115 sha.update(I); 116 Ai = sha.digest(); 117 for (int r = 1; r < ic; r++) 118 Ai = sha.digest(Ai); 119 System.arraycopy(Ai, 0, key, u * i, Math.min(n, u)); 120 if (i + 1 == c) 121 break; 122 concat(Ai, B, 0, B.length); 123 BigInteger B1; 124 B1 = new BigInteger(1, B).add(BigInteger.ONE); 125 126 for (int j = 0; j < I.length; j += v) { 127 BigInteger Ij; 128 int trunc; 129 130 if (tmp.length != v) 131 tmp = new byte[v]; 132 System.arraycopy(I, j, tmp, 0, v); 133 Ij = new BigInteger(1, tmp); 134 Ij = Ij.add(B1); 135 tmp = Ij.toByteArray(); 136 trunc = tmp.length - v; 137 if (trunc >= 0) { 138 System.arraycopy(tmp, trunc, I, j, v); 139 } else if (trunc < 0) { 140 Arrays.fill(I, j, j + (-trunc), (byte)0); 141 System.arraycopy(tmp, 0, I, j + (-trunc), tmp.length); 142 } 143 } 144 } 145 } catch (Exception e) { 146 throw new RuntimeException("internal error: " + e); 147 } 148 return key; 149 } 150 151 private static int roundup(int x, int y) { 152 return ((x + (y - 1)) / y) * y; 153 } 154 155 private static void concat(byte[] src, byte[] dst, int start, int len) { 156 if (src.length == 0) { 157 return; 158 } 159 int loop = len / src.length; 160 int off, i; 161 for (i = 0, off = 0; i < loop; i++, off += src.length) 162 System.arraycopy(src, 0, dst, off + start, src.length); 163 System.arraycopy(src, 0, dst, off + start, len - off); 164 } 165 166 PKCS12PBECipherCore(String symmCipherAlg, int defKeySize) 167 throws NoSuchAlgorithmException { 168 169 algo = symmCipherAlg; 170 keyLength = defKeySize * 8; 171 if (algo.equals("RC4")) { 172 pbeAlgo = "PBEWithSHA1AndRC4_" + keyLength; 173 } else { 174 SymmetricCipher symmCipher = null; 175 if (algo.equals("DESede")) { 176 symmCipher = new DESedeCrypt(); 177 pbeAlgo = "PBEWithSHA1AndDESede"; 178 keyLength = 112; // effective key length 179 } else if (algo.equals("RC2")) { 180 symmCipher = new RC2Crypt(); 181 pbeAlgo = "PBEWithSHA1AndRC2_" + keyLength; 182 } else { 183 throw new NoSuchAlgorithmException("No Cipher implementation " + 184 "for PBEWithSHA1And" + algo); 185 } 186 blockSize = symmCipher.getBlockSize(); 187 cipher = new CipherCore(symmCipher, blockSize); 188 cipher.setMode("CBC"); 189 try { 190 cipher.setPadding("PKCS5Padding"); 191 } catch (NoSuchPaddingException nspe) { 192 // should not happen 193 } 194 } 195 keySize = defKeySize; 196 } 197 198 void implSetMode(String mode) throws NoSuchAlgorithmException { 199 if ((mode != null) && (!mode.equalsIgnoreCase("CBC"))) { 200 throw new NoSuchAlgorithmException("Invalid cipher mode: " 201 + mode); 202 } 203 } 204 205 void implSetPadding(String padding) throws NoSuchPaddingException { 206 if ((padding != null) && 207 (!padding.equalsIgnoreCase("PKCS5Padding"))) { 208 throw new NoSuchPaddingException("Invalid padding scheme: " + 209 padding); 210 } 211 } 212 213 int implGetBlockSize() { 214 return blockSize; 215 } 216 217 int implGetOutputSize(int inLen) { 218 return cipher.getOutputSize(inLen); 219 } 220 221 byte[] implGetIV() { 222 return cipher.getIV(); 223 } 224 225 AlgorithmParameters implGetParameters() { 226 AlgorithmParameters params = null; 227 if (salt == null) { 228 // Cipher is not initialized with parameters; 229 // follow the recommendation in PKCS12 v1.0 230 // section B.4 to generate salt and iCount. 231 salt = new byte[DEFAULT_SALT_LENGTH]; 232 SunJCE.getRandom().nextBytes(salt); 233 iCount = DEFAULT_COUNT; 234 } 235 PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); 236 try { 237 params = AlgorithmParameters.getInstance(pbeAlgo, 238 SunJCE.getInstance()); 239 params.init(pbeSpec); 240 } catch (NoSuchAlgorithmException nsae) { 241 // should never happen 242 throw new RuntimeException( 243 "SunJCE provider is not configured properly"); 244 } catch (InvalidParameterSpecException ipse) { 245 // should never happen 246 throw new RuntimeException("PBEParameterSpec not supported"); 247 } 248 return params; 249 } 250 251 void implInit(int opmode, Key key, AlgorithmParameterSpec params, 252 SecureRandom random) throws InvalidKeyException, 253 InvalidAlgorithmParameterException { 254 implInit(opmode, key, params, random, null); 255 } 256 257 void implInit(int opmode, Key key, AlgorithmParameterSpec params, 258 SecureRandom random, CipherSpi cipherImpl) 259 throws InvalidKeyException, 260 InvalidAlgorithmParameterException { 261 char[] passwdChars = null; 262 salt = null; 263 iCount = 0; 264 if (key instanceof javax.crypto.interfaces.PBEKey) { 265 javax.crypto.interfaces.PBEKey pbeKey = 266 (javax.crypto.interfaces.PBEKey) key; 267 passwdChars = pbeKey.getPassword(); 268 salt = pbeKey.getSalt(); // maybe null if unspecified 269 iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified 270 } else if (key instanceof SecretKey) { 271 byte[] passwdBytes = key.getEncoded(); 272 if ((passwdBytes == null) || 273 !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) { 274 throw new InvalidKeyException("Missing password"); 275 } 276 passwdChars = new char[passwdBytes.length]; 277 for (int i=0; i<passwdChars.length; i++) { 278 passwdChars[i] = (char) (passwdBytes[i] & 0x7f); 279 } 280 } else { 281 throw new InvalidKeyException("SecretKey of PBE type required"); 282 } 283 284 if (((opmode == Cipher.DECRYPT_MODE) || 285 (opmode == Cipher.UNWRAP_MODE)) && 286 ((params == null) && ((salt == null) || (iCount == 0)))) { 287 throw new InvalidAlgorithmParameterException 288 ("Parameters missing"); 289 } 290 291 if (params == null) { 292 // generate default for salt and iteration count if necessary 293 if (salt == null) { 294 salt = new byte[DEFAULT_SALT_LENGTH]; 295 if (random != null) { 296 random.nextBytes(salt); 297 } else { 298 SunJCE.getRandom().nextBytes(salt); 299 } 300 } 301 if (iCount == 0) iCount = DEFAULT_COUNT; 302 } else if (!(params instanceof PBEParameterSpec)) { 303 throw new InvalidAlgorithmParameterException 304 ("PBEParameterSpec type required"); 305 } else { 306 PBEParameterSpec pbeParams = (PBEParameterSpec) params; 307 // make sure the parameter values are consistent 308 if (salt != null) { 309 if (!Arrays.equals(salt, pbeParams.getSalt())) { 310 throw new InvalidAlgorithmParameterException 311 ("Inconsistent value of salt between key and params"); 312 } 313 } else { 314 salt = pbeParams.getSalt(); 315 } 316 if (iCount != 0) { 317 if (iCount != pbeParams.getIterationCount()) { 318 throw new InvalidAlgorithmParameterException 319 ("Different iteration count between key and params"); 320 } 321 } else { 322 iCount = pbeParams.getIterationCount(); 323 } 324 } 325 // salt is recommended to be ideally as long as the output 326 // of the hash function. However, it may be too strict to 327 // force this; so instead, we'll just require the minimum 328 // salt length to be 8-byte which is what PKCS#5 recommends 329 // and openssl does. 330 if (salt.length < 8) { 331 throw new InvalidAlgorithmParameterException 332 ("Salt must be at least 8 bytes long"); 333 } 334 if (iCount <= 0) { 335 throw new InvalidAlgorithmParameterException 336 ("IterationCount must be a positive number"); 337 } 338 byte[] derivedKey = derive(passwdChars, salt, iCount, 339 keySize, CIPHER_KEY); 340 SecretKey cipherKey = new SecretKeySpec(derivedKey, algo); 341 342 if (cipherImpl != null && cipherImpl instanceof ARCFOURCipher) { 343 ((ARCFOURCipher)cipherImpl).engineInit(opmode, cipherKey, random); 344 345 } else { 346 byte[] derivedIv = derive(passwdChars, salt, iCount, 8, 347 CIPHER_IV); 348 IvParameterSpec ivSpec = new IvParameterSpec(derivedIv, 0, 8); 349 350 // initialize the underlying cipher 351 cipher.init(opmode, cipherKey, ivSpec, random); 352 } 353 } 354 355 void implInit(int opmode, Key key, AlgorithmParameters params, 356 SecureRandom random) 357 throws InvalidKeyException, InvalidAlgorithmParameterException { 358 implInit(opmode, key, params, random, null); 359 } 360 361 void implInit(int opmode, Key key, AlgorithmParameters params, 362 SecureRandom random, CipherSpi cipherImpl) 363 throws InvalidKeyException, InvalidAlgorithmParameterException { 364 AlgorithmParameterSpec paramSpec = null; 365 if (params != null) { 366 try { 367 paramSpec = params.getParameterSpec(PBEParameterSpec.class); 368 } catch (InvalidParameterSpecException ipse) { 369 throw new InvalidAlgorithmParameterException( 370 "requires PBE parameters"); 371 } 372 } 373 implInit(opmode, key, paramSpec, random, cipherImpl); 374 } 375 376 void implInit(int opmode, Key key, SecureRandom random) 377 throws InvalidKeyException { 378 implInit(opmode, key, random, null); 379 } 380 381 void implInit(int opmode, Key key, SecureRandom random, 382 CipherSpi cipherImpl) throws InvalidKeyException { 383 try { 384 implInit(opmode, key, (AlgorithmParameterSpec) null, random, 385 cipherImpl); 386 } catch (InvalidAlgorithmParameterException iape) { 387 throw new InvalidKeyException("requires PBE parameters"); 388 } 389 } 390 391 byte[] implUpdate(byte[] in, int inOff, int inLen) { 392 return cipher.update(in, inOff, inLen); 393 } 394 395 int implUpdate(byte[] in, int inOff, int inLen, byte[] out, int outOff) 396 throws ShortBufferException { 397 return cipher.update(in, inOff, inLen, out, outOff); 398 } 399 400 byte[] implDoFinal(byte[] in, int inOff, int inLen) 401 throws IllegalBlockSizeException, BadPaddingException { 402 return cipher.doFinal(in, inOff, inLen); 403 } 404 405 int implDoFinal(byte[] in, int inOff, int inLen, byte[] out, int outOff) 406 throws ShortBufferException, IllegalBlockSizeException, 407 BadPaddingException { 408 return cipher.doFinal(in, inOff, inLen, out, outOff); 409 } 410 411 int implGetKeySize(Key key) throws InvalidKeyException { 412 return keyLength; 413 } 414 415 byte[] implWrap(Key key) throws IllegalBlockSizeException, 416 InvalidKeyException { 417 return cipher.wrap(key); 418 } 419 420 Key implUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, 421 int wrappedKeyType) 422 throws InvalidKeyException, NoSuchAlgorithmException { 423 return cipher.unwrap(wrappedKey, wrappedKeyAlgorithm, 424 wrappedKeyType); 425 } 426 427 public static final class PBEWithSHA1AndDESede extends CipherSpi { 428 private final PKCS12PBECipherCore core; 429 public PBEWithSHA1AndDESede() throws NoSuchAlgorithmException { 430 core = new PKCS12PBECipherCore("DESede", 24); 431 } 432 protected byte[] engineDoFinal(byte[] in, int inOff, int inLen) 433 throws IllegalBlockSizeException, BadPaddingException { 434 return core.implDoFinal(in, inOff, inLen); 435 } 436 protected int engineDoFinal(byte[] in, int inOff, int inLen, 437 byte[] out, int outOff) 438 throws ShortBufferException, IllegalBlockSizeException, 439 BadPaddingException { 440 return core.implDoFinal(in, inOff, inLen, out, outOff); 441 } 442 protected int engineGetBlockSize() { 443 return core.implGetBlockSize(); 444 } 445 protected byte[] engineGetIV() { 446 return core.implGetIV(); 447 } 448 protected int engineGetKeySize(Key key) throws InvalidKeyException { 449 return core.implGetKeySize(key); 450 } 451 protected int engineGetOutputSize(int inLen) { 452 return core.implGetOutputSize(inLen); 453 } 454 protected AlgorithmParameters engineGetParameters() { 455 return core.implGetParameters(); 456 } 457 protected void engineInit(int opmode, Key key, 458 AlgorithmParameterSpec params, 459 SecureRandom random) 460 throws InvalidKeyException, InvalidAlgorithmParameterException { 461 core.implInit(opmode, key, params, random); 462 } 463 protected void engineInit(int opmode, Key key, 464 AlgorithmParameters params, 465 SecureRandom random) 466 throws InvalidKeyException, InvalidAlgorithmParameterException { 467 core.implInit(opmode, key, params, random); 468 } 469 protected void engineInit(int opmode, Key key, SecureRandom random) 470 throws InvalidKeyException { 471 core.implInit(opmode, key, random); 472 } 473 protected void engineSetMode(String mode) 474 throws NoSuchAlgorithmException { 475 core.implSetMode(mode); 476 } 477 protected void engineSetPadding(String paddingScheme) 478 throws NoSuchPaddingException { 479 core.implSetPadding(paddingScheme); 480 } 481 protected Key engineUnwrap(byte[] wrappedKey, 482 String wrappedKeyAlgorithm, 483 int wrappedKeyType) 484 throws InvalidKeyException, NoSuchAlgorithmException { 485 return core.implUnwrap(wrappedKey, wrappedKeyAlgorithm, 486 wrappedKeyType); 487 } 488 protected byte[] engineUpdate(byte[] in, int inOff, int inLen) { 489 return core.implUpdate(in, inOff, inLen); 490 } 491 protected int engineUpdate(byte[] in, int inOff, int inLen, 492 byte[] out, int outOff) 493 throws ShortBufferException { 494 return core.implUpdate(in, inOff, inLen, out, outOff); 495 } 496 protected byte[] engineWrap(Key key) 497 throws IllegalBlockSizeException, InvalidKeyException { 498 return core.implWrap(key); 499 } 500 } 501 502 public static final class PBEWithSHA1AndRC2_40 extends CipherSpi { 503 private final PKCS12PBECipherCore core; 504 public PBEWithSHA1AndRC2_40() throws NoSuchAlgorithmException { 505 core = new PKCS12PBECipherCore("RC2", 5); 506 } 507 protected byte[] engineDoFinal(byte[] in, int inOff, int inLen) 508 throws IllegalBlockSizeException, BadPaddingException { 509 return core.implDoFinal(in, inOff, inLen); 510 } 511 protected int engineDoFinal(byte[] in, int inOff, int inLen, 512 byte[] out, int outOff) 513 throws ShortBufferException, IllegalBlockSizeException, 514 BadPaddingException { 515 return core.implDoFinal(in, inOff, inLen, out, outOff); 516 } 517 protected int engineGetBlockSize() { 518 return core.implGetBlockSize(); 519 } 520 protected byte[] engineGetIV() { 521 return core.implGetIV(); 522 } 523 protected int engineGetKeySize(Key key) throws InvalidKeyException { 524 return core.implGetKeySize(key); 525 } 526 protected int engineGetOutputSize(int inLen) { 527 return core.implGetOutputSize(inLen); 528 } 529 protected AlgorithmParameters engineGetParameters() { 530 return core.implGetParameters(); 531 } 532 protected void engineInit(int opmode, Key key, 533 AlgorithmParameterSpec params, 534 SecureRandom random) 535 throws InvalidKeyException, InvalidAlgorithmParameterException { 536 core.implInit(opmode, key, params, random); 537 } 538 protected void engineInit(int opmode, Key key, 539 AlgorithmParameters params, 540 SecureRandom random) 541 throws InvalidKeyException, InvalidAlgorithmParameterException { 542 core.implInit(opmode, key, params, random); 543 } 544 protected void engineInit(int opmode, Key key, SecureRandom random) 545 throws InvalidKeyException { 546 core.implInit(opmode, key, random); 547 } 548 protected void engineSetMode(String mode) 549 throws NoSuchAlgorithmException { 550 core.implSetMode(mode); 551 } 552 protected void engineSetPadding(String paddingScheme) 553 throws NoSuchPaddingException { 554 core.implSetPadding(paddingScheme); 555 } 556 protected Key engineUnwrap(byte[] wrappedKey, 557 String wrappedKeyAlgorithm, 558 int wrappedKeyType) 559 throws InvalidKeyException, NoSuchAlgorithmException { 560 return core.implUnwrap(wrappedKey, wrappedKeyAlgorithm, 561 wrappedKeyType); 562 } 563 protected byte[] engineUpdate(byte[] in, int inOff, int inLen) { 564 return core.implUpdate(in, inOff, inLen); 565 } 566 protected int engineUpdate(byte[] in, int inOff, int inLen, 567 byte[] out, int outOff) 568 throws ShortBufferException { 569 return core.implUpdate(in, inOff, inLen, out, outOff); 570 } 571 protected byte[] engineWrap(Key key) 572 throws IllegalBlockSizeException, InvalidKeyException { 573 return core.implWrap(key); 574 } 575 } 576 577 public static final class PBEWithSHA1AndRC2_128 extends CipherSpi { 578 private final PKCS12PBECipherCore core; 579 public PBEWithSHA1AndRC2_128() throws NoSuchAlgorithmException { 580 core = new PKCS12PBECipherCore("RC2", 16); 581 } 582 protected byte[] engineDoFinal(byte[] in, int inOff, int inLen) 583 throws IllegalBlockSizeException, BadPaddingException { 584 return core.implDoFinal(in, inOff, inLen); 585 } 586 protected int engineDoFinal(byte[] in, int inOff, int inLen, 587 byte[] out, int outOff) 588 throws ShortBufferException, IllegalBlockSizeException, 589 BadPaddingException { 590 return core.implDoFinal(in, inOff, inLen, out, outOff); 591 } 592 protected int engineGetBlockSize() { 593 return core.implGetBlockSize(); 594 } 595 protected byte[] engineGetIV() { 596 return core.implGetIV(); 597 } 598 protected int engineGetKeySize(Key key) throws InvalidKeyException { 599 return core.implGetKeySize(key); 600 } 601 protected int engineGetOutputSize(int inLen) { 602 return core.implGetOutputSize(inLen); 603 } 604 protected AlgorithmParameters engineGetParameters() { 605 return core.implGetParameters(); 606 } 607 protected void engineInit(int opmode, Key key, 608 AlgorithmParameterSpec params, 609 SecureRandom random) 610 throws InvalidKeyException, InvalidAlgorithmParameterException { 611 core.implInit(opmode, key, params, random); 612 } 613 protected void engineInit(int opmode, Key key, 614 AlgorithmParameters params, 615 SecureRandom random) 616 throws InvalidKeyException, InvalidAlgorithmParameterException { 617 core.implInit(opmode, key, params, random); 618 } 619 protected void engineInit(int opmode, Key key, SecureRandom random) 620 throws InvalidKeyException { 621 core.implInit(opmode, key, random); 622 } 623 protected void engineSetMode(String mode) 624 throws NoSuchAlgorithmException { 625 core.implSetMode(mode); 626 } 627 protected void engineSetPadding(String paddingScheme) 628 throws NoSuchPaddingException { 629 core.implSetPadding(paddingScheme); 630 } 631 protected Key engineUnwrap(byte[] wrappedKey, 632 String wrappedKeyAlgorithm, 633 int wrappedKeyType) 634 throws InvalidKeyException, NoSuchAlgorithmException { 635 return core.implUnwrap(wrappedKey, wrappedKeyAlgorithm, 636 wrappedKeyType); 637 } 638 protected byte[] engineUpdate(byte[] in, int inOff, int inLen) { 639 return core.implUpdate(in, inOff, inLen); 640 } 641 protected int engineUpdate(byte[] in, int inOff, int inLen, 642 byte[] out, int outOff) 643 throws ShortBufferException { 644 return core.implUpdate(in, inOff, inLen, out, outOff); 645 } 646 protected byte[] engineWrap(Key key) 647 throws IllegalBlockSizeException, InvalidKeyException { 648 return core.implWrap(key); 649 } 650 } 651 652 public static final class PBEWithSHA1AndRC4_40 extends CipherSpi { 653 private static final int RC4_KEYSIZE = 5; 654 private final PKCS12PBECipherCore core; 655 private final ARCFOURCipher cipher; 656 657 public PBEWithSHA1AndRC4_40() throws NoSuchAlgorithmException { 658 core = new PKCS12PBECipherCore("RC4", RC4_KEYSIZE); 659 cipher = new ARCFOURCipher(); 660 } 661 protected byte[] engineDoFinal(byte[] in, int inOff, int inLen) 662 throws IllegalBlockSizeException, BadPaddingException { 663 return cipher.engineDoFinal(in, inOff, inLen); 664 } 665 protected int engineDoFinal(byte[] in, int inOff, int inLen, 666 byte[] out, int outOff) 667 throws ShortBufferException, IllegalBlockSizeException, 668 BadPaddingException { 669 return cipher.engineDoFinal(in, inOff, inLen, out, outOff); 670 } 671 protected int engineGetBlockSize() { 672 return cipher.engineGetBlockSize(); 673 } 674 protected byte[] engineGetIV() { 675 return cipher.engineGetIV(); 676 } 677 protected int engineGetKeySize(Key key) throws InvalidKeyException { 678 return RC4_KEYSIZE; 679 } 680 protected int engineGetOutputSize(int inLen) { 681 return cipher.engineGetOutputSize(inLen); 682 } 683 protected AlgorithmParameters engineGetParameters() { 684 return core.implGetParameters(); 685 } 686 protected void engineInit(int opmode, Key key, 687 AlgorithmParameterSpec params, 688 SecureRandom random) 689 throws InvalidKeyException, InvalidAlgorithmParameterException { 690 core.implInit(opmode, key, params, random, cipher); 691 } 692 protected void engineInit(int opmode, Key key, 693 AlgorithmParameters params, 694 SecureRandom random) 695 throws InvalidKeyException, InvalidAlgorithmParameterException { 696 core.implInit(opmode, key, params, random, cipher); 697 } 698 protected void engineInit(int opmode, Key key, SecureRandom random) 699 throws InvalidKeyException { 700 core.implInit(opmode, key, random, cipher); 701 } 702 protected void engineSetMode(String mode) 703 throws NoSuchAlgorithmException { 704 if (mode.equalsIgnoreCase("ECB") == false) { 705 throw new NoSuchAlgorithmException("Unsupported mode " + mode); 706 } 707 } 708 protected void engineSetPadding(String paddingScheme) 709 throws NoSuchPaddingException { 710 if (paddingScheme.equalsIgnoreCase("NoPadding") == false) { 711 throw new NoSuchPaddingException("Padding must be NoPadding"); 712 } 713 } 714 protected Key engineUnwrap(byte[] wrappedKey, 715 String wrappedKeyAlgorithm, 716 int wrappedKeyType) 717 throws InvalidKeyException, NoSuchAlgorithmException { 718 return cipher.engineUnwrap(wrappedKey, wrappedKeyAlgorithm, 719 wrappedKeyType); 720 } 721 protected byte[] engineUpdate(byte[] in, int inOff, int inLen) { 722 return cipher.engineUpdate(in, inOff, inLen); 723 } 724 protected int engineUpdate(byte[] in, int inOff, int inLen, 725 byte[] out, int outOff) 726 throws ShortBufferException { 727 return cipher.engineUpdate(in, inOff, inLen, out, outOff); 728 } 729 protected byte[] engineWrap(Key key) 730 throws IllegalBlockSizeException, InvalidKeyException { 731 return cipher.engineWrap(key); 732 } 733 } 734 735 public static final class PBEWithSHA1AndRC4_128 extends CipherSpi { 736 private static final int RC4_KEYSIZE = 16; 737 private final PKCS12PBECipherCore core; 738 private final ARCFOURCipher cipher; 739 740 public PBEWithSHA1AndRC4_128() throws NoSuchAlgorithmException { 741 core = new PKCS12PBECipherCore("RC4", RC4_KEYSIZE); 742 cipher = new ARCFOURCipher(); 743 } 744 protected byte[] engineDoFinal(byte[] in, int inOff, int inLen) 745 throws IllegalBlockSizeException, BadPaddingException { 746 return cipher.engineDoFinal(in, inOff, inLen); 747 } 748 protected int engineDoFinal(byte[] in, int inOff, int inLen, 749 byte[] out, int outOff) 750 throws ShortBufferException, IllegalBlockSizeException, 751 BadPaddingException { 752 return cipher.engineDoFinal(in, inOff, inLen, out, outOff); 753 } 754 protected int engineGetBlockSize() { 755 return cipher.engineGetBlockSize(); 756 } 757 protected byte[] engineGetIV() { 758 return cipher.engineGetIV(); 759 } 760 protected int engineGetKeySize(Key key) throws InvalidKeyException { 761 return RC4_KEYSIZE; 762 } 763 protected int engineGetOutputSize(int inLen) { 764 return cipher.engineGetOutputSize(inLen); 765 } 766 protected AlgorithmParameters engineGetParameters() { 767 return core.implGetParameters(); 768 } 769 protected void engineInit(int opmode, Key key, 770 AlgorithmParameterSpec params, 771 SecureRandom random) 772 throws InvalidKeyException, InvalidAlgorithmParameterException { 773 core.implInit(opmode, key, params, random, cipher); 774 } 775 protected void engineInit(int opmode, Key key, 776 AlgorithmParameters params, 777 SecureRandom random) 778 throws InvalidKeyException, InvalidAlgorithmParameterException { 779 core.implInit(opmode, key, params, random, cipher); 780 } 781 protected void engineInit(int opmode, Key key, SecureRandom random) 782 throws InvalidKeyException { 783 core.implInit(opmode, key, random, cipher); 784 } 785 protected void engineSetMode(String mode) 786 throws NoSuchAlgorithmException { 787 if (mode.equalsIgnoreCase("ECB") == false) { 788 throw new NoSuchAlgorithmException("Unsupported mode " + mode); 789 } 790 } 791 protected void engineSetPadding(String paddingScheme) 792 throws NoSuchPaddingException { 793 if (paddingScheme.equalsIgnoreCase("NoPadding") == false) { 794 throw new NoSuchPaddingException("Padding must be NoPadding"); 795 } 796 } 797 protected Key engineUnwrap(byte[] wrappedKey, 798 String wrappedKeyAlgorithm, 799 int wrappedKeyType) 800 throws InvalidKeyException, NoSuchAlgorithmException { 801 return cipher.engineUnwrap(wrappedKey, wrappedKeyAlgorithm, 802 wrappedKeyType); 803 } 804 protected byte[] engineUpdate(byte[] in, int inOff, int inLen) { 805 return cipher.engineUpdate(in, inOff, inLen); 806 } 807 protected int engineUpdate(byte[] in, int inOff, int inLen, 808 byte[] out, int outOff) 809 throws ShortBufferException { 810 return cipher.engineUpdate(in, inOff, inLen, out, outOff); 811 } 812 protected byte[] engineWrap(Key key) 813 throws IllegalBlockSizeException, InvalidKeyException { 814 return cipher.engineWrap(key); 815 } 816 } 817} 818