java - Android 运行时错误的自定义加密类

标签 java android encryption aes

我在 stackoverflow 上发现了一个有趣的代码:What are best practices for using AES encryption in Android?

我做了一些更改以使其工作(删除了 implements ICrypto,将 throws CryptoException 更改为 throws Exception,添加了 toHex toByte 函数,并将部分函数改为静态)

我正在尝试通过这样调用来加密字符串:

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

}

最佳答案

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

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

关于java - Android 运行时错误的自定义加密类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16299042/

相关文章:

java - Android:动态壁纸应用程序中的性能 'hickups'

linux - 未记录的内核引导参数?

scala 中的 java.util.Date 增量不一致

android - 强制关闭应用程序时关闭后台服务

java - 线程中出现异常 "main"java.lang.OutOfMemoryError : Java heap space while using util Packages

Android - 在转换的小部件中转换小部件以及由此产生的可用性问题

javascript - 封包加密大文件

java - 努力存储生成的盐以进行 aes 加密/解密

java - 当只允许 SQLException 时,如何抛出 EOFException?

java - 未输入任何内容时代码不会执行