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
y
, it's very hard to deduce the original input x
x
can have arbitrary length
y
will have fixed length
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