AlgorithmParameters implGetParameters() { AlgorithmParameters params = null; if (salt == null) { // Cipher is not initialized with parameters; // follow the recommendation in PKCS12 v1.0 // section B.4 to generate salt and iCount. salt = new byte[DEFAULT_SALT_LENGTH]; SunJCE.getRandom().nextBytes(salt); iCount = DEFAULT_COUNT; } PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); try { params = AlgorithmParameters.getInstance(pbeAlgo, "SunJCE"); } catch (GeneralSecurityException gse) { // should never happen throw new RuntimeException("SunJCE provider is not configured properly"); } try { params.init(pbeSpec); } catch (InvalidParameterSpecException ipse) { // should never happen throw new RuntimeException("PBEParameterSpec not supported"); } return params; }
void implInit( int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random, CipherSpi cipherImpl) throws InvalidKeyException, InvalidAlgorithmParameterException { char[] passwdChars = null; salt = null; iCount = 0; if (key instanceof javax.crypto.interfaces.PBEKey) { javax.crypto.interfaces.PBEKey pbeKey = (javax.crypto.interfaces.PBEKey) key; passwdChars = pbeKey.getPassword(); salt = pbeKey.getSalt(); // maybe null if unspecified iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified } else if (key instanceof SecretKey) { byte[] passwdBytes = key.getEncoded(); if ((passwdBytes == null) || !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) { throw new InvalidKeyException("Missing password"); } passwdChars = new char[passwdBytes.length]; for (int i = 0; i < passwdChars.length; i++) { passwdChars[i] = (char) (passwdBytes[i] & 0x7f); } } else { throw new InvalidKeyException("SecretKey of PBE type required"); } if (((opmode == Cipher.DECRYPT_MODE) || (opmode == Cipher.UNWRAP_MODE)) && ((params == null) && ((salt == null) || (iCount == 0)))) { throw new InvalidAlgorithmParameterException("Parameters missing"); } if (params == null) { // generate default for salt and iteration count if necessary if (salt == null) { salt = new byte[DEFAULT_SALT_LENGTH]; if (random != null) { random.nextBytes(salt); } else { SunJCE.getRandom().nextBytes(salt); } } if (iCount == 0) iCount = DEFAULT_COUNT; } else if (!(params instanceof PBEParameterSpec)) { throw new InvalidAlgorithmParameterException("PBEParameterSpec type required"); } else { PBEParameterSpec pbeParams = (PBEParameterSpec) params; // make sure the parameter values are consistent if (salt != null) { if (!Arrays.equals(salt, pbeParams.getSalt())) { throw new InvalidAlgorithmParameterException( "Inconsistent value of salt between key and params"); } } else { salt = pbeParams.getSalt(); } if (iCount != 0) { if (iCount != pbeParams.getIterationCount()) { throw new InvalidAlgorithmParameterException( "Different iteration count between key and params"); } } else { iCount = pbeParams.getIterationCount(); } } // salt is recommended to be ideally as long as the output // of the hash function. However, it may be too strict to // force this; so instead, we'll just require the minimum // salt length to be 8-byte which is what PKCS#5 recommends // and openssl does. if (salt.length < 8) { throw new InvalidAlgorithmParameterException("Salt must be at least 8 bytes long"); } if (iCount <= 0) { throw new InvalidAlgorithmParameterException("IterationCount must be a positive number"); } byte[] derivedKey = derive(passwdChars, salt, iCount, keySize, CIPHER_KEY); SecretKey cipherKey = new SecretKeySpec(derivedKey, algo); if (cipherImpl != null && cipherImpl instanceof ARCFOURCipher) { ((ARCFOURCipher) cipherImpl).engineInit(opmode, cipherKey, random); } else { byte[] derivedIv = derive(passwdChars, salt, iCount, 8, CIPHER_IV); IvParameterSpec ivSpec = new IvParameterSpec(derivedIv, 0, 8); // initialize the underlying cipher cipher.init(opmode, cipherKey, ivSpec, random); } }