Encryption and Decryption in Java is still very difficult for me to understand. I have been using the following class and methods. I wonder how to improve the safety and how long does the keystring (schlüssel) need to be?
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class AES
{
public static SecretKeySpec makeKey(String schlüssel) throws NoSuchAlgorithmException, UnsupportedEncodingException
{
byte[] key = (schlüssel).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
return new SecretKeySpec(key, "AES");
}
public static String encryptString(String text, SecretKeySpec schlüssel) throws Exception
{
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, schlüssel);
byte[] encrypted = cipher.doFinal(text.getBytes());
BASE64Encoder myEncoder = new BASE64Encoder();
return myEncoder.encode(encrypted);
}
public static String decryptString(String text, SecretKeySpec schlüssel) throws Exception
{
BASE64Decoder myDecoder2 = new BASE64Decoder();
byte[] crypted2 = myDecoder2.decodeBuffer(text);
Cipher cipher2 = Cipher.getInstance("AES");
cipher2.init(Cipher.DECRYPT_MODE, schlüssel);
byte[] cipherData2 = cipher2.doFinal(crypted2);
return new String(cipherData2);
}
}
I have been reading about the topic. But I did not understand how to transfer the ideas into my code. Any help is appreciated, please be kind with an encryption beginner. Thank you.
There are a lot of things wrong in this class.
the class uses a cryptographic hash instead of a password hash - such as PBKDF2 - to derive a key from the password;
you are using ECB mode encryption (the default), you need to use at least CBC, together with an initialization vector (IV);
your class doesn't add any integrity protection, in other words the ciphertext is malleable;
It depends on the use case if you require the integrity protection. So I'll point you to this question for more information about password based encryption (PBE). Note that the answers may still deliver malleable ciphertext.
Furthermore the class contains the following Java mistakes:
it doesn't distinguish between runtime related exceptions (missing algorithms) and input related exceptions;
it uses the default platform encoding for your plaintext;
it is using a Sun internal class to perform the Base 64 encoding/decoding.
Note that people will probably point out to you that you are using 128 bit AES encryption. That's however quite strong and - certainly at this point in time - the least of your worries. Upgrading to 192 or 256 bit AES won't increase security significantly.
Refering to Maarten Bodeswes code I try to bring his code into the form I am using.
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class AESplus
{
public static SecretKeySpec makeKey(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException
{
password = String.format("%040x", new BigInteger(1,password.getBytes(Charset.forName("UTF-8"))));
password = password.substring(password.length()-32, password.length());
final byte[] symKeyData = DatatypeConverter.parseHexBinary(password);
return new SecretKeySpec(symKeyData, "AES");
}
public static String encryptString(String text, SecretKeySpec key) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
final byte[] encodedMessage = text.getBytes(Charset.forName("UTF-8"));
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
final int blockSize = cipher.getBlockSize();
// generate random IV using block size
final byte[] ivData = new byte[blockSize];
final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
rnd.nextBytes(ivData);
final IvParameterSpec iv = new IvParameterSpec(ivData);
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
final byte[] encryptedMessage = cipher.doFinal(encodedMessage);
// concatenate IV and encrypted message
final byte[] ivAndEncryptedMessage = new byte[ivData.length + encryptedMessage.length];
System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage, blockSize, encryptedMessage.length);
return DatatypeConverter.printBase64Binary(ivAndEncryptedMessage);
}
public static String decrytString(String crypttext, SecretKeySpec key) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
final byte[] ivAndEncryptedMessage = DatatypeConverter.parseBase64Binary(crypttext);
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
final int blockSize = cipher.getBlockSize();
// retrieve random IV from start of the received message
final byte[] ivData = new byte[blockSize];
System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
final IvParameterSpec iv = new IvParameterSpec(ivData);
// retrieve the encrypted message itself
final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length - blockSize];
System.arraycopy(ivAndEncryptedMessage, blockSize, encryptedMessage, 0, encryptedMessage.length);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
final byte[] encodedMessage = cipher.doFinal(encryptedMessage);
// concatenate IV and encrypted message
final String message = new String(encodedMessage,Charset.forName("UTF-8"));
return message;
}
}
Related
To decrypt an AES encrypted field through REST API, i've have one issue in understanding the IV(Initialization Vector) and how to use that to decrypt the first block of 16 characters.
Encrypted field from the REST response JSON (description form field):
"description":"84d1d37bdb7a3200750573ffbf96191f:0aZdRxsIqSpFtuszNr73na/J9JuMLNB>0J6T2f2FrV0sUlMmbW4prbZMmXGnLU4W6CDlb5F1lb8js\r\nRHw6tfyZd5ZL//ZUlozE916wvP+zd+>uUfjpk2Bl9o2uAu+1bsNoAVdtP5m5fbnkjxf9yLRzREVVO\r\nIwYQOxNI/CeX2dzF/Uc="
I was able to identify this
"0aZdRxsIqSpFtuszNr73na/J9JuMLNB>0J6T2f2FrV0sUlMmbW4prbZMmXGnLU4W6CDlb5F1lb8js>r\nRHw6tfyZd5ZL//ZUlozE916wvP+zd+>uUfjpk2Bl9o2uAu+1bsNoAVdtP5m5fbnkjxf9yLRzREVV>O\r\nIwYQOxNI/CeX2dzF/Uc="
as the actual description and,
"84d1d37bdb7a3200750573ffbf96191f"
to be somehow related to my question in this post.
Encryption method: AES 128 Bit.
Password: 1234567890123456
Original Text: “new description for new incident.
www.google.com
lets see if the initial part is same or it changes for this new incident”
Decrypted output: “bGOn>22H~KH:38/_for new incident.
www.google.com
lets see if the initial part is same or it changes for this new incident”
Decryption Used: AES/CBC/PKCS5Padding
How to decrypt the first block which is jumbled in the Decrypted output. In other words, how to interpret 84d1d37bdb7a3200750573ffbf96191f in terms of IV to decrypt the first 16 characters ?
Any help would be appreciated.
Below is the Java code:
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class AESDecryption {
private static String key = "1234567890123456";
private static String encryptedStr = "0aZdRxsIqSpFtuszNr73na/J9JuMLNB0J6T2f2FrV0sUlMmbW4prbZMmXGnLU4W6CDlb5F1lb8js\r\nRHw6tfyZd5ZL//ZUlozE916wvP+zd+uUfjpk2Bl9o2uAu+1bsNoAVdtP5m5fbnkjxf9yLRzREVVO\r\nIwYQOxNI/CeX2dzF/Uc=";
private static String padding = "AES/CBC/PKCS5Padding";
private static int iterationCount = 65536;
private static int keyLength = 128;
private static String secretKeyAlg = "PBEWithHmacSHA1AndAES_128";
public static void main(String[] args) throws Exception {
String finalStrDec = null;
SecretKeyFactory factory = SecretKeyFactory.getInstance(secretKeyAlg);
PBEKeySpec spec = new PBEKeySpec(key.toCharArray(), generateSalt(), iterationCount, keyLength);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(new byte[16]);
Cipher cipherDec = Cipher.getInstance(padding);
cipherDec.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
byte[] original = cipherDec.doFinal(Base64.decodeBase64(encryptedStr));
finalStrDec = new String(original);
System.out.println(finalStrDec);
}
public static byte[] generateSalt() throws UnsupportedEncodingException {
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
String salt = new String(bytes);
return salt.getBytes("UTF-8");
}
}
I have the following code which works on Windows and Linux/Unix but will not decrypt an encrypted text that has been encrypted on Linux/Unix or vice versa.
I am aware that this will also generate the same encrypted text everytime, but I've removed some of the code to get to the very basic.
I am sure it's not related to Charset encoding, as the encoded String is the same on both OS, even the SecretKey is the same on both.
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
public class Encryptor {
private static final String password = "passwordKey";
private static final Charset UTF_8 = Charset.forName("UTF-8");
private static final byte [] salt = "test salt as string".getBytes(UTF_8);
public static String encrypt(String text) throws UnsupportedEncodingException {
IvParameterSpec ivSpec = new IvParameterSpec(password.getBytes(UTF_8));
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 10000, ivSpec);
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 10000);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWithSHA256AndAES_256");
SecretKey key = secretKeyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("PBEWithSHA256AndAES_256");
cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);
byte [] encrypted = cipher.doFinal(text.getBytes(UTF_8));
return Base64.encodeBase64String(encrypted);
}
public static String decrypt(String encryptedText) throws UnsupportedEncodingException {
IvParameterSpec ivSpec = new IvParameterSpec(password.getBytes(UTF_8));
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 10000, ivSpec);
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 10000);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWithSHA256AndAES_256");
SecretKey key = secretKeyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("PBEWithSHA256AndAES_256");
cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);
byte [] decoded = Base64.decodeBase64String(encryptedText);
byte [] decrypted = cipher.doFinal(decoded);
return new String(decrypted, UTF_8);
}
public static void main(String args []) throws UnsupportedEncodingException {
String encryptedFromWindows = "eFRvTevgk/oslll+234r5tdsss==";
System.out.println(decrypt(encryptedFromWindows));
}
}
Exception:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
The problem was a bug in the JDK version of _64. Upgraded to _121 and it worked. IT wasn't a known oracle bug but they had mentioned in another similar bug of issues with encryption in that release.
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class Encryption {
public static byte[] encrypted(String t) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException{
byte[] dataToSend = t.getBytes();
byte[] key = new byte[16];
Cipher c = Cipher.getInstance("AES");
SecretKeySpec k = new SecretKeySpec(key, "AES");
c.init(Cipher.ENCRYPT_MODE, k);
byte[] encryptedData = c.doFinal(dataToSend);
return encryptedData;
}
public static byte[] decrypted(byte[] kr) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException{
byte[] key = new byte[16];
SecretKeySpec k = new SecretKeySpec(key, "AES");
byte[] encryptedData = kr;
Cipher c2 = Cipher.getInstance("AES");
c2.init(Cipher.DECRYPT_MODE, k);
byte[] data = c2.doFinal(encryptedData);
return data;
}
public static void main(String args[]) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
//method1
System.out.println(encrypted("adsda"));
String f = new String (encrypted("adsda")); //working on console but not works when stores to cookies because of invalid characters
System.out.println(f);
System.out.println(new String(decrypted(f.getBytes())));// works when decrypting in console, not tried in cookies because not able encrypt
//method2
String x = encrypted("adsda").toString(); // works when stores in cookies works on console
System.out.println(x);
System.out.println(new String(decrypted(x.getBytes())));// decrypt not working both on console and cookies
System.out.println(decrypted(x.getBytes()).toString()); // decrypt not working both on console and cookies
}
}
I created a method to encrypt and decrypt cookies using AES. The details is the comment on the code.
You can't just convert the byte[] returned by encrypted(..) to a String. You need to use an encoding that do not lose data.
Use an encoding like Base64 or even a hex encoding.
I have the following code which almost works:
AES.java
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class AES {
private static final int KEY_LENGTH = 128;
private static final int ITERATIONS = 100;
private static final String ALGORITHM = "AES";
private static final String SECRET_KEY_ALGORITHM = "PBKDF2WithHmacSHA1";
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private final Cipher m_enc_cipher;
private final Cipher m_dec_cipher;
private final byte[] m_iv;
public AES(final char[] password, final byte[] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException,
NoSuchPaddingException, InvalidKeyException,
InvalidParameterSpecException, IllegalBlockSizeException,
BadPaddingException, UnsupportedEncodingException,
InvalidAlgorithmParameterException {
// Derive the key, given password and salt
final SecretKeyFactory factory = SecretKeyFactory
.getInstance(SECRET_KEY_ALGORITHM);
final KeySpec spec = new PBEKeySpec(password, salt, ITERATIONS,
KEY_LENGTH);
final SecretKey tmp = factory.generateSecret(spec);
final SecretKey secret = new SecretKeySpec(tmp.getEncoded(), ALGORITHM);
// Build encryptor and get IV
final Cipher enc_cipher = Cipher.getInstance(TRANSFORMATION);
enc_cipher.init(Cipher.ENCRYPT_MODE, secret);
final AlgorithmParameters params = enc_cipher.getParameters();
final byte[] iv = params.getParameterSpec(IvParameterSpec.class)
.getIV();
// Build decryptor
final Cipher dec_cipher = Cipher.getInstance(TRANSFORMATION);
dec_cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
this.m_enc_cipher = enc_cipher;
this.m_dec_cipher = dec_cipher;
this.m_iv = iv;
}
public AES(final byte[] iv) throws NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException,
InvalidKeyException, InvalidParameterSpecException,
IllegalBlockSizeException, BadPaddingException,
UnsupportedEncodingException, InvalidAlgorithmParameterException {
final AlgorithmParameterSpec aps = new IvParameterSpec(iv);
final KeyGenerator keygen = KeyGenerator.getInstance(ALGORITHM);
keygen.init(KEY_LENGTH);
final SecretKey secret = keygen.generateKey();
// Build encryptor
final Cipher enc_cipher = Cipher.getInstance(TRANSFORMATION);
enc_cipher.init(Cipher.ENCRYPT_MODE, secret, aps);
// Build decryptor
final Cipher dec_cipher = Cipher.getInstance(TRANSFORMATION);
dec_cipher.init(Cipher.DECRYPT_MODE, secret, aps);
this.m_enc_cipher = enc_cipher;
this.m_dec_cipher = dec_cipher;
this.m_iv = iv;
}
public byte[] get_iv() {
return this.m_iv;
}
public byte[] encrypt(final byte[] data) throws NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException,
InvalidKeyException, InvalidParameterSpecException,
IllegalBlockSizeException, BadPaddingException,
UnsupportedEncodingException {
return this.m_enc_cipher.doFinal(data);
}
public byte[] decrypt(final byte[] data) throws IllegalBlockSizeException,
BadPaddingException {
return this.m_dec_cipher.doFinal(data);
}
}
AESTest.java
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.junit.Test;
import static org.junit.Assert.*;
public class AESTest {
#Test
public void test() throws InvalidKeyException, NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException,
InvalidParameterSpecException, IllegalBlockSizeException,
BadPaddingException, UnsupportedEncodingException,
InvalidAlgorithmParameterException {
final char[] password = "my_password".toCharArray();
final byte[] salt = new byte[] { 22, 11 };
final byte[] original_data = "Hello, World!".getBytes("UTF-8");
final AES aesA = new AES(password, salt);
final byte[] encrypted_data = aesA.encrypt(original_data);
System.out.println("Encrypted:");
System.out.println(javax.xml.bind.DatatypeConverter
.printBase64Binary(encrypted_data));
final AES aesB = new AES(aesA.get_iv());
final byte[] decrypted_data_B = aesB.decrypt(encrypted_data);
System.out.println("Decrypted B:");
System.out.println(javax.xml.bind.DatatypeConverter
.printBase64Binary(decrypted_data_B));
assertTrue(Arrays.equals(original_data, decrypted_data_B));
}
}
On the test (AESTest.java), it gives me this error:
javax.crypto.BadPaddingException: Given final block not properly padded
My final purpose is to be able to send an encrypted data block and later get it back.
The term "later" could refer to a day/week/year.
Then, using the same password I want to decrypt it.
Because "later" might be a month I'll need to create a new AES object.
Now, this new AES object must be able to decrypt the data with the same fixed password/salt.
That's all.
I've tried to use the same IV but it doesn't work.
What am I doing wrong here?
Edit #1:
Please pay attention to ITERATIONS as well.
When you init AES by iv you create a different secret. Isnt's it wrong?
You are not using the same password and salt.
As already stated, the second constructor creates a new AES key, so it won't match with the one created in the first constructor. I don't really get your intention in having two different constructors, where in each you create an AES instance fit for encryption as well as another one for decryption? It might make sense to rethink that design and use just one single instance only, depending on whether you want to encrypt or decrypt.
While the key you generate in the first constructor is to be kept secret, the IV being produced is public information and can be safely published publicly, this won't harm the security. However, you should create unique IVs for every encrypted message, otherwise there's attacks that are possible against the CBC mode you are using.
So here's how I would recommend you do it:
Encryption:
Basically the first constructor, leaving out the second instance for decryption. Retrieve the IV that was created.
Decryption:
Again basically the first constructor, with an additional IV parameter. Create the key again from scratch with exactly the same parameters (salt, password, iterations), and this time init the Cipher in decryption mode, additionally passing the IV parameter.
That should do it!
I'm writing an application for Android that uses symmetric key encryption to protect sensitive data. As far as I can tell, Android only directly supports "PBEWithMD5AndDES". How secure is this algorithm? Also, I've included my code below (non-andriod). Is my code correctly encrypting the data?
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class CipherTest
{
private static class EncryptInfo
{
private final byte[] encryptedData;
private final byte[] initVector;
private final byte[] salt;
public EncryptInfo(byte[] encryptedData, byte[] initVector, byte[] salt)
{
this.encryptedData = encryptedData.clone();
this.initVector = initVector.clone();
this.salt = salt.clone();
}
public byte[] getEncryptedData()
{
return encryptedData;
}
public byte[] getInitVector()
{
return initVector;
}
public byte[] getSalt()
{
return salt;
}
}
private static final String keyGenAlgorithm = "PBEWithMD5AndDES";
private static final String keyAlgorithm = "DES";
private static final String cipherTransform = "PBEWithMD5AndDES/CBC/PKCS5Padding";
private static EncryptInfo encrypt(char[] password, byte[] data)
throws NoSuchAlgorithmException, InvalidKeySpecException,
NoSuchPaddingException, InvalidKeyException,
InvalidParameterSpecException, IllegalBlockSizeException,
BadPaddingException, UnsupportedEncodingException
{
byte[] salt = new byte[16];
new SecureRandom().nextBytes(salt);
PBEKeySpec keySpec = new PBEKeySpec(password, salt, 1024);
SecretKeyFactory secretKeyFactory = SecretKeyFactory
.getInstance(keyGenAlgorithm);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
keySpec.clearPassword();
byte[] key = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(key, keyAlgorithm);
Cipher cipher = Cipher.getInstance(cipherTransform);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] initVector = cipher.getParameters().getParameterSpec(
IvParameterSpec.class).getIV();
return new EncryptInfo(cipher.doFinal(data), initVector, salt);
}
public static byte[] decrypt(byte[] data, char[] password, byte[] salt,
byte[] initVector) throws NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException,
InvalidKeyException, InvalidAlgorithmParameterException,
IllegalBlockSizeException, BadPaddingException
{
PBEKeySpec keySpec = new PBEKeySpec(password, salt, 1024);
SecretKeyFactory secretKeyFactory = SecretKeyFactory
.getInstance(keyGenAlgorithm);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
keySpec.clearPassword();
byte[] key = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(key, keyAlgorithm);
Cipher cipher = Cipher.getInstance(cipherTransform);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(
initVector));
return cipher.doFinal(data);
}
public static void main(String[] args) throws Exception
{
char[] password = "password".toCharArray();
EncryptInfo info = encrypt(password, "Message".getBytes());
byte[] decyptedText = decrypt(info.getEncryptedData(), password, info
.getSalt(), info.getInitVector());
System.out.println(new String(decyptedText));
}
}
Both MD5 and DES are weak. If your data being encrypted is really valuable, you should look for some external crypto library for Android that offers AES and SHA256/SHA512 algorithms.
If you want to encrypt data using a symmetric key encryption, I recommend:
1) Use AES, because it is certified by the NSA for data classified as secret.
2) Use a well reviewed implementation so you don't have to research the proper way to configure the code. For example, AESCrypt.
You can find AESCrypt here: http://www.aescrypt.com/java_aes_crypt.html
I've seen AESCrypt used in several financial institutions. AESCrypt for java is a single class that calls JCE methods. Android, JCE is implemented by bouncycastle. I have seen bouncycastle used in several major financial institutions.