[英]AES-128 Encryption not working on Java < 1.7
我已经在学校任务中捣乱了3天,终于在今天完成了它,没有错误且工作正常! 除了,我在Java 1.7上测试它,学校服务器(教授将编译它)运行1.6。 所以,我在1.6上测试了我的代码,希望覆盖我的所有基础,并在解密时得到BadPaddingException
。
[编辑] 警告:此代码不遵循常见的安全实践,不应在生产代码中使用。
最初,我有这个,在1.7上工作正常(对不起,很多代码..所有相关..):
public static String aes128(String key, String data, final int direction) {
SecureRandom rand = new SecureRandom(key.getBytes());
byte[] randBytes = new byte[16];
rand.nextBytes(randBytes);
SecretKey encKey = new SecretKeySpec(randBytes, "AES");
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES");
cipher.init((direction == ENCRYPT ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE), encKey);
} catch (InvalidKeyException e) {
return null;
} catch (NoSuchPaddingException e) {
return null;
} catch (NoSuchAlgorithmException e) {
return null;
}
try {
if (direction == ENCRYPT) {
byte[] encVal = cipher.doFinal(data.getBytes());
String encryptedValue = Base64.encode(encVal);
return encryptedValue;
} else {
byte[] dataBytes = Base64.decode(data);
byte[] encVal = cipher.doFinal(dataBytes);
return new String(encVal);
}
} catch (NullPointerException e) {
return null;
} catch (BadPaddingException e) {
return null;
} catch (IllegalBlockSizeException e) {
return null;
}
}
但是,我的BadPaddingException
catch
块在解密时执行:
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at CipherUtils.aes128(CipherUtils.java:112)
at CipherUtils.decryptFile(CipherUtils.java:44)
at decryptFile.main(decryptFile.java:21)
这就是我试图解决的问题(基本上,我自己添加了所有填充/取消填充,并使用NoPadding
):
public static String aes128(String key, String data, final int direction) {
// PADCHAR = (char)0x10 as String
while (key.length() % 16 > 0)
key = key + PADCHAR; // Added this loop
SecureRandom rand = new SecureRandom(key.getBytes());
byte[] randBytes = new byte[16];
rand.nextBytes(randBytes);
SecretKey encKey = new SecretKeySpec(randBytes, "AES");
AlgorithmParameterSpec paramSpec = new IvParameterSpec(key.getBytes()); // Created this
Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding"); // Added CBC/NoPadding
cipher.init((direction == ENCRYPT ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE), encKey, paramSpec); // Added paramSpec
} catch (InvalidKeyException e) {
return null;
} catch (NoSuchPaddingException e) {
return null;
} catch (NoSuchAlgorithmException e) {
return null;
} catch (InvalidAlgorithmParameterException e) {
return null; // Added this catch{}
}
try {
if (direction == ENCRYPT) {
while (data.length() % 16 > 0)
data = data + PADCHAR; // Added this loop
byte[] encVal = cipher.doFinal(data.getBytes());
String encryptedValue = Base64.encode(encVal);
return encryptedValue;
} else {
byte[] dataBytes = Base64.decode(data);
byte[] encVal = cipher.doFinal(dataBytes);
return new String(encVal);
}
} catch (NullPointerException e) {
return null;
} catch (BadPaddingException e) {
return null;
} catch (IllegalBlockSizeException e) {
return null;
}
}
使用它时,我只是乱搞乱哄哄:
Out: u¢;èÉ÷JRLòB±J°N°[9cRÐ{ªv=]I¯¿©:
´RLA©êí;R([¶Ü9¸ßv&%®µ^#û|Bá (80)
Unpadded: u¢;èÉ÷JRLòB±J°N°[9cRÐ{ªv=]I¯¿©:
´RLA©êí;R([¶Ü9¸ßv&%®µ^#û|Bá (79)
值得注意的是1.6和1.7产生不同的加密字符串。
例如,在1.7上,使用key hi
加密xy
(包括SHA-1
哈希)会产生:
XLUVZBIJv1n/FV2MzaBK3FLPQRCQF2FY+ghyajdqCGsggAN4aac8bfwscrLaQT7BMHJgfnjJLn+/rwGv0UEW+dbRIMQkNAwkGeSjda3aEpk=
在1.6,同样的事情产生:
nqeahRnA0IuRn7HXUD1JnkhWB5uq/Ng+srUBYE3ycGHDC1QB6Xo7cPU6aEJxH7NKqe3kRN3rT/Ctl/OrhqVkyDDThbkY8LLP39ocC3oP/JE=
我没想到任务需要这么长时间,所以我的时间已经用完了,今晚确实需要完成。 如果那时候没有答案,我只会给老师留言。 它似乎是在1.7中修复的一些问题...虽然希望可以通过我的代码中的正确添加/修复来解决。
非常感谢每个人的时间!
首先:
对于几乎所有系统,两次加密相同的明文应该总是 (即非常非常高的概率)产生不同的密文。
传统的例子是,它允许CPA对手通过两个查询区分E(“黎明时的攻击”)和E(“黄昏时的攻击”)。 (有一些系统需要确定性加密,但正确的方法是“合成IV”或密码模式,如CMC和EME。)
最终,问题是SecureRandom()
不是用于密钥派生的。
scrypt()
或bcrypt()
)的东西。
String.getBytes("UTF-8")
。 额外的挑剔:
SecureRandom
在这里很有用。 我一直在看,我不得不同意NullUserException。 问题是使用SecureRandom
。 这意味着你永远不会真正知道你的密钥是什么,因此它不一定是相同的密钥。
encKey来自SecureRandom,它由提供的密钥播种。 因此,如果键是相同的,种子是相同的,所以随机应该是相同的...
...当然,除非Oracle(或其他提供商)更改版本之间的实现。
好的,添加我研究的更多信息。 我认为这个答案最有帮助 。
从用户获取密码和明文,并将它们转换为字节数组。
生成安全的随机盐。
将salt附加到密码并计算其加密哈希值。 重复多次。
使用生成的哈希作为初始化向量和/或密钥加密明文。
保存盐和生成的密文。
对我来说,听起来像SecureRandom
只使用一次来生成salt
但是必须使用密码文本保存salt
以撤消加密过程。 额外的安全性来自步骤的重复和变化(默默无闻)。
注意:我无法找到任何共识,即这些步骤是最佳做法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.