Wednesday, August 8, 2007

Password Encryption

Have you ever felt the need to encrypt those plain text passwords you store in the database for your application authentication?
Would you like to encrypt the plain text in such a way that it can only be interpreted by your application and does not make sense for a naked eye?

Where has your password been?

Most of the web sites today have some sort of a registration module where a user is asked to choose a username/password combination. This data gets stored in the database. You might wonder if the password you provide will be kept well-protected (read encrypted). In case you are the person designing such backend registration component, why not give your users peace of mind by encrypting their passwords?

There are several message-digest algorithms used widely today.

Algorithm Strength
MD5 128 bit
SHA-1 160 bit

Typical registration scenario

Here is a typical flow of how our message digest algorithm can be used to provide one-way password hashing:

1) User registers with some site by submitting the following data:

username password
jsmith mypass

2) before storing the data, a one-way hash of the password is created: "mypass" is transformed into "5yfRRkrhJDbomacm2lsvEdg4GyY="

The data stored in the database ends up looking like this:

username password
jsmith 5yfRRkrhJDbomacm2lsvEdg4GyY=

3) When jsmith comes back to this site later and decides to login using his credentials (jsmith/mypass), the password hash is created in memory (session) and is compared to the one stored in the database. Both values are equal to "5yfRRkrhJDbomacm2lsvEdg4GyY=" since the same password value "mypass" was used both times when submitting his credentials. Therefore, his login will be successful.

Note, any other plaintext password value will produce a different sequence of characters. Even using a similar password value ("mypast") with only one-letter difference, results in an entirely different hash: "hXdvNSKB5Ifd6fauhUAQZ4jA7o8="

plaintext password encrypted password
mypass 5yfRRkrhJDbomacm2lsvEdg4GyY=
mypast hXdvNSKB5Ifd6fauhUAQZ4jA7o8=

As mentioned above, given that strong encryption algorithm such as SHA is used, it is impossible to reverse-engineer the encrypted value from "5yfRRkrhJDbomacm2lsvEdg4GyY=" to "mypass". Therefore, even if a malicious hacker gets a hold of your password digest, he/she won't be able determine what your password is.

Sample Code To Achieve:

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.myorg.SystemUnavailableException;
import sun.misc.BASE64Encoder;
import sun.misc.CharacterEncoder;

public final class PasswordService
{
private static PasswordService instance;

private PasswordService()
{
}

public synchronized String encrypt(String plaintext) throws SystemUnavailableException{
MessageDigest md = null;
try{
md = MessageDigest.getInstance("SHA"); //step 2
}
catch(NoSuchAlgorithmException e){
throw new SystemUnavailableException(e.getMessage());
}
try{
md.update(plaintext.getBytes("UTF-8")); //step 3
}
catch(UnsupportedEncodingException e){
throw new SystemUnavailableException(e.getMessage());
}

byte raw[] = md.digest(); //step 4
String hash = (new BASE64Encoder()).encode(raw); //step 5
return hash; //step 6
}

public static synchronized PasswordService getInstance(){ //step 1
if(instance == null){
instance = new PasswordService();
}
return instance;
}
}



No comments: