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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,13 +25,14 @@
|
||||
|
||||
package com.sun.crypto.provider;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.crypto.spec.PBEParameterSpec;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import java.security.*;
|
||||
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
|
||||
@ -108,81 +109,30 @@ abstract class HmacPKCS12PBECore extends HmacCore {
|
||||
*/
|
||||
protected void engineInit(Key key, AlgorithmParameterSpec params)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
char[] passwdChars;
|
||||
byte[] salt = null;
|
||||
int iCount = 0;
|
||||
if (key instanceof javax.crypto.interfaces.PBEKey) {
|
||||
javax.crypto.interfaces.PBEKey pbeKey =
|
||||
(javax.crypto.interfaces.PBEKey) key;
|
||||
passwdChars = pbeKey.getPassword();
|
||||
salt = pbeKey.getSalt(); // maybe null if unspecified
|
||||
iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified
|
||||
} else if (key instanceof SecretKey) {
|
||||
byte[] passwdBytes;
|
||||
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;
|
||||
char[] password = null;
|
||||
byte[] derivedKey = null;
|
||||
SecretKeySpec cipherKey = null;
|
||||
PBEKeySpec keySpec = PBEUtil.getPBAKeySpec(key, params);
|
||||
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");
|
||||
}
|
||||
derivedKey = PKCS12PBECipherCore.derive(passwdChars, salt,
|
||||
iCount, engineGetMacLength(), PKCS12PBECipherCore.MAC_KEY,
|
||||
algorithm, bl);
|
||||
password = keySpec.getPassword();
|
||||
derivedKey = PKCS12PBECipherCore.derive(
|
||||
password, keySpec.getSalt(),
|
||||
keySpec.getIterationCount(), engineGetMacLength(),
|
||||
PKCS12PBECipherCore.MAC_KEY, algorithm, bl);
|
||||
cipherKey = new SecretKeySpec(derivedKey, "HmacSHA1");
|
||||
super.engineInit(cipherKey, null);
|
||||
} 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.
|
||||
*
|
||||
* 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.spec.*;
|
||||
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import sun.security.util.PBEUtil;
|
||||
|
||||
/**
|
||||
* This class represents password-based encryption as defined by the PKCS #5
|
||||
* standard.
|
||||
@ -43,10 +46,6 @@ import javax.crypto.spec.*;
|
||||
* @see javax.crypto.Cipher
|
||||
*/
|
||||
abstract class PBES2Core extends CipherSpi {
|
||||
|
||||
private static final int DEFAULT_SALT_LENGTH = 20;
|
||||
private static final int DEFAULT_COUNT = 4096;
|
||||
|
||||
// the encapsulated cipher
|
||||
private final CipherCore cipher;
|
||||
private final int keyLength; // in bits
|
||||
@ -54,9 +53,7 @@ abstract class PBES2Core extends CipherSpi {
|
||||
private final PBKDF2Core kdf;
|
||||
private final String pbeAlgo;
|
||||
private final String cipherAlgo;
|
||||
private int iCount = DEFAULT_COUNT;
|
||||
private byte[] salt = null;
|
||||
private IvParameterSpec ivSpec = null;
|
||||
private final PBEUtil.PBES2Params pbes2Params = new PBEUtil.PBES2Params();
|
||||
|
||||
/**
|
||||
* Creates an instance of PBE Scheme 2 according to the selected
|
||||
@ -135,32 +132,8 @@ abstract class PBES2Core extends CipherSpi {
|
||||
}
|
||||
|
||||
protected AlgorithmParameters engineGetParameters() {
|
||||
AlgorithmParameters params = null;
|
||||
if (salt == null) {
|
||||
// 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;
|
||||
return pbes2Params.getAlgorithmParameters(
|
||||
blkSize, pbeAlgo, SunJCE.getInstance(), SunJCE.getRandom());
|
||||
}
|
||||
|
||||
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,
|
||||
AlgorithmParameterSpec params,
|
||||
SecureRandom random)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
|
||||
if (key == null) {
|
||||
throw new InvalidKeyException("Null key");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
PBEKeySpec pbeSpec = pbes2Params.getPBEKeySpec(blkSize, keyLength,
|
||||
opmode, key, params, random);
|
||||
PBKDF2KeyImpl s = null;
|
||||
byte[] derivedKey;
|
||||
try {
|
||||
s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec);
|
||||
derivedKey = s.getEncoded();
|
||||
} catch (InvalidKeySpecException ikse) {
|
||||
throw new InvalidKeyException("Cannot construct PBE key", ikse);
|
||||
} finally {
|
||||
if (s != null) {
|
||||
s.clear();
|
||||
}
|
||||
pbeSpec.clearPassword();
|
||||
}
|
||||
byte[] derivedKey = s.getEncoded();
|
||||
s.clearPassword();
|
||||
SecretKeySpec cipherKey = new SecretKeySpec(derivedKey, cipherAlgo);
|
||||
|
||||
// initialize the underlying cipher
|
||||
cipher.init(opmode, cipherKey, ivSpec, random);
|
||||
SecretKeySpec cipherKey = null;
|
||||
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,
|
||||
SecureRandom random)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
AlgorithmParameterSpec pbeSpec = null;
|
||||
if (params != null) {
|
||||
try {
|
||||
pbeSpec = params.getParameterSpec(PBEParameterSpec.class);
|
||||
} catch (InvalidParameterSpecException ipse) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Wrong parameter type: PBE expected");
|
||||
}
|
||||
}
|
||||
engineInit(opmode, key, pbeSpec, random);
|
||||
engineInit(opmode, key, PBEUtil.PBES2Params.getParameterSpec(params),
|
||||
random);
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,7 +26,7 @@
|
||||
package com.sun.crypto.provider;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.Cleaner;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.Arrays;
|
||||
@ -64,9 +64,9 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
||||
private int iterCount;
|
||||
private byte[] key;
|
||||
|
||||
@SuppressWarnings("serial") // Type of field is not Serializable;
|
||||
// see writeReplace method
|
||||
private Mac prf;
|
||||
// The following fields are not Serializable. See writeReplace method.
|
||||
private transient Mac prf;
|
||||
private transient Cleaner.Cleanable cleaner;
|
||||
|
||||
private static byte[] getPasswordBytes(char[] passwd) {
|
||||
CharBuffer cb = CharBuffer.wrap(passwd);
|
||||
@ -88,17 +88,9 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
||||
*/
|
||||
PBKDF2KeyImpl(PBEKeySpec keySpec, String prfAlgo)
|
||||
throws InvalidKeySpecException {
|
||||
char[] passwd = keySpec.getPassword();
|
||||
if (passwd == null) {
|
||||
// Should allow an empty password.
|
||||
this.passwd = new char[0];
|
||||
} else {
|
||||
this.passwd = passwd.clone();
|
||||
}
|
||||
this.passwd = keySpec.getPassword();
|
||||
// Convert the password from char[] to byte[]
|
||||
byte[] passwdBytes = getPasswordBytes(this.passwd);
|
||||
// remove local copy
|
||||
if (passwd != null) Arrays.fill(passwd, '\0');
|
||||
|
||||
try {
|
||||
this.salt = keySpec.getSalt();
|
||||
@ -124,16 +116,18 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
||||
throw new InvalidKeySpecException(nsae);
|
||||
} finally {
|
||||
Arrays.fill(passwdBytes, (byte) 0x00);
|
||||
|
||||
// Use the cleaner to zero the key when no longer referenced
|
||||
final byte[] k = this.key;
|
||||
final char[] p = this.passwd;
|
||||
CleanerFactory.cleaner().register(this,
|
||||
() -> {
|
||||
Arrays.fill(k, (byte) 0x00);
|
||||
Arrays.fill(p, '\0');
|
||||
});
|
||||
if (key == null) {
|
||||
Arrays.fill(passwd, '\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,
|
||||
@ -211,11 +205,7 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
// The key is zeroized by finalize()
|
||||
// The reachability fence ensures finalize() isn't called early
|
||||
byte[] result = key.clone();
|
||||
Reference.reachabilityFence(this);
|
||||
return result;
|
||||
return key.clone();
|
||||
}
|
||||
|
||||
public String getAlgorithm() {
|
||||
@ -226,16 +216,12 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
||||
return iterCount;
|
||||
}
|
||||
|
||||
public void clearPassword() {
|
||||
Arrays.fill(passwd, (char)0);
|
||||
public void clear() {
|
||||
cleaner.clean();
|
||||
}
|
||||
|
||||
public char[] getPassword() {
|
||||
// The password is zeroized by finalize()
|
||||
// The reachability fence ensures finalize() isn't called early
|
||||
char[] result = passwd.clone();
|
||||
Reference.reachabilityFence(this);
|
||||
return result;
|
||||
return passwd.clone();
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
package com.sun.crypto.provider;
|
||||
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
@ -179,23 +181,29 @@ abstract class PBMAC1Core extends HmacCore {
|
||||
}
|
||||
|
||||
PBKDF2KeyImpl s = null;
|
||||
PBKDF2Core kdf = getKDFImpl(kdfAlgo);
|
||||
byte[] derivedKey;
|
||||
byte[] derivedKey = null;
|
||||
SecretKeySpec cipherKey = null;
|
||||
try {
|
||||
PBKDF2Core kdf = getKDFImpl(kdfAlgo);
|
||||
s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec);
|
||||
derivedKey = s.getEncoded();
|
||||
cipherKey = new SecretKeySpec(derivedKey, kdfAlgo);
|
||||
super.engineInit(cipherKey, null);
|
||||
} catch (InvalidKeySpecException ikse) {
|
||||
throw new InvalidKeyException("Cannot construct PBE key", ikse);
|
||||
} finally {
|
||||
pbeSpec.clearPassword();
|
||||
if (s != null) {
|
||||
s.clearPassword();
|
||||
if (cipherKey != null) {
|
||||
SharedSecrets.getJavaxCryptoSpecAccess()
|
||||
.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 {
|
||||
|
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.
|
||||
*
|
||||
* 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
|
||||
paddingObj = new PKCS5Padding(blockSize);
|
||||
padBuffer = new byte[blockSize];
|
||||
char[] tokenLabel = token.tokenInfo.label;
|
||||
// NSS requires block-sized updates in multi-part operations.
|
||||
reqBlockUpdates = ((tokenLabel[0] == 'N' && tokenLabel[1] == 'S'
|
||||
&& tokenLabel[2] == 'S') ? true : false);
|
||||
reqBlockUpdates = P11Util.isNSS(token);
|
||||
}
|
||||
} else {
|
||||
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.
|
||||
*
|
||||
* 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.sensitive = sensitive;
|
||||
this.extractable = extractable;
|
||||
char[] tokenLabel = this.token.tokenInfo.label;
|
||||
isNSS = (tokenLabel[0] == 'N' && tokenLabel[1] == 'S'
|
||||
&& tokenLabel[2] == 'S');
|
||||
isNSS = P11Util.isNSS(this.token);
|
||||
boolean extractKeyInfo = (!DISABLE_NATIVE_KEYS_EXTRACTION && isNSS &&
|
||||
extractable && !tokenObject);
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
String algorithm, int keyLength, CK_ATTRIBUTE[] attrs,
|
||||
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")
|
||||
private static class P11TlsMasterSecretKey extends P11SecretKey
|
||||
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.
|
||||
*
|
||||
* 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.spec.AlgorithmParameterSpec;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
import javax.crypto.MacSpi;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.PBEParameterSpec;
|
||||
|
||||
import jdk.internal.access.JavaNioAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
@ -39,6 +42,7 @@ import sun.nio.ch.DirectBuffer;
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;
|
||||
import sun.security.util.PBEUtil;
|
||||
|
||||
/**
|
||||
* MAC implementation class. This class currently supports HMAC using
|
||||
@ -65,6 +69,9 @@ final class P11Mac extends MacSpi {
|
||||
// algorithm name
|
||||
private final String algorithm;
|
||||
|
||||
// PBEKeyInfo if algorithm is PBE-related, otherwise null
|
||||
private final P11SecretKeyFactory.PBEKeyInfo svcPbeKi;
|
||||
|
||||
// mechanism object
|
||||
private final CK_MECHANISM ckMechanism;
|
||||
|
||||
@ -88,6 +95,7 @@ final class P11Mac extends MacSpi {
|
||||
super();
|
||||
this.token = token;
|
||||
this.algorithm = algorithm;
|
||||
this.svcPbeKi = P11SecretKeyFactory.getPBEKeyInfo(algorithm);
|
||||
Long params = null;
|
||||
macLength = switch ((int) mechanism) {
|
||||
case (int) CKM_MD5_HMAC -> 16;
|
||||
@ -192,12 +200,53 @@ final class P11Mac extends MacSpi {
|
||||
// see JCE spec
|
||||
protected void engineInit(Key key, AlgorithmParameterSpec params)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
if (params != null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Parameters not supported");
|
||||
}
|
||||
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 {
|
||||
initialize();
|
||||
} 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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,15 +25,19 @@
|
||||
|
||||
package sun.security.pkcs11;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.interfaces.PBEKey;
|
||||
import javax.crypto.spec.*;
|
||||
|
||||
import static sun.security.pkcs11.TemplateManager.*;
|
||||
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import sun.security.pkcs11.wrapper.*;
|
||||
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
|
||||
|
||||
@ -52,44 +56,190 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||
// algorithm name
|
||||
private final String algorithm;
|
||||
|
||||
// PBEKeyInfo if algorithm is PBE-related, otherwise null
|
||||
private final PBEKeyInfo svcPbeKi;
|
||||
|
||||
P11SecretKeyFactory(Token token, String algorithm) {
|
||||
super();
|
||||
this.token = token;
|
||||
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 {
|
||||
keyTypes = new HashMap<String,Long>();
|
||||
addKeyType("RC4", CKK_RC4);
|
||||
addKeyType("ARCFOUR", CKK_RC4);
|
||||
addKeyType("DES", CKK_DES);
|
||||
addKeyType("DESede", CKK_DES3);
|
||||
addKeyType("AES", CKK_AES);
|
||||
addKeyType("Blowfish", CKK_BLOWFISH);
|
||||
addKeyType("ChaCha20", CKK_CHACHA20);
|
||||
addKeyType("ChaCha20-Poly1305", CKK_CHACHA20);
|
||||
putKeyInfo(new KeyInfo("RC4", CKK_RC4));
|
||||
putKeyInfo(new KeyInfo("ARCFOUR", CKK_RC4));
|
||||
putKeyInfo(new KeyInfo("DES", CKK_DES));
|
||||
putKeyInfo(new KeyInfo("DESede", CKK_DES3));
|
||||
putKeyInfo(new KeyInfo("AES", CKK_AES));
|
||||
putKeyInfo(new KeyInfo("Blowfish", CKK_BLOWFISH));
|
||||
putKeyInfo(new KeyInfo("ChaCha20", CKK_CHACHA20));
|
||||
putKeyInfo(new KeyInfo("ChaCha20-Poly1305", CKK_CHACHA20));
|
||||
|
||||
// we don't implement RC2 or IDEA, but we want to be able to generate
|
||||
// keys for those SSL/TLS ciphersuites.
|
||||
addKeyType("RC2", CKK_RC2);
|
||||
addKeyType("IDEA", CKK_IDEA);
|
||||
putKeyInfo(new KeyInfo("RC2", CKK_RC2));
|
||||
putKeyInfo(new KeyInfo("IDEA", CKK_IDEA));
|
||||
|
||||
addKeyType("TlsPremasterSecret", PCKK_TLSPREMASTER);
|
||||
addKeyType("TlsRsaPremasterSecret", PCKK_TLSRSAPREMASTER);
|
||||
addKeyType("TlsMasterSecret", PCKK_TLSMASTER);
|
||||
addKeyType("Generic", CKK_GENERIC_SECRET);
|
||||
putKeyInfo(new KeyInfo("TlsPremasterSecret", PCKK_TLSPREMASTER));
|
||||
putKeyInfo(new KeyInfo("TlsRsaPremasterSecret", PCKK_TLSRSAPREMASTER));
|
||||
putKeyInfo(new KeyInfo("TlsMasterSecret", PCKK_TLSMASTER));
|
||||
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) {
|
||||
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
|
||||
// No pseudo key types
|
||||
static long getPKCS11KeyType(String algorithm) {
|
||||
long kt = getKeyType(algorithm);
|
||||
if (kt == -1 || kt > PCKK_ANY) {
|
||||
@ -98,30 +248,18 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||
return kt;
|
||||
}
|
||||
|
||||
// returns direct lookup result of keyTypes using algorithm
|
||||
static long getKeyType(String algorithm) {
|
||||
Long l = keyTypes.get(algorithm);
|
||||
if (l == null) {
|
||||
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;
|
||||
KeyInfo ki = getKeyInfo(algorithm);
|
||||
return ki == null ? -1 : ki.keyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an arbitrary key of algorithm into a P11Key of provider.
|
||||
* 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 {
|
||||
return convertKey(token, key, algo, null);
|
||||
return convertKey(token, key, svcAlgo, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,30 +267,32 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||
* P11Key of provider.
|
||||
* Used in P11KeyStore.storeSkey.
|
||||
*/
|
||||
static P11Key convertKey(Token token, Key key, String algo,
|
||||
CK_ATTRIBUTE[] extraAttrs)
|
||||
throws InvalidKeyException {
|
||||
static P11Key convertKey(Token token, Key key, String svcAlgo,
|
||||
CK_ATTRIBUTE[] extraAttrs) throws InvalidKeyException {
|
||||
token.ensureValid();
|
||||
if (key == null) {
|
||||
throw new InvalidKeyException("Key must not be null");
|
||||
}
|
||||
if (!(key instanceof SecretKey)) {
|
||||
throw new InvalidKeyException("Key must be a SecretKey");
|
||||
}
|
||||
long algoType;
|
||||
if (algo == null) {
|
||||
algo = key.getAlgorithm();
|
||||
algoType = getKeyType(algo);
|
||||
} else {
|
||||
algoType = getKeyType(algo);
|
||||
long keyAlgorithmType = getKeyType(key.getAlgorithm());
|
||||
if (algoType != keyAlgorithmType) {
|
||||
if ((algoType == PCKK_HMAC) || (algoType == PCKK_SSLMAC)) {
|
||||
// ignore key algorithm for MACs
|
||||
} else {
|
||||
throw new InvalidKeyException
|
||||
("Key algorithm must be " + algo);
|
||||
}
|
||||
final String keyAlgo = key.getAlgorithm();
|
||||
if (keyAlgo == null) {
|
||||
throw new InvalidKeyException("Key must specify its algorithm");
|
||||
}
|
||||
if (svcAlgo == null) {
|
||||
svcAlgo = keyAlgo;
|
||||
}
|
||||
KeyInfo ki = null;
|
||||
KeyInfo si = getKeyInfo(svcAlgo);
|
||||
if (si == null) {
|
||||
throw new InvalidKeyException("Unknown algorithm " + svcAlgo);
|
||||
}
|
||||
// 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) {
|
||||
@ -184,15 +324,159 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||
if (p11Key != null) {
|
||||
return p11Key;
|
||||
}
|
||||
if (!"RAW".equalsIgnoreCase(key.getFormat())) {
|
||||
throw new InvalidKeyException("Encoded format must be RAW");
|
||||
if (key instanceof PBEKey pbeKey) {
|
||||
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);
|
||||
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) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
int b = key[offset] & 0xfe;
|
||||
@ -286,36 +570,51 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||
if (keySpec == null) {
|
||||
throw new InvalidKeySpecException("KeySpec must not be null");
|
||||
}
|
||||
if (keySpec instanceof SecretKeySpec) {
|
||||
if (keySpec instanceof SecretKeySpec secretKeySpec) {
|
||||
try {
|
||||
Key key = convertKey(token, (SecretKey)keySpec, algorithm);
|
||||
Key key = convertKey(token, secretKeySpec, algorithm);
|
||||
return (SecretKey)key;
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InvalidKeySpecException(e);
|
||||
}
|
||||
} else if (keySpec instanceof PBEKeySpec pbeKeySpec &&
|
||||
svcPbeKi != null) {
|
||||
return derivePBEKey(token, pbeKeySpec, svcPbeKi);
|
||||
} else if (algorithm.equalsIgnoreCase("DES")) {
|
||||
if (keySpec instanceof DESKeySpec) {
|
||||
byte[] keyBytes = ((DESKeySpec)keySpec).getKey();
|
||||
keySpec = new SecretKeySpec(keyBytes, "DES");
|
||||
return engineGenerateSecret(keySpec);
|
||||
if (keySpec instanceof DESKeySpec desKeySpec) {
|
||||
return generateDESSecret(desKeySpec.getKey(), "DES");
|
||||
}
|
||||
} else if (algorithm.equalsIgnoreCase("DESede")) {
|
||||
if (keySpec instanceof DESedeKeySpec) {
|
||||
byte[] keyBytes = ((DESedeKeySpec)keySpec).getKey();
|
||||
keySpec = new SecretKeySpec(keyBytes, "DESede");
|
||||
return engineGenerateSecret(keySpec);
|
||||
if (keySpec instanceof DESedeKeySpec desEdeKeySpec) {
|
||||
return generateDESSecret(desEdeKeySpec.getKey(), "DESede");
|
||||
}
|
||||
}
|
||||
throw new InvalidKeySpecException
|
||||
("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 {
|
||||
try {
|
||||
key = engineTranslateKey(key);
|
||||
if (!"RAW".equalsIgnoreCase(key.getFormat())) {
|
||||
throw new InvalidKeySpecException
|
||||
("Could not obtain key bytes");
|
||||
throw new InvalidKeySpecException("Could not obtain key bytes");
|
||||
}
|
||||
byte[] k = key.getEncoded();
|
||||
return k;
|
||||
@ -334,6 +633,9 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi {
|
||||
}
|
||||
if (keySpec.isAssignableFrom(SecretKeySpec.class)) {
|
||||
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")) {
|
||||
try {
|
||||
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.
|
||||
*
|
||||
* 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.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.*;
|
||||
|
||||
import sun.security.pkcs11.wrapper.PKCS11Exception;
|
||||
@ -51,6 +54,46 @@ public final class P11Util {
|
||||
// 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() {
|
||||
Provider p = sun;
|
||||
if (p == null) {
|
||||
|
@ -421,14 +421,23 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
final String className;
|
||||
final List<String> aliases;
|
||||
final int[] mechanisms;
|
||||
final int[] requiredMechs;
|
||||
|
||||
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.algorithm = algorithm;
|
||||
this.className = className;
|
||||
this.aliases = aliases;
|
||||
this.mechanisms = mechanisms;
|
||||
this.requiredMechs = requiredMechs;
|
||||
}
|
||||
private P11Service service(Token token, int mechanism) {
|
||||
return new P11Service
|
||||
@ -470,12 +479,24 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
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,
|
||||
int[] m) {
|
||||
register(new Descriptor(type, algorithm, className,
|
||||
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) {
|
||||
for (int i = 0; i < d.mechanisms.length; i++) {
|
||||
int m = d.mechanisms[i];
|
||||
@ -526,6 +547,7 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
String P11KeyWrapCipher = "sun.security.pkcs11.P11KeyWrapCipher";
|
||||
String P11RSACipher = "sun.security.pkcs11.P11RSACipher";
|
||||
String P11AEADCipher = "sun.security.pkcs11.P11AEADCipher";
|
||||
String P11PBECipher = "sun.security.pkcs11.P11PBECipher";
|
||||
String P11Signature = "sun.security.pkcs11.P11Signature";
|
||||
String P11PSSSignature = "sun.security.pkcs11.P11PSSSignature";
|
||||
|
||||
@ -588,6 +610,24 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
d(MAC, "SslMacSHA1", P11Mac,
|
||||
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,
|
||||
getAliases("PKCS1"),
|
||||
m(CKM_RSA_PKCS_KEY_PAIR_GEN));
|
||||
@ -686,6 +726,60 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
d(SKF, "ChaCha20", P11SecretKeyFactory,
|
||||
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)
|
||||
dA(CIP, "ARCFOUR", P11Cipher,
|
||||
m(CKM_RC4));
|
||||
@ -779,6 +873,44 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
d(CIP, "RSA/ECB/NoPadding", P11RSACipher,
|
||||
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,
|
||||
List.of("NONEwithDSA"),
|
||||
m(CKM_DSA));
|
||||
@ -1169,9 +1301,21 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
if (ds == null) {
|
||||
continue;
|
||||
}
|
||||
descLoop:
|
||||
for (Descriptor d : ds) {
|
||||
Integer oldMech = supportedAlgs.get(d);
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
@ -1272,6 +1416,8 @@ public final class SunPKCS11 extends AuthProvider {
|
||||
} else if (algorithm.contains("/KW/") ||
|
||||
algorithm.contains("/KWP/")) {
|
||||
return new P11KeyWrapCipher(token, algorithm, mechanism);
|
||||
} else if (algorithm.startsWith("PBE")) {
|
||||
return new P11PBECipher(token, algorithm, mechanism);
|
||||
} else {
|
||||
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.
|
||||
@ -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() {
|
||||
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.
|
||||
@ -160,6 +160,18 @@ public class CK_MECHANISM {
|
||||
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
|
||||
// CK_MECHANISM(long) constructor and setParameter(CK_RSA_PKCS_PSS_PARAMS)
|
||||
// methods instead of creating yet another constructor
|
||||
@ -193,11 +205,12 @@ public class CK_MECHANISM {
|
||||
|
||||
sb.append(Constants.INDENT);
|
||||
sb.append("mechanism: ");
|
||||
sb.append(mechanism);
|
||||
sb.append(Functions.getMechanismName(mechanism));
|
||||
sb.append(Constants.NEWLINE);
|
||||
|
||||
sb.append(Constants.INDENT);
|
||||
sb.append("pParameter: ");
|
||||
sb.append("pParameter:");
|
||||
sb.append(Constants.NEWLINE);
|
||||
sb.append(pParameter.toString());
|
||||
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>
|
||||
* <B>PKCS#11 structure:</B>
|
||||
* <PRE>
|
||||
* typedef struct CK_PBE_PARAMS {
|
||||
* CK_CHAR_PTR pInitVector;
|
||||
* CK_CHAR_PTR pPassword;
|
||||
* CK_BYTE_PTR pInitVector;
|
||||
* CK_UTF8CHAR_PTR pPassword;
|
||||
* CK_ULONG ulPasswordLen;
|
||||
* CK_CHAR_PTR pSalt;
|
||||
* CK_BYTE_PTR pSalt;
|
||||
* CK_ULONG ulSaltLen;
|
||||
* CK_ULONG ulIteration;
|
||||
* } CK_PBE_PARAMS;
|
||||
@ -72,15 +72,15 @@ public class CK_PBE_PARAMS {
|
||||
/**
|
||||
* <B>PKCS#11:</B>
|
||||
* <PRE>
|
||||
* CK_CHAR_PTR pInitVector;
|
||||
* CK_BYTE_PTR pInitVector;
|
||||
* </PRE>
|
||||
*/
|
||||
public char[] pInitVector;
|
||||
public byte[] pInitVector;
|
||||
|
||||
/**
|
||||
* <B>PKCS#11:</B>
|
||||
* <PRE>
|
||||
* CK_CHAR_PTR pPassword;
|
||||
* CK_UTF8CHAR_PTR pPassword;
|
||||
* CK_ULONG ulPasswordLen;
|
||||
* </PRE>
|
||||
*/
|
||||
@ -89,11 +89,11 @@ public class CK_PBE_PARAMS {
|
||||
/**
|
||||
* <B>PKCS#11:</B>
|
||||
* <PRE>
|
||||
* CK_CHAR_PTR pSalt
|
||||
* CK_BYTE_PTR pSalt
|
||||
* CK_ULONG ulSaltLen;
|
||||
* </PRE>
|
||||
*/
|
||||
public char[] pSalt;
|
||||
public byte[] pSalt;
|
||||
|
||||
/**
|
||||
* <B>PKCS#11:</B>
|
||||
@ -103,6 +103,12 @@ public class CK_PBE_PARAMS {
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -47,7 +47,7 @@
|
||||
|
||||
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
|
||||
@ -55,13 +55,15 @@ package sun.security.pkcs11.wrapper;
|
||||
* <B>PKCS#11 structure:</B>
|
||||
* <PRE>
|
||||
* 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_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_PTR ulPasswordLen;
|
||||
* } CK_PKCS5_PBKD2_PARAMS;
|
||||
* </PRE>
|
||||
*
|
||||
@ -112,6 +114,24 @@ public class CK_PKCS5_PBKD2_PARAMS {
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@ -122,7 +142,7 @@ public class CK_PKCS5_PBKD2_PARAMS {
|
||||
|
||||
sb.append(Constants.INDENT);
|
||||
sb.append("saltSource: ");
|
||||
sb.append(saltSource);
|
||||
sb.append(Functions.getParamSourcesName(saltSource));
|
||||
sb.append(Constants.NEWLINE);
|
||||
|
||||
sb.append(Constants.INDENT);
|
||||
@ -132,7 +152,7 @@ public class CK_PKCS5_PBKD2_PARAMS {
|
||||
|
||||
sb.append(Constants.INDENT);
|
||||
sb.append("ulSaltSourceDataLen: ");
|
||||
sb.append(pSaltSourceData.length);
|
||||
sb.append(Functions.getLength(pSaltSourceData));
|
||||
sb.append(Constants.NEWLINE);
|
||||
|
||||
sb.append(Constants.INDENT);
|
||||
@ -142,7 +162,7 @@ public class CK_PKCS5_PBKD2_PARAMS {
|
||||
|
||||
sb.append(Constants.INDENT);
|
||||
sb.append("prf: ");
|
||||
sb.append(prf);
|
||||
sb.append(Functions.getPrfName(prf));
|
||||
sb.append(Constants.NEWLINE);
|
||||
|
||||
sb.append(Constants.INDENT);
|
||||
@ -152,7 +172,7 @@ public class CK_PKCS5_PBKD2_PARAMS {
|
||||
|
||||
sb.append(Constants.INDENT);
|
||||
sb.append("ulPrfDataLen: ");
|
||||
sb.append(pPrfData.length);
|
||||
sb.append(Functions.getLength(pPrfData));
|
||||
//buffer.append(Constants.NEWLINE);
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
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.
|
||||
@ -104,6 +104,20 @@ public class Functions {
|
||||
private static final Map<String,Integer> mgfIds =
|
||||
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.
|
||||
*/
|
||||
@ -208,6 +222,16 @@ public class Functions {
|
||||
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 final long[] flagIds;
|
||||
private final String[] flagNames;
|
||||
@ -483,6 +507,22 @@ public class Functions {
|
||||
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
|
||||
* 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);
|
||||
}
|
||||
|
||||
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
|
||||
static {
|
||||
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_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_KEYSTORE, "KeyStore");
|
||||
@ -1352,6 +1408,20 @@ public class Functions {
|
||||
addMGF(CKG_MGF1_SHA3_256, "CKG_MGF1_SHA3_256");
|
||||
addMGF(CKG_MGF1_SHA3_384, "CKG_MGF1_SHA3_384");
|
||||
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.
|
||||
@ -999,6 +999,15 @@ public interface PKCS11Constants {
|
||||
|
||||
// NSS private
|
||||
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
|
||||
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_384_KDF = 0x00000019L;
|
||||
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_GOSTR3411 = 0x00000002L;
|
||||
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 CK_OTP_VALUE = 0x00000000L;
|
||||
public static final long CK_OTP_PIN = 0x00000001L;
|
||||
public static final long CK_OTP_CHALLENGE = 0x00000002L;
|
||||
@ -1153,9 +1165,9 @@ public interface PKCS11Constants {
|
||||
// private NSS attribute (for DSA and DH private keys)
|
||||
public static final long CKA_NETSCAPE_DB = 0xD5A0DB00L;
|
||||
|
||||
// base number of NSS private attributes
|
||||
public static final long CKA_NETSCAPE_BASE /*0x80000000L + 0x4E534350L*/
|
||||
= 0xCE534350L;
|
||||
// base number of NSS private attributes. CKA_NETSCAPE_BASE is now known as
|
||||
// CKM_NSS = CKM_VENDOR_DEFINED | NSSCK_VENDOR_NSS = 0x80000000 | 0x4E534350
|
||||
public static final long CKA_NETSCAPE_BASE = 0xCE534350L;
|
||||
|
||||
// object type for NSS trust
|
||||
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:
|
||||
ckpParamPtr = jRsaPkcsOaepParamToCKRsaPkcsOaepParamPtr(env, jParam, ckpLength);
|
||||
break;
|
||||
case CKM_PBE_SHA1_DES3_EDE_CBC:
|
||||
case CKM_PBE_SHA1_DES2_EDE_CBC:
|
||||
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);
|
||||
break;
|
||||
case CKM_PKCS5_PBKD2:
|
||||
@ -1658,13 +1660,13 @@ jPbeParamToCKPbeParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
|
||||
// retrieve java values
|
||||
jPbeParamsClass = (*env)->FindClass(env, CLASS_PBE_PARAMS);
|
||||
if (jPbeParamsClass == NULL) { return NULL; }
|
||||
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pInitVector", "[C");
|
||||
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pInitVector", "[B");
|
||||
if (fieldID == NULL) { return NULL; }
|
||||
jInitVector = (*env)->GetObjectField(env, jParam, fieldID);
|
||||
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "pPassword", "[C");
|
||||
if (fieldID == NULL) { return NULL; }
|
||||
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; }
|
||||
jSalt = (*env)->GetObjectField(env, jParam, fieldID);
|
||||
fieldID = (*env)->GetFieldID(env, jPbeParamsClass, "ulIteration", "J");
|
||||
@ -1680,15 +1682,15 @@ jPbeParamToCKPbeParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
|
||||
|
||||
// populate using java values
|
||||
ckParamPtr->ulIteration = jLongToCKULong(jIteration);
|
||||
jCharArrayToCKCharArray(env, jInitVector, &(ckParamPtr->pInitVector), &ckTemp);
|
||||
jByteArrayToCKByteArray(env, jInitVector, &(ckParamPtr->pInitVector), &ckTemp);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
goto cleanup;
|
||||
}
|
||||
jCharArrayToCKCharArray(env, jPassword, &(ckParamPtr->pPassword), &(ckParamPtr->ulPasswordLen));
|
||||
jCharArrayToCKUTF8CharArray(env, jPassword, &(ckParamPtr->pPassword), &(ckParamPtr->ulPasswordLen));
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
goto cleanup;
|
||||
}
|
||||
jCharArrayToCKCharArray(env, jSalt, &(ckParamPtr->pSalt), &(ckParamPtr->ulSaltLen));
|
||||
jByteArrayToCKByteArray(env, jSalt, &(ckParamPtr->pSalt), &(ckParamPtr->ulSaltLen));
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
goto cleanup;
|
||||
}
|
||||
@ -1699,6 +1701,9 @@ jPbeParamToCKPbeParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength)
|
||||
return ckParamPtr;
|
||||
cleanup:
|
||||
free(ckParamPtr->pInitVector);
|
||||
if (ckParamPtr->pPassword != NULL) {
|
||||
memset(ckParamPtr->pPassword, 0, ckParamPtr->ulPasswordLen);
|
||||
}
|
||||
free(ckParamPtr->pPassword);
|
||||
free(ckParamPtr->pSalt);
|
||||
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
|
||||
*
|
||||
* @param env - used to call JNI funktions to get the Java classes and objects
|
||||
* @param jParam - the Java CK_PKCS5_PBKD2_PARAMS object to convert
|
||||
* @param env - used to call JNI functions to get the Java classes and objects
|
||||
* @param jParam - the Java object to convert
|
||||
* @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)
|
||||
{
|
||||
CK_PKCS5_PBKD2_PARAMS_PTR ckParamPtr;
|
||||
VersionedPbkd2ParamsPtr ckParamPtr;
|
||||
ParamVersion paramVersion;
|
||||
CK_ULONG_PTR pUlPasswordLen;
|
||||
jclass jPkcs5Pbkd2ParamsClass;
|
||||
jfieldID fieldID;
|
||||
jlong jSaltSource, jIteration, jPrf;
|
||||
jobject jSaltSourceData, jPrfData;
|
||||
jobject jSaltSourceData, jPrfData, jPassword;
|
||||
|
||||
if (pLength != NULL) {
|
||||
*pLength = 0L;
|
||||
}
|
||||
|
||||
// retrieve java values
|
||||
jPkcs5Pbkd2ParamsClass = (*env)->FindClass(env, CLASS_PKCS5_PBKD2_PARAMS);
|
||||
if (jPkcs5Pbkd2ParamsClass == NULL) { return NULL; }
|
||||
if ((jPkcs5Pbkd2ParamsClass =
|
||||
(*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");
|
||||
if (fieldID == NULL) { return NULL; }
|
||||
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");
|
||||
if (fieldID == NULL) { return NULL; }
|
||||
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
|
||||
ckParamPtr = calloc(1, sizeof(CK_PKCS5_PBKD2_PARAMS));
|
||||
// allocate memory for VersionedPbkd2Params and store the structure version
|
||||
ckParamPtr = calloc(1, sizeof(VersionedPbkd2Params));
|
||||
if (ckParamPtr == NULL) {
|
||||
p11ThrowOutOfMemoryError(env, 0);
|
||||
return NULL;
|
||||
}
|
||||
ckParamPtr->version = paramVersion;
|
||||
|
||||
// populate using java values
|
||||
ckParamPtr->saltSource = jLongToCKULong(jSaltSource);
|
||||
jByteArrayToCKByteArray(env, jSaltSourceData, (CK_BYTE_PTR *)
|
||||
&(ckParamPtr->pSaltSourceData), &(ckParamPtr->ulSaltSourceDataLen));
|
||||
PBKD2_PARAM_SET(saltSource, jLongToCKULong(jSaltSource));
|
||||
jByteArrayToCKByteArray(env, jSaltSourceData,
|
||||
(CK_BYTE_PTR *) PBKD2_PARAM_ADDR(pSaltSourceData),
|
||||
PBKD2_PARAM_ADDR(ulSaltSourceDataLen));
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
goto cleanup;
|
||||
}
|
||||
ckParamPtr->iterations = jLongToCKULong(jIteration);
|
||||
ckParamPtr->prf = jLongToCKULong(jPrf);
|
||||
jByteArrayToCKByteArray(env, jPrfData, (CK_BYTE_PTR *)
|
||||
&(ckParamPtr->pPrfData), &(ckParamPtr->ulPrfDataLen));
|
||||
PBKD2_PARAM_SET(iterations, jLongToCKULong(jIteration));
|
||||
PBKD2_PARAM_SET(prf, jLongToCKULong(jPrf));
|
||||
jByteArrayToCKByteArray(env, jPrfData,
|
||||
(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)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
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;
|
||||
cleanup:
|
||||
free(ckParamPtr->pSaltSourceData);
|
||||
free(ckParamPtr->pPrfData);
|
||||
FREE_VERSIONED_PBKD2_MEMBERS(ckParamPtr);
|
||||
free(ckParamPtr);
|
||||
return NULL;
|
||||
|
||||
|
@ -408,11 +408,32 @@ void freeCKMechanismPtr(CK_MECHANISM_PTR mechPtr) {
|
||||
case CKM_CAMELLIA_CTR:
|
||||
// params do not contain pointers
|
||||
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:
|
||||
// currently unsupported mechs by SunPKCS11 provider
|
||||
// CKM_RSA_PKCS_OAEP, CKM_ECMQV_DERIVE,
|
||||
// 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,
|
||||
// CKM_EXTRACT_KEY_FROM_KEY, CKM_OTP, CKM_KIP,
|
||||
// CKM_DSA_PARAMETER_GEN?, CKM_GOSTR3410_*
|
||||
@ -515,12 +536,11 @@ void jBooleanArrayToCKBBoolArray(JNIEnv *env, const jbooleanArray jArray, CK_BBO
|
||||
jboolean* jpTemp;
|
||||
CK_ULONG i;
|
||||
|
||||
if(jArray == NULL) {
|
||||
*ckpLength = jArray == NULL ? 0L : (*env)->GetArrayLength(env, jArray);
|
||||
if(*ckpLength == 0L) {
|
||||
*ckpArray = NULL_PTR;
|
||||
*ckpLength = 0L;
|
||||
return;
|
||||
}
|
||||
*ckpLength = (*env)->GetArrayLength(env, jArray);
|
||||
jpTemp = (jboolean*) calloc(*ckpLength, sizeof(jboolean));
|
||||
if (jpTemp == NULL) {
|
||||
p11ThrowOutOfMemoryError(env, 0);
|
||||
@ -557,12 +577,11 @@ void jByteArrayToCKByteArray(JNIEnv *env, const jbyteArray jArray, CK_BYTE_PTR *
|
||||
jbyte* jpTemp;
|
||||
CK_ULONG i;
|
||||
|
||||
if(jArray == NULL) {
|
||||
*ckpLength = jArray == NULL ? 0L : (*env)->GetArrayLength(env, jArray);
|
||||
if(*ckpLength == 0L) {
|
||||
*ckpArray = NULL_PTR;
|
||||
*ckpLength = 0L;
|
||||
return;
|
||||
}
|
||||
*ckpLength = (*env)->GetArrayLength(env, jArray);
|
||||
jpTemp = (jbyte*) calloc(*ckpLength, sizeof(jbyte));
|
||||
if (jpTemp == NULL) {
|
||||
p11ThrowOutOfMemoryError(env, 0);
|
||||
@ -604,12 +623,11 @@ void jLongArrayToCKULongArray(JNIEnv *env, const jlongArray jArray, CK_ULONG_PTR
|
||||
jlong* jTemp;
|
||||
CK_ULONG i;
|
||||
|
||||
if(jArray == NULL) {
|
||||
*ckpLength = jArray == NULL ? 0L : (*env)->GetArrayLength(env, jArray);
|
||||
if(*ckpLength == 0L) {
|
||||
*ckpArray = NULL_PTR;
|
||||
*ckpLength = 0L;
|
||||
return;
|
||||
}
|
||||
*ckpLength = (*env)->GetArrayLength(env, jArray);
|
||||
jTemp = (jlong*) calloc(*ckpLength, sizeof(jlong));
|
||||
if (jTemp == NULL) {
|
||||
p11ThrowOutOfMemoryError(env, 0);
|
||||
@ -646,12 +664,11 @@ void jCharArrayToCKCharArray(JNIEnv *env, const jcharArray jArray, CK_CHAR_PTR *
|
||||
jchar* jpTemp;
|
||||
CK_ULONG i;
|
||||
|
||||
if(jArray == NULL) {
|
||||
*ckpLength = jArray == NULL ? 0L : (*env)->GetArrayLength(env, jArray);
|
||||
if(*ckpLength == 0L) {
|
||||
*ckpArray = NULL_PTR;
|
||||
*ckpLength = 0L;
|
||||
return;
|
||||
}
|
||||
*ckpLength = (*env)->GetArrayLength(env, jArray);
|
||||
jpTemp = (jchar*) calloc(*ckpLength, sizeof(jchar));
|
||||
if (jpTemp == NULL) {
|
||||
p11ThrowOutOfMemoryError(env, 0);
|
||||
@ -688,12 +705,11 @@ void jCharArrayToCKUTF8CharArray(JNIEnv *env, const jcharArray jArray, CK_UTF8CH
|
||||
jchar* jTemp;
|
||||
CK_ULONG i;
|
||||
|
||||
if(jArray == NULL) {
|
||||
*ckpLength = jArray == NULL ? 0L : (*env)->GetArrayLength(env, jArray);
|
||||
if(*ckpLength == 0L) {
|
||||
*ckpArray = NULL_PTR;
|
||||
*ckpLength = 0L;
|
||||
return;
|
||||
}
|
||||
*ckpLength = (*env)->GetArrayLength(env, jArray);
|
||||
jTemp = (jchar*) calloc(*ckpLength, sizeof(jchar));
|
||||
if (jTemp == NULL) {
|
||||
p11ThrowOutOfMemoryError(env, 0);
|
||||
@ -701,19 +717,20 @@ void jCharArrayToCKUTF8CharArray(JNIEnv *env, const jcharArray jArray, CK_UTF8CH
|
||||
}
|
||||
(*env)->GetCharArrayRegion(env, jArray, 0, *ckpLength, jTemp);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
free(jTemp);
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*ckpArray = (CK_UTF8CHAR_PTR) calloc(*ckpLength, sizeof(CK_UTF8CHAR));
|
||||
if (*ckpArray == NULL) {
|
||||
free(jTemp);
|
||||
p11ThrowOutOfMemoryError(env, 0);
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
for (i=0; i<(*ckpLength); i++) {
|
||||
(*ckpArray)[i] = jCharToCKUTF8Char(jTemp[i]);
|
||||
}
|
||||
cleanup:
|
||||
// Clean possible temporary copies of passwords.
|
||||
memset(jTemp, 0, *ckpLength * sizeof(jchar));
|
||||
free(jTemp);
|
||||
}
|
||||
|
||||
|
@ -67,15 +67,22 @@
|
||||
|
||||
/* 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_TRUST_BASE (CKA_NETSCAPE_BASE + 0x2000)
|
||||
#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_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_DB 0xD5A0DB00
|
||||
#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
|
||||
@ -271,6 +278,7 @@ void printDebug(const char *format, ...);
|
||||
#define CLASS_PBE_PARAMS "sun/security/pkcs11/wrapper/CK_PBE_PARAMS"
|
||||
#define PBE_INIT_VECTOR_SIZE 8
|
||||
#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_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,
|
||||
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_KEY_MAT_PARAMS_PTR jSsl3KeyMatParamToCKSsl3KeyMatParamPtr(JNIEnv *env, jobject jParam, CK_ULONG* pLength);
|
||||
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_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 */
|
||||
|
||||
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.
|
||||
*
|
||||
* 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.NoSuchProviderException;
|
||||
import java.security.Provider;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.List;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class MacSameTest extends PKCS11Test {
|
||||
|
||||
@ -69,14 +67,10 @@ public class MacSameTest extends PKCS11Test {
|
||||
public void main(Provider p) {
|
||||
List<String> algorithms = getSupportedAlgorithms("Mac", "Hmac", p);
|
||||
boolean success = true;
|
||||
SecureRandom srdm = new SecureRandom();
|
||||
|
||||
for (String alg : algorithms) {
|
||||
// first try w/ java secret key object
|
||||
byte[] keyVal = new byte[KEY_SIZE];
|
||||
srdm.nextBytes(keyVal);
|
||||
SecretKey skey = new SecretKeySpec(keyVal, alg);
|
||||
|
||||
SecretKey skey = generateKey(alg, KEY_SIZE);
|
||||
try {
|
||||
doTest(alg, skey, p);
|
||||
} catch (Exception e) {
|
||||
@ -86,6 +80,7 @@ public class MacSameTest extends PKCS11Test {
|
||||
}
|
||||
|
||||
try {
|
||||
// No KeyGenerator support for PBE
|
||||
KeyGenerator kg = KeyGenerator.getInstance(alg, p);
|
||||
kg.init(KEY_SIZE);
|
||||
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.
|
||||
*
|
||||
* 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.List;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
public class ReinitMac extends PKCS11Test {
|
||||
|
||||
@ -51,13 +51,12 @@ public class ReinitMac extends PKCS11Test {
|
||||
Random random = new Random();
|
||||
byte[] data = new byte[10 * 1024];
|
||||
random.nextBytes(data);
|
||||
byte[] keyVal = new byte[16];
|
||||
random.nextBytes(keyVal);
|
||||
|
||||
boolean success = true;
|
||||
for (String alg : algorithms) {
|
||||
SecretKey skey = generateKey(alg, 16);
|
||||
try {
|
||||
doTest(alg, p, keyVal, data);
|
||||
doTest(alg, p, skey, data);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Unexpected exception: " + e);
|
||||
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 {
|
||||
System.out.println("Testing " + alg);
|
||||
SecretKeySpec key = new SecretKeySpec(keyVal, alg);
|
||||
Mac mac = Mac.getInstance(alg, p);
|
||||
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.
|
||||
*
|
||||
* 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.Provider;
|
||||
import java.security.ProviderException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.security.spec.ECParameterSpec;
|
||||
@ -55,6 +56,9 @@ import java.util.ServiceConfigurationError;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import jdk.test.lib.artifacts.Artifact;
|
||||
import jdk.test.lib.artifacts.ArtifactResolver;
|
||||
import jdk.test.lib.artifacts.ArtifactResolverException;
|
||||
@ -828,6 +832,58 @@ public abstract class PKCS11Test {
|
||||
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) {
|
||||
byte data[] = new byte[length];
|
||||
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