Skip to content

Commit 791fc57

Browse files
author
Bradford Wetmore
committed
6383195: javax.crypto.spec.PBEKeySpec is not thread safe
Reviewed-by: weijun
1 parent e052d7f commit 791fc57

File tree

2 files changed

+98
-3
lines changed

2 files changed

+98
-3
lines changed

src/java.base/share/classes/javax/crypto/spec/PBEKeySpec.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2022, 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
@@ -173,7 +173,7 @@ public PBEKeySpec(char[] password, byte[] salt, int iterationCount) {
173173
* Clears the internal copy of the password.
174174
*
175175
*/
176-
public final void clearPassword() {
176+
public final synchronized void clearPassword() {
177177
if (password != null) {
178178
Arrays.fill(password, ' ');
179179
password = null;
@@ -191,7 +191,7 @@ public final void clearPassword() {
191191
* calling <code>clearPassword</code> method.
192192
* @return the password.
193193
*/
194-
public final char[] getPassword() {
194+
public final synchronized char[] getPassword() {
195195
if (password == null) {
196196
throw new IllegalStateException("password has been cleared");
197197
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 6383195
27+
* @summary javax.crypto.spec.PBEKeySpec is not thread safe
28+
*/
29+
30+
/*
31+
* Use one thread to clear the password, another to check the password state.
32+
*
33+
* If a partially cleared password is ever obtained, fail the test.
34+
*/
35+
import java.util.Arrays;
36+
import javax.crypto.spec.PBEKeySpec;
37+
38+
public class PBEKeySpecRacing {
39+
private static final int NUMTESTS = 1000;
40+
private static final int PASSWORD_LEN = 25;
41+
42+
private static PBEKeySpec keySpec;
43+
44+
private static final char[] password;
45+
46+
static {
47+
password = new char[PASSWORD_LEN];
48+
Arrays.fill(password, 'A');
49+
}
50+
51+
// flag for failed test case.
52+
53+
private static volatile char[] failed = null;
54+
55+
public static void main(String[] args) {
56+
System.out.println("Testing: ");
57+
for (int i = 0; i < NUMTESTS; i++) {
58+
keySpec = new PBEKeySpec(password);
59+
Thread reader = new Thread(() -> {
60+
try {
61+
// Repeat until state changes or failure seen
62+
while (true) {
63+
char[] pbePass = keySpec.getPassword();
64+
if (!Arrays.equals(password, pbePass)) {
65+
failed = pbePass;
66+
return;
67+
}
68+
}
69+
} catch (IllegalStateException e) {
70+
System.out.print(".");
71+
}
72+
});
73+
Thread clearer = new Thread(() -> keySpec.clearPassword());
74+
reader.start();
75+
clearer.start();
76+
try {
77+
reader.join();
78+
clearer.join();
79+
} catch (InterruptedException e) {
80+
// Swallow
81+
}
82+
83+
if (failed != null) {
84+
throw new RuntimeException(
85+
"Inconsistent Password: " + Arrays.toString(failed));
86+
}
87+
88+
// avoid long output lines.
89+
if ((i % 80) == 79) {
90+
System.out.println();
91+
}
92+
}
93+
System.out.println("Test PASSED");
94+
}
95+
}

0 commit comments

Comments
 (0)