...
Code Block | ||
---|---|---|
| ||
public final class Password {
private void setPassword(byte[] pass) throws Exception {
bytes[] encrypted = encrypt(pass); // arbitrary encryption scheme
clearArray(pass);
saveBytes(encrypted,"password.bin"); // encrypted password to password.bin
}
private boolean checkPassword(byte[] pass) throws Exception {
boolean arrays_equal;
byte[] encrypted = loadBytes("password.bin"); // load the encrypted password
byte[] decrypted = decrypt(encrypted);
arrays_equal = Arrays.equal(decrypted, pass);
clearArray(decrypted);
clearArray(pass);
return arrays_equal;
}
private clearArray(byte[] a) {
//set all of the elements in a to zero
}
}
|
...
This noncompliant code example implements the SHA-1
hash function through the MessageDigest
class to compare hash values instead of cleartext strings, but uses a String
to store the password.
Code Block | ||
---|---|---|
| ||
import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public final class Password { private void setPassword(String pass) throws Exception { byte[] salt = generateSalt(12); MessageDigest sha_1 = MessageDigest.getInstance("SHA-1"); byte[] hashVal = sha_1.digest((pass+salt).getBytes()); // encode the string and salt saveBytes(salt, "salt.bin"); saveBytes(hashVal,"password.bin"); // save the hash value to credentialspassword.bin } private boolean checkPassword(String pass) throws Exception { byte[] salt = loadBytes("salt.bin"); MessageDigest sha_1 = MessageDigest.getInstance("SHA-1"); byte[] hashVal1 = sha_1.digest((pass+salt).getBytes()); // encode the string and salt byte[] hashVal2 = loadBytes("password.bin"); // load the hash value stored in password.bin return Arrays.equals(hashVal1, hashVal2); } private byte[] generateSalt(int n) { // Generate a random byte array of length n } } |
...
Code Block | ||
---|---|---|
| ||
import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public final class Password { private void setPassword(byte[] pass) throws Exception { byte[] salt = generateSalt(12); byte[] input = appendArrays(pass, salt); MessageDigest sha_1 = MessageDigest.getInstance("SHA-1"); byte[] hashVal = sha_1.digest(input); // encode the string and salt clearArray(pass); clearArray(input); saveBytes(salt, "salt.bin"); saveBytes(hashVal,"password.bin"); // save the hash value to credentialspassword.pwbin } private boolean checkPassword(byte[] pass) throws Exception { byte[] salt = loadBytes("salt.bin"); byte[] input = appendArrays(pass, salt); MessageDigest sha_1 = MessageDigest.getInstance("SHA-1"); byte[] hashVal1 = sha_1.digest(input); // encode the string and salt clearArray(pass); clearArray(input); byte[] hashVal2 = loadBytes("credentialspassword.pwbin"); // load the hash value stored in credentialspassword.pwbin return Arrays.equals(hashVal1, hashVal2); } private byte[] generateSalt(int n) { // Generate a random byte array of length n } private byte[] appendArrays(byte[] a, byte[] b) { // Return a new array of a appended to b } private void clearArray(byte[] a) { // set all of the elements in a to zero } } |
In both the setPassword()
and checkPassword()
methods, the cleartext representation of the password is erased immediately after it is converted into a hash value. Consequently, attackers must work much harder to retrieve the cleartext password after the erasure. Providing truly guaranteed erasure is extremely challenging, likely to be platform-specific and may even be impossible because of the possible involvement of copying garbage collectors, dynamic paging, and other platform features that operate below the level of the Java Language. Note, however, that most other languages share these complications (with the exception of garbage collection).
...