我正在使用自己的自定义加密方法处理安全应用程序,并且在解密邮件时遇到问题。
根据该理论,必须填充输入以满足执行加密所需的位。但填充的位在解密后仍保持不变。
以下是一个例子:
input (before padding) : q
input (after padding) : 113 0 0 0 0 0 0 0 (in Bytes)
然后我执行一些代码:
bytes[] a = encrypt(input);
bytes[] b = decrypt(a);
String output = "";
output = new String(b, "UTF-8");
System.out.println上的输出如下:
b : 113 0 0 0 0 0 0 0
output : q[][][][][][][]
我不知道如何删除填充位。我目前正在使用以下功能:
public String processOutput(String dtxt){
String result = "";
int l = dtxt.length();
for(int i=0;i<l-16;i++) result = result + dtxt.charAt(i);
for(int i=l-16;i<l;i++){
if((long)dtxt.charAt(i)!=0){
result = result + dtxt.charAt(i);
}
} return result;
}
但是这个函数只有在我将输出放到String时才有效。如果输出是文件(假设是图像文件)怎么办?解密后如何删除填充的位?请帮忙。
答案 0 :(得分:2)
您应该使用Cipher.getInstance("AES/CBC/PKCS5Padding")
等填充。正如您现在使用的那样,零填充问题是您无法区分以00
值字节结尾的纯文本和填充。如果你执行unpadding,那么你至少会遇到最后一个块的问题。当然,对于文本,您可以在执行字符解码例程之前删除末尾的00
值字节。另一种方法是在纯文本的开头简单地添加一个64位大小的指示符。
请注意,默认的Oracle Java提供程序没有零填充选项(据我所知),因此您必须自己进行取消填充,否则您将不得不使用另一个JCE提供程序,例如Bouncy Castle provider这确实包括零填充选项(例如Cipher.getInstance("AES/CBC/ZeroPadding")
。
请注意Wikipedia page on padding has much to say on the matter。另请注意,CBC模式本身不提供完整性保护或身份验证,仅保密并且仅在正确使用时才提供。
答案 1 :(得分:0)
您可以在流模式下使用AES等分组密码来完全删除填充。所以你可以使用例如Cipher.getInstance("AES/CTR/NoPadding")
或者您还想要包含身份验证标记Cipher.getInstance("AES/GCM/NoPadding")
。后者会在密文的末尾添加一些字节,您可以使用这些字节来确保使用正确的密钥创建密文,并且密文未被更改。
请注意,您可能会泄漏有关纯文本大小的信息。对于CBC模式也是如此,但在这种情况下,您至少会有16字节(块大小)的余量。使用流模式加密,您将加密到相同数量的字节。另请注意,您需要使用相同的密钥为每次加密使用新的IV值,否则您可能会直接将明文暴露给攻击者。