package sun.security.pkcs11;
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.*;
import static sun.security.pkcs11.TemplateManager.*;
import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
final class P11KeyGenerator extends KeyGeneratorSpi {
private final Token token;
private final String algorithm;
private long mechanism;
private int keySize;
private int significantKeySize;
private long keyType;
private boolean supportBothKeySizes;
private int minKeySize;
private int maxKeySize;
P11KeyGenerator(Token token, String algorithm, long mechanism)
throws PKCS11Exception {
super();
this.token = token;
this.algorithm = algorithm;
this.mechanism = mechanism;
if (this.mechanism == CKM_DES3_KEY_GEN) {
supportBothKeySizes =
(token.provider.config.isEnabled(CKM_DES2_KEY_GEN) &&
(token.getMechanismInfo(CKM_DES2_KEY_GEN) != null));
} else if (this.mechanism == CKM_RC4_KEY_GEN) {
CK_MECHANISM_INFO info = token.getMechanismInfo(mechanism);
if (info.ulMinKeySize < 8) {
minKeySize = (int)info.ulMinKeySize << 3;
maxKeySize = (int)info.ulMaxKeySize << 3;
} else {
minKeySize = (int)info.ulMinKeySize;
maxKeySize = (int)info.ulMaxKeySize;
}
if (minKeySize < 40) minKeySize = 40;
} else if (this.mechanism == CKM_BLOWFISH_KEY_GEN) {
CK_MECHANISM_INFO info = token.getMechanismInfo(mechanism);
maxKeySize = (int)info.ulMaxKeySize << 3;
minKeySize = (int)info.ulMinKeySize << 3;
if (minKeySize < 40) minKeySize = 40;
}
setDefaultKeySize();
}
private void setDefaultKeySize() {
boolean validateKeySize = false;
switch ((int)mechanism) {
case (int)CKM_DES_KEY_GEN:
keySize = 64;
significantKeySize = 56;
keyType = CKK_DES;
break;
case (int)CKM_DES2_KEY_GEN:
keySize = 128;
significantKeySize = 112;
keyType = CKK_DES2;
break;
case (int)CKM_DES3_KEY_GEN:
keySize = 192;
significantKeySize = 168;
keyType = CKK_DES3;
break;
case (int)CKM_AES_KEY_GEN:
keyType = CKK_AES;
keySize = 128;
significantKeySize = 128;
break;
case (int)CKM_RC4_KEY_GEN:
keyType = CKK_RC4;
keySize = 128;
validateKeySize = true;
break;
case (int)CKM_BLOWFISH_KEY_GEN:
keyType = CKK_BLOWFISH;
keySize = 128;
validateKeySize = true;
break;
default:
throw new ProviderException("Unknown mechanism " + mechanism);
}
if (validateKeySize &&
((keySize > maxKeySize) || (keySize < minKeySize))) {
throw new ProviderException("Unsupported key size");
}
}
protected void engineInit(SecureRandom random) {
token.ensureValid();
setDefaultKeySize();
}
protected void engineInit(AlgorithmParameterSpec params,
SecureRandom random) throws InvalidAlgorithmParameterException {
throw new InvalidAlgorithmParameterException
("AlgorithmParameterSpec not supported");
}
protected void engineInit(int keySize, SecureRandom random) {
token.ensureValid();
switch ((int)mechanism) {
case (int)CKM_DES_KEY_GEN:
if ((keySize != this.keySize) &&
(keySize != this.significantKeySize)) {
throw new InvalidParameterException
("DES key length must be 56 bits");
}
break;
case (int)CKM_DES2_KEY_GEN:
case (int)CKM_DES3_KEY_GEN:
long newMechanism;
if ((keySize == 112) || (keySize == 128)) {
newMechanism = CKM_DES2_KEY_GEN;
} else if ((keySize == 168) || (keySize == 192)) {
newMechanism = CKM_DES3_KEY_GEN;
} else {
throw new InvalidParameterException
("DESede key length must be 112, or 168 bits");
}
if (mechanism != newMechanism) {
if (supportBothKeySizes) {
mechanism = newMechanism;
setDefaultKeySize();
} else {
throw new InvalidParameterException
("Only " + significantKeySize +
"-bit DESede key length is supported");
}
}
break;
case (int)CKM_AES_KEY_GEN:
if ((keySize != 128) && (keySize != 192) && (keySize != 256)) {
throw new InvalidParameterException
("AES key length must be 128, 192, or 256 bits");
}
this.keySize = keySize;
significantKeySize = keySize;
break;
case (int)CKM_RC4_KEY_GEN:
case (int)CKM_BLOWFISH_KEY_GEN:
if ((keySize < minKeySize) || (keySize > maxKeySize)) {
throw new InvalidParameterException
(algorithm + " key length must be between " +
minKeySize + " and " + maxKeySize + " bits");
}
this.keySize = keySize;
this.significantKeySize = keySize;
break;
default:
throw new ProviderException("Unknown mechanism " + mechanism);
}
}
protected SecretKey engineGenerateKey() {
Session session = null;
try {
session = token.getObjSession();
CK_ATTRIBUTE[] attributes;
switch ((int)keyType) {
case (int)CKK_DES:
case (int)CKK_DES2:
case (int)CKK_DES3:
attributes = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
};
break;
default:
attributes = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
new CK_ATTRIBUTE(CKA_VALUE_LEN, keySize >> 3),
};
break;
}
attributes = token.getAttributes
(O_GENERATE, CKO_SECRET_KEY, keyType, attributes);
long keyID = token.p11.C_GenerateKey
(session.id(), new CK_MECHANISM(mechanism), attributes);
return P11Key.secretKey
(session, keyID, algorithm, significantKeySize, attributes);
} catch (PKCS11Exception e) {
throw new ProviderException("Could not generate key", e);
} finally {
token.releaseSession(session);
}
}
}