好吧,我打算按照用户的顺序从SD卡加密文件,然后在此之后将其解密。经过一些搜索后,我发现了如何在Android中使用" AES"来完成它。一切都很好,直到用户给我关于Android Nougat解密失败的反馈!我查了一下,不幸的是他们是对的:(
应用程序在Lollipop和Kitkat上表现不错,但没有" NOUGAT"!
我检查了Log(作为首先想到的事情),我看到了这一点:
- 新版Android SDK不再支持加密提供程序。
- 如果您的应用依赖setSeed()从字符串派生键,那么
- 应该切换到使用SecretKeySpec直接加载原始密钥字节OR
- 使用真实密钥派生函数(KDF)。请参阅此处的建议:
- http://android-developers.blogspot.com/2016/06/security-crypto-provider-deprecated-in.html
我有点吓坏了,因为我正在使用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();
}
上找到了一些关于此问题的会谈
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完全删除它,它也会在我的项目中工作!!!
我只是复制CryptoProvider,SHA1PRNG_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上使用简单加密工作失败的序列如下,所以它再次起作用。我的意思是它确实解密但文件再次损坏了!
我真的非常喜欢任何帮助,我想知道如果有人遇到同样的问题并知道如何解决它!?