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