Sunday, January 22, 2012

Writing a password encryptor in Java

Happy New Year everyone!

In a recent project, I need to write a password encryptor so that passwords using my shell scripts are not exposed in clear text. Note that this does not stop people from getting the passwords - it just does not expose the password in clear text.

After doing some research, I've decided to use AES to encrypt my password. It will take in 2 parameters - the key and the password.

Two problems arise:
1. The encryption method outputs in bytes - I need to handle this so that I can encode the byte output as a String (text) and then be able to decode it back to byte to decrypt it back. Many of the examples out there uses sun.misc.Base64Encoder but this is not encouraged (do a google to find out why). There are alternatives. Here's a good link on this. Basically using Apache Commons Codec or Base64.

But the better way if you are using Java6 is to use import javax.xml.bind.DatatypeConverter or else use JavaMail which provides Base64 encoding/decoding via MimeUtility.

In the end I used javax.xml.bind.DatatypeConverter since I am using Java6.

2. The second problem is since I am letting the users decide what key to use, I need to be able to hash the key via MD5 or SHA, then extract the bytes from the hash into the key byte[].

A good discussion on this can be found here.

Note: here's a good link on using DES to do this.

Anyway, here's my final code:
import javax.crypto.Cipher;
import javax.crypto.spec.*;

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

import javax.xml.bind.DatatypeConverter;


public class AES {

// init vector for randomness
static byte[] iv = { (byte) 0xcb, (byte) 0x53, (byte) 0x03, (byte) 0x0f,
(byte) 0xe0, (byte) 0x79, (byte) 0x9d, (byte) 0xdc, (byte) 0x80,
(byte) 0xa9, (byte) 0x83, (byte) 0xf1, (byte) 0x03, (byte) 0xb6,
(byte) 0x59, (byte) 0x83 };


public static void encryptText(String text, String password) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(getKeyFromPassword(password), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding");
aes.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
byte[] encrypted = aes.doFinal((text.getBytes()));
//System.out.println("Encrypted string: " + DatatypeConverter.printBase64Binary(encrypted));
System.out.println(DatatypeConverter.printBase64Binary(encrypted));
}

public static void decryptText(String encrypted, String password) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(getKeyFromPassword(password), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding");
aes.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
//Cipher cipher = Cipher.getInstance("AES");
//cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original = aes.doFinal(DatatypeConverter.parseBase64Binary(encrypted));
String originalString = new String(original);
// System.out.println("Decrypted string: " + originalString + " " + asHex(original));
System.out.println(originalString);
}


public static byte[] md5sum(byte[] buffer) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(buffer);
return md5.digest();
} catch (NoSuchAlgorithmException e) {
System.out.println("MD5 Algorithm not available on this machine");
}
return null;
}

// converts key to machine readable form
public static byte[] getKeyFromPassword(String s) {
return md5sum(s.toString().getBytes());
}

// prints pretty error messages and exits
public static void errorExit(String s) {
System.out.println(s);
System.exit(0);
}

public static void main(String[] args) throws Exception {
String usage = "Usage: java AES [-e | -d] [text] [password]";

if (args.length < 2 || args.length > 3) {
errorExit(usage);
}
if (args[0].equalsIgnoreCase("-e")) {
encryptText(args[1], args[2]);
} else if (args[0].equalsIgnoreCase("-d")) {
decryptText(args[1], args[2]);
} else {
System.out.println(usage);
}
Runtime.getRuntime().gc(); // force flush
}
}

1 comment:

  1. Another link : http://www.daniweb.com/software-development/java/threads/191239

    ReplyDelete