Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Programs that store a password passwords as cleartext (unencrypted text data) risk exposure of the password those passwords in a variety of ways. Although programs generally receive passwords from users as cleartext, they should ensure that the passwords are not stored as cleartext.

...

Cryptographic Hash Functions

The value produced by a hash function is the hash value or message digest. Hash functions are computationally feasible functions whose inverses are computationally infeasible. In practice, a password can be encoded to a hash value, but decoding remains infeasible. The equality of the passwords can be tested through the equality of their hash values.

Always A good practice is to always append a salt to the password being hashed. A salt is a unique (often sequential) , or randomly generated , piece of data that is stored along with the hash value. The use of a salt helps prevent brute-force attacks against the hash value, provided that the salt is long enough to generate sufficient entropy (shorter salt values cannot significantly slow down a brute-force attack). Each password should have its own salt associated with it. If a single salt were used for more than one password, two users would be able to see whether their passwords are the same.

The choice of hash function and salt length presents a trade-off between security and performance. Increases in the time required to compute hash values raise Increasing the effort required for effective brute-force attacks but make the program slower when validating by choosing a stronger hash function can also increase the time required to validate a password. Increasing the length of the salt makes brute-force attacks more difficult, but requires additional storage space.

Java's MessageDigest class provides implementations of various cryptographic hash functions. Avoid defective functions such as the Message-Digest Algorithm (MD5). Hash functions such as Secure Hash Algorithm (SHA)-1 and SHA-2 are maintained by the National Security Agency and are currently considered safe. In practice, many applications use SHA-256 because this hash function has reasonable performance while still being considered secure.

Noncompliant Code Example

This noncompliant code example encrypts and decrypts the password stored in credentials.pw: password.bin using a symmetric key algorithm.

Code Block
bgColor#FFcccc
public final class Password {
  private void setPassword(byte[] pass) throws Exception {
    // Arbitrary encryption scheme
    bytes[] encrypted = encrypt(pass); // Arbitrary encryption scheme
    clearArray(pass);    
    // Encrypted password to password.bin
    saveBytes(encrypted,"password.bin");
 // Encrypted password to password.binclearArray(encrypted); 
  }

  private boolean checkPassword(byte[] pass) throws Exception {
    boolean arrays_equal;// Load the encrypted password
    byte[] encrypted = loadBytes("password.bin"); // Load the encrypted password
    byte[] decrypted = decrypt(encrypted);
    arrays_equalboolean arraysEqual = Arrays.equal(decrypted, pass);
    clearArray(decrypted);
    clearArray(pass);
    return arrays_equalarraysEqual;
  }

  private void clearArray(byte[] a) {
    for (int i = 0; i < a.length; i++) {
      a[i] = 0;
    }
  }
}

An attacker could potentially decrypt this file to discover the password. The attacker could be someone who knows or has figured out the encryption scheme being used by the program, particularly when the attacker has knowledge of the key and encryption scheme used by the program. Passwords should be protected even from system administrators and privileged users. Consequently, using encryption is only partly effective in mitigating password disclosure threats.

Noncompliant Code Example

This noncompliant code example implements uses the SHA-1256 hash function through the MessageDigest class to compare hash values instead of cleartext strings, but it uses a String to store the password:

Code Block
bgColor#FFcccc
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_1msgDigest = MessageDigest.getInstance("SHA-1256");
    // Encode the string and salt
    byte[] hashVal = sha_1msgDigest.digest((pass+salt).getBytes()); // Encode the string and salt
    saveBytes(salt, "salt.bin");
    saveBytes(hashVal,"password.bin"); // Save the hash value to password.bin
    saveBytes(hashVal,"password.bin");
  }

  private boolean checkPassword(String pass) throws Exception {
    byte[] salt = loadBytes("salt.bin");
    MessageDigest sha_1msgDigest = MessageDigest.getInstance("SHA-1256");
    // Encode the string and salt
    byte[] hashVal1 = sha_1msgDigest.digest((pass+salt).getBytes());
    // EncodeLoad the string and salthash value stored in password.bin
    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
  }
}

Even when an attacker knows that the program stores passwords using SHA-1 256 and a 12-byte salt, he or she will be unable to retrieve the unencrypted actual password from password.bin and salt.bin.

Although this approach fixes solves the decryption problem from the previous noncompliant code example, at runtime this code program may inadvertently store the passwords as cleartext in memory. Java string String objects are immutable, and can be copied and internally stored by the Java Virtual Machine. Consequently, Java lacks a mechanism to securely erase a password once it has been stored in a String. See 01. Limit the lifetime of sensitive data for more information.

...

Code Block
bgColor#ccccff
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_1msgDigest = MessageDigest.getInstance("SHA-1256");
    // Encode the string and salt
    byte[] hashVal = sha_1msgDigest.digest(input); // Encode the string and salt   
    clearArray(pass);   
    clearArray(input);
    saveBytes(salt, "salt.bin");   
    // Save the hash value to password.bin
    saveBytes(hashVal,"password.bin"); 
 //  Save the hash value to password.bin clearArray(salt);
    clearArray(hashVal);
  }

  private boolean checkPassword(byte[] pass) throws Exception {
    byte[] salt = loadBytes("salt.bin");
    byte[] input = appendArrays(pass, salt);
    MessageDigest sha_1msgDigest = MessageDigest.getInstance("SHA-1256");
    // Encode the string and salt
    byte[] hashVal1 = sha_1msgDigest.digest(input); // Encode the string and salt
    clearArray(pass);
    clearArray(input);
    // Load the hash value stored in password.bin
    byte[] hashVal2 = loadBytes("password.bin"); //
 Load the hash valueboolean storedarraysEqual in= password.binArrays.equals(hashVal1, hashVal2);
    return Arrays.equalsclearArray(hashVal1, hashVal2));
    clearArray(hashVal2);
    return arraysEqual;
  }

  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) {
    for (int i = 0; i < a.length; i++) {
      a[i] = 0;
    }
  }
}

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, is likely to be platform - specific, and may even be impossible because of the 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).

Applicability

Passwords stored without a secure hash are exposed to malicious users. Violations of this guideline generally have a clear exploit associated with them.

Applications such as password managers may need to retrieve the original password in order to enter it into a third-party application. This is permitted even though it violates the this guideline. The password manager is accessed by a single user and always has the user's permission to store his or her passwords and to display those passwords on command. Consequently, the limit limiting factor to safety and security is the user's competence rather than the program's operation.

Bibliography

...