1

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

细节:

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

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

但是,如果我跳过压缩步骤(只需将纯文本传递给 encrypt 函数),一切正常。如果我跳过加密并只进行压缩,一切也都很好。因此,如果我不将它们结合起来,这些函数似乎在 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(encrypt(gzencode($plain_text)));

这在Java中

解压缩打印(解密(decodeBase64(数据)));

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

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

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

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

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

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

那是在我的 IV 中的单个 0x13 而不是 0x12 浪费了一天。

4

1 回答 1

2

您应该检查 IV,因为它可能只更改包含 ZIP 标头的第一个密文块。

(结束问题,很高兴您解决了问题,在我看来,您解决问题的任何一天都不会浪费:))

于 2012-04-23T00:18:00.230 回答