-
Bug
-
Resolution: Fixed
-
P4
-
5.0
-
b09
-
x86
-
linux
-
Verified
FULL PRODUCT VERSION :
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux mp 2.6.12-12mdksmp #1 SMP Fri Sep 9 17:43:23 CEST 2005 i686 Intel(R) Pentium(R) 4 CPU 2.80GHz unknown GNU/Linux
A DESCRIPTION OF THE PROBLEM :
An instance of the class javax.crypto.spec.PBEKeySpec stores the raw key material (a password) from which an encryption mechanism can derive a cryptographic key.
The password is stored as a char array instead of a String, so it can be overwritten when is no longer needed. Hence, PBEKeySpec objects are mutable.
The problem occurs when two threads share an instance of PBEKeySpec, and one of the threads tries to read the password while the other is clearing it. The thread trying to read the password may obtain a wrong one. The password returned by PBEKeySpec.getPassword() should be a copy of the one given as argument to the constructor, or the method should throw IllegalStateException.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Below there is the source code of a program that demonstrates the problem.
Two threads share an instance of PBEKeySpec. One thread has a loop which calls getPassword(). The loop terminates when the password obtained is different from the original, or when IllegalStateException is thrown. The other threads clears the password.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
PBEKeySpec.clearPassword() should clear the internal copy atomically. In this case, the thread reading the password should never find an incorrect password, and the loop should terminate when it tries to get an already cleared password. In the example program, the thread should print "Password cleared" to standard error, and terminate
ACTUAL -
This is an actual result of running the program.
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Password cleared
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Incorrect Password: [ , , , , , , , , , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Incorrect Password: [ , , , , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Password cleared
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Incorrect Password: [ , , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , A, A, A, A]
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Password cleared
Incorrect Password: [ , , , , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Password cleared
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
REPRODUCIBILITY :
This bug can be reproduced often.
---------- BEGIN SOURCE ----------
import java.util.Arrays;
import javax.crypto.spec.PBEKeySpec;
public class TestPBEKeySpec {
private static final int TIMES = 25;
private static final int PASSWORD_LEN = 25;
private static PBEKeySpec keySpec;
private static char[] pass;
static {
pass = new char[PASSWORD_LEN];
Arrays.fill(pass, 'A');
}
public static void main(String[] args) {
for (int i = 0; i < TIMES; i++) {
keySpec = new PBEKeySpec(pass);
Thread reader = new Thread() {
public void run() {
char[] pbePass;
try {
while (true) {
pbePass = keySpec.getPassword();
if (!Arrays.equals(pass, pbePass))
break;
}
} catch (IllegalStateException e) {
System.err.println("Password cleared");
return;
}
System.err.println("Incorrect Password: "+ Arrays.toString(pbePass));
}
};
Thread clearer = new Thread() {
public void run() {
keySpec.clearPassword();
}
};
reader.start();
clearer.start();
try {
reader.join();
clearer.join();
} catch (InterruptedException e) {
}
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Knowing the existence of the bug, both methods can be easily synchronized externally.
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux mp 2.6.12-12mdksmp #1 SMP Fri Sep 9 17:43:23 CEST 2005 i686 Intel(R) Pentium(R) 4 CPU 2.80GHz unknown GNU/Linux
A DESCRIPTION OF THE PROBLEM :
An instance of the class javax.crypto.spec.PBEKeySpec stores the raw key material (a password) from which an encryption mechanism can derive a cryptographic key.
The password is stored as a char array instead of a String, so it can be overwritten when is no longer needed. Hence, PBEKeySpec objects are mutable.
The problem occurs when two threads share an instance of PBEKeySpec, and one of the threads tries to read the password while the other is clearing it. The thread trying to read the password may obtain a wrong one. The password returned by PBEKeySpec.getPassword() should be a copy of the one given as argument to the constructor, or the method should throw IllegalStateException.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Below there is the source code of a program that demonstrates the problem.
Two threads share an instance of PBEKeySpec. One thread has a loop which calls getPassword(). The loop terminates when the password obtained is different from the original, or when IllegalStateException is thrown. The other threads clears the password.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
PBEKeySpec.clearPassword() should clear the internal copy atomically. In this case, the thread reading the password should never find an incorrect password, and the loop should terminate when it tries to get an already cleared password. In the example program, the thread should print "Password cleared" to standard error, and terminate
ACTUAL -
This is an actual result of running the program.
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Password cleared
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Incorrect Password: [ , , , , , , , , , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Incorrect Password: [ , , , , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Password cleared
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Incorrect Password: [ , , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , A, A, A, A]
Incorrect Password: [ , , , , , , , , , , , , , , , , , , , , , , , , ]
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Password cleared
Incorrect Password: [ , , , , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Incorrect Password: [ , , , , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
Password cleared
Incorrect Password: [ , A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A]
REPRODUCIBILITY :
This bug can be reproduced often.
---------- BEGIN SOURCE ----------
import java.util.Arrays;
import javax.crypto.spec.PBEKeySpec;
public class TestPBEKeySpec {
private static final int TIMES = 25;
private static final int PASSWORD_LEN = 25;
private static PBEKeySpec keySpec;
private static char[] pass;
static {
pass = new char[PASSWORD_LEN];
Arrays.fill(pass, 'A');
}
public static void main(String[] args) {
for (int i = 0; i < TIMES; i++) {
keySpec = new PBEKeySpec(pass);
Thread reader = new Thread() {
public void run() {
char[] pbePass;
try {
while (true) {
pbePass = keySpec.getPassword();
if (!Arrays.equals(pass, pbePass))
break;
}
} catch (IllegalStateException e) {
System.err.println("Password cleared");
return;
}
System.err.println("Incorrect Password: "+ Arrays.toString(pbePass));
}
};
Thread clearer = new Thread() {
public void run() {
keySpec.clearPassword();
}
};
reader.start();
clearer.start();
try {
reader.join();
clearer.join();
} catch (InterruptedException e) {
}
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Knowing the existence of the bug, both methods can be easily synchronized externally.