【问题标题】:AES encrypt/decrypt on Android doesn't runAndroid 上的 AES 加密/解密无法运行
【发布时间】:2012-04-08 01:05:53
【问题描述】:

我需要有关 Android 应用程序的加密/解密方面的帮助。

我解释一下情况。我实际上编写了一个应用程序,它使用 iPhone 应用程序生成和加密的内容。

为了安全起见,用户提供自己的密码以正确加密/解密不同平台之间的数据...

但是,我在 Android 上遇到了这个密码短语的加密/解密问题。

我有两个功能:

public byte[] crypt(String pStringToCrypt) throws Exception{

    byte[] key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    System.arraycopy(this.passphrase.getBytes(), 0, key, 0, this.passphrase.getBytes().length);
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(pStringToCrypt.getBytes());
    return encrypted;

}

用于String的加密,这个函数:

public String decrypt(byte[] pCryptedStringtoDecrypt) throws Exception{
    byte[] key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    System.arraycopy(this.passphrase.getBytes(), 0, key, 0, this.passphrase.getBytes().length);
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    byte[] encrypted = pCryptedStringtoDecrypt;
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    byte[] original = cipher.doFinal(encrypted);
    String originalString = new String(original);
    return originalString;
}

用于String的解密。

我使用crypt方法加密数据时没有报错,字符串被加密了:

encrypted = [26, 119, -108, -24, 81, -128, 18, 35, -96, 10, -38, 69, 111, 40, 109, 107]

如果我尝试将这个字节转换成一个字符串,我会得到这个字符串:

encryptedString = "w��Q�#�\n�Eo(mk"

我认为加密阶段很好。 现在,当我尝试解密此加密字符串时,应用程序崩溃了:

javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
    at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:711)
    at javax.crypto.Cipher.doFinal(Cipher.java:1090)
    at org.vincentsaluzzo.lightrpc.common.security.AES256.decrypt(AES256.java:61)
    at com.vincentsaluzzo.LoginBox.model.SettingsManager.getUserPassphrase(SettingsManager.java:67)
    at com.vincentsaluzzo.LoginBox.mainActivity.onCreate(mainActivity.java:26)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1586)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1638)
    at android.app.ActivityThread.access$1500(ActivityThread.java:117)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:928)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:3647)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
    at dalvik.system.NativeStart.main(Native Method)

而且我不明白为什么会出现这个错误...

你有什么解决办法吗?或者给我一些解释?

【问题讨论】:

  • 您应该发布使用过的密码,否则很难追溯您的代码和加密结果。顺便说一句:永远不要使用密码作为密钥!使用密钥派生函数从密码生成密钥。
  • @Robert 从密码生成密钥的密钥派生函数:你有例子吗?
  • @Robert 好的,但我在 Objective-C 中执行相同的代码(当然,使用 Apple 函数)但结果很好......所以,即使使用密码短语作为密钥也不好,这可能是工作,不是吗?
  • 大多数时候是(字符)编码部分出了问题,而不是实际的加密/解密。那只是为了实现。安全方面仍然可能存在许多问题,例如使用 ECB 模式加密、忘记添加完整性/身份验证、忘记创建随机 IV、直接使用密码作为密钥...

标签: android cryptography aes encryption


【解决方案1】:

好的,在你们所有 cmets 的帮助下,我解决了我的问题。

我解释一下。我已将我的两种方法转换为最简单的方法:

public byte[] crypt(byte[] toCrypt) throws Exception {
    byte[] key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    System.arraycopy(this.passphrase.getBytes(), 0, key, 0, ((this.passphrase.getBytes().length < 16) ? this.passphrase.getBytes().length : 16));
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(toCrypt);
    return encrypted;
}

public byte[] decryptt(byte[] toDecrypt) throws Exception {
    byte[] key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    System.arraycopy(this.passphrase.getBytes(), 0, key, 0, ((this.passphrase.getBytes().length < 16) ? this.passphrase.getBytes().length : 16));
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    byte[] original = cipher.doFinal(toDecrypt);
    return original;
}

简而言之,我在此方法中删除了所有转换为字符串的内容。 我已经检查了我在 Objective-C 中的另一个项目中的方法。 我发现了问题:编码字符串!

有时,如果我加密/解密,我会得到相同的字节数组,但有时,数组是不同的,因为我将这个加密的字节数组存储到 SharedPreference 中的字符串中。 当然有可能,但我只是将字节放入一个新的 String(bytes) 中,基本编码是 UTF-8,所以这就是问题所在。

我用 base 64 编码解决了这个问题。我使用在这里找到的 Base64 类:http://sourceforge.net/projects/iharder/files/base64/2.3/

在将加密的字节数组保存到 SharedPreferences 之前,我将它们编码为 Base64 编码,解密过程也是如此。

【讨论】:

  • 这里的 this.passphrase 是什么??我收到错误,无法解决或不是字段
【解决方案2】:

通常,在密码学中使用getBytes() 将字符串转换为字节并不是一件好事。您受机器上默认字符编码的支配。为加密和解密指定编码要好得多,getBytes("UTF-8")

你没有显示调用代码,你确定你将字节数组(encrypted)传递给解密函数而不是字节数组的字符串,你的“w��Q�#�\n� Eo(mk"?

ECB 模式不安全且会泄露数据。为了安全起见,您需要使用 CBC 模式或 CTR 模式。

【讨论】:

  • 是的,但是最好使用base64编码!
猜你喜欢
  • 2011-10-10
  • 2016-09-22
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多