Skip to content

Commit 41b1472

Browse files
martinuyfranferrax
andcommitted
8301553: Support Password-Based Cryptography in SunPKCS11 (iteration #2)
Co-authored-by: Francisco Ferrari <[email protected]> Co-authored-by: Martin Balao <[email protected]>
1 parent cd48dc2 commit 41b1472

File tree

13 files changed

+200
-108
lines changed

13 files changed

+200
-108
lines changed

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

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@
2525

2626
package com.sun.crypto.provider;
2727

28-
import javax.crypto.SecretKey;
2928
import javax.crypto.spec.SecretKeySpec;
3029
import javax.crypto.spec.PBEKeySpec;
3130
import java.security.*;
3231
import java.security.spec.*;
32+
import java.util.Arrays;
3333

34+
import jdk.internal.access.SharedSecrets;
3435
import sun.security.util.PBEUtil;
3536

3637
/**
@@ -108,17 +109,30 @@ public HmacPKCS12PBECore(String algorithm, int bl) throws NoSuchAlgorithmExcepti
108109
*/
109110
protected void engineInit(Key key, AlgorithmParameterSpec params)
110111
throws InvalidKeyException, InvalidAlgorithmParameterException {
112+
char[] password = null;
113+
byte[] derivedKey = null;
114+
SecretKeySpec cipherKey = null;
111115
PBEKeySpec keySpec = PBEUtil.getPBAKeySpec(key, params);
112-
byte[] derivedKey;
113116
try {
117+
password = keySpec.getPassword();
114118
derivedKey = PKCS12PBECipherCore.derive(
115-
keySpec.getPassword(), keySpec.getSalt(),
119+
password, keySpec.getSalt(),
116120
keySpec.getIterationCount(), engineGetMacLength(),
117121
PKCS12PBECipherCore.MAC_KEY, algorithm, bl);
122+
cipherKey = new SecretKeySpec(derivedKey, "HmacSHA1");
123+
super.engineInit(cipherKey, null);
118124
} finally {
125+
if (cipherKey != null) {
126+
SharedSecrets.getJavaxCryptoSpecAccess()
127+
.clearSecretKeySpec(cipherKey);
128+
}
129+
if (derivedKey != null) {
130+
Arrays.fill(derivedKey, (byte) 0);
131+
}
132+
if (password != null) {
133+
Arrays.fill(password, '\0');
134+
}
119135
keySpec.clearPassword();
120136
}
121-
SecretKey cipherKey = new SecretKeySpec(derivedKey, "HmacSHA1");
122-
super.engineInit(cipherKey, null);
123137
}
124138
}

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

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@
2727

2828
import java.security.*;
2929
import java.security.spec.*;
30+
import java.util.Arrays;
3031
import javax.crypto.*;
3132
import javax.crypto.spec.*;
3233

34+
import jdk.internal.access.SharedSecrets;
3335
import sun.security.util.PBEUtil;
3436

