Passwords never in clear text

Applications should not refer to the clear text versions of passwords - not in the database, not when logging, nor in any other area. The clear text version of the password should be the end user's secret. It should never be directly repeated or stored by an application.

Clear Text Versus Hash
A user inputs a password in its original, unaltered form - that is, in "clear text". However, a database should never store passwords in clear text. Instead, the value stored by the database should be calculated as

stored-value = hash(clear-text-password + salt-value)
The intent here is to store text which cannot be easily reverse-engineered back into the original password. The salt-value is a random string added to the password. It's added to prevent simple dictionary-style reverse engineering of the hashed value of the plain text password.

(Regarding Tomcat5: its implementation of form-based login doesn't allow for the salt value.)

Hash Functions
SHA-1, SHA-256, SHA-384, and SHA-512 are all examples of hash functions. A hash function is also called a MessageDigest. (The MD5 hash has been shown to be defective, and should usually be avoided.)

A hash function is not an encryption. Encrypted items are always meant for eventual decryption. A hash function, on the other hand, is meant only as a one-way operation. The whole idea of a hash function is that it should be very difficult to calculate the original input value, given the hash value.

If y = hash(x) is a hash function, and y and x both represent text strings, then

The above properties allow for passwords (or pass phrases) of arbitrary length, while still letting the underlying database column which stores the hash value to be of fixed width.

Example

This example uses MessageDigest and the SHA-1 hash function:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/** Example hash function values.*/
public final class HashExamples {
  
  public static void main(String... args) {
    try {
      MessageDigest sha = MessageDigest.getInstance("SHA-1");
      byte[] hashOne = sha.digest("color".getBytes());
      log("Hash of 'color':  " + hexEncode(hashOne));
      sha.reset();
      byte[]  hashTwo = sha.digest("colour".getBytes());
      log("Hash of 'colour': " + hexEncode(hashTwo));
    }
    catch (NoSuchAlgorithmException ex){
      log("No such algorithm found in JRE.");
    }
  }
  
  private static void log(Object thing) {
    System.out.println(String.valueOf(thing));
  }

  /**
  * The byte[] returned by MessageDigest does not have a nice
  * textual representation, so some form of encoding is usually performed.
  *
  * This implementation follows the example of David Flanagan's book
  * "Java In A Nutshell", and converts a byte array into a String
  * of hex characters.
  */
  static private String hexEncode( byte[] input){
    StringBuffer result = new StringBuffer();
    char[] digits = {'0', '1', '2', '3', '4','5','6','7','8','9','a','b','c','d','e','f'};
    for (int idx = 0; idx < input.length; ++idx) {
      byte b = input[idx];
      result.append( digits[ (b&0xf0) >> 4 ] );
      result.append( digits[ b&0x0f] );
    }
    return result.toString();
  }  
}
 
Example run:

Hash of 'color':  6dd0fe8001145bec4a12d0e22da711c4970d000b
Hash of 'colour': 79d41a47e8fec55856a6a6c5ba53c2462be4852e