将gzencoded数据传递给mcrypt_encrypt,解密后无法解压缩

时间:2012-04-22 14:34:21

标签: java php encryption gzip block-cipher

为了简短起见,将gzencode(或其他非文本数据)的结果传递给mcrypt_encrypt函数时是否存在已知问题?

详细说明:

基本上我有一个加密/解密适用于纯文本的问题,但如果我将压缩数据传递给加密函数,然后解密并解压缩,我就会解压缩错误。

所以在PHP中,我将gzencode()的结果传递给加密函数。然后我使用base64编码在Web服务网页上显示结果。然后在Java应用程序中,我正在使用GZIPInputStream解码base64,解密和解压缩。我在最后一步得到错误。

但是如果我跳过压缩步骤(只是将纯文本传递给加密函数),一切正常。如果我跳过加密并且只是进行压缩,那么一切也能正常工作。因此,如果我不将它们组合起来,那些函数似乎在PHP和Java方面都能正常工作。

public static function encrypt($str,$key,$iv) {
    $str=Crypto2::pkcs5Pad($str,mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
    $encrypted=mcrypt_encrypt(MCRYPT_RIJNDAEL_128,$key,$str,MCRYPT_MODE_CBC,$iv);
    return $encrypted;
}

public static function pkcs5Pad ($text, $blocksize) {
    $pad = $blocksize - (strlen($text) % $blocksize);
    $padded=$text . str_repeat(chr($pad), $pad);
    return $padded;
} 

Java函数:

public static byte[] decrypt(byte[] inputbuffer) throws Exception {
    Key key = new SecretKeySpec(keybyte, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(iv);
    Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
    c.init(Cipher.DECRYPT_MODE, key, ivSpec);

    c.getBlockSize();
    System.out.println("Block size="+c.getBlockSize());

    int outlen = c.getOutputSize(inputbuffer.length);
    System.out.println("Output length will be:"+outlen);
    byte[] result=c.doFinal(inputbuffer);
    return result;
}

  public static byte[] decodeBase64(String data) throws IOException{ 
    BASE64Decoder decoder = new BASE64Decoder(); 
    byte[] decodedBytes = decoder.decodeBuffer(data);

    return decodedBytes;
  }


   public static void unzipPrint(byte[] data) throws Exception{
    InputStream is=new GZIPInputStream(new ByteArrayInputStream(data));
    int ch2;
    while((ch2=is.read())!=-1) {
        System.out.print((char)ch2);
    }
   }

所以,如果我在PHP中这样做: BASE64_ENCODE(加密(gzencode($ plain_text)));

和Java中的这个

unzipPrint(解密(decodeBase64(数据)));

在解压缩阶段,我得到了可怕的:“java.util.zip.ZipException:超额订阅动态位长度树”。

同样,如果我跳过两端的压缩/解压缩步骤,一切都很好。如果我在两端跳过加密,那么压缩/解压缩工作正常。

编辑:好奇怪,但是在逐字节检查压缩数据的结果字节数组(解码base64和解密之后)后,我发现了一个关闭的SINGLE字节(与原始字节相比) PHP字节数组)的值为1.它是字节数14(Java中的索引13),它的值为110而不是111.我完全不知道这是怎么回事。

因此,如果我将该单个字节从110更改为111,那么我可以成功地使用GZIPOutputStream来解压缩数据。

所以我知道出了什么问题,但不知道为什么。

编辑2:已解决 - >感谢Owlstead的评论,我仔细检查了IV值,发现php和java代码之间存在轻微的差异。这怎么会导致产生的解密数据只有一个字节的差异,我不知道。

在我的IV中,这是一个浪费在一个0x13而不是0x12的日子。

1 个答案:

答案 0 :(得分:2)

你应该检查IV,因为它可能只改变第一个密码文本块,它包含ZIP标题。

(关闭这个问题,很高兴你得到了解决,任何你解决问题的日子都不会浪费在我看来:))