安卓4.2打破了我的加密/解密code和提供的解决方案不起作用 [英] Android 4.2 broke my encrypt/decrypt code and the provided solutions don't work

查看:345
本文介绍了安卓4.2打破了我的加密/解密code和提供的解决方案不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我已经看到了 <一href="http://stackoverflow.com/questions/13389870/android-4-2-broke-my-aes-encrypt-decrypt-$c$c">Android 4.2打破了我的AES加密/解密code 和 在Android 4.2 加密错误 和所提供的解决方案:

First of all, I've already seen Android 4.2 broke my AES encrypt/decrypt code and Encryption error on Android 4.2 and the provided solution:

SecureRandom sr = null;
if (android.os.Build.VERSION.SDK_INT >= JELLY_BEAN_4_2) {
    sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
} else {
    sr = SecureRandom.getInstance("SHA1PRNG");
}

对我来说是不行的,因为,解码加密的Andr​​oid&LT数据时,4.2的Andr​​oid 4.2,我得到:

doesn't work for me, because, when decoding data encrypted in Android<4.2 in Android 4.2, I get:

javax.crypto.BadPaddingException: pad block corrupted
at com.android.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(BaseBlockCipher.java:709)

我的code是非常简单的,一直干到安卓4.2:

My code is quite simple, and was working until Android 4.2:

public static byte[] encrypt(byte[] data, String seed) throws Exception {

    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    SecureRandom secrand = SecureRandom.getInstance("SHA1PRNG");
    secrand.setSeed(seed.getBytes());
    keygen.init(128, secrand);

    SecretKey seckey = keygen.generateKey();
    byte[] rawKey = seckey.getEncoded();

    SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    return cipher.doFinal(data);
}

public static byte[] decrypt(byte[] data, String seed) throws Exception {

    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    SecureRandom secrand = SecureRandom.getInstance("SHA1PRNG");
    secrand.setSeed(seed.getBytes());
    keygen.init(128, secrand);

    SecretKey seckey = keygen.generateKey();
    byte[] rawKey = seckey.getEncoded();

    SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    return cipher.doFinal(data);
}

我的猜测是,默认的提供并不是说在Android的4.2唯一改变的,否则我的code将与所提出的解决方案。

My guess is that the default provider wasn't the only thing that changed in Android 4.2, otherwise my code would work with the proposed solution.

我的code是基于一些后,我发现这里的StackOverflow很久以前;我看到它不同于提到的帖子,因为它只是隐窝和解密字节数组,而其他的解决方案,隐窝和解密字符串(十六进制字符串,我认为)。

My code was based on some post I found here at StackOverflow a long time ago; I see that it differs from the mentioned posts as it just crypts and decrypts byte arrays, whereas the others solutions crypt and decrypt Strings (HEX Strings, I think).

是否有做的种子?它有一个最小/最大长度,字符的限制,等等?

Does it have to do with the seed? Does it have a min/max length, restriction of chars, etc?

任何想法/解决方案?

修改: 大量的测试后,我看到有2个问题:

EDIT: After a lot of tests, I see that there are 2 problems:

    在安卓4.2
  1. 提供商改变(API 17) - >这一个是容易解决,只适用于我的帖子

  1. The provider changed in Android 4.2 (API 17) -> This one is easy to fix, just apply the solution I mentioned at top of the post

BouncyCastle的从1.34改变到1.45在机器人2.2(API 8) - >的Andr​​oid2.3(API 9),所以解密问题我previously告诉是相同的描述如下:<一href="http://stackoverflow.com/questions/4405334/bouncycastle-aes-error-when-upgrading-to-1-45">BouncyCastle升级到1.45 当AES误差

BouncyCastle changed from 1.34 to 1.45 in Android 2.2 (API 8)->Android2.3 (API 9), so the decryption problem I previously told is the same as described here: BouncyCastle AES error when upgrading to 1.45

所以,现在的问题是:?有没有什么办法来恢复BouncyCastle的加密的在BouncyCastle的数据1.34 1.45 +

So now the question is: is there any way to recover data crypted in BouncyCastle 1.34 in BouncyCastle 1.45+?

推荐答案

首先免责声明:

不要的用不完的SecureRandom派生的关键!这被打破,没有什么意义!

DO NOT ever use "SecureRandom" to derive a key! This is broken and doesn't make sense!

如果你从磁​​盘读取的AES密钥,只存储实际的密钥并不会通过这种怪异的舞蹈。您可以通过执行获得SecretKey的用于AES的使用量从字节:

If you're reading an AES key from disk, just store the actual key and don't go through this weird dance. You can get a SecretKey for AES usage from the bytes by doing:

    SecretKey key = new SecretKeySpec(keyBytes, "AES");

如果您使用的是密码派生密钥,按照 Nelenkov的优异教程的与一个好的经验法则是盐大小应的大小相同的密钥输出的警告。它看起来是这样的:

If you're using a password to derive a key, follow Nelenkov's excellent tutorial with the caveat that a good rule of thumb is the salt size should be the same size as the key output. It looks like this:

    /* User types in their password: */
    String password = "password";

    /* Store these things on disk used to derive key later: */
    int iterationCount = 1000;
    int saltLength = 32; // bytes; should be the same size as the output (256 / 8 = 32)
    int keyLength = 256; // 256-bits for AES-256, 128-bits for AES-128, etc
    byte[] salt; // Should be of saltLength

    /* When first creating the key, obtain a salt with this: */
    SecureRandom random = new SecureRandom();
    byte[] salt = new byte[saltLength];
    randomb.nextBytes(salt);

    /* Use this to derive the key from the password: */
    KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt,
                iterationCount, keyLength);
    SecretKeyFactory keyFactory = SecretKeyFactory
                .getInstance("PBKDF2WithHmacSHA1");
    byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
    SecretKey key = new SecretKeySpec(keyBytes, "AES");

就是这样。你还有什么不应该使用。

That's it. Anything else you should not use.

如果您不小心使用了一些其他的方法,如SecureRandom的派生密钥,就可以恢复。 只能用这个来走迁移到一个真正的基于口令的密钥导出函数!它可能不会在其随后所有的工作。

If you accidentally used some other method such as SecureRandom to derive keys, you can recover. Only use this to migrate away to a real Password-Based Key Derivation Function! It may not work at all later.

要使用相同的(有缺陷的,空洞的)的方式得到的钥匙,你的也许的能够做的:

To derive the keys using the same (flawed and inane) way, you might be able to do:

    SecureRandom.getInstance("SHA1PRNG", "Crypto");

这篇关于安卓4.2打破了我的加密/解密code和提供的解决方案不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