2

我在 stackoverflow 上发现了一个有趣的代码:在 Android 中使用 AES 加密的最佳实践是什么?

我进行了一些更改以使其正常工作(已删除implements ICrypto、更改throws CryptoExceptionthrows Exception、添加toHextoByte函数并将一些函数更改为静态)

我试图通过这样调用它来加密一个字符串:

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

我究竟做错了什么?我正在使用 Eclipse,我的代码没有错误,但是当我在 Android AVD 上运行它时,什么都没有发生。Logcat 会弹出一些奇怪的日志,我不知道它们是什么意思。

这是我从 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

我到目前为止的代码是这样的:

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

}
4

1 回答 1

0

读取堆栈跟踪,看起来传递给getSecretKey包含无效值的盐值。具体来说,它应该是一个十六进制值,但它包含一个h.

您的密码可以包含非十六进制字符,但您的 salt 必须是纯十六进制的。

于 2013-04-30T12:19:18.403 回答