如果我使用错误的密钥或错误的盐进行解密,则抛出BadPaddingException。 我希望返回一个不正确的字符串。 doFinal()导致decrypt-method
中的异常消息:This is just an example
Unfug:'ΩÙΩ„SåF?V®ßs.k˚·ºç€èÀHfif∫ÙÉÕ
Exception in thread "main" 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 casino.AES.decryptString(AES.java:130)
at casino.AES.main(AES.java:172)
public static void main(String[] args) throws Exception {
//Encryption
AES encr = new AES();
encr.setKey("KEY");
encr.setSalt("SALT");
encr.setup();
String message = "This is just an example";
System.out.println("Message : " + message);
byte[] code = encr.encrypt(message);
System.out.println("Encrypted Strinng : "+ new String(code, "UTF-8"));
//Decryption
AES dec = new AES();
dec.setKey("INCORRECT"); //<--- incorrect
dec.setSalt("SALT");
dec.setup();
System.out.println(dec.decryptString(code));
}
public synchronized void setKey(String key) throws UnsupportedEncodingException {
this.key = key.getBytes("UTF-8");
isPasswordAlreadySet = true;
}
public synchronized void setSalt(String salt) throws UnsupportedEncodingException {
this.salt = salt.getBytes("UTF-8");
}
public synchronized void setup() throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(key);
digest.update(salt);
byte[] raw = digest.digest();
skeySpec = new SecretKeySpec(raw, "AES");
cipher = Cipher.getInstance("AES");
}
public synchronized byte[] encrypt(byte[] klartext) throws Exception {
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(klartext);
return encrypted;
}
public synchronized byte[] encrypt(String klartext) throws Exception{
return encrypt(klartext.getBytes("UTF-8"));
}
public synchronized byte[] decrypt(byte[] code) throws Exception {
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original = cipher.doFinal(code);
return original;
}
public synchronized double decryptDouble(byte[] code) throws Exception {
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original = cipher.doFinal(code);
return doubleFromBytes( original);
}
谢谢! 弗雷德里克
答案 0 :(得分:6)
填充是一个很好的理智检查。假设错误解密的数据是均匀分布的,那么对于每255个不正确的密码,它只会被正确地PKCS5 / PKCS7填充大约1次。 (1/256 + 1/256 ^ 2 + 1/256 ^ 3 ......)
所以它很有帮助,但它不是你应该依赖的东西 - 实际上几乎是8位的消息摘要是不是对数据完整性的充分测试。
还有一件事:如果攻击者可以反复更改密文并让您解密,(例如可能是存储在cookie中的加密数据),并且如果他们可以在解密数据抛出异常时区分您的行为糟糕的填充,当它只是垃圾,然后他们可以通过“填充oracle攻击”来确定明文。
顺便说一句,如果你实际上想要你期望的行为,你可以使用“AES / CTR / NoPadding”,它不需要精确的块大小,并且总是返回一个解密的字节[ ],无论密钥是否匹配。
答案 1 :(得分:3)
您应该使用带有隐式填充声明的AES(请参阅the available modes)或强制加密/解密数据的长度(以字节为单位)为16的倍数。
此外,默认情况下,java使用ECB模式,根据您使用的数据类型,它可能真的不安全,您应该使用CBC模式。
答案 2 :(得分:0)
SecretKeySpec以独立于提供者的方式指定密钥
http://themasterofmagik.wordpress.com/2014/03/19/simple-aes-encryption-and-decryption-in-java/