2

i have found an interesting code posted here on stackoverflow: What are best practices for using AES encryption in Android?

I have made some changes to make it work (deleted implements ICrypto, changed throws CryptoException to throws Exception, added toHex and toByte Functions and changed some functions to static)

I'm trying to encrypt a string by calling it like this:

String EncryptedText = AdvancedCrypto.encrypt(AdvancedCrypto.getSecretKey("MyPassword", "MySalt"), "TheStringThatIwantEncrypted");

What am I doing wrong? I'm using Eclipse and I have no errors on the code but when I run it on Android AVD nothing really happens. The Logcat pops me some strange logs which I don't know what they mean.

This is what i get from logcat:

 W/System.err(346): java.lang.Exception: Unable to get secret key
 W/System.err(346):     at com.example.enc.AdvancedCrypto.getSecretKey(AdvancedCrypto.java:92)
 W/System.err(346):     at com.example.enc.MainActivity$1.onClick(MainActivity.java:38)
 W/System.err(346):     at android.view.View.performClick(View.java:2364)
 W/System.err(346):     at android.view.View.onTouchEvent(View.java:4179)
 W/System.err(346):     at android.widget.TextView.onTouchEvent(TextView.java:6541)
 W/System.err(346):     at android.view.View.dispatchTouchEvent(View.java:3709)
 W/System.err(346):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
 W/System.err(346):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
 W/System.err(346):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
 W/System.err(346):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
 W/System.err(346):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1659)
 W/System.err(346):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107)
 W/System.err(346):     at android.app.Activity.dispatchTouchEvent(Activity.java:2061)
 W/System.err(346):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1643)
 W/System.err(346):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1691)
 W/System.err(346):     at android.os.Handler.dispatchMessage(Handler.java:99)
 W/System.err(346):     at android.os.Looper.loop(Looper.java:123)
 W/System.err(346):     at android.app.ActivityThread.main(ActivityThread.java:4363)
 W/System.err(346):     at java.lang.reflect.Method.invokeNative(Native Method)
 W/System.err(346):     at java.lang.reflect.Method.invoke(Method.java:521)
 W/System.err(346):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
 W/System.err(346):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
 W/System.err(346):     at dalvik.system.NativeStart.main(Native Method)
 W/System.err(346): Caused by: java.lang.NumberFormatException: unable to parse 'dh' as integer
 W/System.err(346):     at java.lang.Integer.parse(Integer.java:374)
 W/System.err(346):     at java.lang.Integer.parseInt(Integer.java:363)
 W/System.err(346):     at java.lang.Integer.valueOf(Integer.java:688)
 W/System.err(346):     at com.example.enc.AdvancedCrypto.toByte(AdvancedCrypto.java:32)
 W/System.err(346):     at com.example.enc.AdvancedCrypto.getSecretKey(AdvancedCrypto.java:86)
 W/System.err(346):     ... 22 more

The code I have so far is this:

public class AdvancedCrypto {

  public static final String PROVIDER = "BC";
  public static final int SALT_LENGTH = 20;
  public static final int IV_LENGTH = 16;
  public static final int PBE_ITERATION_COUNT = 100;

  private static final String RANDOM_ALGORITHM = "SHA1PRNG";
  private static final String HASH_ALGORITHM = "SHA-512";
  private static final String PBE_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
  private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
  private static final String SECRET_KEY_ALGORITHM = "AES";

  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));
  }

  public static String encrypt(SecretKey secret, String cleartext) throws Exception {
    try {

      byte[] iv = generateIv();
      String ivHex = toHex(iv);
      IvParameterSpec ivspec = new IvParameterSpec(iv);

      Cipher encryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
      encryptionCipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);
      byte[] encryptedText = encryptionCipher.doFinal(cleartext.getBytes("UTF-8"));
      String encryptedHex = toHex(encryptedText);

      return ivHex + encryptedHex;

    } catch (Exception e) {
      throw new Exception("Unable to encrypt", e);
    }
  }

  public static String decrypt(SecretKey secret, String encrypted) throws Exception {
    try {
      Cipher decryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
      String ivHex = encrypted.substring(0, IV_LENGTH * 2);
      String encryptedHex = encrypted.substring(IV_LENGTH * 2);
      IvParameterSpec ivspec = new IvParameterSpec(toByte(ivHex));
      decryptionCipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
      byte[] decryptedText = decryptionCipher.doFinal(toByte(encryptedHex));
      String decrypted = new String(decryptedText, "UTF-8");
      return decrypted;
    } catch (Exception e) {
      throw new Exception("Unable to decrypt", e);
    }
  }

  public static SecretKey getSecretKey(String password, String salt) throws Exception {
    try {
      PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), toByte(salt), PBE_ITERATION_COUNT, 256);
      SecretKeyFactory factory = SecretKeyFactory.getInstance(PBE_ALGORITHM, PROVIDER);
      SecretKey tmp = factory.generateSecret(pbeKeySpec);
      SecretKey secret = new SecretKeySpec(tmp.getEncoded(), SECRET_KEY_ALGORITHM);
      return secret;
    } catch (Exception e) {
      throw new Exception("Unable to get secret key", e);
    }
  }

  public String getHash(String password, String salt) throws Exception {
    try {
      String input = password + salt;
      MessageDigest md = MessageDigest.getInstance(HASH_ALGORITHM, PROVIDER);
      byte[] out = md.digest(input.getBytes("UTF-8"));
      return toHex(out);
    } catch (Exception e) {
      throw new Exception("Unable to get hash", e);
    }
  }

  public String generateSalt() throws Exception {
    try {
      SecureRandom random = SecureRandom.getInstance(RANDOM_ALGORITHM);
      byte[] salt = new byte[SALT_LENGTH];
      random.nextBytes(salt);
      String saltHex = toHex(salt);
      return saltHex;
    } catch (Exception e) {
      throw new Exception("Unable to generate salt", e);
    }
  }

  private static byte[] generateIv() throws NoSuchAlgorithmException, NoSuchProviderException {
    SecureRandom random = SecureRandom.getInstance(RANDOM_ALGORITHM);
    byte[] iv = new byte[IV_LENGTH];
    random.nextBytes(iv);
    return iv;
  }

}
Community
  • 1
  • 1
Light Flow
  • 539
  • 1
  • 6
  • 18
  • "*The Logcat pops me some strange logs which i don't know what they mean.*" > We might know what they mean - please add them to the question. – Duncan Jones Apr 30 '13 at 12:01
  • "*nothing really happens*" > Does it throw an exception? Does it execute the the result looks wrong? – Duncan Jones Apr 30 '13 at 12:02
  • Just Added Logcat Output. When i say "nothing really happens" i mean nothing visually happens (while i expect a toast message with the encrypted message in the code to be shown). I don't get an error visually. All the errors i get is the ones you can see in logcat output. – Light Flow Apr 30 '13 at 12:14

1 Answers1

0

Reading the stack trace, it looks like the salt value passed to getSecretKey contained invalid values. Specifically, it should be a hex value but it contained an h.

Your password can contain non-hexadecimal characters, but your salt must be pure hexadecimal.

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
  • Thank you very much my friend!! Indeed. My salt wasn't pure hexademical, it contained an h. I Changed it and worked like a charm! – Light Flow Apr 30 '13 at 13:17