在查看Android 4.2及更高版本中的加密问题后,我们会查看许多问题和答案(具体来说,4.2之前加密的事情不能再在4.2中解密)但是没有一个答案似乎适合我的情况。
我们有一个服务器端系统,它接受来自我们各种设备客户端(无论是Javascript,iOS,Android还是Windows)的AES加密有效负载,解密数据,然后......做任何需要的事情。在我们最近将我们的Android客户端升级到API级别19之前,这一直工作正常。现在服务器(用C#编写并使用标准的.NET加密库)无法再解密消息,因为PKCS5Padding已损坏。所有其他客户端继续使用服务器就好了。
这是我们的加密方法:
private static String encryptString(String plainText, byte[] key, byte[] salt, byte[] iv) {
try{
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keyspec = new PBEKeySpec(keyToCharArray(key), salt,
getEncryptionKeyIterations(), 256);
SecretKey secretKey = factory.generateSecret(keyspec);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secretKey.getEncoded(), "AES")
, new IvParameterSpec(iv));
return Base64.encodeToString(cipher.doFinal(plainText.getBytes()), Base64.NO_WRAP);
} catch(Exception ex) {
Log.e(TAG, "Unable to encrypt message", ex);
throw new InvalidDataException("Unable to encrypt message");
}
}
使用以下方法生成IV:
public static byte[] getRandomIv() throws InvalidDataException {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
kgen.init(128, sr);
return kgen.generateKey().getEncoded();
} catch(Exception ex) {
Log.e(TAG, "Unable to create random IV", ex);
throw new InvalidDataException("Unable to create random IV");
}
}
我在这里看到的一些帖子说用SecureRandom.getInstance替换SecureRandom.getInstance(" SHA1PRNG")(" SHA1PRNG"," Crypto" )使用Java Crypto而不是OpenSSL。对我们来说,这对另一端的解密没有任何影响。
我也尝试过切换到SpongyCastle,但这并没有解决问题。
我们提供的密钥是用户密码,用已知的盐腌制,然后SHA256散列。这也是服务器上的已知数量,其中密钥在解密之前使用相同的算法加强。
修改
看来它可能确实是IV代。听起来很奇怪,只需使用SecureRandom切换到更简单的IV代似乎"修复"问题。
答案 0 :(得分:1)
似乎问题是IV代。虽然原始代码生成128位密钥(带KeyGenerator的AES输出128位密钥,按照http://docs.oracle.com/javase/7/docs/api/javax/crypto/KeyGenerator.html),但它似乎不再正常工作。
将代码更改为:
public static byte[] getRandomIv() throws InvalidDataException {
try {
SecureRandom sr = new SecureRandom();
byte[] output = new byte[16];
sr.nextBytes(output);
return output;
} catch(Exception ex) {
Log.e(TAG, "Unable to create random IV", ex);
throw new InvalidDataException("Unable to create random IV");
}
}
让库解密来自服务器的消息并成功登录。我们在一系列API级别上测试了这个,返回到API级别10,它运行良好。谢谢你的帮助。