Skip to content

Commit 4a75fd4

Browse files
martinuyfranferrax
andcommitted
8301553: Support Password-Based Cryptography in SunPKCS11
Co-authored-by: Francisco Ferrari Bihurriet <[email protected]> Co-authored-by: Martin Balao <[email protected]> Reviewed-by: valeriep
1 parent 0a4f9ad commit 4a75fd4

30 files changed

+3008
-447
lines changed

src/java.base/share/classes/com/sun/crypto/provider/HmacPKCS12PBECore.java

Lines changed: 26 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,14 @@
2525

2626
package com.sun.crypto.provider;
2727

28-
import java.util.Arrays;
29-
30-
import javax.crypto.SecretKey;
3128
import javax.crypto.spec.SecretKeySpec;
32-
import javax.crypto.spec.PBEParameterSpec;
29+
import javax.crypto.spec.PBEKeySpec;
3330
import java.security.*;
3431
import java.security.spec.*;
32+
import java.util.Arrays;
33+
34+
import jdk.internal.access.SharedSecrets;
35+
import sun.security.util.PBEUtil;
3536

3637
/**
3738
* This is an implementation of the HMAC algorithms as defined
@@ -108,81 +109,30 @@ public HmacPKCS12PBECore(String algorithm, int bl) throws NoSuchAlgorithmExcepti
108109
*/
109110
protected void engineInit(Key key, AlgorithmParameterSpec params)
110111
throws InvalidKeyException, InvalidAlgorithmParameterException {
111-
char[] passwdChars;
112-
byte[] salt = null;
113-
int iCount = 0;
114-
if (key instanceof javax.crypto.interfaces.PBEKey) {
115-
javax.crypto.interfaces.PBEKey pbeKey =
116-
(javax.crypto.interfaces.PBEKey) key;
117-
passwdChars = pbeKey.getPassword();
118-
salt = pbeKey.getSalt(); // maybe null if unspecified
119-
iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified
120-
} else if (key instanceof SecretKey) {
121-
byte[] passwdBytes;
122-
if (!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3)) ||
123-
(passwdBytes = key.getEncoded()) == null) {
124-
throw new InvalidKeyException("Missing password");
125-
}
126-
passwdChars = new char[passwdBytes.length];
127-
for (int i=0; i<passwdChars.length; i++) {
128-
passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
129-
}
130-
Arrays.fill(passwdBytes, (byte)0x00);
131-
} else {
132-
throw new InvalidKeyException("SecretKey of PBE type required");
133-
}
134-
135-
byte[] derivedKey;
112+
char[] password = null;
113+
byte[] derivedKey = null;
114+
SecretKeySpec cipherKey = null;
115+
PBEKeySpec keySpec = PBEUtil.getPBAKeySpec(key, params);
136116
try {
137-
if (params == null) {
138-
// should not auto-generate default values since current
139-
// javax.crypto.Mac api does not have any method for caller to
140-
// retrieve the generated defaults.
141-
if ((salt == null) || (iCount == 0)) {
142-
throw new InvalidAlgorithmParameterException
143-
("PBEParameterSpec required for salt and iteration count");
144-
}
145-
} else if (!(params instanceof PBEParameterSpec)) {
146-
throw new InvalidAlgorithmParameterException
147-
("PBEParameterSpec type required");
148-
} else {
149-
PBEParameterSpec pbeParams = (PBEParameterSpec) params;
150-
// make sure the parameter values are consistent
151-
if (salt != null) {
152-
if (!Arrays.equals(salt, pbeParams.getSalt())) {
153-
throw new InvalidAlgorithmParameterException
154-
("Inconsistent value of salt between key and params");
155-
}
156-
} else {
157-
salt = pbeParams.getSalt();
158-
}
159-
if (iCount != 0) {
160-
if (iCount != pbeParams.getIterationCount()) {
161-
throw new InvalidAlgorithmParameterException
162-
("Different iteration count between key and params");
163-
}
164-
} else {
165-
iCount = pbeParams.getIterationCount();
166-
}
117+
password = keySpec.getPassword();
118+
derivedKey = PKCS12PBECipherCore.derive(
119+
password, keySpec.getSalt(),
120+
keySpec.getIterationCount(), engineGetMacLength(),
121+
PKCS12PBECipherCore.MAC_KEY, algorithm, bl);
122+
cipherKey = new SecretKeySpec(derivedKey, "HmacSHA1");
123+
super.engineInit(cipherKey, null);
124+
} finally {
125+
if (cipherKey != null) {
126+
SharedSecrets.getJavaxCryptoSpecAccess()
127+
.clearSecretKeySpec(cipherKey);
167128
}
168-
// For security purpose, we need to enforce a minimum length
169-
// for salt; just require the minimum salt length to be 8-byte
170-
// which is what PKCS#5 recommends and openssl does.
171-
if (salt.length < 8) {
172-
throw new InvalidAlgorithmParameterException
173-
("Salt must be at least 8 bytes long");
129+
if (derivedKey != null) {
130+
Arrays.fill(derivedKey, (byte) 0);
174131
}
175-
if (iCount <= 0) {
176-
throw new InvalidAlgorithmParameterException
177-
("IterationCount must be a positive number");
132+
if (password != null) {
133+
Arrays.fill(password, '\0');
178134
}
179-
derivedKey = PKCS12PBECipherCore.derive(passwdChars, salt,
180-
iCount, engineGetMacLength(), PKCS12PBECipherCore.MAC_KEY,
181-
algorithm, bl);
182-
} finally {
183-
Arrays.fill(passwdChars, '\0');
135+
keySpec.clearPassword();
184136
}
185-
SecretKey cipherKey = new SecretKeySpec(derivedKey, "HmacSHA1");
186-
super.engineInit(cipherKey, null);
187137
}
188138
}

src/java.base/share/classes/com/sun/crypto/provider/PBES2Core.java

Lines changed: 29 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,9 @@
3131
import javax.crypto.*;
3232
import javax.crypto.spec.*;
3333

34+
import jdk.internal.access.SharedSecrets;
35+
import sun.security.util.PBEUtil;
36+
3437
/**
3538
* This class represents password-based encryption as defined by the PKCS #5
3639
* standard.
@@ -43,20 +46,14 @@
4346
* @see javax.crypto.Cipher
4447
*/
4548
abstract class PBES2Core extends CipherSpi {
46-
47-
private static final int DEFAULT_SALT_LENGTH = 20;
48-
private static final int DEFAULT_COUNT = 4096;
49-
5049
// the encapsulated cipher
5150
private final CipherCore cipher;
5251
private final int keyLength; // in bits
5352
private final int blkSize; // in bits
5453
private final PBKDF2Core kdf;
5554
private final String pbeAlgo;
5655
private final String cipherAlgo;
57-
private int iCount = DEFAULT_COUNT;
58-
private byte[] salt = null;
59-
private IvParameterSpec ivSpec = null;
56+
private final PBEUtil.PBES2Params pbes2Params = new PBEUtil.PBES2Params();
6057

6158
/**
6259
* Creates an instance of PBE Scheme 2 according to the selected
@@ -135,32 +132,8 @@ protected byte[] engineGetIV() {
135132
}
136133

137134
protected AlgorithmParameters engineGetParameters() {
138-
AlgorithmParameters params = null;
139-
if (salt == null) {
140-
// generate random salt and use default iteration count
141-
salt = new byte[DEFAULT_SALT_LENGTH];
142-
SunJCE.getRandom().nextBytes(salt);
143-
iCount = DEFAULT_COUNT;
144-
}
145-
if (ivSpec == null) {
146-
// generate random IV
147-
byte[] ivBytes = new byte[blkSize];
148-
SunJCE.getRandom().nextBytes(ivBytes);
149-
ivSpec = new IvParameterSpec(ivBytes);
150-
}
151-
PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount, ivSpec);
152-
try {
153-
params = AlgorithmParameters.getInstance(pbeAlgo,
154-
SunJCE.getInstance());
155-
params.init(pbeSpec);
156-
} catch (NoSuchAlgorithmException nsae) {
157-
// should never happen
158-
throw new RuntimeException("SunJCE called, but not configured");
159-
} catch (InvalidParameterSpecException ipse) {
160-
// should never happen
161-
throw new RuntimeException("PBEParameterSpec not supported");
162-
}
163-
return params;
135+
return pbes2Params.getAlgorithmParameters(
136+
blkSize, pbeAlgo, SunJCE.getInstance(), SunJCE.getRandom());
164137
}
165138

166139
protected void engineInit(int opmode, Key key, SecureRandom random)
@@ -172,132 +145,46 @@ protected void engineInit(int opmode, Key key, SecureRandom random)
172145
}
173146
}
174147

175-
private static byte[] check(byte[] salt)
176-
throws InvalidAlgorithmParameterException {
177-
if (salt != null && salt.length < 8) {
178-
throw new InvalidAlgorithmParameterException(
179-
"Salt must be at least 8 bytes long");
180-
}
181-
return salt;
182-
}
183-
184-
private static int check(int iCount)
185-
throws InvalidAlgorithmParameterException {
186-
if (iCount < 0) {
187-
throw new InvalidAlgorithmParameterException(
188-
"Iteration count must be a positive number");
189-
}
190-
return iCount == 0 ? DEFAULT_COUNT : iCount;
191-
}
192-
193148
protected void engineInit(int opmode, Key key,
194149
AlgorithmParameterSpec params,
195150
SecureRandom random)
196151
throws InvalidKeyException, InvalidAlgorithmParameterException {
197152

198-
if (key == null) {
199-
throw new InvalidKeyException("Null key");
200-
}
201-
202-
byte[] passwdBytes = key.getEncoded();
203-
char[] passwdChars = null;
204-
salt = null;
205-
iCount = 0;
206-
ivSpec = null;
207-
208-
PBEKeySpec pbeSpec;
209-
try {
210-
if ((passwdBytes == null) ||
211-
!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {
212-
throw new InvalidKeyException("Missing password");
213-
}
214-
215-
boolean doEncrypt = ((opmode == Cipher.ENCRYPT_MODE) ||
216-
(opmode == Cipher.WRAP_MODE));
217-
218-
// Extract from the supplied PBE params, if present
219-
if (params instanceof PBEParameterSpec pbeParams) {
220-
// salt should be non-null per PBEParameterSpec
221-
salt = check(pbeParams.getSalt());
222-
iCount = check(pbeParams.getIterationCount());
223-
AlgorithmParameterSpec ivParams = pbeParams.getParameterSpec();
224-
if (ivParams instanceof IvParameterSpec iv) {
225-
ivSpec = iv;
226-
} else if (ivParams == null && doEncrypt) {
227-
// generate random IV
228-
byte[] ivBytes = new byte[blkSize];
229-
random.nextBytes(ivBytes);
230-
ivSpec = new IvParameterSpec(ivBytes);
231-
} else {
232-
throw new InvalidAlgorithmParameterException(
233-
"Wrong parameter type: IV expected");
234-
}
235-
} else if (params == null && doEncrypt) {
236-
// Try extracting from the key if present. If unspecified,
237-
// PBEKey returns null and 0 respectively.
238-
if (key instanceof javax.crypto.interfaces.PBEKey pbeKey) {
239-
salt = check(pbeKey.getSalt());
240-
iCount = check(pbeKey.getIterationCount());
241-
}
242-
if (salt == null) {
243-
// generate random salt
244-
salt = new byte[DEFAULT_SALT_LENGTH];
245-
random.nextBytes(salt);
246-
}
247-
if (iCount == 0) {
248-
// use default iteration count
249-
iCount = DEFAULT_COUNT;
250-
}
251-
// generate random IV
252-
byte[] ivBytes = new byte[blkSize];
253-
random.nextBytes(ivBytes);
254-
ivSpec = new IvParameterSpec(ivBytes);
255-
} else {
256-
throw new InvalidAlgorithmParameterException
257-
("Wrong parameter type: PBE expected");
258-
}
259-
passwdChars = new char[passwdBytes.length];
260-
for (int i = 0; i < passwdChars.length; i++)
261-
passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
262-
263-
pbeSpec = new PBEKeySpec(passwdChars, salt, iCount, keyLength);
264-
} finally {
265-
// password char[] was cloned in PBEKeySpec constructor,
266-
// so we can zero it out here
267-
if (passwdChars != null) Arrays.fill(passwdChars, '\0');
268-
if (passwdBytes != null) Arrays.fill(passwdBytes, (byte)0x00);
269-
}
270-
271-
PBKDF2KeyImpl s;
272-
153+
PBEKeySpec pbeSpec = pbes2Params.getPBEKeySpec(blkSize, keyLength,
154+
opmode, key, params, random);
155+
PBKDF2KeyImpl s = null;
156+
byte[] derivedKey;
273157
try {
274158
s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec);
159+
derivedKey = s.getEncoded();
275160
} catch (InvalidKeySpecException ikse) {
276161
throw new InvalidKeyException("Cannot construct PBE key", ikse);
277162
} finally {
163+
if (s != null) {
164+
s.clear();
165+
}
278166
pbeSpec.clearPassword();
279167
}
280-
byte[] derivedKey = s.getEncoded();
281-
s.clearPassword();
282-
SecretKeySpec cipherKey = new SecretKeySpec(derivedKey, cipherAlgo);
283168

284-
// initialize the underlying cipher
285-
cipher.init(opmode, cipherKey, ivSpec, random);
169+
SecretKeySpec cipherKey = null;
170+
try {
171+
cipherKey = new SecretKeySpec(derivedKey, cipherAlgo);
172+
// initialize the underlying cipher
173+
cipher.init(opmode, cipherKey, pbes2Params.getIvSpec(), random);
174+
} finally {
175+
if (cipherKey != null) {
176+
SharedSecrets.getJavaxCryptoSpecAccess()
177+
.clearSecretKeySpec(cipherKey);
178+
}
179+
Arrays.fill(derivedKey, (byte) 0);
180+
}
286181
}
287182

288183
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
289184
SecureRandom random)
290185
throws InvalidKeyException, InvalidAlgorithmParameterException {
291-
AlgorithmParameterSpec pbeSpec = null;
292-
if (params != null) {
293-
try {
294-
pbeSpec = params.getParameterSpec(PBEParameterSpec.class);
295-
} catch (InvalidParameterSpecException ipse) {
296-
throw new InvalidAlgorithmParameterException(
297-
"Wrong parameter type: PBE expected");
298-
}
299-
}
300-
engineInit(opmode, key, pbeSpec, random);
186+
engineInit(opmode, key, PBEUtil.PBES2Params.getParameterSpec(params),
187+
random);
301188
}
302189

303190
protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {

0 commit comments

Comments
 (0)