8301553: Support Password-Based Cryptography in SunPKCS11
Co-authored-by: Francisco Ferrari Bihurriet <fferrari@redhat.com> Co-authored-by: Martin Balao <mbalao@openjdk.org> Reviewed-by: valeriep
This commit is contained in:
parent
0a4f9ad637
commit
4a75fd462c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,13 +25,14 @@
|
|||||||
|
|
||||||
package com.sun.crypto.provider;
|
package com.sun.crypto.provider;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import javax.crypto.spec.PBEParameterSpec;
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.spec.*;
|
import java.security.spec.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import jdk.internal.access.SharedSecrets;
|
||||||
|
import sun.security.util.PBEUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an implementation of the HMAC algorithms as defined
|
* This is an implementation of the HMAC algorithms as defined
|
||||||
@ -108,81 +109,30 @@ abstract class HmacPKCS12PBECore extends HmacCore {
|
|||||||
*/
|
*/
|
||||||
protected void engineInit(Key key, AlgorithmParameterSpec params)
|
protected void engineInit(Key key, AlgorithmParameterSpec params)
|
||||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||||
char[] passwdChars;
|
char[] password = null;
|
||||||
byte[] salt = null;
|
byte[] derivedKey = null;
|
||||||
int iCount = 0;
|
SecretKeySpec cipherKey = null;
|
||||||
if (key instanceof javax.crypto.interfaces.PBEKey) {
|
PBEKeySpec keySpec = PBEUtil.getPBAKeySpec(key, params);
|
||||||
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;
|
|
||||||
if (!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3)) ||
|
|
||||||
(passwdBytes = key.getEncoded()) == null) {
|
|
||||||
throw new InvalidKeyException("Missing password");
|
|
||||||
}
|
|
||||||
passwdChars = new char[passwdBytes.length];
|
|
||||||
for (int i=0; i<passwdChars.length; i++) {
|
|
||||||
passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
|
|
||||||
}
|
|
||||||
Arrays.fill(passwdBytes, (byte)0x00);
|
|
||||||
} else {
|
|
||||||
throw new InvalidKeyException("SecretKey of PBE type required");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] derivedKey;
|
|
||||||
try {
|
try {
|
||||||
if (params == null) {
|
password = keySpec.getPassword();
|
||||||
// should not auto-generate default values since current
|
derivedKey = PKCS12PBECipherCore.derive(
|
||||||
// javax.crypto.Mac api does not have any method for caller to
|
password, keySpec.getSalt(),
|
||||||
// retrieve the generated defaults.
|
keySpec.getIterationCount(), engineGetMacLength(),
|
||||||
if ((salt == null) || (iCount == 0)) {
|
PKCS12PBECipherCore.MAC_KEY, algorithm, bl);
|
||||||
throw new InvalidAlgorithmParameterException
|
cipherKey = new SecretKeySpec(derivedKey, "HmacSHA1");
|
||||||
("PBEParameterSpec required for salt and iteration count");
|
super.engineInit(cipherKey, null);
|
||||||
}
|
|
||||||
} 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For security purpose, we need to enforce a minimum length
|
|
||||||
// for salt; 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");
|
|
||||||
}
|
|
||||||
derivedKey = PKCS12PBECipherCore.derive(passwdChars, salt,
|
|
||||||
iCount, engineGetMacLength(), PKCS12PBECipherCore.MAC_KEY,
|
|
||||||
algorithm, bl);
|
|
||||||
} finally {
|
} finally {
|
||||||
Arrays.fill(passwdChars, '\0');
|
if (cipherKey != null) {
|
||||||
|
SharedSecrets.getJavaxCryptoSpecAccess()
|
||||||
|
.clearSecretKeySpec(cipherKey);
|
||||||
|
}
|
||||||
|
if (derivedKey != null) {
|
||||||
|
Arrays.fill(derivedKey, (byte) 0);
|
||||||
|
}
|
||||||
|
if (password != null) {
|
||||||
|
Arrays.fill(password, '\0');
|
||||||
|
}
|
||||||
|
keySpec.clearPassword();
|
||||||
}
|
}
|
||||||
SecretKey cipherKey = new SecretKeySpec(derivedKey, "HmacSHA1");
|
|
||||||
super.engineInit(cipherKey, null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -31,6 +31,9 @@ import java.util.Arrays;
|
|||||||
import javax.crypto.*;
|
import javax.crypto.*;
|
||||||
import javax.crypto.spec.*;
|
import javax.crypto.spec.*;
|
||||||
|
|
||||||
|
import jdk.internal.access.SharedSecrets;
|
||||||
|
import sun.security.util.PBEUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents password-based encryption as defined by the PKCS #5
|
* This class represents password-based encryption as defined by the PKCS #5
|
||||||
* standard.
|
* standard.
|
||||||
@ -43,10 +46,6 @@ import javax.crypto.spec.*;
|
|||||||
* @see javax.crypto.Cipher
|
* @see javax.crypto.Cipher
|
||||||
*/
|
*/
|
||||||
abstract class PBES2Core extends CipherSpi {
|
abstract class PBES2Core extends CipherSpi {
|
||||||
|
|
||||||
private static final int DEFAULT_SALT_LENGTH = 20;
|
|
||||||
private static final int DEFAULT_COUNT = 4096;
|
|
||||||
|
|
||||||
// the encapsulated cipher
|
// the encapsulated cipher
|
||||||
private final CipherCore cipher;
|
private final CipherCore cipher;
|
||||||
private final int keyLength; // in bits
|
private final int keyLength; // in bits
|
||||||
@ -54,9 +53,7 @@ abstract class PBES2Core extends CipherSpi {
|
|||||||
private final PBKDF2Core kdf;
|
private final PBKDF2Core kdf;
|
||||||
private final String pbeAlgo;
|
private final String pbeAlgo;
|
||||||
private final String cipherAlgo;
|
private final String cipherAlgo;
|
||||||
private int iCount = DEFAULT_COUNT;
|
private final PBEUtil.PBES2Params pbes2Params = new PBEUtil.PBES2Params();
|
||||||
private byte[] salt = null;
|
|
||||||
private IvParameterSpec ivSpec = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance of PBE Scheme 2 according to the selected
|
* Creates an instance of PBE Scheme 2 according to the selected
|
||||||
@ -135,32 +132,8 @@ abstract class PBES2Core extends CipherSpi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected AlgorithmParameters engineGetParameters() {
|
protected AlgorithmParameters engineGetParameters() {
|
||||||
AlgorithmParameters params = null;
|
return pbes2Params.getAlgorithmParameters(
|
||||||
if (salt == null) {
|
blkSize, pbeAlgo, SunJCE.getInstance(), SunJCE.getRandom());
|
||||||
// generate random salt and use default iteration count
|
|
||||||
salt = new byte[DEFAULT_SALT_LENGTH];
|
|
||||||
SunJCE.getRandom().nextBytes(salt);
|
|
||||||
iCount = DEFAULT_COUNT;
|
|
||||||
}
|
|
||||||
if (ivSpec == null) {
|
|
||||||
// generate random IV
|
|
||||||
byte[] ivBytes = new byte[blkSize];
|
|
||||||
SunJCE.getRandom().nextBytes(ivBytes);
|
|
||||||
ivSpec = new IvParameterSpec(ivBytes);
|
|
||||||
}
|
|
||||||
PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount, ivSpec);
|
|
||||||
try {
|
|
||||||
params = AlgorithmParameters.getInstance(pbeAlgo,
|
|
||||||
SunJCE.getInstance());
|
|
||||||
params.init(pbeSpec);
|
|
||||||
} catch (NoSuchAlgorithmException nsae) {
|
|
||||||
// should never happen
|
|
||||||
throw new RuntimeException("SunJCE called, but not configured");
|
|
||||||
} catch (InvalidParameterSpecException ipse) {
|
|
||||||
// should never happen
|
|
||||||
throw new RuntimeException("PBEParameterSpec not supported");
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void engineInit(int opmode, Key key, SecureRandom random)
|
protected void engineInit(int opmode, Key key, SecureRandom random)
|
||||||
@ -172,132 +145,46 @@ abstract class PBES2Core extends CipherSpi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] check(byte[] salt)
|
|
||||||
throws InvalidAlgorithmParameterException {
|
|
||||||
if (salt != null && salt.length < 8) {
|
|
||||||
throw new InvalidAlgorithmParameterException(
|
|
||||||
"Salt must be at least 8 bytes long");
|
|
||||||
}
|
|
||||||
return salt;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int check(int iCount)
|
|
||||||
throws InvalidAlgorithmParameterException {
|
|
||||||
if (iCount < 0) {
|
|
||||||
throw new InvalidAlgorithmParameterException(
|
|
||||||
"Iteration count must be a positive number");
|
|
||||||
}
|
|
||||||
return iCount == 0 ? DEFAULT_COUNT : iCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void engineInit(int opmode, Key key,
|
protected void engineInit(int opmode, Key key,
|
||||||
AlgorithmParameterSpec params,
|
AlgorithmParameterSpec params,
|
||||||
SecureRandom random)
|
SecureRandom random)
|
||||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||||
|
|
||||||
if (key == null) {
|
PBEKeySpec pbeSpec = pbes2Params.getPBEKeySpec(blkSize, keyLength,
|
||||||
throw new InvalidKeyException("Null key");
|
opmode, key, params, random);
|
||||||
}
|
PBKDF2KeyImpl s = null;
|
||||||
|
byte[] derivedKey;
|
||||||
byte[] passwdBytes = key.getEncoded();
|
|
||||||
char[] passwdChars = null;
|
|
||||||
salt = null;
|
|
||||||
iCount = 0;
|
|
||||||
ivSpec = null;
|
|
||||||
|
|
||||||
PBEKeySpec pbeSpec;
|
|
||||||
try {
|
|
||||||
if ((passwdBytes == null) ||
|
|
||||||
!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {
|
|
||||||
throw new InvalidKeyException("Missing password");
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean doEncrypt = ((opmode == Cipher.ENCRYPT_MODE) ||
|
|
||||||
(opmode == Cipher.WRAP_MODE));
|
|
||||||
|
|
||||||
// Extract from the supplied PBE params, if present
|
|
||||||
if (params instanceof PBEParameterSpec pbeParams) {
|
|
||||||
// salt should be non-null per PBEParameterSpec
|
|
||||||
salt = check(pbeParams.getSalt());
|
|
||||||
iCount = check(pbeParams.getIterationCount());
|
|
||||||
AlgorithmParameterSpec ivParams = pbeParams.getParameterSpec();
|
|
||||||
if (ivParams instanceof IvParameterSpec iv) {
|
|
||||||
ivSpec = iv;
|
|
||||||
} else if (ivParams == null && doEncrypt) {
|
|
||||||
// generate random IV
|
|
||||||
byte[] ivBytes = new byte[blkSize];
|
|
||||||
random.nextBytes(ivBytes);
|
|
||||||
ivSpec = new IvParameterSpec(ivBytes);
|
|
||||||
} else {
|
|
||||||
throw new InvalidAlgorithmParameterException(
|
|
||||||
"Wrong parameter type: IV expected");
|
|
||||||
}
|
|
||||||
} else if (params == null && doEncrypt) {
|
|
||||||
// Try extracting from the key if present. If unspecified,
|
|
||||||
// PBEKey returns null and 0 respectively.
|
|
||||||
if (key instanceof javax.crypto.interfaces.PBEKey pbeKey) {
|
|
||||||
salt = check(pbeKey.getSalt());
|
|
||||||
iCount = check(pbeKey.getIterationCount());
|
|
||||||
}
|
|
||||||
if (salt == null) {
|
|
||||||
// generate random salt
|
|
||||||
salt = new byte[DEFAULT_SALT_LENGTH];
|
|
||||||
random.nextBytes(salt);
|
|
||||||
}
|
|
||||||
if (iCount == 0) {
|
|
||||||
// use default iteration count
|
|
||||||
iCount = DEFAULT_COUNT;
|
|
||||||
}
|
|
||||||
// generate random IV
|
|
||||||
byte[] ivBytes = new byte[blkSize];
|
|
||||||
random.nextBytes(ivBytes);
|
|
||||||
ivSpec = new IvParameterSpec(ivBytes);
|
|
||||||
} else {
|
|
||||||
throw new InvalidAlgorithmParameterException
|
|
||||||
("Wrong parameter type: PBE 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 {
|
|
||||||
// password char[] was cloned in PBEKeySpec constructor,
|
|
||||||
// so we can zero it out here
|
|
||||||
if (passwdChars != null) Arrays.fill(passwdChars, '\0');
|
|
||||||
if (passwdBytes != null) Arrays.fill(passwdBytes, (byte)0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
PBKDF2KeyImpl s;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec);
|
s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec);
|
||||||
|
derivedKey = s.getEncoded();
|
||||||
} catch (InvalidKeySpecException ikse) {
|
} catch (InvalidKeySpecException ikse) {
|
||||||
throw new InvalidKeyException("Cannot construct PBE key", ikse);
|
throw new InvalidKeyException("Cannot construct PBE key", ikse);
|
||||||
} finally {
|
} finally {
|
||||||
|
if (s != null) {
|
||||||
|
s.clear();
|
||||||
|
}
|
||||||
pbeSpec.clearPassword();
|
pbeSpec.clearPassword();
|
||||||
}
|
}
|
||||||
byte[] derivedKey = s.getEncoded();
|
|
||||||
s.clearPassword();
|
|
||||||
SecretKeySpec cipherKey = new SecretKeySpec(derivedKey, cipherAlgo);
|
|
||||||
|
|
||||||
// initialize the underlying cipher
|
SecretKeySpec cipherKey = null;
|
||||||
cipher.init(opmode, cipherKey, ivSpec, random);
|
try {
|
||||||
|
cipherKey = new SecretKeySpec(derivedKey, cipherAlgo);
|
||||||
|
// initialize the underlying cipher
|
||||||
|
cipher.init(opmode, cipherKey, pbes2Params.getIvSpec(), random);
|
||||||
|
} finally {
|
||||||
|
if (cipherKey != null) {
|
||||||
|
SharedSecrets.getJavaxCryptoSpecAccess()
|
||||||
|
.clearSecretKeySpec(cipherKey);
|
||||||
|
}
|
||||||
|
Arrays.fill(derivedKey, (byte) 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
|
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
|
||||||
SecureRandom random)
|
SecureRandom random)
|
||||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||||
AlgorithmParameterSpec pbeSpec = null;
|
engineInit(opmode, key, PBEUtil.PBES2Params.getParameterSpec(params),
|
||||||
if (params != null) {
|
random);
|
||||||
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) {
|
protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -26,7 +26,7 @@
|
|||||||
package com.sun.crypto.provider;
|
package com.sun.crypto.provider;
|
||||||
|
|
||||||
import java.io.ObjectStreamException;
|
import java.io.ObjectStreamException;
|
||||||
import java.lang.ref.Reference;
|
import java.lang.ref.Cleaner;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.CharBuffer;
|
import java.nio.CharBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -64,9 +64,9 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
|||||||
private int iterCount;
|
private int iterCount;
|
||||||
private byte[] key;
|
private byte[] key;
|
||||||
|
|
||||||
@SuppressWarnings("serial") // Type of field is not Serializable;
|
// The following fields are not Serializable. See writeReplace method.
|
||||||
// see writeReplace method
|
private transient Mac prf;
|
||||||
private Mac prf;
|
private transient Cleaner.Cleanable cleaner;
|
||||||
|
|
||||||
private static byte[] getPasswordBytes(char[] passwd) {
|
private static byte[] getPasswordBytes(char[] passwd) {
|
||||||
CharBuffer cb = CharBuffer.wrap(passwd);
|
CharBuffer cb = CharBuffer.wrap(passwd);
|
||||||
@ -88,17 +88,9 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
|||||||
*/
|
*/
|
||||||
PBKDF2KeyImpl(PBEKeySpec keySpec, String prfAlgo)
|
PBKDF2KeyImpl(PBEKeySpec keySpec, String prfAlgo)
|
||||||
throws InvalidKeySpecException {
|
throws InvalidKeySpecException {
|
||||||
char[] passwd = keySpec.getPassword();
|
this.passwd = keySpec.getPassword();
|
||||||
if (passwd == null) {
|
|
||||||
// Should allow an empty password.
|
|
||||||
this.passwd = new char[0];
|
|
||||||
} else {
|
|
||||||
this.passwd = passwd.clone();
|
|
||||||
}
|
|
||||||
// Convert the password from char[] to byte[]
|
// Convert the password from char[] to byte[]
|
||||||
byte[] passwdBytes = getPasswordBytes(this.passwd);
|
byte[] passwdBytes = getPasswordBytes(this.passwd);
|
||||||
// remove local copy
|
|
||||||
if (passwd != null) Arrays.fill(passwd, '\0');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.salt = keySpec.getSalt();
|
this.salt = keySpec.getSalt();
|
||||||
@ -124,16 +116,18 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
|||||||
throw new InvalidKeySpecException(nsae);
|
throw new InvalidKeySpecException(nsae);
|
||||||
} finally {
|
} finally {
|
||||||
Arrays.fill(passwdBytes, (byte) 0x00);
|
Arrays.fill(passwdBytes, (byte) 0x00);
|
||||||
|
if (key == null) {
|
||||||
// Use the cleaner to zero the key when no longer referenced
|
Arrays.fill(passwd, '\0');
|
||||||
final byte[] k = this.key;
|
}
|
||||||
final char[] p = this.passwd;
|
|
||||||
CleanerFactory.cleaner().register(this,
|
|
||||||
() -> {
|
|
||||||
Arrays.fill(k, (byte) 0x00);
|
|
||||||
Arrays.fill(p, '\0');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
// Use the cleaner to zero the key when no longer referenced
|
||||||
|
final byte[] k = this.key;
|
||||||
|
final char[] p = this.passwd;
|
||||||
|
cleaner = CleanerFactory.cleaner().register(this,
|
||||||
|
() -> {
|
||||||
|
Arrays.fill(k, (byte) 0x00);
|
||||||
|
Arrays.fill(p, '\0');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] deriveKey(final Mac prf, final byte[] password,
|
private static byte[] deriveKey(final Mac prf, final byte[] password,
|
||||||
@ -211,11 +205,7 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getEncoded() {
|
public byte[] getEncoded() {
|
||||||
// The key is zeroized by finalize()
|
return key.clone();
|
||||||
// The reachability fence ensures finalize() isn't called early
|
|
||||||
byte[] result = key.clone();
|
|
||||||
Reference.reachabilityFence(this);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAlgorithm() {
|
public String getAlgorithm() {
|
||||||
@ -226,16 +216,12 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
|||||||
return iterCount;
|
return iterCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearPassword() {
|
public void clear() {
|
||||||
Arrays.fill(passwd, (char)0);
|
cleaner.clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
public char[] getPassword() {
|
public char[] getPassword() {
|
||||||
// The password is zeroized by finalize()
|
return passwd.clone();
|
||||||
// The reachability fence ensures finalize() isn't called early
|
|
||||||
char[] result = passwd.clone();
|
|
||||||
Reference.reachabilityFence(this);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getSalt() {
|
public byte[] getSalt() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
package com.sun.crypto.provider;
|
package com.sun.crypto.provider;
|
||||||
|
|
||||||
|
import jdk.internal.access.SharedSecrets;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
@ -179,23 +181,29 @@ abstract class PBMAC1Core extends HmacCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PBKDF2KeyImpl s = null;
|
PBKDF2KeyImpl s = null;
|
||||||
PBKDF2Core kdf = getKDFImpl(kdfAlgo);
|
byte[] derivedKey = null;
|
||||||
byte[] derivedKey;
|
SecretKeySpec cipherKey = null;
|
||||||
try {
|
try {
|
||||||
|
PBKDF2Core kdf = getKDFImpl(kdfAlgo);
|
||||||
s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec);
|
s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec);
|
||||||
derivedKey = s.getEncoded();
|
derivedKey = s.getEncoded();
|
||||||
|
cipherKey = new SecretKeySpec(derivedKey, kdfAlgo);
|
||||||
|
super.engineInit(cipherKey, null);
|
||||||
} catch (InvalidKeySpecException ikse) {
|
} catch (InvalidKeySpecException ikse) {
|
||||||
throw new InvalidKeyException("Cannot construct PBE key", ikse);
|
throw new InvalidKeyException("Cannot construct PBE key", ikse);
|
||||||
} finally {
|
} finally {
|
||||||
pbeSpec.clearPassword();
|
if (cipherKey != null) {
|
||||||
if (s != null) {
|
SharedSecrets.getJavaxCryptoSpecAccess()
|
||||||
s.clearPassword();
|
.clearSecretKeySpec(cipherKey);
|
||||||
}
|
}
|
||||||
|
if (derivedKey != null) {
|
||||||
|
Arrays.fill(derivedKey, (byte) 0);
|
||||||
|
}
|
||||||
|
if (s != null) {
|
||||||
|
s.clear();
|
||||||
|
}
|
||||||
|
pbeSpec.clearPassword();
|
||||||
}
|
}
|
||||||
SecretKey cipherKey = new SecretKeySpec(derivedKey, kdfAlgo);
|
|
||||||
Arrays.fill(derivedKey, (byte)0);
|
|
||||||
|
|
||||||
super.engineInit(cipherKey, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class HmacSHA1 extends PBMAC1Core {
|
public static final class HmacSHA1 extends PBMAC1Core {
|
||||||
|
355
src/java.base/share/classes/sun/security/util/PBEUtil.java
Normal file
355
src/java.base/share/classes/sun/security/util/PBEUtil.java
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Red Hat, Inc.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.security.util;
|
||||||
|
|
||||||
|
import java.security.AlgorithmParameters;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.Provider;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import java.security.spec.InvalidParameterSpecException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
import javax.crypto.spec.PBEParameterSpec;
|
||||||
|
|
||||||
|
public final class PBEUtil {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PBES2Params is an auxiliary class that represents the state needed for
|
||||||
|
* PBES2 operations (iterations count, salt and IV) and its (re)
|
||||||
|
* initialization logic. Users of this class are CipherSpi implementors that
|
||||||
|
* support PBES2 cryptography (RFC #8018), such as PBES2Core (SunJCE) and
|
||||||
|
* P11PBECipher (SunPKCS11).
|
||||||
|
*
|
||||||
|
* CipherSpi implementors must call ::getPBEKeySpec in every engine
|
||||||
|
* initialization (CipherSpi::engineInit override) to reset the state and
|
||||||
|
* get new values in a PBEKeySpec instance. These new values are taken
|
||||||
|
* from parameters, defaults or generated randomly.
|
||||||
|
*
|
||||||
|
* After engine initialization, values in effect can be extracted with
|
||||||
|
* ::getAlgorithmParameters (as AlgorithmParameters) or ::getIvSpec (as
|
||||||
|
* IvParameterSpec).
|
||||||
|
*/
|
||||||
|
public static final class PBES2Params {
|
||||||
|
private static final int DEFAULT_SALT_LENGTH = 20;
|
||||||
|
private static final int DEFAULT_ITERATIONS = 4096;
|
||||||
|
|
||||||
|
private int iCount;
|
||||||
|
private byte[] salt;
|
||||||
|
private IvParameterSpec ivSpec;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a PBES2Params instance. May generate random salt and
|
||||||
|
* IV if not passed and the operation is encryption. If initialization
|
||||||
|
* fails, values are reset. Used by PBES2Params and P11PBECipher
|
||||||
|
* (SunPKCS11).
|
||||||
|
*/
|
||||||
|
public void initialize(int blkSize, int opmode, int iCount, byte[] salt,
|
||||||
|
AlgorithmParameterSpec ivSpec, SecureRandom random)
|
||||||
|
throws InvalidAlgorithmParameterException {
|
||||||
|
try {
|
||||||
|
boolean doEncrypt = opmode == Cipher.ENCRYPT_MODE ||
|
||||||
|
opmode == Cipher.WRAP_MODE;
|
||||||
|
if (ivSpec instanceof IvParameterSpec iv) {
|
||||||
|
this.ivSpec = iv;
|
||||||
|
} else if (ivSpec == null && doEncrypt) {
|
||||||
|
byte[] ivBytes = new byte[blkSize];
|
||||||
|
random.nextBytes(ivBytes);
|
||||||
|
this.ivSpec = new IvParameterSpec(ivBytes);
|
||||||
|
} else {
|
||||||
|
throw new InvalidAlgorithmParameterException("Wrong " +
|
||||||
|
"parameter type: IvParameterSpec " +
|
||||||
|
(doEncrypt ? "or null " : "") + "expected");
|
||||||
|
}
|
||||||
|
this.iCount = iCount == 0 ? DEFAULT_ITERATIONS : iCount;
|
||||||
|
if (salt == null) {
|
||||||
|
if (doEncrypt) {
|
||||||
|
salt = new byte[DEFAULT_SALT_LENGTH];
|
||||||
|
random.nextBytes(salt);
|
||||||
|
} else {
|
||||||
|
throw new InvalidAlgorithmParameterException("Salt " +
|
||||||
|
"needed for decryption");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.salt = salt;
|
||||||
|
} catch (InvalidAlgorithmParameterException e) {
|
||||||
|
this.ivSpec = null;
|
||||||
|
this.iCount = 0;
|
||||||
|
this.salt = null;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Obtain an IvParameterSpec for Cipher services. This method returns
|
||||||
|
* null when the state is not initialized. Used by PBES2Core (SunJCE)
|
||||||
|
* and P11PBECipher (SunPKCS11).
|
||||||
|
*/
|
||||||
|
public IvParameterSpec getIvSpec() {
|
||||||
|
return ivSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Obtain AlgorithmParameters for Cipher services. This method will
|
||||||
|
* initialize PBES2Params if needed, generating new values randomly or
|
||||||
|
* assigning from defaults. If PBES2Params is initialized, existing
|
||||||
|
* values will be returned. Used by PBES2Core (SunJCE) and
|
||||||
|
* P11PBECipher (SunPKCS11).
|
||||||
|
*/
|
||||||
|
public AlgorithmParameters getAlgorithmParameters(int blkSize,
|
||||||
|
String pbeAlgo, Provider algParamsProv, SecureRandom random) {
|
||||||
|
AlgorithmParameters params;
|
||||||
|
try {
|
||||||
|
if (iCount == 0 && salt == null && ivSpec == null) {
|
||||||
|
initialize(blkSize, Cipher.ENCRYPT_MODE, 0, null, null,
|
||||||
|
random);
|
||||||
|
}
|
||||||
|
params = AlgorithmParameters.getInstance(pbeAlgo,
|
||||||
|
algParamsProv);
|
||||||
|
params.init(new PBEParameterSpec(salt, iCount, ivSpec));
|
||||||
|
} catch (NoSuchAlgorithmException nsae) {
|
||||||
|
// should never happen
|
||||||
|
throw new RuntimeException("AlgorithmParameters for "
|
||||||
|
+ pbeAlgo + " not configured");
|
||||||
|
} catch (InvalidParameterSpecException ipse) {
|
||||||
|
// should never happen
|
||||||
|
throw new RuntimeException("PBEParameterSpec not supported");
|
||||||
|
} catch (InvalidAlgorithmParameterException iape) {
|
||||||
|
// should never happen
|
||||||
|
throw new RuntimeException("Error initializing PBES2Params");
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize PBES2Params and obtain a PBEKeySpec for Cipher services.
|
||||||
|
* Data from the key, parameters, defaults or random may be used for
|
||||||
|
* initialization. Used by PBES2Core (SunJCE) and P11PBECipher
|
||||||
|
* (SunPKCS11).
|
||||||
|
*/
|
||||||
|
public PBEKeySpec getPBEKeySpec(int blkSize, int keyLength, int opmode,
|
||||||
|
Key key, AlgorithmParameterSpec params, SecureRandom random)
|
||||||
|
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||||
|
if (key == null) {
|
||||||
|
throw new InvalidKeyException("Null key");
|
||||||
|
}
|
||||||
|
byte[] passwdBytes;
|
||||||
|
char[] passwdChars = null;
|
||||||
|
if (!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3)) ||
|
||||||
|
(passwdBytes = key.getEncoded()) == null) {
|
||||||
|
throw new InvalidKeyException("Missing password");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int iCountInit;
|
||||||
|
byte[] saltInit;
|
||||||
|
AlgorithmParameterSpec ivSpecInit;
|
||||||
|
// Extract from the supplied PBE params, if present
|
||||||
|
if (params instanceof PBEParameterSpec pbeParams) {
|
||||||
|
// salt should be non-null per PBEParameterSpec
|
||||||
|
iCountInit = check(pbeParams.getIterationCount());
|
||||||
|
saltInit = check(pbeParams.getSalt());
|
||||||
|
ivSpecInit = pbeParams.getParameterSpec();
|
||||||
|
} else if (params == null) {
|
||||||
|
// Try extracting from the key if present. If unspecified,
|
||||||
|
// PBEKey returns 0 and null respectively.
|
||||||
|
if (key instanceof javax.crypto.interfaces.PBEKey pbeKey) {
|
||||||
|
iCountInit = check(pbeKey.getIterationCount());
|
||||||
|
saltInit = check(pbeKey.getSalt());
|
||||||
|
} else {
|
||||||
|
iCountInit = 0;
|
||||||
|
saltInit = null;
|
||||||
|
}
|
||||||
|
ivSpecInit = null;
|
||||||
|
} else {
|
||||||
|
throw new InvalidAlgorithmParameterException(
|
||||||
|
"Wrong parameter type: PBE expected");
|
||||||
|
}
|
||||||
|
initialize(blkSize, opmode, iCountInit, saltInit, ivSpecInit,
|
||||||
|
random);
|
||||||
|
passwdChars = new char[passwdBytes.length];
|
||||||
|
for (int i = 0; i < passwdChars.length; i++) {
|
||||||
|
passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
|
||||||
|
}
|
||||||
|
return new PBEKeySpec(passwdChars, salt, iCount, keyLength);
|
||||||
|
} finally {
|
||||||
|
// password char[] was cloned in PBEKeySpec constructor,
|
||||||
|
// so we can zero it out here
|
||||||
|
if (passwdChars != null) Arrays.fill(passwdChars, '\0');
|
||||||
|
if (passwdBytes != null) Arrays.fill(passwdBytes, (byte)0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Obtain an AlgorithmParameterSpec from an AlgorithmParameters
|
||||||
|
* instance, for Cipher services. Used by PBES2Core (SunJCE) and
|
||||||
|
* P11PBECipher (SunPKCS11).
|
||||||
|
*/
|
||||||
|
public static AlgorithmParameterSpec getParameterSpec(
|
||||||
|
AlgorithmParameters params)
|
||||||
|
throws InvalidAlgorithmParameterException {
|
||||||
|
AlgorithmParameterSpec pbeSpec = null;
|
||||||
|
if (params != null) {
|
||||||
|
try {
|
||||||
|
pbeSpec = params.getParameterSpec(PBEParameterSpec.class);
|
||||||
|
} catch (InvalidParameterSpecException ipse) {
|
||||||
|
throw new InvalidAlgorithmParameterException(
|
||||||
|
"Wrong parameter type: PBE expected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pbeSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] check(byte[] salt)
|
||||||
|
throws InvalidAlgorithmParameterException {
|
||||||
|
if (salt != null && salt.length < 8) {
|
||||||
|
throw new InvalidAlgorithmParameterException(
|
||||||
|
"Salt must be at least 8 bytes long");
|
||||||
|
}
|
||||||
|
return salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int check(int iCount)
|
||||||
|
throws InvalidAlgorithmParameterException {
|
||||||
|
if (iCount < 0) {
|
||||||
|
throw new InvalidAlgorithmParameterException(
|
||||||
|
"Iteration count must be a positive number");
|
||||||
|
}
|
||||||
|
return iCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Obtain a PBEKeySpec for Mac services, after key and parameters
|
||||||
|
* validation. Used by HmacPKCS12PBECore (SunJCE) and P11Mac (SunPKCS11).
|
||||||
|
*/
|
||||||
|
public static PBEKeySpec getPBAKeySpec(Key key,
|
||||||
|
AlgorithmParameterSpec params)
|
||||||
|
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||||
|
char[] passwdChars;
|
||||||
|
byte[] salt = null;
|
||||||
|
int iCount = 0;
|
||||||
|
if (key instanceof javax.crypto.interfaces.PBEKey pbeKey) {
|
||||||
|
passwdChars = pbeKey.getPassword();
|
||||||
|
salt = pbeKey.getSalt(); // maybe null if unspecified
|
||||||
|
iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified
|
||||||
|
} else if (key instanceof SecretKey) {
|
||||||
|
byte[] passwdBytes;
|
||||||
|
if (!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3)) ||
|
||||||
|
(passwdBytes = key.getEncoded()) == null) {
|
||||||
|
throw new InvalidKeyException("Missing password");
|
||||||
|
}
|
||||||
|
passwdChars = new char[passwdBytes.length];
|
||||||
|
for (int i = 0; i < passwdChars.length; i++) {
|
||||||
|
passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
|
||||||
|
}
|
||||||
|
Arrays.fill(passwdBytes, (byte)0x00);
|
||||||
|
} else {
|
||||||
|
throw new InvalidKeyException("SecretKey of PBE type required");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (params == null) {
|
||||||
|
// should not auto-generate default values since current
|
||||||
|
// javax.crypto.Mac api does not have any method for caller to
|
||||||
|
// retrieve the generated defaults.
|
||||||
|
if ((salt == null) || (iCount == 0)) {
|
||||||
|
throw new InvalidAlgorithmParameterException(
|
||||||
|
"PBEParameterSpec required for salt " +
|
||||||
|
"and iteration 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// For security purpose, we need to enforce a minimum length
|
||||||
|
// for salt; 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");
|
||||||
|
}
|
||||||
|
return new PBEKeySpec(passwdChars, salt, iCount);
|
||||||
|
} finally {
|
||||||
|
Arrays.fill(passwdChars, '\0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that the key implements the PBEKey interface. If params is an
|
||||||
|
* instance of PBEParameterSpec, validate consistency with the key's
|
||||||
|
* derivation data. Used by P11Mac and P11PBECipher (SunPKCS11).
|
||||||
|
*/
|
||||||
|
public static void checkKeyAndParams(Key key,
|
||||||
|
AlgorithmParameterSpec params, String algorithm)
|
||||||
|
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||||
|
if (key instanceof javax.crypto.interfaces.PBEKey pbeKey) {
|
||||||
|
if (params instanceof PBEParameterSpec pbeParams) {
|
||||||
|
if (pbeParams.getIterationCount() !=
|
||||||
|
pbeKey.getIterationCount() ||
|
||||||
|
!Arrays.equals(pbeParams.getSalt(), pbeKey.getSalt())) {
|
||||||
|
throw new InvalidAlgorithmParameterException(
|
||||||
|
"Salt or iteration count parameters are " +
|
||||||
|
"not consistent with PBE key");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new InvalidKeyException(
|
||||||
|
"Cannot use a " + algorithm + " service with a key that " +
|
||||||
|
"does not implement javax.crypto.interfaces.PBEKey");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -262,10 +262,8 @@ final class P11Cipher extends CipherSpi {
|
|||||||
// no native padding support; use our own padding impl
|
// no native padding support; use our own padding impl
|
||||||
paddingObj = new PKCS5Padding(blockSize);
|
paddingObj = new PKCS5Padding(blockSize);
|
||||||
padBuffer = new byte[blockSize];
|
padBuffer = new byte[blockSize];
|
||||||
char[] tokenLabel = token.tokenInfo.label;
|
|
||||||
// NSS requires block-sized updates in multi-part operations.
|
// NSS requires block-sized updates in multi-part operations.
|
||||||
reqBlockUpdates = ((tokenLabel[0] == 'N' && tokenLabel[1] == 'S'
|
reqBlockUpdates = P11Util.isNSS(token);
|
||||||
&& tokenLabel[2] == 'S') ? true : false);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new NoSuchPaddingException("Unsupported padding " + padding);
|
throw new NoSuchPaddingException("Unsupported padding " + padding);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -141,9 +141,7 @@ abstract class P11Key implements Key, Length {
|
|||||||
this.tokenObject = tokenObject;
|
this.tokenObject = tokenObject;
|
||||||
this.sensitive = sensitive;
|
this.sensitive = sensitive;
|
||||||
this.extractable = extractable;
|
this.extractable = extractable;
|
||||||
char[] tokenLabel = this.token.tokenInfo.label;
|
isNSS = P11Util.isNSS(this.token);
|
||||||
isNSS = (tokenLabel[0] == 'N' && tokenLabel[1] == 'S'
|
|
||||||
&& tokenLabel[2] == 'S');
|
|
||||||
boolean extractKeyInfo = (!DISABLE_NATIVE_KEYS_EXTRACTION && isNSS &&
|
boolean extractKeyInfo = (!DISABLE_NATIVE_KEYS_EXTRACTION && isNSS &&
|
||||||
extractable && !tokenObject);
|
extractable && !tokenObject);
|
||||||
this.keyIDHolder = new NativeKeyHolder(this, keyID, session,
|
this.keyIDHolder = new NativeKeyHolder(this, keyID, session,
|
||||||
@ -354,6 +352,18 @@ abstract class P11Key implements Key, Length {
|
|||||||
return new P11SecretKey(session, keyID, algorithm, keyLength, attrs);
|
return new P11SecretKey(session, keyID, algorithm, keyLength, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SecretKey pbeKey(Session session, long keyID, String algorithm,
|
||||||
|
int keyLength, CK_ATTRIBUTE[] attrs, char[] password, byte[] salt,
|
||||||
|
int iterationCount) {
|
||||||
|
attrs = getAttributes(session, keyID, attrs, new CK_ATTRIBUTE[] {
|
||||||
|
new CK_ATTRIBUTE(CKA_TOKEN),
|
||||||
|
new CK_ATTRIBUTE(CKA_SENSITIVE),
|
||||||
|
new CK_ATTRIBUTE(CKA_EXTRACTABLE),
|
||||||
|
});
|
||||||
|
return new P11PBEKey(session, keyID, algorithm, keyLength,
|
||||||
|
attrs, password, salt, iterationCount);
|
||||||
|
}
|
||||||
|
|
||||||
static SecretKey masterSecretKey(Session session, long keyID,
|
static SecretKey masterSecretKey(Session session, long keyID,
|
||||||
String algorithm, int keyLength, CK_ATTRIBUTE[] attrs,
|
String algorithm, int keyLength, CK_ATTRIBUTE[] attrs,
|
||||||
int major, int minor) {
|
int major, int minor) {
|
||||||
@ -487,6 +497,45 @@ abstract class P11Key implements Key, Length {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final class P11PBEKey extends P11SecretKey
|
||||||
|
implements PBEKey {
|
||||||
|
private static final long serialVersionUID = 6847576994253634876L;
|
||||||
|
private char[] password;
|
||||||
|
private final byte[] salt;
|
||||||
|
private final int iterationCount;
|
||||||
|
P11PBEKey(Session session, long keyID, String algorithm,
|
||||||
|
int keyLength, CK_ATTRIBUTE[] attributes,
|
||||||
|
char[] password, byte[] salt, int iterationCount) {
|
||||||
|
super(session, keyID, algorithm, keyLength, attributes);
|
||||||
|
this.password = password.clone();
|
||||||
|
this.salt = salt.clone();
|
||||||
|
this.iterationCount = iterationCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char[] getPassword() {
|
||||||
|
if (password == null) {
|
||||||
|
throw new IllegalStateException("password has been cleared");
|
||||||
|
}
|
||||||
|
return password.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getSalt() {
|
||||||
|
return salt.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIterationCount() {
|
||||||
|
return iterationCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearPassword() {
|
||||||
|
Arrays.fill(password, '\0');
|
||||||
|
password = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
private static class P11TlsMasterSecretKey extends P11SecretKey
|
private static class P11TlsMasterSecretKey extends P11SecretKey
|
||||||
implements TlsMasterSecret {
|
implements TlsMasterSecret {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -29,8 +29,11 @@ import java.nio.ByteBuffer;
|
|||||||
|
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.spec.AlgorithmParameterSpec;
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
|
||||||
import javax.crypto.MacSpi;
|
import javax.crypto.MacSpi;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
import javax.crypto.spec.PBEParameterSpec;
|
||||||
|
|
||||||
import jdk.internal.access.JavaNioAccess;
|
import jdk.internal.access.JavaNioAccess;
|
||||||
import jdk.internal.access.SharedSecrets;
|
import jdk.internal.access.SharedSecrets;
|
||||||
@ -39,6 +42,7 @@ import sun.nio.ch.DirectBuffer;
|
|||||||
import sun.security.pkcs11.wrapper.*;
|
import sun.security.pkcs11.wrapper.*;
|
||||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||||
|
import sun.security.util.PBEUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MAC implementation class. This class currently supports HMAC using
|
* MAC implementation class. This class currently supports HMAC using
|
||||||
@ -65,6 +69,9 @@ final class P11Mac extends MacSpi {
|
|||||||
// algorithm name
|
// algorithm name
|
||||||
private final String algorithm;
|
private final String algorithm;
|
||||||
|
|
||||||
|
// PBEKeyInfo if algorithm is PBE-related, otherwise null
|
||||||
|
private final P11SecretKeyFactory.PBEKeyInfo svcPbeKi;
|
||||||
|
|
||||||
// mechanism object
|
// mechanism object
|
||||||
private final CK_MECHANISM ckMechanism;
|
private final CK_MECHANISM ckMechanism;
|
||||||
|
|
||||||
@ -88,6 +95,7 @@ final class P11Mac extends MacSpi {
|
|||||||
super();
|
super();
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
|
this.svcPbeKi = P11SecretKeyFactory.getPBEKeyInfo(algorithm);
|
||||||
Long params = null;
|
Long params = null;
|
||||||
macLength = switch ((int) mechanism) {
|
macLength = switch ((int) mechanism) {
|
||||||
case (int) CKM_MD5_HMAC -> 16;
|
case (int) CKM_MD5_HMAC -> 16;
|
||||||
@ -192,12 +200,53 @@ final class P11Mac extends MacSpi {
|
|||||||
// see JCE spec
|
// see JCE spec
|
||||||
protected void engineInit(Key key, AlgorithmParameterSpec params)
|
protected void engineInit(Key key, AlgorithmParameterSpec params)
|
||||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||||
if (params != null) {
|
|
||||||
throw new InvalidAlgorithmParameterException
|
|
||||||
("Parameters not supported");
|
|
||||||
}
|
|
||||||
reset(true);
|
reset(true);
|
||||||
p11Key = P11SecretKeyFactory.convertKey(token, key, algorithm);
|
p11Key = null;
|
||||||
|
if (svcPbeKi != null) {
|
||||||
|
if (key instanceof P11Key) {
|
||||||
|
// If the key is a P11Key, it must come from a PBE derivation
|
||||||
|
// because this is a PBE Mac service. In addition to checking
|
||||||
|
// the key, check that params (if passed) are consistent.
|
||||||
|
PBEUtil.checkKeyAndParams(key, params, algorithm);
|
||||||
|
} else {
|
||||||
|
// If the key is not a P11Key, a derivation is needed. Data for
|
||||||
|
// derivation has to be carried either as part of the key or
|
||||||
|
// params. Use SunPKCS11 PBE key derivation to obtain a P11Key.
|
||||||
|
// Assign the derived key to p11Key because conversion is never
|
||||||
|
// needed for this case.
|
||||||
|
PBEKeySpec pbeKeySpec = PBEUtil.getPBAKeySpec(key, params);
|
||||||
|
try {
|
||||||
|
P11Key.P11PBEKey p11PBEKey =
|
||||||
|
P11SecretKeyFactory.derivePBEKey(token,
|
||||||
|
pbeKeySpec, svcPbeKi);
|
||||||
|
// This Mac service uses the token where the derived key
|
||||||
|
// lives so there won't be any need to re-derive and use
|
||||||
|
// the password. The p11Key cannot be accessed out of this
|
||||||
|
// class.
|
||||||
|
p11PBEKey.clearPassword();
|
||||||
|
p11Key = p11PBEKey;
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
throw new InvalidKeyException(e);
|
||||||
|
} finally {
|
||||||
|
pbeKeySpec.clearPassword();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (params instanceof PBEParameterSpec pbeParams) {
|
||||||
|
// For PBE services, reassign params to the underlying
|
||||||
|
// service params. Notice that Mac services expect this
|
||||||
|
// value to be null.
|
||||||
|
params = pbeParams.getParameterSpec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (params != null) {
|
||||||
|
throw new InvalidAlgorithmParameterException(
|
||||||
|
"Parameters not supported");
|
||||||
|
}
|
||||||
|
// In non-PBE cases and PBE cases where we didn't derive,
|
||||||
|
// a key conversion might be needed.
|
||||||
|
if (p11Key == null) {
|
||||||
|
p11Key = P11SecretKeyFactory.convertKey(token, key, algorithm);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
initialize();
|
initialize();
|
||||||
} catch (PKCS11Exception e) {
|
} catch (PKCS11Exception e) {
|
||||||
|
@ -0,0 +1,228 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Red Hat, Inc.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.security.pkcs11;
|
||||||
|
|
||||||
|
import java.security.AlgorithmParameters;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import javax.crypto.BadPaddingException;
|
||||||
|
import javax.crypto.CipherSpi;
|
||||||
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
import javax.crypto.ShortBufferException;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
import javax.crypto.spec.PBEParameterSpec;
|
||||||
|
|
||||||
|
import sun.security.jca.JCAUtil;
|
||||||
|
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||||
|
import sun.security.pkcs11.wrapper.PKCS11Exception;
|
||||||
|
import sun.security.util.PBEUtil;
|
||||||
|
|
||||||
|
final class P11PBECipher extends CipherSpi {
|
||||||
|
private final Token token;
|
||||||
|
private final String pbeAlg;
|
||||||
|
private final P11Cipher cipher;
|
||||||
|
private final int blkSize;
|
||||||
|
private final P11SecretKeyFactory.PBEKeyInfo svcPbeKi;
|
||||||
|
private final PBEUtil.PBES2Params pbes2Params = new PBEUtil.PBES2Params();
|
||||||
|
|
||||||
|
P11PBECipher(Token token, String pbeAlg, long cipherMech)
|
||||||
|
throws PKCS11Exception, NoSuchAlgorithmException {
|
||||||
|
super();
|
||||||
|
String cipherTrans;
|
||||||
|
if (cipherMech == CKM_AES_CBC_PAD || cipherMech == CKM_AES_CBC) {
|
||||||
|
cipherTrans = "AES/CBC/PKCS5Padding";
|
||||||
|
} else {
|
||||||
|
throw new NoSuchAlgorithmException(
|
||||||
|
"Cipher transformation not supported.");
|
||||||
|
}
|
||||||
|
cipher = new P11Cipher(token, cipherTrans, cipherMech);
|
||||||
|
blkSize = cipher.engineGetBlockSize();
|
||||||
|
this.pbeAlg = pbeAlg;
|
||||||
|
svcPbeKi = P11SecretKeyFactory.getPBEKeyInfo(pbeAlg);
|
||||||
|
assert svcPbeKi != null : "algorithm must be in KeyInfo map";
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected void engineSetMode(String mode)
|
||||||
|
throws NoSuchAlgorithmException {
|
||||||
|
cipher.engineSetMode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected void engineSetPadding(String padding)
|
||||||
|
throws NoSuchPaddingException {
|
||||||
|
cipher.engineSetPadding(padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected int engineGetBlockSize() {
|
||||||
|
return cipher.engineGetBlockSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected int engineGetOutputSize(int inputLen) {
|
||||||
|
return cipher.engineGetOutputSize(inputLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected byte[] engineGetIV() {
|
||||||
|
return cipher.engineGetIV();
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected AlgorithmParameters engineGetParameters() {
|
||||||
|
return pbes2Params.getAlgorithmParameters(blkSize, pbeAlg,
|
||||||
|
P11Util.getSunJceProvider(), JCAUtil.getSecureRandom());
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected void engineInit(int opmode, Key key,
|
||||||
|
SecureRandom random) throws InvalidKeyException {
|
||||||
|
try {
|
||||||
|
engineInit(opmode, key, (AlgorithmParameterSpec) null, random);
|
||||||
|
} catch (InvalidAlgorithmParameterException e) {
|
||||||
|
throw new InvalidKeyException("requires PBE parameters", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected void engineInit(int opmode, Key key,
|
||||||
|
AlgorithmParameterSpec params, SecureRandom random)
|
||||||
|
throws InvalidKeyException,
|
||||||
|
InvalidAlgorithmParameterException {
|
||||||
|
if (key instanceof P11Key) {
|
||||||
|
// If the key is a P11Key, it must come from a PBE derivation
|
||||||
|
// because this is a PBE Cipher service. In addition to checking the
|
||||||
|
// key, check that params (if passed) are consistent.
|
||||||
|
PBEUtil.checkKeyAndParams(key, params, pbeAlg);
|
||||||
|
// At this point, we know that the key is a P11PBEKey.
|
||||||
|
P11Key.P11PBEKey p11PBEKey = (P11Key.P11PBEKey) key;
|
||||||
|
// PBE services require a PBE key of the same algorithm and the
|
||||||
|
// underlying service (non-PBE) won't check it.
|
||||||
|
if (!pbeAlg.equals(p11PBEKey.getAlgorithm())) {
|
||||||
|
throw new InvalidKeyException("Cannot use a " +
|
||||||
|
p11PBEKey.getAlgorithm() + " key for a " + pbeAlg +
|
||||||
|
" service");
|
||||||
|
}
|
||||||
|
if (params instanceof PBEParameterSpec pbeParams) {
|
||||||
|
params = pbeParams.getParameterSpec();
|
||||||
|
}
|
||||||
|
pbes2Params.initialize(blkSize, opmode,
|
||||||
|
p11PBEKey.getIterationCount(), p11PBEKey.getSalt(), params,
|
||||||
|
random);
|
||||||
|
} else {
|
||||||
|
// If the key is not a P11Key, a derivation is needed. Data for
|
||||||
|
// derivation has to be carried either as part of the key or params.
|
||||||
|
// Use SunPKCS11 PBE key derivation to obtain a P11Key.
|
||||||
|
PBEKeySpec pbeSpec = pbes2Params.getPBEKeySpec(
|
||||||
|
blkSize, svcPbeKi.keyLen, opmode, key, params, random);
|
||||||
|
try {
|
||||||
|
P11Key.P11PBEKey p11PBEKey = P11SecretKeyFactory.derivePBEKey(
|
||||||
|
token, pbeSpec, svcPbeKi);
|
||||||
|
// The internal Cipher service uses the token where the
|
||||||
|
// derived key lives so there won't be any need to re-derive
|
||||||
|
// and use the password. The key cannot be accessed out of this
|
||||||
|
// class.
|
||||||
|
p11PBEKey.clearPassword();
|
||||||
|
key = p11PBEKey;
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
throw new InvalidKeyException(e);
|
||||||
|
} finally {
|
||||||
|
pbeSpec.clearPassword();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cipher.engineInit(opmode, key, pbes2Params.getIvSpec(), random);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected void engineInit(int opmode, Key key,
|
||||||
|
AlgorithmParameters params, SecureRandom random)
|
||||||
|
throws InvalidKeyException,
|
||||||
|
InvalidAlgorithmParameterException {
|
||||||
|
engineInit(opmode, key, PBEUtil.PBES2Params.getParameterSpec(params),
|
||||||
|
random);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected byte[] engineUpdate(byte[] input, int inputOffset,
|
||||||
|
int inputLen) {
|
||||||
|
return cipher.engineUpdate(input, inputOffset, inputLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected int engineUpdate(byte[] input, int inputOffset,
|
||||||
|
int inputLen, byte[] output, int outputOffset)
|
||||||
|
throws ShortBufferException {
|
||||||
|
return cipher.engineUpdate(input, inputOffset, inputLen,
|
||||||
|
output, outputOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected byte[] engineDoFinal(byte[] input, int inputOffset,
|
||||||
|
int inputLen)
|
||||||
|
throws IllegalBlockSizeException, BadPaddingException {
|
||||||
|
return cipher.engineDoFinal(input, inputOffset, inputLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected int engineDoFinal(byte[] input, int inputOffset,
|
||||||
|
int inputLen, byte[] output, int outputOffset)
|
||||||
|
throws ShortBufferException, IllegalBlockSizeException,
|
||||||
|
BadPaddingException {
|
||||||
|
return cipher.engineDoFinal(input, inputOffset, inputLen, output,
|
||||||
|
outputOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see JCE spec
|
||||||
|
@Override
|
||||||
|
protected int engineGetKeySize(Key key) {
|
||||||
|
// It's guaranteed that when engineInit succeeds, the key length
|
||||||
|
// for the underlying cipher is equal to the PBE service key length.
|
||||||
|
// Otherwise, initialization fails.
|
||||||
|
return svcPbeKi.keyLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,15 +25,19 @@
|
|||||||
|
|
||||||
package sun.security.pkcs11;
|
package sun.security.pkcs11;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.spec.*;
|
import java.security.spec.*;
|
||||||
|
|
||||||
import javax.crypto.*;
|
import javax.crypto.*;
|
||||||
|
import javax.crypto.interfaces.PBEKey;
|
||||||
import javax.crypto.spec.*;
|
import javax.crypto.spec.*;
|
||||||
|
|
||||||
import static sun.security.pkcs11.TemplateManager.*;
|
import static sun.security.pkcs11.TemplateManager.*;
|
||||||
|
|
||||||
|
import jdk.internal.access.SharedSecrets;
|
||||||
import sun.security.pkcs11.wrapper.*;
|
import sun.security.pkcs11.wrapper.*;
|
||||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||||
|
|
||||||
@ -52,44 +56,190 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
|||||||
// algorithm name
|
// algorithm name
|
||||||
private final String algorithm;
|
private final String algorithm;
|
||||||
|
|
||||||
|
// PBEKeyInfo if algorithm is PBE-related, otherwise null
|
||||||
|
private final PBEKeyInfo svcPbeKi;
|
||||||
|
|
||||||
P11SecretKeyFactory(Token token, String algorithm) {
|
P11SecretKeyFactory(Token token, String algorithm) {
|
||||||
super();
|
super();
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
|
this.svcPbeKi = getPBEKeyInfo(algorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<String,Long> keyTypes;
|
private static final Map<String, KeyInfo> keyInfo = new HashMap<>();
|
||||||
|
private static final KeyInfo HMAC = new KeyInfo("HMAC", PCKK_HMAC);
|
||||||
|
private static final KeyInfo SSLMAC = new KeyInfo("SSLMAC", PCKK_SSLMAC);
|
||||||
|
|
||||||
|
static KeyInfo getKeyInfo(String algo) {
|
||||||
|
KeyInfo ki = keyInfo.get(algo);
|
||||||
|
if (ki == null) {
|
||||||
|
String algoUpper = algo.toUpperCase(Locale.ENGLISH);
|
||||||
|
ki = keyInfo.get(algoUpper);
|
||||||
|
if (ki == null) {
|
||||||
|
if (algoUpper.startsWith("HMAC")) {
|
||||||
|
return HMAC;
|
||||||
|
} else if (algoUpper.startsWith("SSLMAC")) {
|
||||||
|
return SSLMAC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ki;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PBEKeyInfo getPBEKeyInfo(String algo) {
|
||||||
|
if (getKeyInfo(algo) instanceof PBEKeyInfo pbeKi) {
|
||||||
|
return pbeKi;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void putKeyInfo(KeyInfo ki) {
|
||||||
|
keyInfo.put(ki.algo, ki);
|
||||||
|
keyInfo.put(ki.algo.toUpperCase(Locale.ENGLISH), ki);
|
||||||
|
}
|
||||||
|
|
||||||
|
static sealed class KeyInfo permits PBEKeyInfo {
|
||||||
|
public final String algo;
|
||||||
|
public final long keyType;
|
||||||
|
|
||||||
|
KeyInfo(String algo, long keyType) {
|
||||||
|
this.algo = algo;
|
||||||
|
this.keyType = keyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The P11SecretKeyFactory::convertKey method needs to know if a service
|
||||||
|
// type and a key are compatible. Trivial cases such as having the same
|
||||||
|
// algorithm names are handled directly. KeyInfo::checkUse helps with
|
||||||
|
// cases that require to retrieve the key's KeyInfo (ki), in addition to
|
||||||
|
// the service's KeyInfo (si), to make a decision.
|
||||||
|
static boolean checkUse(KeyInfo ki, KeyInfo si) {
|
||||||
|
if (si instanceof PBEKeyInfo && !si.algo.equals(ki.algo)) {
|
||||||
|
// PBE services require a PBE key of the same algorithm.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ki instanceof PBKDF2KeyInfo) {
|
||||||
|
// We cannot tell what the PBE key was derived for,
|
||||||
|
// so any service is allowed in principle.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// This path handles non-PBE cases where aliases are used (i.e:
|
||||||
|
// RC4 vs ARCFOUR) and mixed PBE - non-PBE cases (i.e.: a
|
||||||
|
// PBE-derived AES key used in an AES Cipher service).
|
||||||
|
return ki.keyType == si.keyType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract sealed class PBEKeyInfo extends KeyInfo
|
||||||
|
permits AESPBEKeyInfo, PBKDF2KeyInfo, P12MacPBEKeyInfo {
|
||||||
|
public static final long INVALID_PRF = -1;
|
||||||
|
public final long kdfMech;
|
||||||
|
public final long prfMech;
|
||||||
|
public final int keyLen;
|
||||||
|
public final CK_ATTRIBUTE[] extraAttrs;
|
||||||
|
|
||||||
|
protected PBEKeyInfo(String algo, long kdfMech, long prfMech,
|
||||||
|
long keyType, int keyLen, CK_ATTRIBUTE[] extraAttrs) {
|
||||||
|
super(algo, keyType);
|
||||||
|
this.kdfMech = kdfMech;
|
||||||
|
this.prfMech = prfMech;
|
||||||
|
this.keyLen = keyLen;
|
||||||
|
this.extraAttrs = extraAttrs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class AESPBEKeyInfo extends PBEKeyInfo {
|
||||||
|
private static final CK_ATTRIBUTE[] attr = new CK_ATTRIBUTE[] {
|
||||||
|
CK_ATTRIBUTE.ENCRYPT_TRUE};
|
||||||
|
|
||||||
|
AESPBEKeyInfo(String algo, long prfMech, int keyLen) {
|
||||||
|
super(algo, CKM_PKCS5_PBKD2, prfMech, CKK_AES, keyLen, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class PBKDF2KeyInfo extends PBEKeyInfo {
|
||||||
|
private static final CK_ATTRIBUTE[] attr = new CK_ATTRIBUTE[] {
|
||||||
|
CK_ATTRIBUTE.ENCRYPT_TRUE, CK_ATTRIBUTE.SIGN_TRUE};
|
||||||
|
|
||||||
|
PBKDF2KeyInfo(String algo, long prfMech) {
|
||||||
|
super(algo, CKM_PKCS5_PBKD2, prfMech, CKK_GENERIC_SECRET, -1, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class P12MacPBEKeyInfo extends PBEKeyInfo {
|
||||||
|
private static final CK_ATTRIBUTE[] attr = new CK_ATTRIBUTE[] {
|
||||||
|
CK_ATTRIBUTE.SIGN_TRUE};
|
||||||
|
|
||||||
|
P12MacPBEKeyInfo(String algo, long kdfMech, int keyLen) {
|
||||||
|
super(algo, kdfMech, PBEKeyInfo.INVALID_PRF,
|
||||||
|
CKK_GENERIC_SECRET, keyLen, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
keyTypes = new HashMap<String,Long>();
|
putKeyInfo(new KeyInfo("RC4", CKK_RC4));
|
||||||
addKeyType("RC4", CKK_RC4);
|
putKeyInfo(new KeyInfo("ARCFOUR", CKK_RC4));
|
||||||
addKeyType("ARCFOUR", CKK_RC4);
|
putKeyInfo(new KeyInfo("DES", CKK_DES));
|
||||||
addKeyType("DES", CKK_DES);
|
putKeyInfo(new KeyInfo("DESede", CKK_DES3));
|
||||||
addKeyType("DESede", CKK_DES3);
|
putKeyInfo(new KeyInfo("AES", CKK_AES));
|
||||||
addKeyType("AES", CKK_AES);
|
putKeyInfo(new KeyInfo("Blowfish", CKK_BLOWFISH));
|
||||||
addKeyType("Blowfish", CKK_BLOWFISH);
|
putKeyInfo(new KeyInfo("ChaCha20", CKK_CHACHA20));
|
||||||
addKeyType("ChaCha20", CKK_CHACHA20);
|
putKeyInfo(new KeyInfo("ChaCha20-Poly1305", CKK_CHACHA20));
|
||||||
addKeyType("ChaCha20-Poly1305", CKK_CHACHA20);
|
|
||||||
|
|
||||||
// we don't implement RC2 or IDEA, but we want to be able to generate
|
// we don't implement RC2 or IDEA, but we want to be able to generate
|
||||||
// keys for those SSL/TLS ciphersuites.
|
// keys for those SSL/TLS ciphersuites.
|
||||||
addKeyType("RC2", CKK_RC2);
|
putKeyInfo(new KeyInfo("RC2", CKK_RC2));
|
||||||
addKeyType("IDEA", CKK_IDEA);
|
putKeyInfo(new KeyInfo("IDEA", CKK_IDEA));
|
||||||
|
|
||||||
addKeyType("TlsPremasterSecret", PCKK_TLSPREMASTER);
|
putKeyInfo(new KeyInfo("TlsPremasterSecret", PCKK_TLSPREMASTER));
|
||||||
addKeyType("TlsRsaPremasterSecret", PCKK_TLSRSAPREMASTER);
|
putKeyInfo(new KeyInfo("TlsRsaPremasterSecret", PCKK_TLSRSAPREMASTER));
|
||||||
addKeyType("TlsMasterSecret", PCKK_TLSMASTER);
|
putKeyInfo(new KeyInfo("TlsMasterSecret", PCKK_TLSMASTER));
|
||||||
addKeyType("Generic", CKK_GENERIC_SECRET);
|
putKeyInfo(new KeyInfo("Generic", CKK_GENERIC_SECRET));
|
||||||
|
|
||||||
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA1AndAES_128",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA1, 128));
|
||||||
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA224AndAES_128",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA224, 128));
|
||||||
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA256AndAES_128",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA256, 128));
|
||||||
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA384AndAES_128",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA384, 128));
|
||||||
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA512AndAES_128",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA512, 128));
|
||||||
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA1AndAES_256",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA1, 256));
|
||||||
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA224AndAES_256",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA224, 256));
|
||||||
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA256AndAES_256",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA256, 256));
|
||||||
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA384AndAES_256",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA384, 256));
|
||||||
|
putKeyInfo(new AESPBEKeyInfo("PBEWithHmacSHA512AndAES_256",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA512, 256));
|
||||||
|
|
||||||
|
putKeyInfo(new PBKDF2KeyInfo("PBKDF2WithHmacSHA1",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA1));
|
||||||
|
putKeyInfo(new PBKDF2KeyInfo("PBKDF2WithHmacSHA224",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA224));
|
||||||
|
putKeyInfo(new PBKDF2KeyInfo("PBKDF2WithHmacSHA256",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA256));
|
||||||
|
putKeyInfo(new PBKDF2KeyInfo("PBKDF2WithHmacSHA384",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA384));
|
||||||
|
putKeyInfo(new PBKDF2KeyInfo("PBKDF2WithHmacSHA512",
|
||||||
|
CKP_PKCS5_PBKD2_HMAC_SHA512));
|
||||||
|
|
||||||
|
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA1",
|
||||||
|
CKM_PBA_SHA1_WITH_SHA1_HMAC, 160));
|
||||||
|
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA224",
|
||||||
|
CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN, 224));
|
||||||
|
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA256",
|
||||||
|
CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN, 256));
|
||||||
|
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA384",
|
||||||
|
CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN, 384));
|
||||||
|
putKeyInfo(new P12MacPBEKeyInfo("HmacPBESHA512",
|
||||||
|
CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN, 512));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addKeyType(String name, long id) {
|
// No pseudo key types
|
||||||
Long l = Long.valueOf(id);
|
|
||||||
keyTypes.put(name, l);
|
|
||||||
keyTypes.put(name.toUpperCase(Locale.ENGLISH), l);
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns the PKCS11 key type of the specified algorithm
|
|
||||||
// no pseudo KeyTypes
|
|
||||||
static long getPKCS11KeyType(String algorithm) {
|
static long getPKCS11KeyType(String algorithm) {
|
||||||
long kt = getKeyType(algorithm);
|
long kt = getKeyType(algorithm);
|
||||||
if (kt == -1 || kt > PCKK_ANY) {
|
if (kt == -1 || kt > PCKK_ANY) {
|
||||||
@ -98,30 +248,18 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
|||||||
return kt;
|
return kt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns direct lookup result of keyTypes using algorithm
|
|
||||||
static long getKeyType(String algorithm) {
|
static long getKeyType(String algorithm) {
|
||||||
Long l = keyTypes.get(algorithm);
|
KeyInfo ki = getKeyInfo(algorithm);
|
||||||
if (l == null) {
|
return ki == null ? -1 : ki.keyType;
|
||||||
algorithm = algorithm.toUpperCase(Locale.ENGLISH);
|
|
||||||
l = keyTypes.get(algorithm);
|
|
||||||
if (l == null) {
|
|
||||||
if (algorithm.startsWith("HMAC")) {
|
|
||||||
return PCKK_HMAC;
|
|
||||||
} else if (algorithm.startsWith("SSLMAC")) {
|
|
||||||
return PCKK_SSLMAC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (l != null) ? l.longValue() : -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an arbitrary key of algorithm into a P11Key of provider.
|
* Convert an arbitrary key of algorithm into a P11Key of provider.
|
||||||
* Used in engineTranslateKey(), P11Cipher.init(), and P11Mac.init().
|
* Used in engineTranslateKey(), P11Cipher.init(), and P11Mac.init().
|
||||||
*/
|
*/
|
||||||
static P11Key convertKey(Token token, Key key, String algo)
|
static P11Key convertKey(Token token, Key key, String svcAlgo)
|
||||||
throws InvalidKeyException {
|
throws InvalidKeyException {
|
||||||
return convertKey(token, key, algo, null);
|
return convertKey(token, key, svcAlgo, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -129,30 +267,32 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
|||||||
* P11Key of provider.
|
* P11Key of provider.
|
||||||
* Used in P11KeyStore.storeSkey.
|
* Used in P11KeyStore.storeSkey.
|
||||||
*/
|
*/
|
||||||
static P11Key convertKey(Token token, Key key, String algo,
|
static P11Key convertKey(Token token, Key key, String svcAlgo,
|
||||||
CK_ATTRIBUTE[] extraAttrs)
|
CK_ATTRIBUTE[] extraAttrs) throws InvalidKeyException {
|
||||||
throws InvalidKeyException {
|
|
||||||
token.ensureValid();
|
token.ensureValid();
|
||||||
if (key == null) {
|
|
||||||
throw new InvalidKeyException("Key must not be null");
|
|
||||||
}
|
|
||||||
if (!(key instanceof SecretKey)) {
|
if (!(key instanceof SecretKey)) {
|
||||||
throw new InvalidKeyException("Key must be a SecretKey");
|
throw new InvalidKeyException("Key must be a SecretKey");
|
||||||
}
|
}
|
||||||
long algoType;
|
final String keyAlgo = key.getAlgorithm();
|
||||||
if (algo == null) {
|
if (keyAlgo == null) {
|
||||||
algo = key.getAlgorithm();
|
throw new InvalidKeyException("Key must specify its algorithm");
|
||||||
algoType = getKeyType(algo);
|
}
|
||||||
} else {
|
if (svcAlgo == null) {
|
||||||
algoType = getKeyType(algo);
|
svcAlgo = keyAlgo;
|
||||||
long keyAlgorithmType = getKeyType(key.getAlgorithm());
|
}
|
||||||
if (algoType != keyAlgorithmType) {
|
KeyInfo ki = null;
|
||||||
if ((algoType == PCKK_HMAC) || (algoType == PCKK_SSLMAC)) {
|
KeyInfo si = getKeyInfo(svcAlgo);
|
||||||
// ignore key algorithm for MACs
|
if (si == null) {
|
||||||
} else {
|
throw new InvalidKeyException("Unknown algorithm " + svcAlgo);
|
||||||
throw new InvalidKeyException
|
}
|
||||||
("Key algorithm must be " + algo);
|
// Check if the key can be used for the service.
|
||||||
}
|
// Any key can be used for a MAC service.
|
||||||
|
if (svcAlgo != keyAlgo &&
|
||||||
|
si.keyType != PCKK_HMAC && si.keyType != PCKK_SSLMAC) {
|
||||||
|
ki = getKeyInfo(keyAlgo);
|
||||||
|
if (ki == null || !KeyInfo.checkUse(ki, si)) {
|
||||||
|
throw new InvalidKeyException("Cannot use a " + keyAlgo +
|
||||||
|
" key for a " + svcAlgo + " service");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (key instanceof P11Key p11Key) {
|
if (key instanceof P11Key p11Key) {
|
||||||
@ -184,15 +324,159 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
|||||||
if (p11Key != null) {
|
if (p11Key != null) {
|
||||||
return p11Key;
|
return p11Key;
|
||||||
}
|
}
|
||||||
if (!"RAW".equalsIgnoreCase(key.getFormat())) {
|
if (key instanceof PBEKey pbeKey) {
|
||||||
throw new InvalidKeyException("Encoded format must be RAW");
|
ki = ki == null ? getKeyInfo(keyAlgo) : ki;
|
||||||
|
if (ki instanceof PBEKeyInfo pbeKi) {
|
||||||
|
PBEKeySpec keySpec = getPbeKeySpec(pbeKey);
|
||||||
|
try {
|
||||||
|
p11Key = derivePBEKey(token, keySpec, pbeKi);
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
throw new InvalidKeyException(e);
|
||||||
|
} finally {
|
||||||
|
keySpec.clearPassword();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new InvalidKeyException("Cannot derive unknown " +
|
||||||
|
keyAlgo + " algorithm");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (si instanceof PBEKeyInfo) {
|
||||||
|
throw new InvalidKeyException("PBE service requires a PBE key");
|
||||||
|
}
|
||||||
|
if (!"RAW".equalsIgnoreCase(key.getFormat())) {
|
||||||
|
throw new InvalidKeyException("Encoded format must be RAW");
|
||||||
|
}
|
||||||
|
byte[] encoded = key.getEncoded();
|
||||||
|
try {
|
||||||
|
p11Key = createKey(token, encoded, svcAlgo, si.keyType,
|
||||||
|
extraAttrs);
|
||||||
|
} finally {
|
||||||
|
Arrays.fill(encoded, (byte) 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
byte[] encoded = key.getEncoded();
|
|
||||||
p11Key = createKey(token, encoded, algo, algoType, extraAttrs);
|
|
||||||
token.secretCache.put(key, p11Key);
|
token.secretCache.put(key, p11Key);
|
||||||
return p11Key;
|
return p11Key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static P11Key.P11PBEKey derivePBEKey(Token token, PBEKeySpec keySpec,
|
||||||
|
PBEKeyInfo pbeKi) throws InvalidKeySpecException {
|
||||||
|
token.ensureValid();
|
||||||
|
if (keySpec == null) {
|
||||||
|
throw new InvalidKeySpecException("PBEKeySpec must not be null");
|
||||||
|
}
|
||||||
|
Session session = null;
|
||||||
|
char[] password = null;
|
||||||
|
char[] encPassword = null;
|
||||||
|
try {
|
||||||
|
session = token.getObjSession();
|
||||||
|
CK_MECHANISM ckMech;
|
||||||
|
password = keySpec.getPassword();
|
||||||
|
byte[] salt = keySpec.getSalt();
|
||||||
|
int itCount = keySpec.getIterationCount();
|
||||||
|
int keySize = keySpec.getKeyLength();
|
||||||
|
assert password != null :
|
||||||
|
"PBEKeySpec does not allow a null password";
|
||||||
|
if (salt == null) {
|
||||||
|
throw new InvalidKeySpecException("Salt not found");
|
||||||
|
}
|
||||||
|
assert salt.length > 0 : "PBEKeySpec does not allow an empty salt";
|
||||||
|
if (itCount < 1) {
|
||||||
|
throw new InvalidKeySpecException("Iteration count must be " +
|
||||||
|
"a non-zero positive integer");
|
||||||
|
}
|
||||||
|
if (pbeKi.keyLen > 0) {
|
||||||
|
if (keySize == 0) {
|
||||||
|
keySize = pbeKi.keyLen;
|
||||||
|
} else if (keySize != pbeKi.keyLen) {
|
||||||
|
throw new InvalidKeySpecException(
|
||||||
|
"Key length is invalid for " + pbeKi.algo + " (" +
|
||||||
|
"expecting " + pbeKi.keyLen + " but was " +
|
||||||
|
keySize + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keySize < 1 || keySize % 8 != 0) {
|
||||||
|
throw new InvalidKeySpecException("Key length must be " +
|
||||||
|
"multiple of 8 and greater than zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pbeKi.kdfMech == CKM_PKCS5_PBKD2) {
|
||||||
|
encPassword = P11Util.encodePassword(password,
|
||||||
|
StandardCharsets.UTF_8, 0);
|
||||||
|
CK_VERSION p11Ver = token.p11.getVersion();
|
||||||
|
if (P11Util.isNSS(token) || p11Ver.major < 2 ||
|
||||||
|
p11Ver.major == 2 && p11Ver.minor < 40) {
|
||||||
|
// NSS keeps using the old structure beyond PKCS #11 v2.40.
|
||||||
|
ckMech = new CK_MECHANISM(pbeKi.kdfMech,
|
||||||
|
new CK_PKCS5_PBKD2_PARAMS(encPassword, salt,
|
||||||
|
itCount, pbeKi.prfMech));
|
||||||
|
} else {
|
||||||
|
ckMech = new CK_MECHANISM(pbeKi.kdfMech,
|
||||||
|
new CK_PKCS5_PBKD2_PARAMS2(encPassword, salt,
|
||||||
|
itCount, pbeKi.prfMech));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* PKCS #12 "General Method" PBKD (RFC 7292, Appendix B.2).
|
||||||
|
*
|
||||||
|
* According to PKCS #11, "password" in CK_PBE_PARAMS is of
|
||||||
|
* CK_UTF8CHAR_PTR type. While this suggests a UTF-8 encoding,
|
||||||
|
* RFC 7292 Appendix B.1 indicates that the password has to be
|
||||||
|
* encoded as a BMPString with a 2-bytes NULL terminator.
|
||||||
|
*/
|
||||||
|
encPassword = P11Util.encodePassword(password,
|
||||||
|
StandardCharsets.UTF_16BE, 2);
|
||||||
|
ckMech = new CK_MECHANISM(pbeKi.kdfMech,
|
||||||
|
new CK_PBE_PARAMS(encPassword, salt, itCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
CK_ATTRIBUTE[] attrs =
|
||||||
|
new CK_ATTRIBUTE[3 + pbeKi.extraAttrs.length];
|
||||||
|
attrs[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY);
|
||||||
|
attrs[1] = new CK_ATTRIBUTE(CKA_VALUE_LEN, keySize >> 3);
|
||||||
|
attrs[2] = new CK_ATTRIBUTE(CKA_KEY_TYPE, pbeKi.keyType);
|
||||||
|
System.arraycopy(pbeKi.extraAttrs, 0, attrs, 3,
|
||||||
|
pbeKi.extraAttrs.length);
|
||||||
|
CK_ATTRIBUTE[] attr = token.getAttributes(
|
||||||
|
O_GENERATE, CKO_SECRET_KEY, pbeKi.keyType, attrs);
|
||||||
|
long keyID = token.p11.C_GenerateKey(session.id(), ckMech, attr);
|
||||||
|
return (P11Key.P11PBEKey) P11Key.pbeKey(session, keyID, pbeKi.algo,
|
||||||
|
keySize, attr, password, salt, itCount);
|
||||||
|
} catch (PKCS11Exception e) {
|
||||||
|
throw new InvalidKeySpecException("Could not create key", e);
|
||||||
|
} finally {
|
||||||
|
if (encPassword != null) {
|
||||||
|
Arrays.fill(encPassword, '\0');
|
||||||
|
}
|
||||||
|
if (password != null) {
|
||||||
|
Arrays.fill(password, '\0');
|
||||||
|
}
|
||||||
|
token.releaseSession(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PBEKeySpec getPbeKeySpec(PBEKey pbeKey) {
|
||||||
|
int keyLength = 0;
|
||||||
|
if ("RAW".equalsIgnoreCase(pbeKey.getFormat())) {
|
||||||
|
byte[] encoded = pbeKey.getEncoded();
|
||||||
|
if (encoded != null) {
|
||||||
|
keyLength = encoded.length << 3;
|
||||||
|
Arrays.fill(encoded, (byte) 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int ic = pbeKey.getIterationCount();
|
||||||
|
byte[] salt = pbeKey.getSalt();
|
||||||
|
char[] pwd = pbeKey.getPassword();
|
||||||
|
try {
|
||||||
|
return keyLength == 0 ?
|
||||||
|
new PBEKeySpec(pwd, salt, ic) :
|
||||||
|
new PBEKeySpec(pwd, salt, ic, keyLength);
|
||||||
|
} finally {
|
||||||
|
if (pwd != null) {
|
||||||
|
Arrays.fill(pwd, '\0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void fixDESParity(byte[] key, int offset) {
|
static void fixDESParity(byte[] key, int offset) {
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
int b = key[offset] & 0xfe;
|
int b = key[offset] & 0xfe;
|
||||||
@ -286,36 +570,51 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
|||||||
if (keySpec == null) {
|
if (keySpec == null) {
|
||||||
throw new InvalidKeySpecException("KeySpec must not be null");
|
throw new InvalidKeySpecException("KeySpec must not be null");
|
||||||
}
|
}
|
||||||
if (keySpec instanceof SecretKeySpec) {
|
if (keySpec instanceof SecretKeySpec secretKeySpec) {
|
||||||
try {
|
try {
|
||||||
Key key = convertKey(token, (SecretKey)keySpec, algorithm);
|
Key key = convertKey(token, secretKeySpec, algorithm);
|
||||||
return (SecretKey)key;
|
return (SecretKey)key;
|
||||||
} catch (InvalidKeyException e) {
|
} catch (InvalidKeyException e) {
|
||||||
throw new InvalidKeySpecException(e);
|
throw new InvalidKeySpecException(e);
|
||||||
}
|
}
|
||||||
|
} else if (keySpec instanceof PBEKeySpec pbeKeySpec &&
|
||||||
|
svcPbeKi != null) {
|
||||||
|
return derivePBEKey(token, pbeKeySpec, svcPbeKi);
|
||||||
} else if (algorithm.equalsIgnoreCase("DES")) {
|
} else if (algorithm.equalsIgnoreCase("DES")) {
|
||||||
if (keySpec instanceof DESKeySpec) {
|
if (keySpec instanceof DESKeySpec desKeySpec) {
|
||||||
byte[] keyBytes = ((DESKeySpec)keySpec).getKey();
|
return generateDESSecret(desKeySpec.getKey(), "DES");
|
||||||
keySpec = new SecretKeySpec(keyBytes, "DES");
|
|
||||||
return engineGenerateSecret(keySpec);
|
|
||||||
}
|
}
|
||||||
} else if (algorithm.equalsIgnoreCase("DESede")) {
|
} else if (algorithm.equalsIgnoreCase("DESede")) {
|
||||||
if (keySpec instanceof DESedeKeySpec) {
|
if (keySpec instanceof DESedeKeySpec desEdeKeySpec) {
|
||||||
byte[] keyBytes = ((DESedeKeySpec)keySpec).getKey();
|
return generateDESSecret(desEdeKeySpec.getKey(), "DESede");
|
||||||
keySpec = new SecretKeySpec(keyBytes, "DESede");
|
|
||||||
return engineGenerateSecret(keySpec);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new InvalidKeySpecException
|
throw new InvalidKeySpecException
|
||||||
("Unsupported spec: " + keySpec.getClass().getName());
|
("Unsupported spec: " + keySpec.getClass().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SecretKey generateDESSecret(byte[] keyBytes, String desAlgo)
|
||||||
|
throws InvalidKeySpecException {
|
||||||
|
SecretKeySpec secretKeySpec = null;
|
||||||
|
try {
|
||||||
|
secretKeySpec = new SecretKeySpec(keyBytes, desAlgo);
|
||||||
|
return engineGenerateSecret(secretKeySpec);
|
||||||
|
} finally {
|
||||||
|
if (secretKeySpec != null) {
|
||||||
|
SharedSecrets.getJavaxCryptoSpecAccess()
|
||||||
|
.clearSecretKeySpec(secretKeySpec);
|
||||||
|
}
|
||||||
|
if (keyBytes != null) {
|
||||||
|
Arrays.fill(keyBytes, (byte) 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] getKeyBytes(SecretKey key) throws InvalidKeySpecException {
|
private byte[] getKeyBytes(SecretKey key) throws InvalidKeySpecException {
|
||||||
try {
|
try {
|
||||||
key = engineTranslateKey(key);
|
key = engineTranslateKey(key);
|
||||||
if (!"RAW".equalsIgnoreCase(key.getFormat())) {
|
if (!"RAW".equalsIgnoreCase(key.getFormat())) {
|
||||||
throw new InvalidKeySpecException
|
throw new InvalidKeySpecException("Could not obtain key bytes");
|
||||||
("Could not obtain key bytes");
|
|
||||||
}
|
}
|
||||||
byte[] k = key.getEncoded();
|
byte[] k = key.getEncoded();
|
||||||
return k;
|
return k;
|
||||||
@ -334,6 +633,9 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
|||||||
}
|
}
|
||||||
if (keySpec.isAssignableFrom(SecretKeySpec.class)) {
|
if (keySpec.isAssignableFrom(SecretKeySpec.class)) {
|
||||||
return new SecretKeySpec(getKeyBytes(key), algorithm);
|
return new SecretKeySpec(getKeyBytes(key), algorithm);
|
||||||
|
} else if (keySpec.isAssignableFrom(PBEKeySpec.class) &&
|
||||||
|
key instanceof PBEKey pbeKey && svcPbeKi != null) {
|
||||||
|
return getPbeKeySpec(pbeKey);
|
||||||
} else if (algorithm.equalsIgnoreCase("DES")) {
|
} else if (algorithm.equalsIgnoreCase("DES")) {
|
||||||
try {
|
try {
|
||||||
if (keySpec.isAssignableFrom(DESKeySpec.class)) {
|
if (keySpec.isAssignableFrom(DESKeySpec.class)) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -27,6 +27,9 @@ package sun.security.pkcs11;
|
|||||||
|
|
||||||
import java.lang.ref.Cleaner;
|
import java.lang.ref.Cleaner;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.CharBuffer;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
|
|
||||||
import sun.security.pkcs11.wrapper.PKCS11Exception;
|
import sun.security.pkcs11.wrapper.PKCS11Exception;
|
||||||
@ -51,6 +54,46 @@ public final class P11Util {
|
|||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isNSS(Token token) {
|
||||||
|
char[] tokenLabel = token.tokenInfo.label;
|
||||||
|
if (tokenLabel != null && tokenLabel.length >= 3) {
|
||||||
|
return (tokenLabel[0] == 'N' && tokenLabel[1] == 'S'
|
||||||
|
&& tokenLabel[2] == 'S');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char[] encodePassword(char[] password, Charset cs,
|
||||||
|
int nullTermBytes) {
|
||||||
|
/*
|
||||||
|
* When a Java char (2 bytes) is converted to CK_UTF8CHAR (1 byte) for
|
||||||
|
* a PKCS #11 (native) call, the high-order byte is discarded (see
|
||||||
|
* jCharArrayToCKUTF8CharArray in p11_util.c). In order to have an
|
||||||
|
* encoded string passed to C_GenerateKey, we need to account for
|
||||||
|
* truncation and expand beforehand: high and low parts of each char
|
||||||
|
* are split into 2 chars. As an example, this is the transformation
|
||||||
|
* for a NULL terminated password "a" that has to be encoded in
|
||||||
|
* UTF-16 BE:
|
||||||
|
* char[] password => [ 0x0061, 0x0000 ]
|
||||||
|
* / \ / \
|
||||||
|
* ByteBuffer passwordBytes => [ 0x00, 0x61, 0x00, 0x00 ]
|
||||||
|
* | | | |
|
||||||
|
* char[] encPassword => [0x0000, 0x0061, 0x0000, 0x0000]
|
||||||
|
* | | | |
|
||||||
|
* PKCS #11 call (bytes) => [ 0x00, 0x61, 0x00, 0x00 ]
|
||||||
|
*/
|
||||||
|
ByteBuffer passwordBytes = cs.encode(CharBuffer.wrap(password));
|
||||||
|
char[] encPassword =
|
||||||
|
new char[passwordBytes.remaining() + nullTermBytes];
|
||||||
|
int i = 0;
|
||||||
|
while (passwordBytes.hasRemaining()) {
|
||||||
|
encPassword[i] = (char) (passwordBytes.get() & 0xFF);
|
||||||
|
// Erase password bytes as we read during encoding.
|
||||||
|
passwordBytes.put(i++, (byte) 0);
|
||||||
|
}
|
||||||
|
return encPassword;
|
||||||
|
}
|
||||||
|
|
||||||
static Provider getSunProvider() {
|
static Provider getSunProvider() {
|
||||||
Provider p = sun;
|
Provider p = sun;
|
||||||
if (p == null) {
|
if (p == null) {
|
||||||
|
@ -421,14 +421,23 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
final String className;
|
final String className;
|
||||||
final List<String> aliases;
|
final List<String> aliases;
|
||||||
final int[] mechanisms;
|
final int[] mechanisms;
|
||||||
|
final int[] requiredMechs;
|
||||||
|
|
||||||
private Descriptor(String type, String algorithm, String className,
|
private Descriptor(String type, String algorithm, String className,
|
||||||
List<String> aliases, int[] mechanisms) {
|
List<String> aliases, int[] mechanisms) {
|
||||||
|
this(type, algorithm, className, aliases, mechanisms, null);
|
||||||
|
}
|
||||||
|
// mechanisms is a list of possible mechanisms that implement the
|
||||||
|
// algorithm, at least one of them must be available. requiredMechs
|
||||||
|
// is a list of auxiliary mechanisms, all of them must be available
|
||||||
|
private Descriptor(String type, String algorithm, String className,
|
||||||
|
List<String> aliases, int[] mechanisms, int[] requiredMechs) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
this.className = className;
|
this.className = className;
|
||||||
this.aliases = aliases;
|
this.aliases = aliases;
|
||||||
this.mechanisms = mechanisms;
|
this.mechanisms = mechanisms;
|
||||||
|
this.requiredMechs = requiredMechs;
|
||||||
}
|
}
|
||||||
private P11Service service(Token token, int mechanism) {
|
private P11Service service(Token token, int mechanism) {
|
||||||
return new P11Service
|
return new P11Service
|
||||||
@ -470,12 +479,24 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
register(new Descriptor(type, algorithm, className, aliases, m));
|
register(new Descriptor(type, algorithm, className, aliases, m));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void d(String type, String algorithm, String className,
|
||||||
|
int[] m, int[] requiredMechs) {
|
||||||
|
register(new Descriptor(type, algorithm, className, null, m,
|
||||||
|
requiredMechs));
|
||||||
|
}
|
||||||
|
|
||||||
private static void dA(String type, String algorithm, String className,
|
private static void dA(String type, String algorithm, String className,
|
||||||
int[] m) {
|
int[] m) {
|
||||||
register(new Descriptor(type, algorithm, className,
|
register(new Descriptor(type, algorithm, className,
|
||||||
getAliases(algorithm), m));
|
getAliases(algorithm), m));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void dA(String type, String algorithm, String className,
|
||||||
|
int[] m, int[] requiredMechs) {
|
||||||
|
register(new Descriptor(type, algorithm, className,
|
||||||
|
getAliases(algorithm), m, requiredMechs));
|
||||||
|
}
|
||||||
|
|
||||||
private static void register(Descriptor d) {
|
private static void register(Descriptor d) {
|
||||||
for (int i = 0; i < d.mechanisms.length; i++) {
|
for (int i = 0; i < d.mechanisms.length; i++) {
|
||||||
int m = d.mechanisms[i];
|
int m = d.mechanisms[i];
|
||||||
@ -526,6 +547,7 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
String P11KeyWrapCipher = "sun.security.pkcs11.P11KeyWrapCipher";
|
String P11KeyWrapCipher = "sun.security.pkcs11.P11KeyWrapCipher";
|
||||||
String P11RSACipher = "sun.security.pkcs11.P11RSACipher";
|
String P11RSACipher = "sun.security.pkcs11.P11RSACipher";
|
||||||
String P11AEADCipher = "sun.security.pkcs11.P11AEADCipher";
|
String P11AEADCipher = "sun.security.pkcs11.P11AEADCipher";
|
||||||
|
String P11PBECipher = "sun.security.pkcs11.P11PBECipher";
|
||||||
String P11Signature = "sun.security.pkcs11.P11Signature";
|
String P11Signature = "sun.security.pkcs11.P11Signature";
|
||||||
String P11PSSSignature = "sun.security.pkcs11.P11PSSSignature";
|
String P11PSSSignature = "sun.security.pkcs11.P11PSSSignature";
|
||||||
|
|
||||||
@ -588,6 +610,24 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
d(MAC, "SslMacSHA1", P11Mac,
|
d(MAC, "SslMacSHA1", P11Mac,
|
||||||
m(CKM_SSL3_SHA1_MAC));
|
m(CKM_SSL3_SHA1_MAC));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PBA HMacs
|
||||||
|
*
|
||||||
|
* KeyDerivationMech must be supported
|
||||||
|
* for these services to be available.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
d(MAC, "HmacPBESHA1", P11Mac, m(CKM_SHA_1_HMAC),
|
||||||
|
m(CKM_PBA_SHA1_WITH_SHA1_HMAC));
|
||||||
|
d(MAC, "HmacPBESHA224", P11Mac, m(CKM_SHA224_HMAC),
|
||||||
|
m(CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN));
|
||||||
|
d(MAC, "HmacPBESHA256", P11Mac, m(CKM_SHA256_HMAC),
|
||||||
|
m(CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN));
|
||||||
|
d(MAC, "HmacPBESHA384", P11Mac, m(CKM_SHA384_HMAC),
|
||||||
|
m(CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN));
|
||||||
|
d(MAC, "HmacPBESHA512", P11Mac, m(CKM_SHA512_HMAC),
|
||||||
|
m(CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN));
|
||||||
|
|
||||||
d(KPG, "RSA", P11KeyPairGenerator,
|
d(KPG, "RSA", P11KeyPairGenerator,
|
||||||
getAliases("PKCS1"),
|
getAliases("PKCS1"),
|
||||||
m(CKM_RSA_PKCS_KEY_PAIR_GEN));
|
m(CKM_RSA_PKCS_KEY_PAIR_GEN));
|
||||||
@ -686,6 +726,60 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
d(SKF, "ChaCha20", P11SecretKeyFactory,
|
d(SKF, "ChaCha20", P11SecretKeyFactory,
|
||||||
m(CKM_CHACHA20_POLY1305));
|
m(CKM_CHACHA20_POLY1305));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PBE Secret Key Factories
|
||||||
|
*
|
||||||
|
* KeyDerivationPrf must be supported for these services
|
||||||
|
* to be available.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
d(SKF, "PBEWithHmacSHA1AndAES_128",
|
||||||
|
P11SecretKeyFactory, m(CKM_PKCS5_PBKD2), m(CKM_SHA_1_HMAC));
|
||||||
|
d(SKF, "PBEWithHmacSHA224AndAES_128",
|
||||||
|
P11SecretKeyFactory, m(CKM_PKCS5_PBKD2), m(CKM_SHA224_HMAC));
|
||||||
|
d(SKF, "PBEWithHmacSHA256AndAES_128",
|
||||||
|
P11SecretKeyFactory, m(CKM_PKCS5_PBKD2), m(CKM_SHA256_HMAC));
|
||||||
|
d(SKF, "PBEWithHmacSHA384AndAES_128",
|
||||||
|
P11SecretKeyFactory, m(CKM_PKCS5_PBKD2), m(CKM_SHA384_HMAC));
|
||||||
|
d(SKF, "PBEWithHmacSHA512AndAES_128",
|
||||||
|
P11SecretKeyFactory, m(CKM_PKCS5_PBKD2), m(CKM_SHA512_HMAC));
|
||||||
|
d(SKF, "PBEWithHmacSHA1AndAES_256",
|
||||||
|
P11SecretKeyFactory, m(CKM_PKCS5_PBKD2), m(CKM_SHA_1_HMAC));
|
||||||
|
d(SKF, "PBEWithHmacSHA224AndAES_256",
|
||||||
|
P11SecretKeyFactory, m(CKM_PKCS5_PBKD2), m(CKM_SHA224_HMAC));
|
||||||
|
d(SKF, "PBEWithHmacSHA256AndAES_256",
|
||||||
|
P11SecretKeyFactory, m(CKM_PKCS5_PBKD2), m(CKM_SHA256_HMAC));
|
||||||
|
d(SKF, "PBEWithHmacSHA384AndAES_256",
|
||||||
|
P11SecretKeyFactory, m(CKM_PKCS5_PBKD2), m(CKM_SHA384_HMAC));
|
||||||
|
d(SKF, "PBEWithHmacSHA512AndAES_256",
|
||||||
|
P11SecretKeyFactory, m(CKM_PKCS5_PBKD2), m(CKM_SHA512_HMAC));
|
||||||
|
/*
|
||||||
|
* PBA Secret Key Factories
|
||||||
|
*/
|
||||||
|
d(SKF, "HmacPBESHA1", P11SecretKeyFactory,
|
||||||
|
m(CKM_PBA_SHA1_WITH_SHA1_HMAC));
|
||||||
|
d(SKF, "HmacPBESHA224", P11SecretKeyFactory,
|
||||||
|
m(CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN));
|
||||||
|
d(SKF, "HmacPBESHA256", P11SecretKeyFactory,
|
||||||
|
m(CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN));
|
||||||
|
d(SKF, "HmacPBESHA384", P11SecretKeyFactory,
|
||||||
|
m(CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN));
|
||||||
|
d(SKF, "HmacPBESHA512", P11SecretKeyFactory,
|
||||||
|
m(CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN));
|
||||||
|
/*
|
||||||
|
* PBKDF2 Secret Key Factories
|
||||||
|
*/
|
||||||
|
dA(SKF, "PBKDF2WithHmacSHA1", P11SecretKeyFactory,
|
||||||
|
m(CKM_PKCS5_PBKD2), m(CKM_SHA_1_HMAC));
|
||||||
|
d(SKF, "PBKDF2WithHmacSHA224", P11SecretKeyFactory,
|
||||||
|
m(CKM_PKCS5_PBKD2), m(CKM_SHA224_HMAC));
|
||||||
|
d(SKF, "PBKDF2WithHmacSHA256", P11SecretKeyFactory,
|
||||||
|
m(CKM_PKCS5_PBKD2), m(CKM_SHA256_HMAC));
|
||||||
|
d(SKF, "PBKDF2WithHmacSHA384", P11SecretKeyFactory,
|
||||||
|
m(CKM_PKCS5_PBKD2), m(CKM_SHA384_HMAC));
|
||||||
|
d(SKF, "PBKDF2WithHmacSHA512", P11SecretKeyFactory,
|
||||||
|
m(CKM_PKCS5_PBKD2), m(CKM_SHA512_HMAC));
|
||||||
|
|
||||||
// XXX attributes for Ciphers (supported modes, padding)
|
// XXX attributes for Ciphers (supported modes, padding)
|
||||||
dA(CIP, "ARCFOUR", P11Cipher,
|
dA(CIP, "ARCFOUR", P11Cipher,
|
||||||
m(CKM_RC4));
|
m(CKM_RC4));
|
||||||
@ -779,6 +873,44 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
d(CIP, "RSA/ECB/NoPadding", P11RSACipher,
|
d(CIP, "RSA/ECB/NoPadding", P11RSACipher,
|
||||||
m(CKM_RSA_X_509));
|
m(CKM_RSA_X_509));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PBE Ciphers
|
||||||
|
*
|
||||||
|
* KeyDerivationMech and KeyDerivationPrf must be supported
|
||||||
|
* for these services to be available.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
d(CIP, "PBEWithHmacSHA1AndAES_128", P11PBECipher,
|
||||||
|
m(CKM_AES_CBC_PAD, CKM_AES_CBC),
|
||||||
|
m(CKM_PKCS5_PBKD2, CKM_SHA_1_HMAC));
|
||||||
|
d(CIP, "PBEWithHmacSHA224AndAES_128", P11PBECipher,
|
||||||
|
m(CKM_AES_CBC_PAD, CKM_AES_CBC),
|
||||||
|
m(CKM_PKCS5_PBKD2, CKM_SHA224_HMAC));
|
||||||
|
d(CIP, "PBEWithHmacSHA256AndAES_128", P11PBECipher,
|
||||||
|
m(CKM_AES_CBC_PAD, CKM_AES_CBC),
|
||||||
|
m(CKM_PKCS5_PBKD2, CKM_SHA256_HMAC));
|
||||||
|
d(CIP, "PBEWithHmacSHA384AndAES_128", P11PBECipher,
|
||||||
|
m(CKM_AES_CBC_PAD, CKM_AES_CBC),
|
||||||
|
m(CKM_PKCS5_PBKD2, CKM_SHA384_HMAC));
|
||||||
|
d(CIP, "PBEWithHmacSHA512AndAES_128", P11PBECipher,
|
||||||
|
m(CKM_AES_CBC_PAD, CKM_AES_CBC),
|
||||||
|
m(CKM_PKCS5_PBKD2, CKM_SHA512_HMAC));
|
||||||
|
d(CIP, "PBEWithHmacSHA1AndAES_256", P11PBECipher,
|
||||||
|
m(CKM_AES_CBC_PAD, CKM_AES_CBC),
|
||||||
|
m(CKM_PKCS5_PBKD2, CKM_SHA_1_HMAC));
|
||||||
|
d(CIP, "PBEWithHmacSHA224AndAES_256", P11PBECipher,
|
||||||
|
m(CKM_AES_CBC_PAD, CKM_AES_CBC),
|
||||||
|
m(CKM_PKCS5_PBKD2, CKM_SHA224_HMAC));
|
||||||
|
d(CIP, "PBEWithHmacSHA256AndAES_256", P11PBECipher,
|
||||||
|
m(CKM_AES_CBC_PAD, CKM_AES_CBC),
|
||||||
|
m(CKM_PKCS5_PBKD2, CKM_SHA256_HMAC));
|
||||||
|
d(CIP, "PBEWithHmacSHA384AndAES_256", P11PBECipher,
|
||||||
|
m(CKM_AES_CBC_PAD, CKM_AES_CBC),
|
||||||
|
m(CKM_PKCS5_PBKD2, CKM_SHA384_HMAC));
|
||||||
|
d(CIP, "PBEWithHmacSHA512AndAES_256", P11PBECipher,
|
||||||
|
m(CKM_AES_CBC_PAD, CKM_AES_CBC),
|
||||||
|
m(CKM_PKCS5_PBKD2, CKM_SHA512_HMAC));
|
||||||
|
|
||||||
d(SIG, "RawDSA", P11Signature,
|
d(SIG, "RawDSA", P11Signature,
|
||||||
List.of("NONEwithDSA"),
|
List.of("NONEwithDSA"),
|
||||||
m(CKM_DSA));
|
m(CKM_DSA));
|
||||||
@ -1169,9 +1301,21 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
if (ds == null) {
|
if (ds == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
descLoop:
|
||||||
for (Descriptor d : ds) {
|
for (Descriptor d : ds) {
|
||||||
Integer oldMech = supportedAlgs.get(d);
|
Integer oldMech = supportedAlgs.get(d);
|
||||||
if (oldMech == null) {
|
if (oldMech == null) {
|
||||||
|
if (d.requiredMechs != null) {
|
||||||
|
// Check that other mechanisms required for the
|
||||||
|
// service are supported before listing it as
|
||||||
|
// available for the first time.
|
||||||
|
for (int requiredMech : d.requiredMechs) {
|
||||||
|
if (token.getMechanismInfo(
|
||||||
|
requiredMech & 0xFFFFFFFFL) == null) {
|
||||||
|
continue descLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
supportedAlgs.put(d, integerMech);
|
supportedAlgs.put(d, integerMech);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1272,6 +1416,8 @@ public final class SunPKCS11 extends AuthProvider {
|
|||||||
} else if (algorithm.contains("/KW/") ||
|
} else if (algorithm.contains("/KW/") ||
|
||||||
algorithm.contains("/KWP/")) {
|
algorithm.contains("/KWP/")) {
|
||||||
return new P11KeyWrapCipher(token, algorithm, mechanism);
|
return new P11KeyWrapCipher(token, algorithm, mechanism);
|
||||||
|
} else if (algorithm.startsWith("PBE")) {
|
||||||
|
return new P11PBECipher(token, algorithm, mechanism);
|
||||||
} else {
|
} else {
|
||||||
return new P11Cipher(token, algorithm, mechanism);
|
return new P11Cipher(token, algorithm, mechanism);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
||||||
@ -100,9 +100,9 @@ public class CK_ECDH1_DERIVE_PARAMS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the string representation of CK_PKCS5_PBKD2_PARAMS.
|
* Returns the string representation of CK_ECDH1_DERIVE_PARAMS.
|
||||||
*
|
*
|
||||||
* @return the string representation of CK_PKCS5_PBKD2_PARAMS
|
* @return the string representation of CK_ECDH1_DERIVE_PARAMS
|
||||||
*/
|
*/
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
||||||
@ -160,6 +160,18 @@ public class CK_MECHANISM {
|
|||||||
init(mechanism, params);
|
init(mechanism, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CK_MECHANISM(long mechanism, CK_PBE_PARAMS params) {
|
||||||
|
init(mechanism, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CK_MECHANISM(long mechanism, CK_PKCS5_PBKD2_PARAMS params) {
|
||||||
|
init(mechanism, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CK_MECHANISM(long mechanism, CK_PKCS5_PBKD2_PARAMS2 params) {
|
||||||
|
init(mechanism, params);
|
||||||
|
}
|
||||||
|
|
||||||
// For PSS. the parameter may be set multiple times, use the
|
// For PSS. the parameter may be set multiple times, use the
|
||||||
// CK_MECHANISM(long) constructor and setParameter(CK_RSA_PKCS_PSS_PARAMS)
|
// CK_MECHANISM(long) constructor and setParameter(CK_RSA_PKCS_PSS_PARAMS)
|
||||||
// methods instead of creating yet another constructor
|
// methods instead of creating yet another constructor
|
||||||
@ -193,11 +205,12 @@ public class CK_MECHANISM {
|
|||||||
|
|
||||||
sb.append(Constants.INDENT);
|
sb.append(Constants.INDENT);
|
||||||
sb.append("mechanism: ");
|
sb.append("mechanism: ");
|
||||||
sb.append(mechanism);
|
sb.append(Functions.getMechanismName(mechanism));
|
||||||
sb.append(Constants.NEWLINE);
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
sb.append(Constants.INDENT);
|
sb.append(Constants.INDENT);
|
||||||
sb.append("pParameter: ");
|
sb.append("pParameter:");
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
sb.append(pParameter.toString());
|
sb.append(pParameter.toString());
|
||||||
sb.append(Constants.NEWLINE);
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
@ -50,15 +50,15 @@ package sun.security.pkcs11.wrapper;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class CK_PBE_PARAMS provides all of the necessary information required byte
|
* class CK_PBE_PARAMS provides all the necessary information required by
|
||||||
* the CKM_PBE mechanisms and the CKM_PBA_SHA1_WITH_SHA1_HMAC mechanism.<p>
|
* the CKM_PBE mechanisms and the CKM_PBA_SHA1_WITH_SHA1_HMAC mechanism.<p>
|
||||||
* <B>PKCS#11 structure:</B>
|
* <B>PKCS#11 structure:</B>
|
||||||
* <PRE>
|
* <PRE>
|
||||||
* typedef struct CK_PBE_PARAMS {
|
* typedef struct CK_PBE_PARAMS {
|
||||||
* CK_CHAR_PTR pInitVector;
|
* CK_BYTE_PTR pInitVector;
|
||||||
* CK_CHAR_PTR pPassword;
|
* CK_UTF8CHAR_PTR pPassword;
|
||||||
* CK_ULONG ulPasswordLen;
|
* CK_ULONG ulPasswordLen;
|
||||||
* CK_CHAR_PTR pSalt;
|
* CK_BYTE_PTR pSalt;
|
||||||
* CK_ULONG ulSaltLen;
|
* CK_ULONG ulSaltLen;
|
||||||
* CK_ULONG ulIteration;
|
* CK_ULONG ulIteration;
|
||||||
* } CK_PBE_PARAMS;
|
* } CK_PBE_PARAMS;
|
||||||
@ -72,15 +72,15 @@ public class CK_PBE_PARAMS {
|
|||||||
/**
|
/**
|
||||||
* <B>PKCS#11:</B>
|
* <B>PKCS#11:</B>
|
||||||
* <PRE>
|
* <PRE>
|
||||||
* CK_CHAR_PTR pInitVector;
|
* CK_BYTE_PTR pInitVector;
|
||||||
* </PRE>
|
* </PRE>
|
||||||
*/
|
*/
|
||||||
public char[] pInitVector;
|
public byte[] pInitVector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <B>PKCS#11:</B>
|
* <B>PKCS#11:</B>
|
||||||
* <PRE>
|
* <PRE>
|
||||||
* CK_CHAR_PTR pPassword;
|
* CK_UTF8CHAR_PTR pPassword;
|
||||||
* CK_ULONG ulPasswordLen;
|
* CK_ULONG ulPasswordLen;
|
||||||
* </PRE>
|
* </PRE>
|
||||||
*/
|
*/
|
||||||
@ -89,11 +89,11 @@ public class CK_PBE_PARAMS {
|
|||||||
/**
|
/**
|
||||||
* <B>PKCS#11:</B>
|
* <B>PKCS#11:</B>
|
||||||
* <PRE>
|
* <PRE>
|
||||||
* CK_CHAR_PTR pSalt
|
* CK_BYTE_PTR pSalt
|
||||||
* CK_ULONG ulSaltLen;
|
* CK_ULONG ulSaltLen;
|
||||||
* </PRE>
|
* </PRE>
|
||||||
*/
|
*/
|
||||||
public char[] pSalt;
|
public byte[] pSalt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <B>PKCS#11:</B>
|
* <B>PKCS#11:</B>
|
||||||
@ -103,6 +103,12 @@ public class CK_PBE_PARAMS {
|
|||||||
*/
|
*/
|
||||||
public long ulIteration;
|
public long ulIteration;
|
||||||
|
|
||||||
|
public CK_PBE_PARAMS(char[] pPassword, byte[] pSalt, long ulIteration) {
|
||||||
|
this.pPassword = pPassword;
|
||||||
|
this.pSalt = pSalt;
|
||||||
|
this.ulIteration = ulIteration;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the string representation of CK_PBE_PARAMS.
|
* Returns the string representation of CK_PBE_PARAMS.
|
||||||
*
|
*
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
package sun.security.pkcs11.wrapper;
|
package sun.security.pkcs11.wrapper;
|
||||||
|
|
||||||
|
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class CK_PKCS5_PBKD2_PARAMS provides the parameters to the CKM_PKCS5_PBKD2
|
* class CK_PKCS5_PBKD2_PARAMS provides the parameters to the CKM_PKCS5_PBKD2
|
||||||
@ -55,13 +55,15 @@ package sun.security.pkcs11.wrapper;
|
|||||||
* <B>PKCS#11 structure:</B>
|
* <B>PKCS#11 structure:</B>
|
||||||
* <PRE>
|
* <PRE>
|
||||||
* typedef struct CK_PKCS5_PBKD2_PARAMS {
|
* typedef struct CK_PKCS5_PBKD2_PARAMS {
|
||||||
* CK_PKCS5_PBKD2_SALT_SOURCE_TYPE saltSource;
|
* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
|
||||||
* CK_VOID_PTR pSaltSourceData;
|
* CK_VOID_PTR pSaltSourceData;
|
||||||
* CK_ULONG ulSaltSourceDataLen;
|
* CK_ULONG ulSaltSourceDataLen;
|
||||||
* CK_ULONG iterations;
|
* CK_ULONG iterations;
|
||||||
* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
|
* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
|
||||||
* CK_VOID_PTR pPrfData;
|
* CK_VOID_PTR pPrfData;
|
||||||
* CK_ULONG ulPrfDataLen;
|
* CK_ULONG ulPrfDataLen;
|
||||||
|
* CK_UTF8CHAR_PTR pPassword;
|
||||||
|
* CK_ULONG_PTR ulPasswordLen;
|
||||||
* } CK_PKCS5_PBKD2_PARAMS;
|
* } CK_PKCS5_PBKD2_PARAMS;
|
||||||
* </PRE>
|
* </PRE>
|
||||||
*
|
*
|
||||||
@ -112,6 +114,24 @@ public class CK_PKCS5_PBKD2_PARAMS {
|
|||||||
*/
|
*/
|
||||||
public byte[] pPrfData;
|
public byte[] pPrfData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_UTF8CHAR_PTR pPassword
|
||||||
|
* CK_ULONG_PTR ulPasswordLen;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public char[] pPassword;
|
||||||
|
|
||||||
|
public CK_PKCS5_PBKD2_PARAMS(char[] pPassword, byte[] pSalt,
|
||||||
|
long iterations, long prf) {
|
||||||
|
this.pPassword = pPassword;
|
||||||
|
this.pSaltSourceData = pSalt;
|
||||||
|
this.iterations = iterations;
|
||||||
|
this.prf = prf;
|
||||||
|
this.saltSource = CKZ_SALT_SPECIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the string representation of CK_PKCS5_PBKD2_PARAMS.
|
* Returns the string representation of CK_PKCS5_PBKD2_PARAMS.
|
||||||
*
|
*
|
||||||
@ -122,7 +142,7 @@ public class CK_PKCS5_PBKD2_PARAMS {
|
|||||||
|
|
||||||
sb.append(Constants.INDENT);
|
sb.append(Constants.INDENT);
|
||||||
sb.append("saltSource: ");
|
sb.append("saltSource: ");
|
||||||
sb.append(saltSource);
|
sb.append(Functions.getParamSourcesName(saltSource));
|
||||||
sb.append(Constants.NEWLINE);
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
sb.append(Constants.INDENT);
|
sb.append(Constants.INDENT);
|
||||||
@ -132,7 +152,7 @@ public class CK_PKCS5_PBKD2_PARAMS {
|
|||||||
|
|
||||||
sb.append(Constants.INDENT);
|
sb.append(Constants.INDENT);
|
||||||
sb.append("ulSaltSourceDataLen: ");
|
sb.append("ulSaltSourceDataLen: ");
|
||||||
sb.append(pSaltSourceData.length);
|
sb.append(Functions.getLength(pSaltSourceData));
|
||||||
sb.append(Constants.NEWLINE);
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
sb.append(Constants.INDENT);
|
sb.append(Constants.INDENT);
|
||||||
@ -142,7 +162,7 @@ public class CK_PKCS5_PBKD2_PARAMS {
|
|||||||
|
|
||||||
sb.append(Constants.INDENT);
|
sb.append(Constants.INDENT);
|
||||||
sb.append("prf: ");
|
sb.append("prf: ");
|
||||||
sb.append(prf);
|
sb.append(Functions.getPrfName(prf));
|
||||||
sb.append(Constants.NEWLINE);
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
sb.append(Constants.INDENT);
|
sb.append(Constants.INDENT);
|
||||||
@ -152,7 +172,7 @@ public class CK_PKCS5_PBKD2_PARAMS {
|
|||||||
|
|
||||||
sb.append(Constants.INDENT);
|
sb.append(Constants.INDENT);
|
||||||
sb.append("ulPrfDataLen: ");
|
sb.append("ulPrfDataLen: ");
|
||||||
sb.append(pPrfData.length);
|
sb.append(Functions.getLength(pPrfData));
|
||||||
//buffer.append(Constants.NEWLINE);
|
//buffer.append(Constants.NEWLINE);
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
|
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Red Hat, Inc.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.security.pkcs11.wrapper;
|
||||||
|
|
||||||
|
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class CK_PKCS5_PBKD2_PARAMS2 provides the parameters to the CKM_PKCS5_PBKD2
|
||||||
|
* mechanism.<p>
|
||||||
|
* <b>PKCS#11 structure:</b>
|
||||||
|
* <pre>
|
||||||
|
* typedef struct CK_PKCS5_PBKD2_PARAMS2 {
|
||||||
|
* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
|
||||||
|
* CK_VOID_PTR pSaltSourceData;
|
||||||
|
* CK_ULONG ulSaltSourceDataLen;
|
||||||
|
* CK_ULONG iterations;
|
||||||
|
* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
|
||||||
|
* CK_VOID_PTR pPrfData;
|
||||||
|
* CK_ULONG ulPrfDataLen;
|
||||||
|
* CK_UTF8CHAR_PTR pPassword;
|
||||||
|
* CK_ULONG ulPasswordLen;
|
||||||
|
* } CK_PKCS5_PBKD2_PARAMS2;
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CK_PKCS5_PBKD2_PARAMS2 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public long saltSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_VOID_PTR pSaltSourceData;
|
||||||
|
* CK_ULONG ulSaltSourceDataLen;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public byte[] pSaltSourceData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_ULONG iterations;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public long iterations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public long prf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_VOID_PTR pPrfData;
|
||||||
|
* CK_ULONG ulPrfDataLen;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public byte[] pPrfData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>PKCS#11:</b>
|
||||||
|
* <pre>
|
||||||
|
* CK_UTF8CHAR_PTR pPassword
|
||||||
|
* CK_ULONG ulPasswordLen;
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public char[] pPassword;
|
||||||
|
|
||||||
|
public CK_PKCS5_PBKD2_PARAMS2(char[] pPassword, byte[] pSalt,
|
||||||
|
long iterations, long prf) {
|
||||||
|
this.pPassword = pPassword;
|
||||||
|
this.pSaltSourceData = pSalt;
|
||||||
|
this.iterations = iterations;
|
||||||
|
this.prf = prf;
|
||||||
|
this.saltSource = CKZ_SALT_SPECIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation of CK_PKCS5_PBKD2_PARAMS2.
|
||||||
|
*
|
||||||
|
* @return the string representation of CK_PKCS5_PBKD2_PARAMS2
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("saltSource: ");
|
||||||
|
sb.append(Functions.getParamSourcesName(saltSource));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("pSaltSourceData: ");
|
||||||
|
sb.append(Functions.toHexString(pSaltSourceData));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("ulSaltSourceDataLen: ");
|
||||||
|
sb.append(Functions.getLength(pSaltSourceData));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("iterations: ");
|
||||||
|
sb.append(iterations);
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("prf: ");
|
||||||
|
sb.append(Functions.getPrfName(prf));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("pPrfData: ");
|
||||||
|
sb.append(Functions.toHexString(pPrfData));
|
||||||
|
sb.append(Constants.NEWLINE);
|
||||||
|
|
||||||
|
sb.append(Constants.INDENT);
|
||||||
|
sb.append("ulPrfDataLen: ");
|
||||||
|
sb.append(Functions.getLength(pPrfData));
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -94,9 +94,9 @@ public class CK_X9_42_DH1_DERIVE_PARAMS {
|
|||||||
public byte[] pPublicData;
|
public byte[] pPublicData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the string representation of CK_PKCS5_PBKD2_PARAMS.
|
* Returns the string representation of CK_X9_42_DH1_DERIVE_PARAMS.
|
||||||
*
|
*
|
||||||
* @return the string representation of CK_PKCS5_PBKD2_PARAMS
|
* @return the string representation of CK_X9_42_DH1_DERIVE_PARAMS
|
||||||
*/
|
*/
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
||||||
@ -104,6 +104,20 @@ public class Functions {
|
|||||||
private static final Map<String,Integer> mgfIds =
|
private static final Map<String,Integer> mgfIds =
|
||||||
new HashMap<String,Integer>();
|
new HashMap<String,Integer>();
|
||||||
|
|
||||||
|
// Pseudo-random functions (CKP_*)
|
||||||
|
private static final Map<Integer,String> prfNames =
|
||||||
|
new HashMap<Integer,String>();
|
||||||
|
|
||||||
|
private static final Map<String,Integer> prfIds =
|
||||||
|
new HashMap<String,Integer>();
|
||||||
|
|
||||||
|
// Salt/Encoding parameter sources (CKZ_*)
|
||||||
|
private static final Map<Integer,String> paramSourcesNames =
|
||||||
|
new HashMap<Integer,String>();
|
||||||
|
|
||||||
|
private static final Map<String,Integer> paramSourcesIds =
|
||||||
|
new HashMap<String,Integer>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For converting numbers to their hex presentation.
|
* For converting numbers to their hex presentation.
|
||||||
*/
|
*/
|
||||||
@ -208,6 +222,16 @@ public class Functions {
|
|||||||
return helpBigInteger.toString(2);
|
return helpBigInteger.toString(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a byte array length as int
|
||||||
|
*
|
||||||
|
* @param value the byte array to get its length
|
||||||
|
* @return the byte array length as int or 0 if null
|
||||||
|
*/
|
||||||
|
public static int getLength(byte[] value) {
|
||||||
|
return value == null ? 0 : value.length;
|
||||||
|
}
|
||||||
|
|
||||||
private static class Flags {
|
private static class Flags {
|
||||||
private final long[] flagIds;
|
private final long[] flagIds;
|
||||||
private final String[] flagNames;
|
private final String[] flagNames;
|
||||||
@ -483,6 +507,22 @@ public class Functions {
|
|||||||
return getId(mgfIds, name);
|
return getId(mgfIds, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getPrfName(long id) {
|
||||||
|
return getName(prfNames, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getPrfId(String name) {
|
||||||
|
return getId(prfIds, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getParamSourcesName(long id) {
|
||||||
|
return getName(paramSourcesNames, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getParamSourcesId(String name) {
|
||||||
|
return getId(paramSourcesIds, name);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the given arrays for equalitiy. This method considers both arrays as
|
* Check the given arrays for equalitiy. This method considers both arrays as
|
||||||
* equal, if both are <code>null</code> or both have the same length and
|
* equal, if both are <code>null</code> or both have the same length and
|
||||||
@ -638,6 +678,14 @@ public class Functions {
|
|||||||
addMapping(mgfNames, mgfIds, id, name);
|
addMapping(mgfNames, mgfIds, id, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addPrf(long id, String name) {
|
||||||
|
addMapping(prfNames, prfIds, id, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addParamSources(long id, String name) {
|
||||||
|
addMapping(paramSourcesNames, paramSourcesIds, id, name);
|
||||||
|
}
|
||||||
|
|
||||||
// The ordering here follows the PKCS11Constants class
|
// The ordering here follows the PKCS11Constants class
|
||||||
static {
|
static {
|
||||||
addMech(CKM_RSA_PKCS_KEY_PAIR_GEN, "CKM_RSA_PKCS_KEY_PAIR_GEN");
|
addMech(CKM_RSA_PKCS_KEY_PAIR_GEN, "CKM_RSA_PKCS_KEY_PAIR_GEN");
|
||||||
@ -1098,6 +1146,14 @@ public class Functions {
|
|||||||
addMech(CKM_VENDOR_DEFINED, "CKM_VENDOR_DEFINED");
|
addMech(CKM_VENDOR_DEFINED, "CKM_VENDOR_DEFINED");
|
||||||
|
|
||||||
addMech(CKM_NSS_TLS_PRF_GENERAL, "CKM_NSS_TLS_PRF_GENERAL");
|
addMech(CKM_NSS_TLS_PRF_GENERAL, "CKM_NSS_TLS_PRF_GENERAL");
|
||||||
|
addMech(CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN,
|
||||||
|
"CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN");
|
||||||
|
addMech(CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN,
|
||||||
|
"CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN");
|
||||||
|
addMech(CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN,
|
||||||
|
"CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN");
|
||||||
|
addMech(CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN,
|
||||||
|
"CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN");
|
||||||
|
|
||||||
addMech(PCKM_SECURERANDOM, "SecureRandom");
|
addMech(PCKM_SECURERANDOM, "SecureRandom");
|
||||||
addMech(PCKM_KEYSTORE, "KeyStore");
|
addMech(PCKM_KEYSTORE, "KeyStore");
|
||||||
@ -1352,6 +1408,20 @@ public class Functions {
|
|||||||
addMGF(CKG_MGF1_SHA3_256, "CKG_MGF1_SHA3_256");
|
addMGF(CKG_MGF1_SHA3_256, "CKG_MGF1_SHA3_256");
|
||||||
addMGF(CKG_MGF1_SHA3_384, "CKG_MGF1_SHA3_384");
|
addMGF(CKG_MGF1_SHA3_384, "CKG_MGF1_SHA3_384");
|
||||||
addMGF(CKG_MGF1_SHA3_512, "CKG_MGF1_SHA3_512");
|
addMGF(CKG_MGF1_SHA3_512, "CKG_MGF1_SHA3_512");
|
||||||
|
|
||||||
|
addPrf(CKP_PKCS5_PBKD2_HMAC_SHA1, "CKP_PKCS5_PBKD2_HMAC_SHA1");
|
||||||
|
addPrf(CKP_PKCS5_PBKD2_HMAC_GOSTR3411,
|
||||||
|
"CKP_PKCS5_PBKD2_HMAC_GOSTR3411");
|
||||||
|
addPrf(CKP_PKCS5_PBKD2_HMAC_SHA224, "CKP_PKCS5_PBKD2_HMAC_SHA224");
|
||||||
|
addPrf(CKP_PKCS5_PBKD2_HMAC_SHA256, "CKP_PKCS5_PBKD2_HMAC_SHA256");
|
||||||
|
addPrf(CKP_PKCS5_PBKD2_HMAC_SHA384, "CKP_PKCS5_PBKD2_HMAC_SHA384");
|
||||||
|
addPrf(CKP_PKCS5_PBKD2_HMAC_SHA512, "CKP_PKCS5_PBKD2_HMAC_SHA512");
|
||||||
|
addPrf(CKP_PKCS5_PBKD2_HMAC_SHA512_224,
|
||||||
|
"CKP_PKCS5_PBKD2_HMAC_SHA512_224");
|
||||||
|
addPrf(CKP_PKCS5_PBKD2_HMAC_SHA512_256,
|
||||||
|
"CKP_PKCS5_PBKD2_HMAC_SHA512_256");
|
||||||
|
|
||||||
|
addParamSources(CKZ_SALT_SPECIFIED, "CKZ_SALT_SPECIFIED");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
|
||||||
@ -999,6 +999,15 @@ public interface PKCS11Constants {
|
|||||||
|
|
||||||
// NSS private
|
// NSS private
|
||||||
public static final long CKM_NSS_TLS_PRF_GENERAL = 0x80000373L;
|
public static final long CKM_NSS_TLS_PRF_GENERAL = 0x80000373L;
|
||||||
|
// Additional PKCS #12 PBE key derivation algorithms defined in NSS v3.29
|
||||||
|
public static final long CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN
|
||||||
|
/* (CKM_NSS + 29) */ = 0xCE53436DL;
|
||||||
|
public static final long CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN
|
||||||
|
/* (CKM_NSS + 30) */ = 0xCE53436EL;
|
||||||
|
public static final long CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN
|
||||||
|
/* (CKM_NSS + 31) */ = 0xCE53436FL;
|
||||||
|
public static final long CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN
|
||||||
|
/* (CKM_NSS + 32) */ = 0xCE534370L;
|
||||||
|
|
||||||
// internal ids for our pseudo mechanisms SecureRandom and KeyStore
|
// internal ids for our pseudo mechanisms SecureRandom and KeyStore
|
||||||
public static final long PCKM_SECURERANDOM = 0x7FFFFF20L;
|
public static final long PCKM_SECURERANDOM = 0x7FFFFF20L;
|
||||||
@ -1103,7 +1112,9 @@ public interface PKCS11Constants {
|
|||||||
public static final long CKD_BLAKE2B_256_KDF = 0x00000018L;
|
public static final long CKD_BLAKE2B_256_KDF = 0x00000018L;
|
||||||
public static final long CKD_BLAKE2B_384_KDF = 0x00000019L;
|
public static final long CKD_BLAKE2B_384_KDF = 0x00000019L;
|
||||||
public static final long CKD_BLAKE2B_512_KDF = 0x0000001aL;
|
public static final long CKD_BLAKE2B_512_KDF = 0x0000001aL;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// PBKDF2 support, used in P11Util
|
||||||
public static final long CKP_PKCS5_PBKD2_HMAC_SHA1 = 0x00000001L;
|
public static final long CKP_PKCS5_PBKD2_HMAC_SHA1 = 0x00000001L;
|
||||||
public static final long CKP_PKCS5_PBKD2_HMAC_GOSTR3411 = 0x00000002L;
|
public static final long CKP_PKCS5_PBKD2_HMAC_GOSTR3411 = 0x00000002L;
|
||||||
public static final long CKP_PKCS5_PBKD2_HMAC_SHA224 = 0x00000003L;
|
public static final long CKP_PKCS5_PBKD2_HMAC_SHA224 = 0x00000003L;
|
||||||
@ -1115,6 +1126,7 @@ public interface PKCS11Constants {
|
|||||||
|
|
||||||
public static final long CKZ_SALT_SPECIFIED = 0x00000001L;
|
public static final long CKZ_SALT_SPECIFIED = 0x00000001L;
|
||||||
|
|
||||||
|
/*
|
||||||
public static final long CK_OTP_VALUE = 0x00000000L;
|
public static final long CK_OTP_VALUE = 0x00000000L;
|
||||||
public static final long CK_OTP_PIN = 0x00000001L;
|
public static final long CK_OTP_PIN = 0x00000001L;
|
||||||
public static final long CK_OTP_CHALLENGE = 0x00000002L;
|
public static final long CK_OTP_CHALLENGE = 0x00000002L;
|
||||||
@ -1153,9 +1165,9 @@ public interface PKCS11Constants {
|
|||||||
// private NSS attribute (for DSA and DH private keys)
|
// private NSS attribute (for DSA and DH private keys)
|
||||||
public static final long CKA_NETSCAPE_DB = 0xD5A0DB00L;
|
public static final long CKA_NETSCAPE_DB = 0xD5A0DB00L;
|
||||||
|
|
||||||
// base number of NSS private attributes
|
// base number of NSS private attributes. CKA_NETSCAPE_BASE is now known as
|
||||||
public static final long CKA_NETSCAPE_BASE /*0x80000000L + 0x4E534350L*/
|
// CKM_NSS = CKM_VENDOR_DEFINED | NSSCK_VENDOR_NSS = 0x80000000 | 0x4E534350
|
||||||
= 0xCE534350L;
|
public static final long CKA_NETSCAPE_BASE = 0xCE534350L;
|
||||||
|
|
||||||
// object type for NSS trust
|
// object type for NSS trust
|
||||||
public static final long CKO_NETSCAPE_TRUST = 0xCE534353L;
|
public static final long CKO_NETSCAPE_TRUST = 0xCE534353L;
|
||||||
|
@ -1512,9 +1512,11 @@ CK_VOID_PTR jMechParamToCKMechParamPtrSlow(JNIEnv *env, jobject jParam,
|
|||||||
case CKM_RSA_PKCS_OAEP:
|
case CKM_RSA_PKCS_OAEP:
|
||||||
ckpParamPtr = jRsaPkcsOaepParamToCKRsaPkcsOaepParamPtr(env, jParam, ckpLength);
|
ckpParamPtr = jRsaPkcsOaepParamToCKRsaPkcsOaepParamPtr(env, jParam, ckpLength);
|
||||||
break;
|
break;
|
||||||
case CKM_PBE_SHA1_DES3_EDE_CBC:
|
|
||||||
case CKM_PBE_SHA1_DES2_EDE_CBC:
|
|
||||||
case CKM_PBA_SHA1_WITH_SHA1_HMAC:
|
case CKM_PBA_SHA1_WITH_SHA1_HMAC:
|
||||||
|
case CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN:
|
||||||
|
case CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN:
|
||||||
|
case CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN:
|
||||||
|
case CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN:
|
||||||
ckpParamPtr = jPbeParamToCKPbeParamPtr(env, jParam, ckpLength);
|
ckpParamPtr = jPbeParamToCKPbeParamPtr(env, jParam, ckpLength);
|
||||||
break;
|
break;
|
||||||
case CKM_PKCS5_PBKD2:
|
case CKM_PKCS5_PBKD2:
|
||||||
@ -1658,13 +1660,13 @@ jPbeParamToCKPbeParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
|
|||||||
// retrieve java values
|
// retrieve java values
|
||||||
jPbeParamsClass = (*env)->FindClass(env, CLASS_PBE_PARAMS);
|
jPbeParamsClass = (*env)->FindClass(env, CLASS_PBE_PARAMS);
|
||||||
if (jPbeParamsClass == NULL) { return NULL; }
|
if (jPbeParamsClass == NULL) { return NULL; }
|
||||||
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pInitVector", "[C");
|
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pInitVector", "[B");
|
||||||
if (fieldID == NULL) { return NULL; }
|
if (fieldID == NULL) { return NULL; }
|
||||||
jInitVector = (*env)->GetObjectField(env, jParam, fieldID);
|
jInitVector = (*env)->GetObjectField(env, jParam, fieldID);
|
||||||
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pPassword", "[C");
|
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pPassword", "[C");
|
||||||
if (fieldID == NULL) { return NULL; }
|
if (fieldID == NULL) { return NULL; }
|
||||||
jPassword = (*env)->GetObjectField(env, jParam, fieldID);
|
jPassword = (*env)->GetObjectField(env, jParam, fieldID);
|
||||||
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pSalt", "[C");
|
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pSalt", "[B");
|
||||||
if (fieldID == NULL) { return NULL; }
|
if (fieldID == NULL) { return NULL; }
|
||||||
jSalt = (*env)->GetObjectField(env, jParam, fieldID);
|
jSalt = (*env)->GetObjectField(env, jParam, fieldID);
|
||||||
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "ulIteration", "J");
|
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "ulIteration", "J");
|
||||||
@ -1680,15 +1682,15 @@ jPbeParamToCKPbeParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
|
|||||||
|
|
||||||
// populate using java values
|
// populate using java values
|
||||||
ckParamPtr->ulIteration = jLongToCKULong(jIteration);
|
ckParamPtr->ulIteration = jLongToCKULong(jIteration);
|
||||||
jCharArrayToCKCharArray(env, jInitVector, &(ckParamPtr->pInitVector), &ckTemp);
|
jByteArrayToCKByteArray(env, jInitVector, &(ckParamPtr->pInitVector), &ckTemp);
|
||||||
if ((*env)->ExceptionCheck(env)) {
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
jCharArrayToCKCharArray(env, jPassword, &(ckParamPtr->pPassword), &(ckParamPtr->ulPasswordLen));
|
jCharArrayToCKUTF8CharArray(env, jPassword, &(ckParamPtr->pPassword), &(ckParamPtr->ulPasswordLen));
|
||||||
if ((*env)->ExceptionCheck(env)) {
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
jCharArrayToCKCharArray(env, jSalt, &(ckParamPtr->pSalt), &(ckParamPtr->ulSaltLen));
|
jByteArrayToCKByteArray(env, jSalt, &(ckParamPtr->pSalt), &(ckParamPtr->ulSaltLen));
|
||||||
if ((*env)->ExceptionCheck(env)) {
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
@ -1699,6 +1701,9 @@ jPbeParamToCKPbeParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
|
|||||||
return ckParamPtr;
|
return ckParamPtr;
|
||||||
cleanup:
|
cleanup:
|
||||||
free(ckParamPtr->pInitVector);
|
free(ckParamPtr->pInitVector);
|
||||||
|
if (ckParamPtr->pPassword != NULL) {
|
||||||
|
memset(ckParamPtr->pPassword, 0, ckParamPtr->ulPasswordLen);
|
||||||
|
}
|
||||||
free(ckParamPtr->pPassword);
|
free(ckParamPtr->pPassword);
|
||||||
free(ckParamPtr->pSalt);
|
free(ckParamPtr->pSalt);
|
||||||
free(ckParamPtr);
|
free(ckParamPtr);
|
||||||
@ -1767,31 +1772,60 @@ void copyBackPBEInitializationVector(JNIEnv *env, CK_MECHANISM *ckMechanism, job
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PBKD2_PARAM_SET(member, value) \
|
||||||
|
do { \
|
||||||
|
if(ckParamPtr->version == PARAMS) { \
|
||||||
|
ckParamPtr->params.v1.member = value; \
|
||||||
|
} else { \
|
||||||
|
ckParamPtr->params.v2.member = value; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define PBKD2_PARAM_ADDR(member) \
|
||||||
|
( \
|
||||||
|
(ckParamPtr->version == PARAMS) ? \
|
||||||
|
(void*) &ckParamPtr->params.v1.member : \
|
||||||
|
(void*) &ckParamPtr->params.v2.member \
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* converts the Java CK_PKCS5_PBKD2_PARAMS object to a CK_PKCS5_PBKD2_PARAMS
|
* converts a Java CK_PKCS5_PBKD2_PARAMS object to a CK_PKCS5_PBKD2_PARAMS
|
||||||
|
* pointer, or a Java CK_PKCS5_PBKD2_PARAMS2 object to a CK_PKCS5_PBKD2_PARAMS2
|
||||||
* pointer
|
* pointer
|
||||||
*
|
*
|
||||||
* @param env - used to call JNI funktions to get the Java classes and objects
|
* @param env - used to call JNI functions to get the Java classes and objects
|
||||||
* @param jParam - the Java CK_PKCS5_PBKD2_PARAMS object to convert
|
* @param jParam - the Java object to convert
|
||||||
* @param pLength - length of the allocated memory of the returned pointer
|
* @param pLength - length of the allocated memory of the returned pointer
|
||||||
* @return pointer to the new CK_PKCS5_PBKD2_PARAMS structure
|
* @return pointer to the new structure
|
||||||
*/
|
*/
|
||||||
CK_PKCS5_PBKD2_PARAMS_PTR
|
CK_VOID_PTR
|
||||||
jPkcs5Pbkd2ParamToCKPkcs5Pbkd2ParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
|
jPkcs5Pbkd2ParamToCKPkcs5Pbkd2ParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
|
||||||
{
|
{
|
||||||
CK_PKCS5_PBKD2_PARAMS_PTR ckParamPtr;
|
VersionedPbkd2ParamsPtr ckParamPtr;
|
||||||
|
ParamVersion paramVersion;
|
||||||
|
CK_ULONG_PTR pUlPasswordLen;
|
||||||
jclass jPkcs5Pbkd2ParamsClass;
|
jclass jPkcs5Pbkd2ParamsClass;
|
||||||
jfieldID fieldID;
|
jfieldID fieldID;
|
||||||
jlong jSaltSource, jIteration, jPrf;
|
jlong jSaltSource, jIteration, jPrf;
|
||||||
jobject jSaltSourceData, jPrfData;
|
jobject jSaltSourceData, jPrfData, jPassword;
|
||||||
|
|
||||||
if (pLength != NULL) {
|
if (pLength != NULL) {
|
||||||
*pLength = 0L;
|
*pLength = 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve java values
|
// retrieve java values
|
||||||
jPkcs5Pbkd2ParamsClass = (*env)->FindClass(env, CLASS_PKCS5_PBKD2_PARAMS);
|
if ((jPkcs5Pbkd2ParamsClass =
|
||||||
if (jPkcs5Pbkd2ParamsClass == NULL) { return NULL; }
|
(*env)->FindClass(env, CLASS_PKCS5_PBKD2_PARAMS)) != NULL
|
||||||
|
&& (*env)->IsInstanceOf(env, jParam, jPkcs5Pbkd2ParamsClass)) {
|
||||||
|
paramVersion = PARAMS;
|
||||||
|
} else if ((jPkcs5Pbkd2ParamsClass =
|
||||||
|
(*env)->FindClass(env, CLASS_PKCS5_PBKD2_PARAMS2)) != NULL
|
||||||
|
&& (*env)->IsInstanceOf(env, jParam, jPkcs5Pbkd2ParamsClass)) {
|
||||||
|
paramVersion = PARAMS2;
|
||||||
|
} else {
|
||||||
|
p11ThrowPKCS11RuntimeException(env, "Unknown PBKD2 mechanism parameters class.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
fieldID = (*env)->GetFieldID(env, jPkcs5Pbkd2ParamsClass, "saltSource", "J");
|
fieldID = (*env)->GetFieldID(env, jPkcs5Pbkd2ParamsClass, "saltSource", "J");
|
||||||
if (fieldID == NULL) { return NULL; }
|
if (fieldID == NULL) { return NULL; }
|
||||||
jSaltSource = (*env)->GetLongField(env, jParam, fieldID);
|
jSaltSource = (*env)->GetLongField(env, jParam, fieldID);
|
||||||
@ -1807,36 +1841,60 @@ jPkcs5Pbkd2ParamToCKPkcs5Pbkd2ParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pL
|
|||||||
fieldID = (*env)->GetFieldID(env, jPkcs5Pbkd2ParamsClass, "pPrfData", "[B");
|
fieldID = (*env)->GetFieldID(env, jPkcs5Pbkd2ParamsClass, "pPrfData", "[B");
|
||||||
if (fieldID == NULL) { return NULL; }
|
if (fieldID == NULL) { return NULL; }
|
||||||
jPrfData = (*env)->GetObjectField(env, jParam, fieldID);
|
jPrfData = (*env)->GetObjectField(env, jParam, fieldID);
|
||||||
|
fieldID = (*env)->GetFieldID(env, jPkcs5Pbkd2ParamsClass, "pPassword", "[C");
|
||||||
|
if (fieldID == NULL) { return NULL; }
|
||||||
|
jPassword = (*env)->GetObjectField(env, jParam, fieldID);
|
||||||
|
|
||||||
// allocate memory for CK_PKCS5_PBKD2_PARAMS pointer
|
// allocate memory for VersionedPbkd2Params and store the structure version
|
||||||
ckParamPtr = calloc(1, sizeof(CK_PKCS5_PBKD2_PARAMS));
|
ckParamPtr = calloc(1, sizeof(VersionedPbkd2Params));
|
||||||
if (ckParamPtr == NULL) {
|
if (ckParamPtr == NULL) {
|
||||||
p11ThrowOutOfMemoryError(env, 0);
|
p11ThrowOutOfMemoryError(env, 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
ckParamPtr->version = paramVersion;
|
||||||
|
|
||||||
// populate using java values
|
// populate using java values
|
||||||
ckParamPtr->saltSource = jLongToCKULong(jSaltSource);
|
PBKD2_PARAM_SET(saltSource, jLongToCKULong(jSaltSource));
|
||||||
jByteArrayToCKByteArray(env, jSaltSourceData, (CK_BYTE_PTR *)
|
jByteArrayToCKByteArray(env, jSaltSourceData,
|
||||||
&(ckParamPtr->pSaltSourceData), &(ckParamPtr->ulSaltSourceDataLen));
|
(CK_BYTE_PTR *) PBKD2_PARAM_ADDR(pSaltSourceData),
|
||||||
|
PBKD2_PARAM_ADDR(ulSaltSourceDataLen));
|
||||||
if ((*env)->ExceptionCheck(env)) {
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
ckParamPtr->iterations = jLongToCKULong(jIteration);
|
PBKD2_PARAM_SET(iterations, jLongToCKULong(jIteration));
|
||||||
ckParamPtr->prf = jLongToCKULong(jPrf);
|
PBKD2_PARAM_SET(prf, jLongToCKULong(jPrf));
|
||||||
jByteArrayToCKByteArray(env, jPrfData, (CK_BYTE_PTR *)
|
jByteArrayToCKByteArray(env, jPrfData,
|
||||||
&(ckParamPtr->pPrfData), &(ckParamPtr->ulPrfDataLen));
|
(CK_BYTE_PTR *) PBKD2_PARAM_ADDR(pPrfData),
|
||||||
|
PBKD2_PARAM_ADDR(ulPrfDataLen));
|
||||||
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (ckParamPtr->version == PARAMS) {
|
||||||
|
pUlPasswordLen = calloc(1, sizeof(CK_ULONG));
|
||||||
|
if (pUlPasswordLen == NULL) {
|
||||||
|
p11ThrowOutOfMemoryError(env, 0);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
ckParamPtr->params.v1.ulPasswordLen = pUlPasswordLen;
|
||||||
|
} else {
|
||||||
|
pUlPasswordLen = &ckParamPtr->params.v2.ulPasswordLen;
|
||||||
|
}
|
||||||
|
jCharArrayToCKUTF8CharArray(env, jPassword,
|
||||||
|
(CK_CHAR_PTR *) PBKD2_PARAM_ADDR(pPassword),
|
||||||
|
pUlPasswordLen);
|
||||||
if ((*env)->ExceptionCheck(env)) {
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pLength != NULL) {
|
if (pLength != NULL) {
|
||||||
*pLength = sizeof(CK_PKCS5_PBKD2_PARAMS);
|
*pLength = (ckParamPtr->version == PARAMS ?
|
||||||
|
sizeof(ckParamPtr->params.v1) :
|
||||||
|
sizeof(ckParamPtr->params.v2));
|
||||||
}
|
}
|
||||||
|
// VersionedPbkd2ParamsPtr is equivalent to CK_PKCS5_PBKD2_PARAMS[2]_PTR
|
||||||
return ckParamPtr;
|
return ckParamPtr;
|
||||||
cleanup:
|
cleanup:
|
||||||
free(ckParamPtr->pSaltSourceData);
|
FREE_VERSIONED_PBKD2_MEMBERS(ckParamPtr);
|
||||||
free(ckParamPtr->pPrfData);
|
|
||||||
free(ckParamPtr);
|
free(ckParamPtr);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -408,11 +408,32 @@ void freeCKMechanismPtr(CK_MECHANISM_PTR mechPtr) {
|
|||||||
case CKM_CAMELLIA_CTR:
|
case CKM_CAMELLIA_CTR:
|
||||||
// params do not contain pointers
|
// params do not contain pointers
|
||||||
break;
|
break;
|
||||||
|
case CKM_PKCS5_PBKD2:
|
||||||
|
// get the versioned structure from behind memory
|
||||||
|
TRACE0(((VersionedPbkd2ParamsPtr)tmp)->version == PARAMS ?
|
||||||
|
"[ CK_PKCS5_PBKD2_PARAMS ]\n" :
|
||||||
|
"[ CK_PKCS5_PBKD2_PARAMS2 ]\n");
|
||||||
|
FREE_VERSIONED_PBKD2_MEMBERS((VersionedPbkd2ParamsPtr)tmp);
|
||||||
|
break;
|
||||||
|
case CKM_PBA_SHA1_WITH_SHA1_HMAC:
|
||||||
|
case CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN:
|
||||||
|
case CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN:
|
||||||
|
case CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN:
|
||||||
|
case CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN:
|
||||||
|
TRACE0("[ CK_PBE_PARAMS ]\n");
|
||||||
|
free(((CK_PBE_PARAMS_PTR)tmp)->pInitVector);
|
||||||
|
if (((CK_PBE_PARAMS_PTR)tmp)->pPassword != NULL) {
|
||||||
|
memset(((CK_PBE_PARAMS_PTR)tmp)->pPassword, 0,
|
||||||
|
((CK_PBE_PARAMS_PTR)tmp)->ulPasswordLen);
|
||||||
|
}
|
||||||
|
free(((CK_PBE_PARAMS_PTR)tmp)->pPassword);
|
||||||
|
free(((CK_PBE_PARAMS_PTR)tmp)->pSalt);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// currently unsupported mechs by SunPKCS11 provider
|
// currently unsupported mechs by SunPKCS11 provider
|
||||||
// CKM_RSA_PKCS_OAEP, CKM_ECMQV_DERIVE,
|
// CKM_RSA_PKCS_OAEP, CKM_ECMQV_DERIVE,
|
||||||
// CKM_X9_42_*, CKM_KEA_DERIVE, CKM_RC2_*, CKM_RC5_*,
|
// CKM_X9_42_*, CKM_KEA_DERIVE, CKM_RC2_*, CKM_RC5_*,
|
||||||
// CKM_SKIPJACK_*, CKM_KEY_WRAP_SET_OAEP, CKM_PKCS5_PBKD2,
|
// CKM_SKIPJACK_*, CKM_KEY_WRAP_SET_OAEP,
|
||||||
// PBE mechs, WTLS mechs, CMS mechs,
|
// PBE mechs, WTLS mechs, CMS mechs,
|
||||||
// CKM_EXTRACT_KEY_FROM_KEY, CKM_OTP, CKM_KIP,
|
// CKM_EXTRACT_KEY_FROM_KEY, CKM_OTP, CKM_KIP,
|
||||||
// CKM_DSA_PARAMETER_GEN?, CKM_GOSTR3410_*
|
// CKM_DSA_PARAMETER_GEN?, CKM_GOSTR3410_*
|
||||||
@ -515,12 +536,11 @@ void jBooleanArrayToCKBBoolArray(JNIEnv *env, const jbooleanArray jArray, CK_BBO
|
|||||||
jboolean* jpTemp;
|
jboolean* jpTemp;
|
||||||
CK_ULONG i;
|
CK_ULONG i;
|
||||||
|
|
||||||
if(jArray == NULL) {
|
*ckpLength = jArray == NULL ? 0L : (*env)->GetArrayLength(env, jArray);
|
||||||
|
if(*ckpLength == 0L) {
|
||||||
*ckpArray = NULL_PTR;
|
*ckpArray = NULL_PTR;
|
||||||
*ckpLength = 0L;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*ckpLength = (*env)->GetArrayLength(env, jArray);
|
|
||||||
jpTemp = (jboolean*) calloc(*ckpLength, sizeof(jboolean));
|
jpTemp = (jboolean*) calloc(*ckpLength, sizeof(jboolean));
|
||||||
if (jpTemp == NULL) {
|
if (jpTemp == NULL) {
|
||||||
p11ThrowOutOfMemoryError(env, 0);
|
p11ThrowOutOfMemoryError(env, 0);
|
||||||
@ -557,12 +577,11 @@ void jByteArrayToCKByteArray(JNIEnv *env, const jbyteArray jArray, CK_BYTE_PTR *
|
|||||||
jbyte* jpTemp;
|
jbyte* jpTemp;
|
||||||
CK_ULONG i;
|
CK_ULONG i;
|
||||||
|
|
||||||
if(jArray == NULL) {
|
*ckpLength = jArray == NULL ? 0L : (*env)->GetArrayLength(env, jArray);
|
||||||
|
if(*ckpLength == 0L) {
|
||||||
*ckpArray = NULL_PTR;
|
*ckpArray = NULL_PTR;
|
||||||
*ckpLength = 0L;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*ckpLength = (*env)->GetArrayLength(env, jArray);
|
|
||||||
jpTemp = (jbyte*) calloc(*ckpLength, sizeof(jbyte));
|
jpTemp = (jbyte*) calloc(*ckpLength, sizeof(jbyte));
|
||||||
if (jpTemp == NULL) {
|
if (jpTemp == NULL) {
|
||||||
p11ThrowOutOfMemoryError(env, 0);
|
p11ThrowOutOfMemoryError(env, 0);
|
||||||
@ -604,12 +623,11 @@ void jLongArrayToCKULongArray(JNIEnv *env, const jlongArray jArray, CK_ULONG_PTR
|
|||||||
jlong* jTemp;
|
jlong* jTemp;
|
||||||
CK_ULONG i;
|
CK_ULONG i;
|
||||||
|
|
||||||
if(jArray == NULL) {
|
*ckpLength = jArray == NULL ? 0L : (*env)->GetArrayLength(env, jArray);
|
||||||
|
if(*ckpLength == 0L) {
|
||||||
*ckpArray = NULL_PTR;
|
*ckpArray = NULL_PTR;
|
||||||
*ckpLength = 0L;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*ckpLength = (*env)->GetArrayLength(env, jArray);
|
|
||||||
jTemp = (jlong*) calloc(*ckpLength, sizeof(jlong));
|
jTemp = (jlong*) calloc(*ckpLength, sizeof(jlong));
|
||||||
if (jTemp == NULL) {
|
if (jTemp == NULL) {
|
||||||
p11ThrowOutOfMemoryError(env, 0);
|
p11ThrowOutOfMemoryError(env, 0);
|
||||||
@ -646,12 +664,11 @@ void jCharArrayToCKCharArray(JNIEnv *env, const jcharArray jArray, CK_CHAR_PTR *
|
|||||||
jchar* jpTemp;
|
jchar* jpTemp;
|
||||||
CK_ULONG i;
|
CK_ULONG i;
|
||||||
|
|
||||||
if(jArray == NULL) {
|
*ckpLength = jArray == NULL ? 0L : (*env)->GetArrayLength(env, jArray);
|
||||||
|
if(*ckpLength == 0L) {
|
||||||
*ckpArray = NULL_PTR;
|
*ckpArray = NULL_PTR;
|
||||||
*ckpLength = 0L;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*ckpLength = (*env)->GetArrayLength(env, jArray);
|
|
||||||
jpTemp = (jchar*) calloc(*ckpLength, sizeof(jchar));
|
jpTemp = (jchar*) calloc(*ckpLength, sizeof(jchar));
|
||||||
if (jpTemp == NULL) {
|
if (jpTemp == NULL) {
|
||||||
p11ThrowOutOfMemoryError(env, 0);
|
p11ThrowOutOfMemoryError(env, 0);
|
||||||
@ -688,12 +705,11 @@ void jCharArrayToCKUTF8CharArray(JNIEnv *env, const jcharArray jArray, CK_UTF8CH
|
|||||||
jchar* jTemp;
|
jchar* jTemp;
|
||||||
CK_ULONG i;
|
CK_ULONG i;
|
||||||
|
|
||||||
if(jArray == NULL) {
|
*ckpLength = jArray == NULL ? 0L : (*env)->GetArrayLength(env, jArray);
|
||||||
|
if(*ckpLength == 0L) {
|
||||||
*ckpArray = NULL_PTR;
|
*ckpArray = NULL_PTR;
|
||||||
*ckpLength = 0L;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*ckpLength = (*env)->GetArrayLength(env, jArray);
|
|
||||||
jTemp = (jchar*) calloc(*ckpLength, sizeof(jchar));
|
jTemp = (jchar*) calloc(*ckpLength, sizeof(jchar));
|
||||||
if (jTemp == NULL) {
|
if (jTemp == NULL) {
|
||||||
p11ThrowOutOfMemoryError(env, 0);
|
p11ThrowOutOfMemoryError(env, 0);
|
||||||
@ -701,19 +717,20 @@ void jCharArrayToCKUTF8CharArray(JNIEnv *env, const jcharArray jArray, CK_UTF8CH
|
|||||||
}
|
}
|
||||||
(*env)->GetCharArrayRegion(env, jArray, 0, *ckpLength, jTemp);
|
(*env)->GetCharArrayRegion(env, jArray, 0, *ckpLength, jTemp);
|
||||||
if ((*env)->ExceptionCheck(env)) {
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
free(jTemp);
|
goto cleanup;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*ckpArray = (CK_UTF8CHAR_PTR) calloc(*ckpLength, sizeof(CK_UTF8CHAR));
|
*ckpArray = (CK_UTF8CHAR_PTR) calloc(*ckpLength, sizeof(CK_UTF8CHAR));
|
||||||
if (*ckpArray == NULL) {
|
if (*ckpArray == NULL) {
|
||||||
free(jTemp);
|
|
||||||
p11ThrowOutOfMemoryError(env, 0);
|
p11ThrowOutOfMemoryError(env, 0);
|
||||||
return;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
for (i=0; i<(*ckpLength); i++) {
|
for (i=0; i<(*ckpLength); i++) {
|
||||||
(*ckpArray)[i] = jCharToCKUTF8Char(jTemp[i]);
|
(*ckpArray)[i] = jCharToCKUTF8Char(jTemp[i]);
|
||||||
}
|
}
|
||||||
|
cleanup:
|
||||||
|
// Clean possible temporary copies of passwords.
|
||||||
|
memset(jTemp, 0, *ckpLength * sizeof(jchar));
|
||||||
free(jTemp);
|
free(jTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,15 +67,22 @@
|
|||||||
|
|
||||||
/* extra PKCS#11 constants not in the standard include files */
|
/* extra PKCS#11 constants not in the standard include files */
|
||||||
|
|
||||||
|
/* CKA_NETSCAPE_BASE is now known as CKM_NSS (CKM_VENDOR_DEFINED | NSSCK_VENDOR_NSS) */
|
||||||
#define CKA_NETSCAPE_BASE (0x80000000 + 0x4E534350)
|
#define CKA_NETSCAPE_BASE (0x80000000 + 0x4E534350)
|
||||||
#define CKA_NETSCAPE_TRUST_BASE (CKA_NETSCAPE_BASE + 0x2000)
|
#define CKA_NETSCAPE_TRUST_BASE (CKA_NETSCAPE_BASE + 0x2000)
|
||||||
#define CKA_NETSCAPE_TRUST_SERVER_AUTH (CKA_NETSCAPE_TRUST_BASE + 8)
|
#define CKA_NETSCAPE_TRUST_SERVER_AUTH (CKA_NETSCAPE_TRUST_BASE + 8)
|
||||||
#define CKA_NETSCAPE_TRUST_CLIENT_AUTH (CKA_NETSCAPE_TRUST_BASE + 9)
|
#define CKA_NETSCAPE_TRUST_CLIENT_AUTH (CKA_NETSCAPE_TRUST_BASE + 9)
|
||||||
#define CKA_NETSCAPE_TRUST_CODE_SIGNING (CKA_NETSCAPE_TRUST_BASE + 10)
|
#define CKA_NETSCAPE_TRUST_CODE_SIGNING (CKA_NETSCAPE_TRUST_BASE + 10)
|
||||||
#define CKA_NETSCAPE_TRUST_EMAIL_PROTECTION (CKA_NETSCAPE_TRUST_BASE + 11)
|
#define CKA_NETSCAPE_TRUST_EMAIL_PROTECTION (CKA_NETSCAPE_TRUST_BASE + 11)
|
||||||
#define CKA_NETSCAPE_DB 0xD5A0DB00
|
#define CKA_NETSCAPE_DB 0xD5A0DB00
|
||||||
#define CKM_NSS_TLS_PRF_GENERAL 0x80000373
|
#define CKM_NSS_TLS_PRF_GENERAL 0x80000373
|
||||||
|
|
||||||
|
/* additional PKCS #12 PBE key derivation algorithms defined in NSS v3.29 */
|
||||||
|
#define CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN (CKA_NETSCAPE_BASE + 29)
|
||||||
|
#define CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN (CKA_NETSCAPE_BASE + 30)
|
||||||
|
#define CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN (CKA_NETSCAPE_BASE + 31)
|
||||||
|
#define CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN (CKA_NETSCAPE_BASE + 32)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Define the PKCS#11 functions to include and exclude. Reduces the size
|
Define the PKCS#11 functions to include and exclude. Reduces the size
|
||||||
@ -271,6 +278,7 @@ void printDebug(const char *format, ...);
|
|||||||
#define CLASS_PBE_PARAMS "sun/security/pkcs11/wrapper/CK_PBE_PARAMS"
|
#define CLASS_PBE_PARAMS "sun/security/pkcs11/wrapper/CK_PBE_PARAMS"
|
||||||
#define PBE_INIT_VECTOR_SIZE 8
|
#define PBE_INIT_VECTOR_SIZE 8
|
||||||
#define CLASS_PKCS5_PBKD2_PARAMS "sun/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS"
|
#define CLASS_PKCS5_PBKD2_PARAMS "sun/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS"
|
||||||
|
#define CLASS_PKCS5_PBKD2_PARAMS2 "sun/security/pkcs11/wrapper/CK_PKCS5_PBKD2_PARAMS2"
|
||||||
#define CLASS_EXTRACT_PARAMS "sun/security/pkcs11/wrapper/CK_EXTRACT_PARAMS"
|
#define CLASS_EXTRACT_PARAMS "sun/security/pkcs11/wrapper/CK_EXTRACT_PARAMS"
|
||||||
|
|
||||||
#define CLASS_ECDH1_DERIVE_PARAMS "sun/security/pkcs11/wrapper/CK_ECDH1_DERIVE_PARAMS"
|
#define CLASS_ECDH1_DERIVE_PARAMS "sun/security/pkcs11/wrapper/CK_ECDH1_DERIVE_PARAMS"
|
||||||
@ -383,7 +391,7 @@ CK_VOID_PTR jMechParamToCKMechParamPtr(JNIEnv *env, jobject jParam, CK_MECHANISM
|
|||||||
CK_RSA_PKCS_OAEP_PARAMS_PTR jRsaPkcsOaepParamToCKRsaPkcsOaepParamPtr(JNIEnv *env,
|
CK_RSA_PKCS_OAEP_PARAMS_PTR jRsaPkcsOaepParamToCKRsaPkcsOaepParamPtr(JNIEnv *env,
|
||||||
jobject jParam, CK_ULONG* pLength);
|
jobject jParam, CK_ULONG* pLength);
|
||||||
CK_PBE_PARAMS_PTR jPbeParamToCKPbeParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_PBE_PARAMS_PTR jPbeParamToCKPbeParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
CK_PKCS5_PBKD2_PARAMS_PTR jPkcs5Pbkd2ParamToCKPkcs5Pbkd2ParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_VOID_PTR jPkcs5Pbkd2ParamToCKPkcs5Pbkd2ParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR jSsl3MasterKeyDeriveParamToCKSsl3MasterKeyDeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR jSsl3MasterKeyDeriveParamToCKSsl3MasterKeyDeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
CK_SSL3_KEY_MAT_PARAMS_PTR jSsl3KeyMatParamToCKSsl3KeyMatParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_SSL3_KEY_MAT_PARAMS_PTR jSsl3KeyMatParamToCKSsl3KeyMatParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
CK_KEY_DERIVATION_STRING_DATA jKeyDerivationStringDataToCKKeyDerivationStringData(JNIEnv *env, jobject jParam);
|
CK_KEY_DERIVATION_STRING_DATA jKeyDerivationStringDataToCKKeyDerivationStringData(JNIEnv *env, jobject jParam);
|
||||||
@ -393,6 +401,41 @@ CK_ECDH2_DERIVE_PARAMS_PTR jEcdh2DeriveParamToCKEcdh2DeriveParamPtr(JNIEnv *env,
|
|||||||
CK_X9_42_DH1_DERIVE_PARAMS_PTR jX942Dh1DeriveParamToCKX942Dh1DeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_X9_42_DH1_DERIVE_PARAMS_PTR jX942Dh1DeriveParamToCKX942Dh1DeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
CK_X9_42_DH2_DERIVE_PARAMS_PTR jX942Dh2DeriveParamToCKX942Dh2DeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
CK_X9_42_DH2_DERIVE_PARAMS_PTR jX942Dh2DeriveParamToCKX942Dh2DeriveParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||||
|
|
||||||
|
/* handling of CK_PKCS5_PBKD2_PARAMS and CK_PKCS5_PBKD2_PARAMS2 */
|
||||||
|
typedef enum {PARAMS=0, PARAMS2} ParamVersion;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
CK_PKCS5_PBKD2_PARAMS v1;
|
||||||
|
CK_PKCS5_PBKD2_PARAMS2 v2;
|
||||||
|
} params;
|
||||||
|
ParamVersion version;
|
||||||
|
} VersionedPbkd2Params, *VersionedPbkd2ParamsPtr;
|
||||||
|
|
||||||
|
#define FREE_VERSIONED_PBKD2_MEMBERS(verParamsPtr) \
|
||||||
|
do { \
|
||||||
|
if ((verParamsPtr)->version == PARAMS) { \
|
||||||
|
free((verParamsPtr)->params.v1.pSaltSourceData); \
|
||||||
|
free((verParamsPtr)->params.v1.pPrfData); \
|
||||||
|
if ((verParamsPtr)->params.v1.pPassword != NULL && \
|
||||||
|
(verParamsPtr)->params.v1.ulPasswordLen \
|
||||||
|
!= NULL) { \
|
||||||
|
memset((verParamsPtr)->params.v1.pPassword, 0, \
|
||||||
|
*((verParamsPtr)->params.v1.ulPasswordLen)); \
|
||||||
|
} \
|
||||||
|
free((verParamsPtr)->params.v1.pPassword); \
|
||||||
|
free((verParamsPtr)->params.v1.ulPasswordLen); \
|
||||||
|
} else { \
|
||||||
|
free((verParamsPtr)->params.v2.pSaltSourceData); \
|
||||||
|
free((verParamsPtr)->params.v2.pPrfData); \
|
||||||
|
if ((verParamsPtr)->params.v2.pPassword != NULL) { \
|
||||||
|
memset((verParamsPtr)->params.v2.pPassword, 0, \
|
||||||
|
(verParamsPtr)->params.v2.ulPasswordLen); \
|
||||||
|
} \
|
||||||
|
free((verParamsPtr)->params.v2.pPassword); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
/* functions to copy the returned values inside CK-mechanism back to Java object */
|
/* functions to copy the returned values inside CK-mechanism back to Java object */
|
||||||
|
|
||||||
void copyBackPBEInitializationVector(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMechanism);
|
void copyBackPBEInitializationVector(JNIEnv *env, CK_MECHANISM *ckMechanism, jobject jMechanism);
|
||||||
|
259
test/jdk/sun/security/pkcs11/Cipher/PBECipher.java
Normal file
259
test/jdk/sun/security/pkcs11/Cipher/PBECipher.java
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.AlgorithmParameters;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.Provider;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.Security;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
import javax.crypto.interfaces.PBEKey;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
import javax.crypto.spec.PBEParameterSpec;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8301553
|
||||||
|
* @summary test password based encryption on SunPKCS11's Cipher service
|
||||||
|
* @library /test/lib ..
|
||||||
|
* @run main/othervm/timeout=30 PBECipher
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class PBECipher extends PKCS11Test {
|
||||||
|
private static final char[] password = "123456".toCharArray();
|
||||||
|
private static final byte[] salt = "abcdefgh".getBytes(
|
||||||
|
StandardCharsets.UTF_8);
|
||||||
|
private static final int iterations = 1000;
|
||||||
|
private static final int AES_BLOCK_SIZE = 16;
|
||||||
|
private static final PBEParameterSpec pbeSpec = new PBEParameterSpec(salt,
|
||||||
|
iterations, new IvParameterSpec(new byte[AES_BLOCK_SIZE]));
|
||||||
|
private static final String plainText = "This is a known plain text!";
|
||||||
|
private static final String sep = "======================================" +
|
||||||
|
"===================================";
|
||||||
|
|
||||||
|
private enum Configuration {
|
||||||
|
// Pass salt and iterations to a Cipher through a PBEParameterSpec.
|
||||||
|
PBEParameterSpec,
|
||||||
|
|
||||||
|
// Derive a key using SunPKCS11's SecretKeyFactory (wrapping password,
|
||||||
|
// salt and iterations in a PBEKeySpec), and pass it to a Cipher.
|
||||||
|
SecretKeyFactoryDerivedKey,
|
||||||
|
|
||||||
|
// Pass salt and iterations to a Cipher through an AlgorithmParameters.
|
||||||
|
AlgorithmParameters,
|
||||||
|
|
||||||
|
// Pass password, salt and iterations and iterations to
|
||||||
|
// a Cipher through an anonymous class implementing the
|
||||||
|
// javax.crypto.interfaces.PBEKey interface.
|
||||||
|
AnonymousPBEKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Provider sunJCE = Security.getProvider("SunJCE");
|
||||||
|
|
||||||
|
private record AssertionData(String pbeCipherAlgo, String cipherAlgo,
|
||||||
|
BigInteger expectedCiphertext) {}
|
||||||
|
|
||||||
|
private static AssertionData cipherAssertionData(String pbeCipherAlgo,
|
||||||
|
String cipherAlgo, String staticExpectedCiphertextString) {
|
||||||
|
BigInteger staticExpectedCiphertext =
|
||||||
|
new BigInteger(staticExpectedCiphertextString, 16);
|
||||||
|
BigInteger expectedCiphertext = null;
|
||||||
|
if (sunJCE != null) {
|
||||||
|
try {
|
||||||
|
expectedCiphertext = computeCipherText(sunJCE, pbeCipherAlgo,
|
||||||
|
pbeCipherAlgo, Configuration.PBEParameterSpec);
|
||||||
|
checkAssertionValues(expectedCiphertext,
|
||||||
|
staticExpectedCiphertext);
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
// Move to staticExpectedCiphertext as it's unlikely
|
||||||
|
// that any of the algorithms are available.
|
||||||
|
sunJCE = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expectedCiphertext == null) {
|
||||||
|
expectedCiphertext = staticExpectedCiphertext;
|
||||||
|
}
|
||||||
|
return new AssertionData(pbeCipherAlgo, cipherAlgo, expectedCiphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkAssertionValues(BigInteger expectedValue,
|
||||||
|
BigInteger staticExpectedValue) {
|
||||||
|
if (!expectedValue.equals(staticExpectedValue)) {
|
||||||
|
printHex("SunJCE value", expectedValue);
|
||||||
|
printHex("Static value", staticExpectedValue);
|
||||||
|
throw new Error("Static and SunJCE values do not match.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generated with SunJCE.
|
||||||
|
private static final AssertionData[] assertionData = new AssertionData[]{
|
||||||
|
cipherAssertionData("PBEWithHmacSHA1AndAES_128",
|
||||||
|
"AES/CBC/PKCS5Padding", "ba1c9614d550912925d99e0bc8969032" +
|
||||||
|
"7ac6258b72117dcf750c19ee6ca73dd4"),
|
||||||
|
cipherAssertionData("PBEWithHmacSHA224AndAES_128",
|
||||||
|
"AES/CBC/PKCS5Padding", "41960c43ca99cf2184511aaf2f0508a9" +
|
||||||
|
"7da3762ee6c2b7e2027c8076811f2e52"),
|
||||||
|
cipherAssertionData("PBEWithHmacSHA256AndAES_128",
|
||||||
|
"AES/CBC/PKCS5Padding", "6bb6a3dc3834e81e5ca6b5e70073ff46" +
|
||||||
|
"903b188940a269ed26db2ffe622b8e16"),
|
||||||
|
cipherAssertionData("PBEWithHmacSHA384AndAES_128",
|
||||||
|
"AES/CBC/PKCS5Padding", "22aabf7a6a059415dc4ca7d985f3de06" +
|
||||||
|
"8f8300ca48d8de585d802670f4c1d9bd"),
|
||||||
|
cipherAssertionData("PBEWithHmacSHA512AndAES_128",
|
||||||
|
"AES/CBC/PKCS5Padding", "b523e7c462a0b7fd74e492b3a6550464" +
|
||||||
|
"ceebe81f08649ae163673afc242ad8a2"),
|
||||||
|
cipherAssertionData("PBEWithHmacSHA1AndAES_256",
|
||||||
|
"AES/CBC/PKCS5Padding", "1e7c25e166afae069cec68ef9affca61" +
|
||||||
|
"aea02ab1c3dc7471cb767ed7d6e37af0"),
|
||||||
|
cipherAssertionData("PBEWithHmacSHA224AndAES_256",
|
||||||
|
"AES/CBC/PKCS5Padding", "6701f1cc75b6494ec4bd27158aa2c15d" +
|
||||||
|
"7d10bc2f1fbb7d92d8277c7edfd1dd57"),
|
||||||
|
cipherAssertionData("PBEWithHmacSHA256AndAES_256",
|
||||||
|
"AES/CBC/PKCS5Padding", "f82eb2fc016505baeb23ecdf85163933" +
|
||||||
|
"5e8d6d48b48631185641febb75898a1d"),
|
||||||
|
cipherAssertionData("PBEWithHmacSHA384AndAES_256",
|
||||||
|
"AES/CBC/PKCS5Padding", "ee9528022e58cdd9be80cd88443e03b3" +
|
||||||
|
"de13376cf97c53d946d5c5dfc88097be"),
|
||||||
|
cipherAssertionData("PBEWithHmacSHA512AndAES_256",
|
||||||
|
"AES/CBC/PKCS5Padding", "18f472912ffaa31824e20a5486324e14" +
|
||||||
|
"0225e20cb158762e8647b1216fe0ab7e"),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final class NoRandom extends SecureRandom {
|
||||||
|
@Override
|
||||||
|
public void nextBytes(byte[] bytes) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void main(Provider sunPKCS11) throws Exception {
|
||||||
|
System.out.println("SunPKCS11: " + sunPKCS11.getName());
|
||||||
|
for (Configuration conf : Configuration.values()) {
|
||||||
|
for (AssertionData data : assertionData) {
|
||||||
|
testWith(sunPKCS11, data, true, conf);
|
||||||
|
if (conf != Configuration.PBEParameterSpec &&
|
||||||
|
conf != Configuration.AlgorithmParameters) {
|
||||||
|
testWith(sunPKCS11, data, false, conf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("TEST PASS - OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testWith(Provider sunPKCS11, AssertionData data,
|
||||||
|
boolean testPBEService, Configuration conf) throws Exception {
|
||||||
|
String svcAlgo = testPBEService ? data.pbeCipherAlgo : data.cipherAlgo;
|
||||||
|
System.out.println(sep + System.lineSeparator() + svcAlgo
|
||||||
|
+ " (with " + conf.name() + ")");
|
||||||
|
|
||||||
|
BigInteger cipherText = computeCipherText(sunPKCS11, svcAlgo,
|
||||||
|
data.pbeCipherAlgo, conf);
|
||||||
|
printHex("Cipher Text", cipherText);
|
||||||
|
|
||||||
|
if (!cipherText.equals(data.expectedCiphertext)) {
|
||||||
|
printHex("Expected Cipher Text", data.expectedCiphertext);
|
||||||
|
throw new Exception("Expected Cipher Text did not match");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigInteger computeCipherText(Provider p, String svcAlgo,
|
||||||
|
String keyAlgo, Configuration conf)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
Cipher cipher = Cipher.getInstance(svcAlgo, p);
|
||||||
|
switch (conf) {
|
||||||
|
case PBEParameterSpec, AlgorithmParameters -> {
|
||||||
|
SecretKey key = getPasswordOnlyPBEKey();
|
||||||
|
switch (conf) {
|
||||||
|
case PBEParameterSpec -> {
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, key, pbeSpec);
|
||||||
|
}
|
||||||
|
case AlgorithmParameters -> {
|
||||||
|
AlgorithmParameters algoParams =
|
||||||
|
AlgorithmParameters.getInstance("PBES2");
|
||||||
|
algoParams.init(pbeSpec);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, key, algoParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case SecretKeyFactoryDerivedKey -> {
|
||||||
|
SecretKey key = getDerivedSecretKey(p, keyAlgo);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, key,
|
||||||
|
pbeSpec.getParameterSpec());
|
||||||
|
}
|
||||||
|
case AnonymousPBEKey -> {
|
||||||
|
SecretKey key = getAnonymousPBEKey(keyAlgo,
|
||||||
|
svcAlgo.equals(keyAlgo));
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, key, new NoRandom());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new BigInteger(1, cipher.doFinal(
|
||||||
|
plainText.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey getPasswordOnlyPBEKey()
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
return SecretKeyFactory.getInstance("PBE")
|
||||||
|
.generateSecret(new PBEKeySpec(password));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey getDerivedSecretKey(Provider sunPKCS11,
|
||||||
|
String algorithm) throws GeneralSecurityException {
|
||||||
|
return SecretKeyFactory.getInstance(algorithm, sunPKCS11)
|
||||||
|
.generateSecret(new PBEKeySpec(password, salt, iterations));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey getAnonymousPBEKey(String algorithm,
|
||||||
|
boolean isPbeCipherSvc) {
|
||||||
|
return new PBEKey() {
|
||||||
|
public byte[] getSalt() { return salt.clone(); }
|
||||||
|
public int getIterationCount() { return iterations; }
|
||||||
|
public String getAlgorithm() { return algorithm; }
|
||||||
|
public String getFormat() { return "RAW"; }
|
||||||
|
public char[] getPassword() { return password.clone(); }
|
||||||
|
public byte[] getEncoded() {
|
||||||
|
byte[] encodedKey = null;
|
||||||
|
if (isPbeCipherSvc) {
|
||||||
|
encodedKey = new byte[password.length];
|
||||||
|
for (int i = 0; i < password.length; i++) {
|
||||||
|
encodedKey[i] = (byte) (password[i] & 0x7f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return encodedKey;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printHex(String title, BigInteger b) {
|
||||||
|
String repr = (b == null) ? "buffer is null" : b.toString(16);
|
||||||
|
System.out.println(title + ": " + repr + System.lineSeparator());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
main(new PBECipher());
|
||||||
|
}
|
||||||
|
}
|
136
test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java
Normal file
136
test/jdk/sun/security/pkcs11/KeyStore/ImportKeyToP12.java
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.Provider;
|
||||||
|
import java.security.Security;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8301553
|
||||||
|
* @summary test SunPKCS11's password based privacy and integrity
|
||||||
|
* applied to PKCS #12 keystores
|
||||||
|
* @library /test/lib ..
|
||||||
|
* @modules java.base/sun.security.util
|
||||||
|
* @run main/othervm/timeout=30 ImportKeyToP12
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class ImportKeyToP12 extends PKCS11Test {
|
||||||
|
private static final String alias = "alias";
|
||||||
|
private static final char[] password = "123456".toCharArray();
|
||||||
|
private static final Key key = new SecretKeySpec(new byte[] {
|
||||||
|
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
|
||||||
|
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf }, "AES");
|
||||||
|
private static final String[] pbeCipherAlgs = new String[] {
|
||||||
|
"PBEWithHmacSHA1AndAES_128", "PBEWithHmacSHA224AndAES_128",
|
||||||
|
"PBEWithHmacSHA256AndAES_128", "PBEWithHmacSHA384AndAES_128",
|
||||||
|
"PBEWithHmacSHA512AndAES_128", "PBEWithHmacSHA1AndAES_256",
|
||||||
|
"PBEWithHmacSHA224AndAES_256", "PBEWithHmacSHA256AndAES_256",
|
||||||
|
"PBEWithHmacSHA384AndAES_256", "PBEWithHmacSHA512AndAES_256"
|
||||||
|
};
|
||||||
|
private static final String[] pbeMacAlgs = new String[] {
|
||||||
|
"HmacPBESHA1", "HmacPBESHA224", "HmacPBESHA256",
|
||||||
|
"HmacPBESHA384", "HmacPBESHA512"
|
||||||
|
};
|
||||||
|
private static final KeyStore p12;
|
||||||
|
private static final String sep = "======================================" +
|
||||||
|
"===================================";
|
||||||
|
|
||||||
|
static {
|
||||||
|
KeyStore tP12 = null;
|
||||||
|
try {
|
||||||
|
tP12 = KeyStore.getInstance("PKCS12");
|
||||||
|
} catch (KeyStoreException e) {}
|
||||||
|
p12 = tP12;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void main(Provider sunPKCS11) throws Exception {
|
||||||
|
System.out.println("SunPKCS11: " + sunPKCS11.getName());
|
||||||
|
// Test all privacy PBE algorithms with an integrity algorithm fixed
|
||||||
|
for (String pbeCipherAlg : pbeCipherAlgs) {
|
||||||
|
// Make sure that SunPKCS11 implements the Cipher algorithm
|
||||||
|
Cipher.getInstance(pbeCipherAlg, sunPKCS11);
|
||||||
|
testWith(sunPKCS11, pbeCipherAlg, pbeMacAlgs[0]);
|
||||||
|
}
|
||||||
|
// Test all integrity PBE algorithms with a privacy algorithm fixed
|
||||||
|
for (String pbeMacAlg : pbeMacAlgs) {
|
||||||
|
// Make sure that SunPKCS11 implements the Mac algorithm
|
||||||
|
Mac.getInstance(pbeMacAlg, sunPKCS11);
|
||||||
|
testWith(sunPKCS11, pbeCipherAlgs[0], pbeMacAlg);
|
||||||
|
}
|
||||||
|
System.out.println("TEST PASS - OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Consistency test: 1) store a secret key in a PKCS #12 keystore using
|
||||||
|
* PBE algorithms from SunPKCS11 and, 2) read the secret key from the
|
||||||
|
* PKCS #12 keystore using PBE algorithms from other security providers
|
||||||
|
* such as SunJCE.
|
||||||
|
*/
|
||||||
|
private void testWith(Provider sunPKCS11, String pbeCipherAlg,
|
||||||
|
String pbeMacAlg) throws Exception {
|
||||||
|
System.out.println(sep + System.lineSeparator() +
|
||||||
|
"Cipher PBE: " + pbeCipherAlg + System.lineSeparator() +
|
||||||
|
"Mac PBE: " + pbeMacAlg);
|
||||||
|
|
||||||
|
System.setProperty("keystore.pkcs12.macAlgorithm", pbeMacAlg);
|
||||||
|
System.setProperty("keystore.pkcs12.keyProtectionAlgorithm",
|
||||||
|
pbeCipherAlg);
|
||||||
|
|
||||||
|
// Create an empty PKCS #12 keystore
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
p12.load(null, password);
|
||||||
|
|
||||||
|
// Use PBE privacy and integrity algorithms from SunPKCS11 to store
|
||||||
|
// the secret key
|
||||||
|
Security.insertProviderAt(sunPKCS11, 1);
|
||||||
|
p12.setKeyEntry(alias, key, password, null);
|
||||||
|
p12.store(baos, password);
|
||||||
|
|
||||||
|
// Use PBE privacy and integrity algorithms from other security
|
||||||
|
// providers, such as SunJCE, to read the secret key
|
||||||
|
Security.removeProvider(sunPKCS11.getName());
|
||||||
|
p12.load(new ByteArrayInputStream(baos.toByteArray()), password);
|
||||||
|
Key k = p12.getKey(alias, password);
|
||||||
|
|
||||||
|
if (!MessageDigest.isEqual(key.getEncoded(), k.getEncoded())) {
|
||||||
|
throw new Exception("Keys differ. Consistency check failed.");
|
||||||
|
}
|
||||||
|
System.out.println("Secret key import successful"
|
||||||
|
+ System.lineSeparator() + sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
main(new ImportKeyToP12());
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -37,12 +37,10 @@ import java.security.InvalidKeyException;
|
|||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
import javax.crypto.KeyGenerator;
|
import javax.crypto.KeyGenerator;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
|
|
||||||
public class MacSameTest extends PKCS11Test {
|
public class MacSameTest extends PKCS11Test {
|
||||||
|
|
||||||
@ -69,14 +67,10 @@ public class MacSameTest extends PKCS11Test {
|
|||||||
public void main(Provider p) {
|
public void main(Provider p) {
|
||||||
List<String> algorithms = getSupportedAlgorithms("Mac", "Hmac", p);
|
List<String> algorithms = getSupportedAlgorithms("Mac", "Hmac", p);
|
||||||
boolean success = true;
|
boolean success = true;
|
||||||
SecureRandom srdm = new SecureRandom();
|
|
||||||
|
|
||||||
for (String alg : algorithms) {
|
for (String alg : algorithms) {
|
||||||
// first try w/ java secret key object
|
// first try w/ java secret key object
|
||||||
byte[] keyVal = new byte[KEY_SIZE];
|
SecretKey skey = generateKey(alg, KEY_SIZE);
|
||||||
srdm.nextBytes(keyVal);
|
|
||||||
SecretKey skey = new SecretKeySpec(keyVal, alg);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
doTest(alg, skey, p);
|
doTest(alg, skey, p);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -86,6 +80,7 @@ public class MacSameTest extends PKCS11Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// No KeyGenerator support for PBE
|
||||||
KeyGenerator kg = KeyGenerator.getInstance(alg, p);
|
KeyGenerator kg = KeyGenerator.getInstance(alg, p);
|
||||||
kg.init(KEY_SIZE);
|
kg.init(KEY_SIZE);
|
||||||
skey = kg.generateKey();
|
skey = kg.generateKey();
|
||||||
|
204
test/jdk/sun/security/pkcs11/Mac/PBAMac.java
Normal file
204
test/jdk/sun/security/pkcs11/Mac/PBAMac.java
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.Provider;
|
||||||
|
import java.security.Security;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
import javax.crypto.interfaces.PBEKey;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
import javax.crypto.spec.PBEParameterSpec;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8301553
|
||||||
|
* @summary test password based authentication on SunPKCS11's Mac service
|
||||||
|
* @library /test/lib ..
|
||||||
|
* @run main/othervm/timeout=30 PBAMac
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class PBAMac extends PKCS11Test {
|
||||||
|
private static final char[] password = "123456".toCharArray();
|
||||||
|
private static final byte[] salt = "abcdefgh".getBytes(
|
||||||
|
StandardCharsets.UTF_8);
|
||||||
|
private static final int iterations = 1000;
|
||||||
|
private static final String plainText = "This is a known plain text!";
|
||||||
|
private static final String sep = "======================================" +
|
||||||
|
"===================================";
|
||||||
|
|
||||||
|
private enum Configuration {
|
||||||
|
// Pass salt and iterations to a Mac through a PBEParameterSpec.
|
||||||
|
PBEParameterSpec,
|
||||||
|
|
||||||
|
// Derive a key using SunPKCS11's SecretKeyFactory (wrapping password,
|
||||||
|
// salt and iterations in a PBEKeySpec), and pass it to a Mac.
|
||||||
|
SecretKeyFactoryDerivedKey,
|
||||||
|
|
||||||
|
// Pass password, salt and iterations and iterations to
|
||||||
|
// a Mac through an anonymous class implementing the
|
||||||
|
// javax.crypto.interfaces.PBEKey interface.
|
||||||
|
AnonymousPBEKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Provider sunJCE = Security.getProvider("SunJCE");
|
||||||
|
|
||||||
|
private record AssertionData(String pbeHmacAlgo, String hmacAlgo,
|
||||||
|
BigInteger expectedMac) {}
|
||||||
|
|
||||||
|
private static AssertionData macAssertionData(String pbeHmacAlgo,
|
||||||
|
String hmacAlgo, String staticExpectedMacString) {
|
||||||
|
BigInteger staticExpectedMac = new BigInteger(staticExpectedMacString,
|
||||||
|
16);
|
||||||
|
BigInteger expectedMac = null;
|
||||||
|
if (sunJCE != null) {
|
||||||
|
try {
|
||||||
|
expectedMac = computeMac(sunJCE, pbeHmacAlgo,
|
||||||
|
pbeHmacAlgo, Configuration.PBEParameterSpec);
|
||||||
|
checkAssertionValues(expectedMac, staticExpectedMac);
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
// Move to staticExpectedMac as it's unlikely
|
||||||
|
// that any of the algorithms are available.
|
||||||
|
sunJCE = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expectedMac == null) {
|
||||||
|
expectedMac = staticExpectedMac;
|
||||||
|
}
|
||||||
|
return new AssertionData(pbeHmacAlgo, hmacAlgo, expectedMac);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkAssertionValues(BigInteger expectedValue,
|
||||||
|
BigInteger staticExpectedValue) {
|
||||||
|
if (!expectedValue.equals(staticExpectedValue)) {
|
||||||
|
printHex("SunJCE value", expectedValue);
|
||||||
|
printHex("Static value", staticExpectedValue);
|
||||||
|
throw new Error("Static and SunJCE values do not match.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generated with SunJCE.
|
||||||
|
private static final AssertionData[] assertionData = new AssertionData[]{
|
||||||
|
macAssertionData("HmacPBESHA1", "HmacSHA1",
|
||||||
|
"707606929395e4297adc63d520ac7d22f3f5fa66"),
|
||||||
|
macAssertionData("HmacPBESHA224", "HmacSHA224",
|
||||||
|
"4ffb5ad4974a7a9fca5a36ebe3e34dd443c07fb68c392f8b611657e6"),
|
||||||
|
macAssertionData("HmacPBESHA256", "HmacSHA256",
|
||||||
|
"9e8c102c212d2fd1334dc497acb4e002b04e84713b7eda5a63807af2" +
|
||||||
|
"989d3e50"),
|
||||||
|
macAssertionData("HmacPBESHA384", "HmacSHA384",
|
||||||
|
"77f31a785d4f2220251143a4ba80f5610d9d0aeaebb4a278b8a7535c" +
|
||||||
|
"8cea8e8211809ba450458e351c5b66d691839c23"),
|
||||||
|
macAssertionData("HmacPBESHA512", "HmacSHA512",
|
||||||
|
"a53f942a844b234a69c1f92cba20ef272c4394a3cf4024dc16d9dbac" +
|
||||||
|
"1969870b1c2b28b897149a1a3b9ad80a7ca8c547dfabf3ed5f144c6b" +
|
||||||
|
"593900b62e120c45"),
|
||||||
|
};
|
||||||
|
|
||||||
|
public void main(Provider sunPKCS11) throws Exception {
|
||||||
|
System.out.println("SunPKCS11: " + sunPKCS11.getName());
|
||||||
|
for (Configuration conf : Configuration.values()) {
|
||||||
|
for (AssertionData data : assertionData) {
|
||||||
|
testWith(sunPKCS11, data, true, conf);
|
||||||
|
if (conf != Configuration.PBEParameterSpec) {
|
||||||
|
testWith(sunPKCS11, data, false, conf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("TEST PASS - OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testWith(Provider sunPKCS11, AssertionData data,
|
||||||
|
boolean testPBEService, Configuration conf) throws Exception {
|
||||||
|
String svcAlgo = testPBEService ? data.pbeHmacAlgo : data.hmacAlgo;
|
||||||
|
System.out.println(sep + System.lineSeparator() + svcAlgo
|
||||||
|
+ " (with " + conf.name() + ")");
|
||||||
|
|
||||||
|
BigInteger mac = computeMac(sunPKCS11, svcAlgo, data.pbeHmacAlgo, conf);
|
||||||
|
printHex("HMAC", mac);
|
||||||
|
|
||||||
|
if (!mac.equals(data.expectedMac)) {
|
||||||
|
printHex("Expected HMAC", data.expectedMac);
|
||||||
|
throw new Exception("Expected HMAC did not match");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigInteger computeMac(Provider p, String svcAlgo,
|
||||||
|
String keyAlgo, Configuration conf)
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
Mac mac = Mac.getInstance(svcAlgo, p);
|
||||||
|
switch (conf) {
|
||||||
|
case PBEParameterSpec -> {
|
||||||
|
SecretKey key = getPasswordOnlyPBEKey();
|
||||||
|
mac.init(key, new PBEParameterSpec(salt, iterations));
|
||||||
|
}
|
||||||
|
case SecretKeyFactoryDerivedKey -> {
|
||||||
|
SecretKey key = getDerivedSecretKey(p, keyAlgo);
|
||||||
|
mac.init(key);
|
||||||
|
}
|
||||||
|
case AnonymousPBEKey -> {
|
||||||
|
SecretKey key = getAnonymousPBEKey(keyAlgo);
|
||||||
|
mac.init(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new BigInteger(1, mac.doFinal(
|
||||||
|
plainText.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey getPasswordOnlyPBEKey()
|
||||||
|
throws GeneralSecurityException {
|
||||||
|
return SecretKeyFactory.getInstance("PBE")
|
||||||
|
.generateSecret(new PBEKeySpec(password));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey getDerivedSecretKey(Provider sunPKCS11,
|
||||||
|
String algorithm) throws GeneralSecurityException {
|
||||||
|
return SecretKeyFactory.getInstance(algorithm, sunPKCS11)
|
||||||
|
.generateSecret(new PBEKeySpec(password, salt, iterations));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey getAnonymousPBEKey(String algorithm) {
|
||||||
|
return new PBEKey() {
|
||||||
|
public byte[] getSalt() { return salt.clone(); }
|
||||||
|
public int getIterationCount() { return iterations; }
|
||||||
|
public String getAlgorithm() { return algorithm; }
|
||||||
|
public String getFormat() { return "RAW"; }
|
||||||
|
public char[] getPassword() { return password.clone(); }
|
||||||
|
public byte[] getEncoded() { return null; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printHex(String title, BigInteger b) {
|
||||||
|
String repr = (b == null) ? "buffer is null" : b.toString(16);
|
||||||
|
System.out.println(title + ": " + repr + System.lineSeparator());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
main(new PBAMac());
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -37,7 +37,7 @@ import java.security.Provider;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.SecretKey;
|
||||||
|
|
||||||
public class ReinitMac extends PKCS11Test {
|
public class ReinitMac extends PKCS11Test {
|
||||||
|
|
||||||
@ -51,13 +51,12 @@ public class ReinitMac extends PKCS11Test {
|
|||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
byte[] data = new byte[10 * 1024];
|
byte[] data = new byte[10 * 1024];
|
||||||
random.nextBytes(data);
|
random.nextBytes(data);
|
||||||
byte[] keyVal = new byte[16];
|
|
||||||
random.nextBytes(keyVal);
|
|
||||||
|
|
||||||
boolean success = true;
|
boolean success = true;
|
||||||
for (String alg : algorithms) {
|
for (String alg : algorithms) {
|
||||||
|
SecretKey skey = generateKey(alg, 16);
|
||||||
try {
|
try {
|
||||||
doTest(alg, p, keyVal, data);
|
doTest(alg, p, skey, data);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("Unexpected exception: " + e);
|
System.out.println("Unexpected exception: " + e);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -72,10 +71,9 @@ public class ReinitMac extends PKCS11Test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doTest(String alg, Provider p, byte[] keyVal, byte[] data)
|
private void doTest(String alg, Provider p, SecretKey key, byte[] data)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
System.out.println("Testing " + alg);
|
System.out.println("Testing " + alg);
|
||||||
SecretKeySpec key = new SecretKeySpec(keyVal, alg);
|
|
||||||
Mac mac = Mac.getInstance(alg, p);
|
Mac mac = Mac.getInstance(alg, p);
|
||||||
mac.init(key);
|
mac.init(key);
|
||||||
mac.init(key);
|
mac.init(key);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -40,6 +40,7 @@ import java.security.NoSuchProviderException;
|
|||||||
import java.security.Policy;
|
import java.security.Policy;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.security.ProviderException;
|
import java.security.ProviderException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.spec.ECGenParameterSpec;
|
import java.security.spec.ECGenParameterSpec;
|
||||||
import java.security.spec.ECParameterSpec;
|
import java.security.spec.ECParameterSpec;
|
||||||
@ -55,6 +56,9 @@ import java.util.ServiceConfigurationError;
|
|||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
import jdk.test.lib.artifacts.Artifact;
|
import jdk.test.lib.artifacts.Artifact;
|
||||||
import jdk.test.lib.artifacts.ArtifactResolver;
|
import jdk.test.lib.artifacts.ArtifactResolver;
|
||||||
import jdk.test.lib.artifacts.ArtifactResolverException;
|
import jdk.test.lib.artifacts.ArtifactResolverException;
|
||||||
@ -828,6 +832,58 @@ public abstract class PKCS11Test {
|
|||||||
return algorithms;
|
return algorithms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final SecureRandom srdm = new SecureRandom();
|
||||||
|
|
||||||
|
static SecretKey generateKey(String alg, int keySize) {
|
||||||
|
if (alg.contains("PBE")) {
|
||||||
|
return generateKeyPBE(alg, keySize);
|
||||||
|
} else {
|
||||||
|
return generateKeyNonPBE(alg, keySize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey generateKeyNonPBE(String alg, int keySize) {
|
||||||
|
byte[] keyVal = new byte[keySize];
|
||||||
|
srdm.nextBytes(keyVal);
|
||||||
|
return new SecretKeySpec(keyVal, alg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey generateKeyPBE(String alg, int keySize) {
|
||||||
|
char[] pass = new char[keySize];
|
||||||
|
for (int i = 0; i < pass.length; i++) {
|
||||||
|
pass[i] = (char) ('0' + srdm.nextInt(74));
|
||||||
|
}
|
||||||
|
byte[] salt = new byte[srdm.nextInt(8, 16)];
|
||||||
|
srdm.nextBytes(salt);
|
||||||
|
int iterations = srdm.nextInt(1, 1000);
|
||||||
|
return new javax.crypto.interfaces.PBEKey() {
|
||||||
|
@Override
|
||||||
|
public String getAlgorithm() {
|
||||||
|
return "PBE";
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String getFormat() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public byte[] getEncoded() {
|
||||||
|
throw new RuntimeException("Should not be called");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public char[] getPassword() {
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public byte[] getSalt() {
|
||||||
|
return salt;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getIterationCount() {
|
||||||
|
return iterations;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static byte[] generateData(int length) {
|
static byte[] generateData(int length) {
|
||||||
byte data[] = new byte[length];
|
byte data[] = new byte[length];
|
||||||
for (int i=0; i<data.length; i++) {
|
for (int i=0; i<data.length; i++) {
|
||||||
|
517
test/jdk/sun/security/pkcs11/SecretKeyFactory/TestPBKD.java
Normal file
517
test/jdk/sun/security/pkcs11/SecretKeyFactory/TestPBKD.java
Normal file
@ -0,0 +1,517 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.ReflectiveOperationException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.Provider;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.security.spec.KeySpec;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
import javax.crypto.interfaces.PBEKey;
|
||||||
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8301553
|
||||||
|
* @summary test key derivation on a SunPKCS11 SecretKeyFactory service
|
||||||
|
* @library /test/lib ..
|
||||||
|
* @modules java.base/com.sun.crypto.provider:open
|
||||||
|
* @run main/othervm/timeout=30 TestPBKD
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class TestPBKD extends PKCS11Test {
|
||||||
|
private static final String sep = "======================================" +
|
||||||
|
"===================================";
|
||||||
|
|
||||||
|
private enum Configuration {
|
||||||
|
// Pass password, salt and iterations to a
|
||||||
|
// SecretKeyFactory through a PBEKeySpec.
|
||||||
|
PBEKeySpec,
|
||||||
|
|
||||||
|
// Pass password, salt and iterations and iterations to a
|
||||||
|
// SecretKeyFactory through an anonymous class implementing
|
||||||
|
// the javax.crypto.interfaces.PBEKey interface.
|
||||||
|
AnonymousPBEKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Provider sunJCE = Security.getProvider("SunJCE");
|
||||||
|
|
||||||
|
private static BigInteger i(byte[] data) {
|
||||||
|
return new BigInteger(1, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private record AssertionData(String algo, PBEKeySpec keySpec,
|
||||||
|
BigInteger expectedKey) {}
|
||||||
|
|
||||||
|
private static AssertionData p12PBKDAssertionData(String algo,
|
||||||
|
char[] password, int keyLen, String hashAlgo, int blockLen,
|
||||||
|
String staticExpectedKeyString) {
|
||||||
|
PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterations, keyLen);
|
||||||
|
BigInteger staticExpectedKey = new BigInteger(staticExpectedKeyString,
|
||||||
|
16);
|
||||||
|
BigInteger expectedKey;
|
||||||
|
try {
|
||||||
|
// Since we need to access an internal
|
||||||
|
// SunJCE API, we use reflection.
|
||||||
|
Class<?> PKCS12PBECipherCore = Class.forName(
|
||||||
|
"com.sun.crypto.provider.PKCS12PBECipherCore");
|
||||||
|
|
||||||
|
Field macKeyField = PKCS12PBECipherCore.getDeclaredField("MAC_KEY");
|
||||||
|
macKeyField.setAccessible(true);
|
||||||
|
int MAC_KEY = (int) macKeyField.get(null);
|
||||||
|
|
||||||
|
Method deriveMethod = PKCS12PBECipherCore.getDeclaredMethod(
|
||||||
|
"derive", char[].class, byte[].class, int.class,
|
||||||
|
int.class, int.class, String.class, int.class);
|
||||||
|
deriveMethod.setAccessible(true);
|
||||||
|
expectedKey = i((byte[]) deriveMethod.invoke(null,
|
||||||
|
keySpec.getPassword(), keySpec.getSalt(),
|
||||||
|
keySpec.getIterationCount(), keySpec.getKeyLength() / 8,
|
||||||
|
MAC_KEY, hashAlgo, blockLen));
|
||||||
|
checkAssertionValues(expectedKey, staticExpectedKey);
|
||||||
|
} catch (ReflectiveOperationException ignored) {
|
||||||
|
expectedKey = staticExpectedKey;
|
||||||
|
}
|
||||||
|
return new AssertionData(algo, keySpec, expectedKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AssertionData pbkd2AssertionData(String algo,
|
||||||
|
char[] password, int keyLen, String kdfAlgo,
|
||||||
|
String staticExpectedKeyString) {
|
||||||
|
PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterations, keyLen);
|
||||||
|
BigInteger staticExpectedKey = new BigInteger(staticExpectedKeyString,
|
||||||
|
16);
|
||||||
|
BigInteger expectedKey = null;
|
||||||
|
if (sunJCE != null) {
|
||||||
|
try {
|
||||||
|
expectedKey = i(SecretKeyFactory.getInstance(kdfAlgo, sunJCE)
|
||||||
|
.generateSecret(keySpec).getEncoded());
|
||||||
|
checkAssertionValues(expectedKey, staticExpectedKey);
|
||||||
|
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||||
|
// Move to staticExpectedKey as it's unlikely
|
||||||
|
// that any of the algorithms are available.
|
||||||
|
sunJCE = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expectedKey == null) {
|
||||||
|
expectedKey = staticExpectedKey;
|
||||||
|
}
|
||||||
|
return new AssertionData(algo, keySpec, expectedKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkAssertionValues(BigInteger expectedValue,
|
||||||
|
BigInteger staticExpectedValue) {
|
||||||
|
if (!expectedValue.equals(staticExpectedValue)) {
|
||||||
|
printHex("SunJCE value", expectedValue);
|
||||||
|
printHex("Static value", staticExpectedValue);
|
||||||
|
throw new Error("Static and SunJCE values do not match.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final char[] pwd = "123456\uA4F7".toCharArray();
|
||||||
|
private static final char[] emptyPwd = new char[0];
|
||||||
|
private static final byte[] salt = "abcdefgh".getBytes(
|
||||||
|
StandardCharsets.UTF_8);
|
||||||
|
private static final int iterations = 1000;
|
||||||
|
|
||||||
|
// Generated with SunJCE. Keep a reference to some
|
||||||
|
// entries for tests executing invalid conditions.
|
||||||
|
private static final AssertionData hmacPBESHA1Data =
|
||||||
|
p12PBKDAssertionData("HmacPBESHA1", pwd, 160, "SHA-1", 64,
|
||||||
|
"13156c6bee8e13ef568231e0174651afa5a358b0");
|
||||||
|
private static final AssertionData hmacPBESHA224Data =
|
||||||
|
p12PBKDAssertionData("HmacPBESHA224", pwd, 224, "SHA-224", 64,
|
||||||
|
"d93acf4b3bea8a89d098e290928840c0b693a30cad0117f70ace50c2");
|
||||||
|
private static final AssertionData pbeWithHmacSHA512AndAES256Data =
|
||||||
|
pbkd2AssertionData("PBEWithHmacSHA512AndAES_256", pwd, 256,
|
||||||
|
"PBKDF2WithHmacSHA512", "845560159e2f3f51dad8d6e0feccc898" +
|
||||||
|
"7e3077595f90b60ab96d4f29203927b0");
|
||||||
|
private static final AssertionData pbkdf2WithHmacSHA256Data =
|
||||||
|
pbkd2AssertionData("PBKDF2WithHmacSHA256", pwd, 384,
|
||||||
|
"PBKDF2WithHmacSHA256", "6851e387278dd5a3a0d05e4d742f59d8" +
|
||||||
|
"44984e3e9b619488a42b93dd6453f630ae3e2ad7ed809fa9e98a7921" +
|
||||||
|
"87d62e84");
|
||||||
|
private static final AssertionData[] assertionData = new AssertionData[]{
|
||||||
|
hmacPBESHA1Data,
|
||||||
|
hmacPBESHA224Data,
|
||||||
|
p12PBKDAssertionData("HmacPBESHA256", pwd, 256, "SHA-256", 64,
|
||||||
|
"1bb3ed1ffb784ed32f59b4d7515971699af99cf67a2e574000964c8e" +
|
||||||
|
"1eba1c45"),
|
||||||
|
p12PBKDAssertionData("HmacPBESHA384", pwd, 384, "SHA-384", 128,
|
||||||
|
"d4ce121d3cec88a8c8b0c6225f7f996b72d76017c2d91bc51fd47985" +
|
||||||
|
"86d1012d1ad03a39fdcd0fdc438d164ab50259fc"),
|
||||||
|
p12PBKDAssertionData("HmacPBESHA512", pwd, 512, "SHA-512", 128,
|
||||||
|
"5f80b350986e5156669193eaa42a107e7d6636d82fb550f67af5b2c2" +
|
||||||
|
"f546d977b70e52bbbcb6bb8976f9d3f0eaf9bfef5306c50ee5ccda3e" +
|
||||||
|
"e4c4c7c8421fe4d"),
|
||||||
|
pbkd2AssertionData("PBEWithHmacSHA1AndAES_128", pwd, 128,
|
||||||
|
"PBKDF2WithHmacSHA1", "29958f3f1c942e50903189eb7f1ba09d"),
|
||||||
|
pbkd2AssertionData("PBEWithHmacSHA224AndAES_128", pwd, 128,
|
||||||
|
"PBKDF2WithHmacSHA224", "e328140e31f4ffb15af806986c23ee4e"),
|
||||||
|
pbkd2AssertionData("PBEWithHmacSHA256AndAES_128", pwd, 128,
|
||||||
|
"PBKDF2WithHmacSHA256", "6851e387278dd5a3a0d05e4d742f59d8"),
|
||||||
|
pbkd2AssertionData("PBEWithHmacSHA384AndAES_128", pwd, 128,
|
||||||
|
"PBKDF2WithHmacSHA384", "5570e2fb1a664910f055b71643b52351"),
|
||||||
|
pbkd2AssertionData("PBEWithHmacSHA512AndAES_128", pwd, 128,
|
||||||
|
"PBKDF2WithHmacSHA512", "845560159e2f3f51dad8d6e0feccc898"),
|
||||||
|
pbkd2AssertionData("PBEWithHmacSHA1AndAES_256", pwd, 256,
|
||||||
|
"PBKDF2WithHmacSHA1", "29958f3f1c942e50903189eb7f1ba09d40" +
|
||||||
|
"b5552da5e645dad4b5911ce0f2f06b"),
|
||||||
|
pbkd2AssertionData("PBEWithHmacSHA224AndAES_256", pwd, 256,
|
||||||
|
"PBKDF2WithHmacSHA224", "e328140e31f4ffb15af806986c23ee4e" +
|
||||||
|
"7daa2119fee8c64aef7c1f4c1871724e"),
|
||||||
|
pbkd2AssertionData("PBEWithHmacSHA256AndAES_256", pwd, 256,
|
||||||
|
"PBKDF2WithHmacSHA256", "6851e387278dd5a3a0d05e4d742f59d8" +
|
||||||
|
"44984e3e9b619488a42b93dd6453f630"),
|
||||||
|
pbkd2AssertionData("PBEWithHmacSHA384AndAES_256", pwd, 256,
|
||||||
|
"PBKDF2WithHmacSHA384", "5570e2fb1a664910f055b71643b52351" +
|
||||||
|
"d7d0ad3a18912086f80d974f2acc2efb"),
|
||||||
|
pbeWithHmacSHA512AndAES256Data,
|
||||||
|
pbkd2AssertionData("PBKDF2WithHmacSHA1", pwd, 240,
|
||||||
|
"PBKDF2WithHmacSHA1", "29958f3f1c942e50903189eb7f1ba09d40" +
|
||||||
|
"b5552da5e645dad4b5911ce0f2"),
|
||||||
|
pbkd2AssertionData("PBKDF2WithHmacSHA224", pwd, 336,
|
||||||
|
"PBKDF2WithHmacSHA224", "e328140e31f4ffb15af806986c23ee4e" +
|
||||||
|
"7daa2119fee8c64aef7c1f4c1871724e0ea628577e0ab54fa7c6"),
|
||||||
|
pbkdf2WithHmacSHA256Data,
|
||||||
|
pbkd2AssertionData("PBKDF2WithHmacSHA384", pwd, 576,
|
||||||
|
"PBKDF2WithHmacSHA384", "5570e2fb1a664910f055b71643b52351" +
|
||||||
|
"d7d0ad3a18912086f80d974f2acc2efba52650d4bf872455820f24c8" +
|
||||||
|
"46742161da84a1b4c3f197f4347308e8841a8971cf686aef29107396"),
|
||||||
|
pbkd2AssertionData("PBKDF2WithHmacSHA512", pwd, 768,
|
||||||
|
"PBKDF2WithHmacSHA512", "845560159e2f3f51dad8d6e0feccc898" +
|
||||||
|
"7e3077595f90b60ab96d4f29203927b00aa1a11e4d19d4f275a7f453" +
|
||||||
|
"14be500dacc3c1de9f704827b396463ccaa8957344d41bd64d9d09ff" +
|
||||||
|
"474e776469d326b1ee6ee5a5d854b86d3d7a25084afd6d6f"),
|
||||||
|
p12PBKDAssertionData("HmacPBESHA512", emptyPwd, 512, "SHA-512",
|
||||||
|
128, "90b6e088490c6c5e6b6e81209bd769d27df3868cae79591577a" +
|
||||||
|
"c35b46e4c6ebcc4b90f4943e3cb165f9d1789d938235f4b35ba74df9" +
|
||||||
|
"e509fbbb7aa329a432445"),
|
||||||
|
pbkd2AssertionData("PBEWithHmacSHA512AndAES_256", emptyPwd, 256,
|
||||||
|
"PBKDF2WithHmacSHA512", "3a5c5fd11e4d381b32e11baa93d7b128" +
|
||||||
|
"09e016e48e0542c5d3453fc240a0fa76"),
|
||||||
|
};
|
||||||
|
|
||||||
|
public void main(Provider sunPKCS11) throws Exception {
|
||||||
|
System.out.println("SunPKCS11: " + sunPKCS11.getName());
|
||||||
|
|
||||||
|
// Test valid cases.
|
||||||
|
for (Configuration conf : Configuration.values()) {
|
||||||
|
for (AssertionData data : assertionData) {
|
||||||
|
testValidWith(sunPKCS11, data, conf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test invalid cases.
|
||||||
|
testInvalidTranslateKey(sunPKCS11);
|
||||||
|
testInvalidGenerateSecret(sunPKCS11);
|
||||||
|
testInvalidGetKeySpec(sunPKCS11);
|
||||||
|
|
||||||
|
System.out.println("TEST PASS - OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testValidWith(Provider sunPKCS11, AssertionData data,
|
||||||
|
Configuration conf) throws Exception {
|
||||||
|
System.out.println(sep + System.lineSeparator() + data.algo
|
||||||
|
+ " (with " + conf.name() + ")");
|
||||||
|
|
||||||
|
SecretKeyFactory skf = SecretKeyFactory.getInstance(data.algo,
|
||||||
|
sunPKCS11);
|
||||||
|
SecretKey derivedKey = switch (conf) {
|
||||||
|
case PBEKeySpec -> skf.generateSecret(data.keySpec);
|
||||||
|
case AnonymousPBEKey -> skf.translateKey(getAnonymousPBEKey(
|
||||||
|
data.algo, data.keySpec));
|
||||||
|
};
|
||||||
|
BigInteger derivedKeyValue = i(derivedKey.getEncoded());
|
||||||
|
printHex("Derived Key", derivedKeyValue);
|
||||||
|
|
||||||
|
if (!derivedKeyValue.equals(data.expectedKey)) {
|
||||||
|
printHex("Expected Derived Key", data.expectedKey);
|
||||||
|
throw new Exception("Expected Derived Key did not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skf.translateKey(derivedKey) != derivedKey) {
|
||||||
|
throw new Exception("SecretKeyFactory::translateKey must return " +
|
||||||
|
"the same key when a P11PBEKey from the same token is " +
|
||||||
|
"passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
testGetKeySpec(data, skf, derivedKey);
|
||||||
|
if (sunJCE != null && data.algo.startsWith("PBKDF2")) {
|
||||||
|
testTranslateP11PBEKeyToSunJCE(data.algo, (PBEKey) derivedKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecretKey getAnonymousPBEKey(String algorithm,
|
||||||
|
PBEKeySpec keySpec) {
|
||||||
|
return new PBEKey() {
|
||||||
|
public byte[] getSalt() { return keySpec.getSalt(); }
|
||||||
|
public int getIterationCount() {
|
||||||
|
return keySpec.getIterationCount();
|
||||||
|
}
|
||||||
|
public String getAlgorithm() { return algorithm; }
|
||||||
|
public String getFormat() { return "RAW"; }
|
||||||
|
public char[] getPassword() { return keySpec.getPassword(); }
|
||||||
|
public byte[] getEncoded() {
|
||||||
|
return new byte[keySpec.getKeyLength() / 8];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printHex(String title, BigInteger b) {
|
||||||
|
String repr = (b == null) ? "buffer is null" : b.toString(16);
|
||||||
|
System.out.println(title + ": " + repr + System.lineSeparator());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testGetKeySpec(AssertionData data,
|
||||||
|
SecretKeyFactory skf, SecretKey derivedKey) throws Exception {
|
||||||
|
System.out.println(sep + System.lineSeparator()
|
||||||
|
+ "SecretKeyFactory::getKeySpec() (for " + data.algo + ")");
|
||||||
|
KeySpec skfKeySpec = skf.getKeySpec(derivedKey, PBEKeySpec.class);
|
||||||
|
if (skfKeySpec instanceof PBEKeySpec skfPBEKeySpec) {
|
||||||
|
char[] specPassword = skfPBEKeySpec.getPassword();
|
||||||
|
byte[] specSalt = skfPBEKeySpec.getSalt();
|
||||||
|
int specIterations = skfPBEKeySpec.getIterationCount();
|
||||||
|
int specKeyLength = skfPBEKeySpec.getKeyLength();
|
||||||
|
System.out.println(" spec key length (bits): " + specKeyLength);
|
||||||
|
System.out.println(" spec password: "
|
||||||
|
+ String.valueOf(specPassword));
|
||||||
|
System.out.println(" spec iteration count: " + specIterations);
|
||||||
|
printHex(" spec salt", i(specSalt));
|
||||||
|
|
||||||
|
if (!Arrays.equals(specPassword, data.keySpec.getPassword())) {
|
||||||
|
throw new Exception("Password differs");
|
||||||
|
}
|
||||||
|
if (!Arrays.equals(specSalt, data.keySpec.getSalt())) {
|
||||||
|
throw new Exception("Salt differs");
|
||||||
|
}
|
||||||
|
if (specIterations != data.keySpec.getIterationCount()) {
|
||||||
|
throw new Exception("Iteration count differs");
|
||||||
|
}
|
||||||
|
if (specKeyLength != data.keySpec.getKeyLength()) {
|
||||||
|
throw new Exception("Key length differs");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Exception("Invalid key spec type: " + skfKeySpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test extracting key bytes with a SecretKeySpec.
|
||||||
|
SecretKeySpec secretKeySpec = (SecretKeySpec)
|
||||||
|
skf.getKeySpec(derivedKey, SecretKeySpec.class);
|
||||||
|
if (!Arrays.equals(secretKeySpec.getEncoded(),
|
||||||
|
derivedKey.getEncoded())) {
|
||||||
|
throw new Exception("Unable to extract key bytes with a " +
|
||||||
|
"SecretKeySpec");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testTranslateP11PBEKeyToSunJCE(String algorithm,
|
||||||
|
PBEKey p11PbeK) throws Exception {
|
||||||
|
System.out.println(sep + System.lineSeparator()
|
||||||
|
+ "Translate P11PBEKey to SunJCE (for " + algorithm + ")");
|
||||||
|
SecretKey jceK = SecretKeyFactory.getInstance(algorithm, sunJCE)
|
||||||
|
.translateKey(p11PbeK);
|
||||||
|
BigInteger jceEncoded = i(jceK.getEncoded());
|
||||||
|
printHex(" translated to SunJCE", jceEncoded);
|
||||||
|
if (jceK instanceof PBEKey jcePbeK) {
|
||||||
|
if (!Arrays.equals(jcePbeK.getPassword(), p11PbeK.getPassword())) {
|
||||||
|
throw new Exception("Password differs");
|
||||||
|
}
|
||||||
|
if (!Arrays.equals(jcePbeK.getSalt(), p11PbeK.getSalt())) {
|
||||||
|
throw new Exception("Salt differs");
|
||||||
|
}
|
||||||
|
if (jcePbeK.getIterationCount() != p11PbeK.getIterationCount()) {
|
||||||
|
throw new Exception("Iteration count differs");
|
||||||
|
}
|
||||||
|
if (!jceEncoded.equals(i(p11PbeK.getEncoded()))) {
|
||||||
|
throw new Exception("Encoded key differs");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Exception("Unexpected key type for SunJCE key: "
|
||||||
|
+ jceK.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface Action {
|
||||||
|
void run() throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertThrows(Class<?> expectedExc, String expectedMsg,
|
||||||
|
Action action) throws Exception {
|
||||||
|
String shtExpected = "Should have thrown '"
|
||||||
|
+ expectedExc.getSimpleName() + ": " + expectedMsg + "'";
|
||||||
|
try {
|
||||||
|
action.run();
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (expectedExc.isAssignableFrom(e.getClass()) &&
|
||||||
|
e.getMessage().equals(expectedMsg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new Exception(shtExpected + ", but threw '" +
|
||||||
|
e.getClass().getSimpleName() + ": " + e.getMessage() + "'");
|
||||||
|
}
|
||||||
|
throw new Exception(shtExpected + ", but it didn't throw");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testInvalidTranslateKey(Provider sunPKCS11)
|
||||||
|
throws Exception {
|
||||||
|
System.out.println(sep + System.lineSeparator()
|
||||||
|
+ "Invalid SecretKeyFactory::translateKey tests");
|
||||||
|
|
||||||
|
SecretKeyFactory skf1 = SecretKeyFactory.getInstance(
|
||||||
|
hmacPBESHA1Data.algo, sunPKCS11);
|
||||||
|
SecretKeyFactory skf2 = SecretKeyFactory.getInstance("AES", sunPKCS11);
|
||||||
|
SecretKeyFactory skf3 = SecretKeyFactory.getInstance(
|
||||||
|
pbkdf2WithHmacSHA256Data.algo, sunPKCS11);
|
||||||
|
PBEKey p11PbeKey = (PBEKey) skf1.translateKey(getAnonymousPBEKey(
|
||||||
|
skf1.getAlgorithm(), hmacPBESHA1Data.keySpec));
|
||||||
|
Class<?> e = InvalidKeyException.class;
|
||||||
|
|
||||||
|
System.out.println(" * Non-PBEKey key to PBE SecretKeyFactory");
|
||||||
|
assertThrows(e, "PBE service requires a PBE key",
|
||||||
|
() -> skf1.translateKey(new SecretKeySpec(
|
||||||
|
new byte[10], hmacPBESHA1Data.algo)));
|
||||||
|
|
||||||
|
System.out.println(" * PBEKey key to PBE SecretKeyFactory of a " +
|
||||||
|
"different algorithm");
|
||||||
|
assertThrows(e, "Cannot use a " + hmacPBESHA1Data.algo + " key for a " +
|
||||||
|
hmacPBESHA224Data.algo + " service",
|
||||||
|
() -> SecretKeyFactory.getInstance(hmacPBESHA224Data.algo,
|
||||||
|
sunPKCS11).translateKey(p11PbeKey));
|
||||||
|
|
||||||
|
System.out.println(" * Non-AES PBEKey key to AES SecretKeyFactory");
|
||||||
|
assertThrows(e, "Cannot use a " + hmacPBESHA1Data.algo + " key for a " +
|
||||||
|
skf2.getAlgorithm() + " service",
|
||||||
|
() -> skf2.translateKey(p11PbeKey));
|
||||||
|
|
||||||
|
System.out.println(" * Inconsistent key length between key and " +
|
||||||
|
"algorithm");
|
||||||
|
PBEKeySpec kSpec1 = new PBEKeySpec(pwd, salt, 1, 16);
|
||||||
|
assertThrows(e, InvalidKeySpecException.class.getName() + ": Key " +
|
||||||
|
"length is invalid for " + skf1.getAlgorithm() + " (expecting" +
|
||||||
|
" " + hmacPBESHA1Data.keySpec.getKeyLength() + " but was " +
|
||||||
|
kSpec1.getKeyLength() + ")",
|
||||||
|
() -> skf1.translateKey(getAnonymousPBEKey(
|
||||||
|
skf1.getAlgorithm(), kSpec1)));
|
||||||
|
|
||||||
|
System.out.println(" * Invalid key length in bits");
|
||||||
|
PBEKeySpec kSpec2 = new PBEKeySpec(pwd, salt, 1);
|
||||||
|
assertThrows(e, InvalidKeySpecException.class.getName() + ": Key " +
|
||||||
|
"length must be multiple of 8 and greater than zero",
|
||||||
|
() -> skf3.translateKey(getAnonymousPBEKey(
|
||||||
|
skf3.getAlgorithm(), kSpec2)));
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testInvalidGenerateSecret(Provider sunPKCS11)
|
||||||
|
throws Exception {
|
||||||
|
System.out.println(sep + System.lineSeparator()
|
||||||
|
+ "Invalid SecretKeyFactory::generateSecret tests");
|
||||||
|
|
||||||
|
SecretKeyFactory skf1 = SecretKeyFactory.getInstance(
|
||||||
|
hmacPBESHA1Data.algo, sunPKCS11);
|
||||||
|
SecretKeyFactory skf2 = SecretKeyFactory.getInstance(
|
||||||
|
pbeWithHmacSHA512AndAES256Data.algo, sunPKCS11);
|
||||||
|
SecretKeyFactory skf3 = SecretKeyFactory.getInstance(
|
||||||
|
"PBKDF2WithHmacSHA512", sunPKCS11);
|
||||||
|
SecretKeyFactory skf4 = SecretKeyFactory.getInstance("AES", sunPKCS11);
|
||||||
|
Class<?> e = InvalidKeySpecException.class;
|
||||||
|
|
||||||
|
System.out.println(" * Missing salt and iteration count");
|
||||||
|
assertThrows(e, "Salt not found",
|
||||||
|
() -> skf1.generateSecret(new PBEKeySpec(pwd)));
|
||||||
|
|
||||||
|
System.out.println(" * Inconsistent key length between spec and " +
|
||||||
|
"algorithm");
|
||||||
|
PBEKeySpec kSpec = new PBEKeySpec(pwd, salt, 1, 16);
|
||||||
|
assertThrows(e, "Key length is invalid for " + skf1.getAlgorithm() +
|
||||||
|
" (expecting " + hmacPBESHA1Data.keySpec.getKeyLength() +
|
||||||
|
" but was " + kSpec.getKeyLength() + ")",
|
||||||
|
() -> skf1.generateSecret(kSpec));
|
||||||
|
assertThrows(e, "Key length is invalid for " + skf2.getAlgorithm() +
|
||||||
|
" (expecting " + pbeWithHmacSHA512AndAES256Data.keySpec
|
||||||
|
.getKeyLength() + " but was " + kSpec.getKeyLength() + ")",
|
||||||
|
() -> skf2.generateSecret(kSpec));
|
||||||
|
|
||||||
|
System.out.println(" * Invalid key length in bits");
|
||||||
|
String msg = "Key length must be multiple of 8 and greater than zero";
|
||||||
|
assertThrows(e, msg,
|
||||||
|
() -> skf3.generateSecret(new PBEKeySpec(pwd, salt, 1)));
|
||||||
|
assertThrows(e, msg,
|
||||||
|
() -> skf3.generateSecret(new PBEKeySpec(pwd, salt, 1, 3)));
|
||||||
|
|
||||||
|
System.out.println(" * PBEKeySpec to non-PBE SecretKeyFactory");
|
||||||
|
assertThrows(e, "Unsupported spec: javax.crypto.spec.PBEKeySpec",
|
||||||
|
() -> skf4.generateSecret(kSpec));
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testInvalidGetKeySpec(Provider sunPKCS11)
|
||||||
|
throws Exception {
|
||||||
|
System.out.println(sep + System.lineSeparator()
|
||||||
|
+ "Invalid SecretKeyFactory::getKeySpec tests");
|
||||||
|
|
||||||
|
SecretKeyFactory skf1 = SecretKeyFactory.getInstance(
|
||||||
|
hmacPBESHA1Data.algo, sunPKCS11);
|
||||||
|
SecretKeyFactory skf2 = SecretKeyFactory.getInstance(
|
||||||
|
"AES", sunPKCS11);
|
||||||
|
PBEKey p11PbeKey = (PBEKey) skf1.translateKey(getAnonymousPBEKey(
|
||||||
|
skf1.getAlgorithm(), hmacPBESHA1Data.keySpec));
|
||||||
|
Class<?> e = InvalidKeySpecException.class;
|
||||||
|
|
||||||
|
System.out.println(" * null KeySpec class");
|
||||||
|
assertThrows(e, "key and keySpec must not be null",
|
||||||
|
() -> skf1.getKeySpec(p11PbeKey, null));
|
||||||
|
|
||||||
|
System.out.println(" * Invalid key type for PBEKeySpec");
|
||||||
|
assertThrows(e, "Unsupported spec: " + PBEKeySpec.class.getName(),
|
||||||
|
() -> skf1.getKeySpec(new SecretKeySpec(new byte[16],
|
||||||
|
skf1.getAlgorithm()), PBEKeySpec.class));
|
||||||
|
|
||||||
|
System.out.println(" * Invalid PBE key and PBEKeySpec for " +
|
||||||
|
skf2.getAlgorithm() + " SecretKeyFactory");
|
||||||
|
assertThrows(e, "Unsupported spec: " + PBEKeySpec.class.getName(),
|
||||||
|
() -> skf2.getKeySpec(p11PbeKey, PBEKeySpec.class));
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
main(new TestPBKD());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user