You are on page 1of 4

In this tutorial we will implement a full data encryption decryption cycle with

Java (only data, not file encryption);


encrypt some data using a secret key, salt and iterations and decrypt using the
same parameters.
We are using the Java Cryptography Extension (JCE) for data encryption/decryptio
n operations. This extension is available in Java 1.4.2 and above; you will have
to manually download it for older versions (here). Java supports a number of of
encryption algorithms, however we will demonstrate only AES algorithm (the Adva
nced Encryption Standard) usage.
Why should we encrypt data?
Encryption and Decryption are highly important security steps; now there are fil
e and data encryption software as well.
Data encryption is the mechanism of converting a message (plain text) into some
other text (called ciphertext)
so that readers can not understand the original message; however some authorized
party can understand that ciphertext using the method called Decryption which c
onverts the ciphertext into original message.
As many software applications store sensitive personal data in databases, encryp
tion has become a must. Ideally nobody (including the software developers) shoul
d not be able to view these user specific real data.
Simple Data Encryption/Decryption Example with AES
For encryption we must use a secret key along with an algorithm. In the followin
g example we use an algorithm called AES 128 and the bytes of the word "ThisIsAS
ecretKey" as the secret key (the best secret key we found in this world).
AES algorithm can use a key of 128 bits (16 bytes * 8); so we selected that key.

package org.kamal.crypto;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.*;
public class SimpleProtector {
private static final String ALGORITHM = "AES";
private static final byte[] keyValue =
new byte[] { 'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e',
't', 'K', 'e', 'y' };
public static String encrypt(String valueToEnc) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encValue = c.doFinal(valueToEnc.getBytes());
String encryptedValue = new BASE64Encoder().encode(encValue);
return encryptedValue;
}
public static String decrypt(String encryptedValue) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedValue);
byte[] decValue = c.doFinal(decordedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
private static Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, ALGORITHM);
// SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM)
;
// key = keyFactory.generateSecret(new DESKeySpec(keyValue));
return key;
}
}
We use "generateKey()" method to generate a secret key for AES algorithm with a
given key. You can change the used algorithm by changing this Key generation; th
e commented out code shows the use of DES algorithm (Data Encryption Standard).
Following is a simple class to test the above implementation.
package org.kamal.crypto;
public class TestSimpleProtector {
public static void main(String[] args) throws Exception {
String password = "mypassword";
String passwordEnc = SimpleProtector.encrypt(password);
String passwordDec = SimpleProtector.decrypt(passwordEnc);
System.out.println("Plain Text : " + password);
System.out.println("Encrypted : " + passwordEnc);
System.out.println("Decrypted : " + passwordDec);
}
}
Following is the output we got from above test; so you clearly see that the orig
inal text is reproduced after the decryption operation.
Plain Text : mypassword
Encrypted : sBhCap4urE50a/dGuhNgrw==
Decrypted : mypassword
The encrypted value is not simply related to the plain text, so it provides some
security to the password.
The Risk with Simple Protector
When you use the above mentioned method to encrypt all passwords in your databas
e, it makes an attacker's task easier.
Since the same key is used, if an attacker find a way to get the plain text, the
he can use that same method to get all the other plain-texts in the database in
minutes.
Use Salt and iterations to improve
To make the attackers job harder we can use two methods; called adding Salt and
using Iterations.
A Salt is another plain-text appended to the given plain text, before generating
the encrypted value.
We use a unique Salt per each plain-text so that the value used to encrypt is ge
tting much stronger making it harder for an attacker to guess with a brute force
or dictionary attack. Following class shows the improved version of SimpleProte
ctor class.
package org.kamal.crypto;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.*;
public class Protector {
private static final String ALGORITHM = "AES";
private static final int ITERATIONS = 2;
private static final byte[] keyValue =
new byte[] { 'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e',
't', 'K', 'e', 'y'};
public static String encrypt(String value, String salt) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
String valueToEnc = null;
String eValue = value;
for (int i = 0; i < ITERATIONS; i++) {
valueToEnc = salt + eValue;
byte[] encValue = c.doFinal(valueToEnc.getBytes());
eValue = new BASE64Encoder().encode(encValue);
}
return eValue;
}
public static String decrypt(String value, String salt) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
String dValue = null;
String valueToDecrypt = value;
for (int i = 0; i < ITERATIONS; i++) {
byte[] decordedValue = new BASE64Decoder().decodeBuffer(valueToDecry
pt);
byte[] decValue = c.doFinal(decordedValue);
dValue = new String(decValue).substring(salt.length());
valueToDecrypt = dValue;
}
return dValue;
}
private static Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, ALGORITHM);
// SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM)
;
// key = keyFactory.generateSecret(new DESKeySpec(keyValue));
return key;
}
}
You need to store the clear Salt with the stored encrypted value since the salt
is required at the decrypt operation.
We just used a sentence as the 'salt', but you should use a random letters/numbe
rs for that to avoid any dictionary attacks.
package org.kamal.crypto;
public class TestProtector {
public static void main(String[] args) throws Exception {
String password = "mypassword";
String salt = "this is a simple clear salt";
String passwordEnc = Protector.encrypt(password, salt);
String passwordDec = Protector.decrypt(passwordEnc, salt);
System.out.println("Salt Text : " + salt);
System.out.println("Plain Text : " + password);
System.out.println("Encrypted : " + passwordEnc);
System.out.println("Decrypted : " + passwordDec);
}
}
The output from the above class looks as follows.
Salt Text : this is a simple clear salt
Plain Text : mypassword
Encrypted : GX8jEr04o6PC+IE+f6DXq+zuRiZ2nsSL+UYxYRh9vK28xt/GrLqnbrP3hkXSW5S3jNgz
XkrLSmXm
fwRw+eBMWQJO+8tlSEE9D2Y9qEzowX18s4W81U/D9JL3JX7uJtwp
Decrypted : mypassword
When using Salt, you can store each (clear text) Salt in the database per each e
ncrypted text. It would be better if we pass the secrete key while initializing
or instantiating the (Protector) encryption class rather than hard coding it in
the class itself (for simplicity we used a hard coded key for this tutorial).