Android – 在解密中删除填充的位

我正在使用我自己的自定义加密方法处理安全应用程序,并且在解密消息时遇到问题。

根据该理论,必须填充输入以满足执行加密所需的位。 但填充的位在解密后仍保持不变。

这是一个例子:

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[][][][][][][] 

我不知道如何删除填充位。 我目前正在使用以下function:

 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时才有效。 如果输出是文件(假设是图像文件)怎么办? 解密后如何删除填充的位? 请帮忙。

您应该使用填充,如Cipher.getInstance("AES/CBC/PKCS5Padding") 。 正如您现在使用的那样,零填充问题是您无法区分以00值字节结尾的纯文本和填充。 如果你执行unpadding,那么你至少会遇到最后一个块的问题。 当然,使用文本,您可以在执行字符解码例程之前删除末尾的00值字节。 另一种方法是在纯文本的开头简单地添加一个64位大小的指示符。

请注意,默认的Oracle Java提供程序没有零填充选项(据我所知),因此您必须自己进行取消填充,或者您必须使用另一个JCE提供程序,例如包含零填充的Bouncy Castle提供程序选项(例如,对于Cipher.getInstance("AES/CBC/ZeroPadding")

请注意, 关于填充的维基百科页面在这个问题上有很多话要说 。 另请注意,CBC模式本身不提供完整性保护或身份validation,仅提供机密性且仅在正确使用时才提供。

您可以在流模式下使用AES等分组密码来完全删除填充。 因此,您可以使用例如Cipher.getInstance("AES/CTR/NoPadding")或者您还想要包含身份validation标记Cipher.getInstance("AES/GCM/NoPadding") 。 后者将在密文的末尾添加一些字节,您可以使用它来确保使用正确的密钥创建密文,并且密文未被更改。

请注意,您可能会泄漏有关纯文本大小的信息。 对于CBC模式也是如此,但在这种情况下,您至少会有16字节(块大小)的余量。 使用流模式加密,您将加密到完全相同的字节数。 另请注意,您需要使用相同的密钥为每次加密使用新的IV值,否则您可能会直接将明文暴露给攻击者。