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

时间:2013-05-23 12:26:09

标签: java android cryptography padding

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

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

以下是一个例子:

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

2 个答案:

答案 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值,否则您可能会直接将明文暴露给攻击者。