3537
/**
@@ -150,22 +152,32 @@ protected void engineInit(int opmode, Key key,
150152

151153
PBEKeySpec pbeSpec = pbes2Params.getPBEKeySpec(blkSize, keyLength,
152154
opmode, key, params, random);
153-
154-
PBKDF2KeyImpl s;
155-
155+
PBKDF2KeyImpl s = null;
156+
byte[] derivedKey;
156157
try {
157158
s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec);
159+
derivedKey = s.getEncoded();
158160
} catch (InvalidKeySpecException ikse) {
159161
throw new InvalidKeyException("Cannot construct PBE key", ikse);
160162
} finally {
163+
if (s != null) {
164+
s.clear();
165+
}
161166
pbeSpec.clearPassword();
162167
}
163-
byte[] derivedKey = s.getEncoded();
164-
s.clearPassword();
165-
SecretKeySpec cipherKey = new SecretKeySpec(derivedKey, cipherAlgo);
166168

167-
// initialize the underlying cipher
168-
cipher.init(opmode, cipherKey, pbes2Params.getIvSpec(), 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+
}
169181
}
170182

171183
protected void engineInit(int opmode, Key key, AlgorithmParameters params,

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

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2005, 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
@@ -26,7 +26,7 @@
2626
package com.sun.crypto.provider;
2727

2828
import java.io.ObjectStreamException;
29-
import java.lang.ref.Reference;
29+
import java.lang.ref.Cleaner;
3030
import java.nio.ByteBuffer;
3131
import java.nio.CharBuffer;
3232
import java.util.Arrays;
@@ -64,9 +64,11 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
6464
private int iterCount;
6565
private byte[] key;
6666

67-
@SuppressWarnings("serial") // Type of field is not Serializable;
68-
// see writeReplace method
67+
// The following fields are not Serializable. See writeReplace method.
68+
@SuppressWarnings("serial")
6969
private Mac prf;
70+
@SuppressWarnings("serial")
71+
private Cleaner.Cleanable cleaner;
7072

7173
private static byte[] getPasswordBytes(char[] passwd) {
7274
CharBuffer cb = CharBuffer.wrap(passwd);
@@ -88,17 +90,9 @@ private static byte[] getPasswordBytes(char[] passwd) {
8890
*/
8991
PBKDF2KeyImpl(PBEKeySpec keySpec, String prfAlgo)
9092
throws InvalidKeySpecException {
91-
char[] passwd = keySpec.getPassword();
92-
if (passwd == null) {
93-
// Should allow an empty password.
94-
this.passwd = new char[0];
95-
} else {
96-
this.passwd = passwd.clone();
97-
}
93+
this.passwd = keySpec.getPassword();
9894
// Convert the password from char[] to byte[]
9995
byte[] passwdBytes = getPasswordBytes(this.passwd);
100-
// remove local copy
101-
if (passwd != null) Arrays.fill(passwd, '\0');
10296

10397
try {
10498
this.salt = keySpec.getSalt();
@@ -124,16 +118,18 @@ private static byte[] getPasswordBytes(char[] passwd) {
124118
throw new InvalidKeySpecException(nsae);
125119
} finally {
126120
Arrays.fill(passwdBytes, (byte) 0x00);
127-
128-
// Use the cleaner to zero the key when no longer referenced
129-
final byte[] k = this.key;
130-
final char[] p = this.passwd;
131-
CleanerFactory.cleaner().register(this,
132-
() -> {
133-
Arrays.fill(k, (byte) 0x00);
134-
Arrays.fill(p, '\0');
135-
});
121+
if (key == null) {
122+
Arrays.fill(passwd, '\0');
123+
}
136124
}
125+
// Use the cleaner to zero the key when no longer referenced
126+
final byte[] k = this.key;
127+
final char[] p = this.passwd;
128+
cleaner = CleanerFactory.cleaner().register(this,
129+
() -> {
130+
Arrays.fill(k, (byte) 0x00);
131+
Arrays.fill(p, '\0');
132+
});
137133
}
138134

139135
private static byte[] deriveKey(final Mac prf, final byte[] password,
@@ -211,11 +207,7 @@ public boolean equals(Object obj) {
211207
}
212208

213209
public byte[] getEncoded() {
214-
// The key is zeroized by finalize()
215-
// The reachability fence ensures finalize() isn't called early
216-
byte[] result = key.clone();
217-
Reference.reachabilityFence(this);
218-
return result;
210+
return key.clone();
219211
}
220212

221213
public String getAlgorithm() {
@@ -226,16 +218,12 @@ public int getIterationCount() {
226218
return iterCount;
227219
}
228220

229-
public void clearPassword() {
230-
Arrays.fill(passwd, (char)0);
221+
public void clear() {
222+
cleaner.clean();
231223
}
232224

233225
public char[] getPassword() {
234-
// The password is zeroized by finalize()
235-
// The reachability fence ensures finalize() isn't called early
236-
char[] result = passwd.clone();
237-
Reference.reachabilityFence(this);
238-
return result;
226+
return passwd.clone();
239227
}
240228

241229
public byte[] getSalt() {

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

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2022, 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,6 +25,8 @@
2525

2626
package com.sun.crypto.provider;
2727

28+
import jdk.internal.access.SharedSecrets;
29+
2830
import java.util.Arrays;
2931

3032
import javax.crypto.SecretKey;
@@ -179,23 +181,29 @@ protected void engineInit(Key key, AlgorithmParameterSpec params)
179181
}
180182

181183
PBKDF2KeyImpl s = null;
182-
PBKDF2Core kdf = getKDFImpl(kdfAlgo);
183-
byte[] derivedKey;
184+
byte[] derivedKey = null;
185+
SecretKeySpec cipherKey = null;
184186
try {
187+
PBKDF2Core kdf = getKDFImpl(kdfAlgo);
185188
s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec);
186189
derivedKey = s.getEncoded();
190+
cipherKey = new SecretKeySpec(derivedKey, kdfAlgo);
191+
super.engineInit(cipherKey, null);
187192
} catch (InvalidKeySpecException ikse) {
188193
throw new InvalidKeyException("Cannot construct PBE key", ikse);
189194
} finally {
190-
pbeSpec.clearPassword();
195+
if (cipherKey != null) {
196+
SharedSecrets.getJavaxCryptoSpecAccess()
197+
.clearSecretKeySpec(cipherKey);
198+
}
199+
if (derivedKey != null) {
200+
Arrays.fill(derivedKey, (byte) 0);
201+
}
191202
if (s != null) {
192-
s.clearPassword();
203+
s.clear();
193204
}
205+
pbeSpec.clearPassword();
194206
}
195-
SecretKey cipherKey = new SecretKeySpec(derivedKey, kdfAlgo);
196-
Arrays.fill(derivedKey, (byte)0);
197-
198-
super.engineInit(cipherKey, null);
199207
}
200208

201209
public static final class HmacSHA1 extends PBMAC1Core {

src/java.base/share/classes/sun/security/util/PBEUtil.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public final class PBEUtil {
5959
* ::getAlgorithmParameters (as AlgorithmParameters) or ::getIvSpec (as
6060
* IvParameterSpec).
6161
*/
62-
public final static class PBES2Params {
62+
public static final class PBES2Params {
6363
private static final int DEFAULT_SALT_LENGTH = 20;
6464
private static final int DEFAULT_ITERATIONS = 4096;
6565

@@ -126,20 +126,17 @@ public PBEKeySpec getPBEKeySpec(int blkSize, int keyLength, int opmode,
126126
throw new InvalidKeyException("Null key");
127127
}
128128

129-
byte[] passwdBytes = key.getEncoded();
130129
char[] passwdChars = null;
131130
salt = null;
132131
iCount = 0;
133132
ivSpec = null;
134-
135133
PBEKeySpec pbeSpec;
134+
byte[] passwdBytes;
135+
if (!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3)) ||
136+
(passwdBytes = key.getEncoded()) == null) {
137+
throw new InvalidKeyException("Missing password");
138+
}
136139
try {
137-
if ((passwdBytes == null) ||
138-
!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0,
139-
3))) {
140-
throw new InvalidKeyException("Missing password");
141-
}
142-
143140
boolean doEncrypt = ((opmode == Cipher.ENCRYPT_MODE) ||
144141
(opmode == Cipher.WRAP_MODE));
145142

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ private static abstract class P11PublicKey extends P11Key implements
497497
}
498498
}
499499

500-
private static final class P11PBEKey extends P11SecretKey
500+
static final class P11PBEKey extends P11SecretKey
501501
implements PBEKey {
502502
private static final long serialVersionUID = 6847576994253634876L;
503503
private final char[] password;
@@ -507,8 +507,8 @@ private static final class P11PBEKey extends P11SecretKey
507507
int keyLength, CK_ATTRIBUTE[] attributes,
508508
char[] password, byte[] salt, int iterationCount) {
509509
super(session, keyID, algorithm, keyLength, attributes);
510-
this.password = password;
511-
this.salt = salt;
510+
this.password = password.clone();
511+
this.salt = salt.clone();
512512
this.iterationCount = iterationCount;
513513
}
514514

@@ -526,6 +526,10 @@ public byte[] getSalt() {
526526
public int getIterationCount() {
527527
return iterationCount;
528528
}
529+
530+
void clearPassword() {
531+
Arrays.fill(password, '\0');
532+
}
529533
}
530534

531535
@SuppressWarnings("deprecation")

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.security.spec.InvalidKeySpecException;
3333

3434
import javax.crypto.MacSpi;
35+
import javax.crypto.spec.PBEKeySpec;
3536
import javax.crypto.spec.PBEParameterSpec;
3637

3738
import jdk.internal.access.JavaNioAccess;
@@ -213,11 +214,21 @@ protected void engineInit(Key key, AlgorithmParameterSpec params)
213214
// params. Use SunPKCS11 PBE key derivation to obtain a P11Key.
214215
// Assign the derived key to p11Key because conversion is never
215216
// needed for this case.
217+
PBEKeySpec pbeKeySpec = PBEUtil.getPBAKeySpec(key, params);
216218
try {
217-
p11Key = P11SecretKeyFactory.derivePBEKey(token,
218-
PBEUtil.getPBAKeySpec(key, params), svcPbeKi);
219+
P11Key.P11PBEKey p11PBEKey =
220+
P11SecretKeyFactory.derivePBEKey(token,
221+
pbeKeySpec, svcPbeKi);
222+
// This Mac service uses the token where the derived key
223+
// lives so there won't be any need to re-derive and use
224+
// the password. The p11Key cannot be accessed out of this
225+
// class.
226+
p11PBEKey.clearPassword();
227+
p11Key = p11PBEKey;
219228
} catch (InvalidKeySpecException e) {
220229
throw new InvalidKeyException(e);
230+
} finally {
231+
pbeKeySpec.clearPassword();
221232
}
222233
}
223234
if (params instanceof PBEParameterSpec pbeParams) {

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PBECipher.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import javax.crypto.spec.PBEKeySpec;
4242
import javax.crypto.spec.PBEParameterSpec;
4343

44-
import com.sun.crypto.provider.SunJCE;
4544
import sun.security.jca.JCAUtil;
4645
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
4746
import sun.security.pkcs11.wrapper.PKCS11Exception;
@@ -146,10 +145,18 @@ protected void engineInit(int opmode, Key key,
146145
PBEKeySpec pbeSpec = pbes2Params.getPBEKeySpec(
147146
blkSize, svcPbeKi.keyLen, opmode, key, params, random);
148147
try {
149-
key = P11SecretKeyFactory.derivePBEKey(
148+
P11Key.P11PBEKey p11PBEKey = P11SecretKeyFactory.derivePBEKey(
150149
token, pbeSpec, svcPbeKi);
150+
// The internal Cipher service uses the token where the
151+
// derived key lives so there won't be any need to re-derive
152+
// and use the password. The key cannot be accessed out of this
153+
// class.
154+
p11PBEKey.clearPassword();
155+
key = p11PBEKey;
151156
} catch (InvalidKeySpecException e) {
152157
throw new InvalidKeyException(e);
158+
} finally {
159+
pbeSpec.clearPassword();
153160
}
154161
params = pbes2Params.getIvSpec();
155162
}

0 commit comments

Comments
 (0)