Encrypt/Decrypt Strings

8 votes · 12 comments

Simple helper class to encrypt and decrypt strings using AES128. The result is Ascii-encoded (actually hex, no base64), so no byte[] has to be stored. A SEED value is used as a shared secret ("Master-Password"). Only with the same SEED the stored values can be decrypted.

raw ·
copy
· download
package net.sf.andhsli.hotspotlogin; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; /** * Usage: * <pre> * String crypto = SimpleCrypto.encrypt(masterpassword, cleartext) * ... * String cleartext = SimpleCrypto.decrypt(masterpassword, crypto) * </pre> * @author ferenc.hechler */ public class SimpleCrypto { public static String encrypt(String seed, String cleartext) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = encrypt(rawKey, cleartext.getBytes()); return toHex(result); } public static String decrypt(String seed, String encrypted) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] enc = toByte(encrypted); byte[] result = decrypt(rawKey, enc); return new String(result); } private static byte[] getRawKey(byte[] seed) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); sr.setSeed(seed); kgen.init(128, sr); // 192 and 256 bits may not be available SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); return raw; } private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(clear); return encrypted; } private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] decrypted = cipher.doFinal(encrypted); return decrypted; } public static String toHex(String txt) { return toHex(txt.getBytes()); } public static String fromHex(String hex) { return new String(toByte(hex)); } public static byte[] toByte(String hexString) { int len = hexString.length()/2; byte[] result = new byte[len]; for (int i = 0; i < len; i++) result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue(); return result; } public static String toHex(byte[] buf) { if (buf == null) return ""; StringBuffer result = new StringBuffer(2*buf.length); for (int i = 0; i < buf.length; i++) { appendHex(result, buf[i]); } return result.toString(); } private final static String HEX = "0123456789ABCDEF"; private static void appendHex(StringBuffer sb, byte b) { sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f)); } }
Add a comment

12 Comments

At the end, why did it change to HEX ? That causes data's size to bigger than original size.

Reply · March 17, 2011, 5:49 a.m.

There are several reasons why you could want a HEX output -- eg. logging and copy&pasting the encoded string. If you don't need it, just skip the toHex step and use the byte[] object directly.

Reply · March 18, 2011, 3:22 p.m.

The best would be to use Base64 encoding. This has the same advantages as the Hex-Encoding and inflates the size only by one third. As Sissi said, just replace the toHex() Call.

Reply · March 27, 2011, 8:41 p.m.

Hi.., is this method compatible if want use encrypt/ decrypt in php? if yes, can show how to encrypt/ decrypt with php?

Reply · April 25, 2011, 9:25 a.m.

If you look in the home page... you will see at the bottom (exactly 19 snippets before this one). that I put a complete example of how to encrypt/decrypt between PHP & Java (Android)

link: http://www.androidsnippets.com/encrypt-decrypt-between-android-and-php

Reply · Sept. 21, 2011, 2:29 p.m.

i am sad to say ,i just can not manage it .what goes wrong

Reply · May 5, 2011, 10:10 a.m.

Thanks for sharing! It works just fine. I was curious about one thing: the code yields different results when I run it on my computer as a Java application and when I run it on Android on my app (so I can't share encrypted data from one to the other). Is that expected or even desired?

Reply · May 23, 2011, 10:56 a.m.

Tested the snippet with a couple of values... encryption & decryption, and it gives at decryption a Exception:

javax.crypto.BadPaddingException: Given final block not properly padded

when either the seed from decrypt(String seed, String encrypted) differs from the original seed from encrypt(String seed, String cleartext). Tested with same & different length seed.

This doesn't seem to be normal behavior for a encryption mechanism; shouldn't decrypt() return a unreadable/mixture of symbols when either the seed or the encrypted parameter from decrypt() differ from the correct values (and not a Exception)

Reply · Aug. 26, 2011, 11:42 a.m.

Is this really that safe to use say a cracker were to come and find this and after decompiling your code using say dex2jar they could easily find your key and with this source backtrack and unencode what ever you were encoding I myself could do this in 30 seconds or less

Reply · Sept. 20, 2011, 4:18 a.m.

I tried to modify it so it didn't convert to Hex but got "IllegalBlockSizeException: last block incomplete in decryption" error.

I only changed 2 lines (see below) and got rid of the Hex subs.

Any suggestions? The code worked great but gave huge results. After modification it seemed to encrypt well but couldn't decrypt.

public class SimpleCrypto2 {

public static String encrypt(String seed, String cleartext) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] result = encrypt(rawKey, cleartext.getBytes());          
        return result.toString();  // <-- new line

// return toHex(result); <-- old line }

public static String decrypt(String seed, String encrypted) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] enc = encrypted.getBytes();  // <-- new line

// byte[] enc = toByte(encrypted); <--old line byte[] result = decrypt(rawKey, enc); return new String(result); }

Reply · Oct. 12, 2011, 1:02 a.m.

I think I figured out the problem. When I convert the encrypted byte array to a string some of the information is lost because not all characters can be in a string (like return, line feed, whatever). I'm a noob at all this and I'm just guessing. Someone let me know if I'm wrong. Anyway, I think I see the advantages of using Hex. I plan to store the encrypted info in a SQLite database so it can't have any freaky characters.

Could someone explain in more detail how to use Base 64 encoding instead? It'd be great if it used less space.

Thanks!

Reply · Oct. 12, 2011, 7:45 p.m.

Use the one I created.. that problem was solved:

http://www.androidsnippets.com/encrypt-decrypt-between-android-and-php

Reply · Oct. 20, 2011, 2:34 p.m.

Use the one I created.. that problem was solved:

http://www.androidsnippets.com/encrypt-decrypt-between-android-and-php

Reply · Oct. 20, 2011, 2:34 p.m.