package com.sun.crypto.provider;
import com.sun.crypto.spec.PBE2ParameterSpec;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.*;
import java.util.Arrays;
import javax.crypto.*;
import javax.crypto.interfaces.*;
import javax.crypto.spec.*;
abstract class PBES2Core extends CipherSpi {
private static final int DEFAULT_SALT_LENGTH = 20;
private static final int DEFAULT_COUNT = 4096;
private final CipherCore cipher;
private final int keyLength;
private final int blkSize;
private final PBKDF2Core kdf;
private final String pbeAlgo;
private final String cipherAlgo;
private int iCount = DEFAULT_COUNT;
private byte[] salt = null;
private IvParameterSpec ivSpec = null;
PBES2Core(String kdfAlgo, String cipherAlgo, int keySize)
throws NoSuchAlgorithmException, NoSuchPaddingException {
this.cipherAlgo = cipherAlgo;
keyLength = keySize * 8;
pbeAlgo = "PBEWith" + kdfAlgo + "And" + cipherAlgo + "_" + keyLength;
if (cipherAlgo.equals("AES")) {
blkSize = AESConstants.AES_BLOCK_SIZE;
cipher = new CipherCore(new AESCrypt(), blkSize);
switch(kdfAlgo) {
case "HmacSHA1":
kdf = new PBKDF2Core.HmacSHA1();
break;
case "HmacSHA224":
kdf = new PBKDF2Core.HmacSHA224();
break;
case "HmacSHA256":
kdf = new PBKDF2Core.HmacSHA256();
break;
case "HmacSHA384":
kdf = new PBKDF2Core.HmacSHA384();
break;
case "HmacSHA512":
kdf = new PBKDF2Core.HmacSHA512();
break;
default:
throw new NoSuchAlgorithmException(
"No Cipher implementation for " + kdfAlgo);
}
} else {
throw new NoSuchAlgorithmException("No Cipher implementation for " +
pbeAlgo);
}
cipher.setMode("CBC");
cipher.setPadding("PKCS5Padding");
}
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
if ((mode != null) && (!mode.equalsIgnoreCase("CBC"))) {
throw new NoSuchAlgorithmException("Invalid cipher mode: " + mode);
}
}
protected void engineSetPadding(String paddingScheme)
throws NoSuchPaddingException {
if ((paddingScheme != null) &&
(!paddingScheme.equalsIgnoreCase("PKCS5Padding"))) {
throw new NoSuchPaddingException("Invalid padding scheme: " +
paddingScheme);
}
}
protected int engineGetBlockSize() {
return blkSize;
}
protected int engineGetOutputSize(int inputLen) {
return cipher.getOutputSize(inputLen);
}
protected byte[] engineGetIV() {
return cipher.getIV();
}
protected AlgorithmParameters engineGetParameters() {
AlgorithmParameters params = null;
if (salt == null) {
salt = new byte[DEFAULT_SALT_LENGTH];
SunJCE.RANDOM.nextBytes(salt);
iCount = DEFAULT_COUNT;
}
if (ivSpec == null) {
byte[] ivBytes = new byte[blkSize];
SunJCE.RANDOM.nextBytes(ivBytes);
ivSpec = new IvParameterSpec(ivBytes);
}
PBE2ParameterSpec pbeSpec =new PBE2ParameterSpec(salt, iCount, ivSpec);
try {
params = AlgorithmParameters.getInstance(pbeAlgo, "SunJCE");
} catch (NoSuchAlgorithmException nsae) {
throw new RuntimeException("SunJCE called, but not configured");
} catch (NoSuchProviderException nspe) {
throw new RuntimeException("SunJCE called, but not configured");
}
try {
params.init(pbeSpec);
} catch (InvalidParameterSpecException ipse) {
throw new RuntimeException("PBEParameterSpec not supported");
}
return params;
}
protected void engineInit(int opmode, Key key, SecureRandom random)
throws InvalidKeyException {
try {
engineInit(opmode, key, (AlgorithmParameterSpec) null, random);
} catch (InvalidAlgorithmParameterException ie) {
InvalidKeyException ike =
new InvalidKeyException("requires PBE parameters");
ike.initCause(ie);
throw ike;
}
}
protected void engineInit(int opmode, Key key,
AlgorithmParameterSpec params,
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
if (key == null) {
throw new InvalidKeyException("Null key");
}
byte[] passwdBytes = key.getEncoded();
char[] passwdChars = null;
PBEKeySpec pbeSpec;
try {
if ((passwdBytes == null) ||
!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {
throw new InvalidKeyException("Missing password");
}
if (key instanceof javax.crypto.interfaces.PBEKey) {
salt = ((javax.crypto.interfaces.PBEKey)key).getSalt();
if (salt != null && salt.length < 8) {
throw new InvalidAlgorithmParameterException(
"Salt must be at least 8 bytes long");
}
iCount = ((javax.crypto.interfaces.PBEKey)key).getIterationCount();
if (iCount == 0) {
iCount = DEFAULT_COUNT;
} else if (iCount < 0) {
throw new InvalidAlgorithmParameterException(
"Iteration count must be a positive number");
}
}
if (params == null) {
if (salt == null) {
salt = new byte[DEFAULT_SALT_LENGTH];
random.nextBytes(salt);
iCount = DEFAULT_COUNT;
}
if ((opmode == Cipher.ENCRYPT_MODE) ||
(opmode == Cipher.WRAP_MODE)) {
byte[] ivBytes = new byte[blkSize];
random.nextBytes(ivBytes);
ivSpec = new IvParameterSpec(ivBytes);
}
} else {
if (!(params instanceof PBEParameterSpec)) {
throw new InvalidAlgorithmParameterException
("Wrong parameter type: PBE expected");
}
byte[] specSalt = ((PBEParameterSpec) params).getSalt();
if (specSalt != null && specSalt.length < 8) {
throw new InvalidAlgorithmParameterException(
"Salt must be at least 8 bytes long");
}
salt = specSalt;
int specICount = ((PBEParameterSpec) params).getIterationCount();
if (specICount == 0) {
specICount = DEFAULT_COUNT;
} else if (specICount < 0) {
throw new InvalidAlgorithmParameterException(
"Iteration count must be a positive number");
}
iCount = specICount;
AlgorithmParameterSpec specParams;
if (params instanceof PBE2ParameterSpec &&
(specParams = ((PBE2ParameterSpec) params).getParameterSpec()) != null) {
if (specParams instanceof IvParameterSpec) {
ivSpec = (IvParameterSpec)specParams;
} else {
throw new InvalidAlgorithmParameterException(
"Wrong parameter type: IV expected");
}
} else if ((opmode == Cipher.ENCRYPT_MODE) ||
(opmode == Cipher.WRAP_MODE)) {
byte[] ivBytes = new byte[blkSize];
random.nextBytes(ivBytes);
ivSpec = new IvParameterSpec(ivBytes);
} else {
throw new InvalidAlgorithmParameterException(
"Missing parameter type: IV expected");
}
}
passwdChars = new char[passwdBytes.length];
for (int i = 0; i < passwdChars.length; i++)
passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
pbeSpec = new PBEKeySpec(passwdChars, salt, iCount, keyLength);
} finally {
if (passwdChars != null) Arrays.fill(passwdChars, '\0');
if (passwdBytes != null) Arrays.fill(passwdBytes, (byte)0x00);
}
SecretKey s = null;
try {
s = kdf.engineGenerateSecret(pbeSpec);
} catch (InvalidKeySpecException ikse) {
InvalidKeyException ike =
new InvalidKeyException("Cannot construct PBE key");
ike.initCause(ikse);
throw ike;
}
byte[] derivedKey = s.getEncoded();
SecretKeySpec cipherKey = new SecretKeySpec(derivedKey, cipherAlgo);
cipher.init(opmode, cipherKey, ivSpec, random);
}
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
AlgorithmParameterSpec pbeSpec = null;
if (params != null) {
try {
pbeSpec = params.getParameterSpec(PBEParameterSpec.class);
} catch (InvalidParameterSpecException ipse) {
throw new InvalidAlgorithmParameterException(
"Wrong parameter type: PBE expected");
}
}
engineInit(opmode, key, pbeSpec, random);
}
protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
return cipher.update(input, inputOffset, inputLen);
}
protected int engineUpdate(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset)
throws ShortBufferException {
return cipher.update(input, inputOffset, inputLen,
output, outputOffset);
}
protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException, BadPaddingException {
return cipher.doFinal(input, inputOffset, inputLen);
}
protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset)
throws ShortBufferException, IllegalBlockSizeException,
BadPaddingException {
return cipher.doFinal(input, inputOffset, inputLen,
output, outputOffset);
}
protected int engineGetKeySize(Key key) throws InvalidKeyException {
return keyLength;
}
protected byte[] engineWrap(Key key)
throws IllegalBlockSizeException, InvalidKeyException {
return cipher.wrap(key);
}
protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
int wrappedKeyType)
throws InvalidKeyException, NoSuchAlgorithmException {
byte[] encodedKey;
return cipher.unwrap(wrappedKey, wrappedKeyAlgorithm,
wrappedKeyType);
}
public static final class HmacSHA1AndAES_128 extends PBES2Core {
public HmacSHA1AndAES_128()
throws NoSuchAlgorithmException, NoSuchPaddingException {
super("HmacSHA1", "AES", 16);
}
}
public static final class HmacSHA224AndAES_128 extends PBES2Core {
public HmacSHA224AndAES_128()
throws NoSuchAlgorithmException, NoSuchPaddingException {
super("HmacSHA224", "AES", 16);
}
}
public static final class HmacSHA256AndAES_128 extends PBES2Core {
public HmacSHA256AndAES_128()
throws NoSuchAlgorithmException, NoSuchPaddingException {
super("HmacSHA256", "AES", 16);
}
}
public static final class HmacSHA384AndAES_128 extends PBES2Core {
public HmacSHA384AndAES_128()
throws NoSuchAlgorithmException, NoSuchPaddingException {
super("HmacSHA384", "AES", 16);
}
}
public static final class HmacSHA512AndAES_128 extends PBES2Core {
public HmacSHA512AndAES_128()
throws NoSuchAlgorithmException, NoSuchPaddingException {
super("HmacSHA512", "AES", 16);
}
}
public static final class HmacSHA1AndAES_256 extends PBES2Core {
public HmacSHA1AndAES_256()
throws NoSuchAlgorithmException, NoSuchPaddingException {
super("HmacSHA1", "AES", 32);
}
}
public static final class HmacSHA224AndAES_256 extends PBES2Core {
public HmacSHA224AndAES_256()
throws NoSuchAlgorithmException, NoSuchPaddingException {
super("HmacSHA224", "AES", 32);
}
}
public static final class HmacSHA256AndAES_256 extends PBES2Core {
public HmacSHA256AndAES_256()
throws NoSuchAlgorithmException, NoSuchPaddingException {
super("HmacSHA256", "AES", 32);
}
}
public static final class HmacSHA384AndAES_256 extends PBES2Core {
public HmacSHA384AndAES_256()
throws NoSuchAlgorithmException, NoSuchPaddingException {
super("HmacSHA384", "AES", 32);
}
}
public static final class HmacSHA512AndAES_256 extends PBES2Core {
public HmacSHA512AndAES_256()
throws NoSuchAlgorithmException, NoSuchPaddingException {
super("HmacSHA512", "AES", 32);
}
}
}