在Android N(牛轧糖)中使用AES加密文件后解密失败

时间:2017-11-01 08:57:04

标签: android encryption aes android-7.0-nougat secret-key

好吧,我打算按照用户的顺序从SD卡加密文件,然后在此之后将其解密。经过一些搜索后,我发现了如何在Android中使用" AES"来完成它。一切都很好,直到用户给我关于Android Nougat解密失败的反馈!我查了一下,不幸的是他们是对的:(

应用程序在Lollipop和Kitkat上表现不错,但没有" NOUGAT"!

我检查了Log(作为首先想到的事情),我看到了这一点:

  

我有点吓坏了,因为我正在使用Crypto-Provider !!!

public static byte[] generateKey(String password) throws Exception {
    byte[] keyStart = password.getBytes("UTF-8");
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom random = SecureRandom.getInstance("[SHA1PRNG][1]", "Crypto");
    random.setSeed(keyStart);
    kgen.init(128, random);
    SecretKey skey = kgen.generateKey();
    return skey.getEncoded();
}

然后我在SO [1][2]

上找到了一些关于此问题的会谈

developer网站说我们不应再使用加密提供程序来生成AES的密钥,因为:

  

此提供程序仅提供了算法的实现   SecureSandom实例的“SHA1PRNG”。问题是,   SHA1PRNG算法在加密方面不够强大。

而我们应该像这样生成密钥:

public byte[] generateKeyForAES(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
    /* 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  
    /* When first creating the key, obtain a salt with this: */
    SecureRandom random = new SecureRandom();
    byte[] salt = new byte[saltLength];
    random.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");

    return key.getEncoded();
}

作为一个好孩子,我取代了新的生成钥匙的方式,但它没有工作! (糟糕的谷歌)然后我开始好好看看这个代码,我意识到,因为每次我们运行这个方法,"盐"正在生成" RANDOM"我们无法生成两次相同的密钥。所以你要么节省盐!在第一次生成之后或使用静态盐。好吧,我用的是静态盐:)

byte[] salt = {(byte) 0xA4, (byte) 0x0B, (byte) 0xC8, (byte) 0x34, (byte) 0xD6, (byte) 0x95, (byte) 0xF3, (byte) 0x13};

正如你猜测的那样,是的,它也没有用!我的意思是它确实解密了文件,但它已损坏!检索不到同一个文件!

自从我遇到这个问题并经历了很多方法来解决它以来,这已经是一个星期,但它们都没有奏效。

有很多关于SO的谈判是关于"无法通过AES解密#34;但要么提出一种不起作用或无关紧要的方法!

有人说在生成密钥之后初始化密码时转换算法存在问题,而不是:

Cipher cipher = Cipher.getInstance("AES");

我们应该这样做:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

但在解密之后甚至从一开始就无法解密,它比解密一些损坏的文件(当然大小相同)更糟糕!

在我筋疲力尽之后,我认为忘记所有的安全风险并让它发挥作用!!! 然后,@ artjom-b在他的ANSWER中说我试图在我的项目中本地导入CryptoProvider类,然后即使Android完全删除它,它也会在我的项目中工作!!!

我只是复制CryptoProviderSHA1PRNG_SecureRandomImpl,当然还有所有相关的类,并将它放在我的源代码包中,然后 ,回到我用来为AES生成密钥的早期方法,我改变生成密钥方法如下:

public static byte[] generateKey(String password) throws Exception {
    byte[] keyStart = password.getBytes("UTF-8");
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom random = SecureRandom.getInstance("SHA1PRNG", new CryptoProvider());
    random.setSeed(keyStart);
    kgen.init(128, random);
    SecretKey skey = kgen.generateKey();
    return skey.getEncoded();
}

您可能已经注意到SucureRandom被初始化的方式已经改变了! "crypto" {I}引用我的本地提供商并将其转为:

SecureRandom random = SecureRandom.getInstance("SHA1PRNG", new CryptoProvider());

由于我在Android N上使用简单加密工作失败的序列如下,所以它再次起作用。我的意思是它确实解密但文件再次损坏了!

我真的非常喜欢任何帮助,我想知道如果有人遇到同样的问题并知道如何解决它!?

0 个答案:

没有答案