在压缩数据字节数组的末尾添加一些垃圾字节后,是不是可以使用 GZIP 解压缩数据?
Posted
技术标签:
【中文标题】在压缩数据字节数组的末尾添加一些垃圾字节后,是不是可以使用 GZIP 解压缩数据?【英文标题】:Is it possible to decompress data using GZIP, after some garbage-bytes are added to the end of compressed data byte array?在压缩数据字节数组的末尾添加一些垃圾字节后,是否可以使用 GZIP 解压缩数据? 【发布时间】:2020-09-10 01:17:56 【问题描述】:这只是c#中的一个示例,我的意思是在末尾添加垃圾数据,请将其视为伪代码:
[Test]
public void TestGzipCompressor_WhenCompressCalledWithAddedExtraDataToTheEnd_ShouldReturnValidData()
var extraBytesToAddToTheEnd = new byte[] 1, 2, 3, 4 ;
//creating a test-byte array
var bytesToPopulateArrayWith= new byte[9] 1, 2, 3, 4, 5, 6, 7, 8, 9 ;
var byteList = new List<byte> ;
for (int i = 0; i < 100; i++)
inputBytes.AddRange(bytesToPopulateArrayWith);
//Getting data as a compressed byte list
List<byte> compressedBytes = GzipCompressor.Compress(byteList);
//adding extra garbage-bytes to the end of the compressed data byte-array
compressedBytes.AddRange(extraBytesToAddToTheEnd);
//Getting original data after decompression
byte[] decompressedBytes = GzipCompressor.Decompress(compressedBytes.ToArray());
decompressedBytes.Should().BeEquivalentTo(stringBytes);
如果我们添加少于 5 个字节,它就可以完美运行:
var extraBytesToAddToTheEnd = new byte[] 1, 2, 3, 4 ;
但在末尾添加 5 个或更多字节会引发“存档条目是使用不支持的压缩方法压缩的”错误。
var extraBytesToAddToTheEnd = new byte[] 1, 2, 3, 4, 5 ;
压缩器实现如下:
public static class GzipCompressor
[NotNull]
public static byte[] Compress([NotNull] byte[] bytes)
using var memoryStream = new MemoryStream();
using var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress);
gzipStream.Write(bytes, 0, bytes.Length);
gzipStream.Flush();
return memoryStream.ToArray();
[NotNull]
public static byte[] Decompress([NotNull] byte[] bytes)
using var memoryStream = new MemoryStream();
using var gzipStream = new GZipStream(new MemoryStream(bytes), CompressionMode.Decompress);
gzipStream.CopyTo(memoryStream);
gzipStream.Flush();
return memoryStream.ToArray();
GZIP 是否可以解压缩最后带有一些垃圾字节的压缩数据? 为什么它可以使用 4 个字节或更少,但没有更多?我的实现有问题吗? 谢谢!
【问题讨论】:
你这里的用例是什么,为什么需要这样做?如果您需要在非常特定的文件格式的末尾对数据进行编码,为什么不添加数据,在末尾添加一个大小,当您去解压缩时,读取末尾的大小,删除数据,然后解压缩。至于为什么你可以逃脱 4 个字节,谁知道,你必须阅读 RFC,这可能有很多原因,比如填充,这实际上可能会因其他植入而失败...... 您应该阅读规范。如果您想添加自己的数据,您可以阅读有关如何执行此操作的规范,特别是2.3.1.1
部分:tools.ietf.org/html/rfc1952#page-8
【参考方案1】:
如果不深入研究 GZipStream 实现,我猜它正在读取您附加的数据并尝试将其解释为 gzip 帧头,当它收到意外输入时会引发异常。
gzip 文件格式详见RFC 1952。它由一系列都遵循特定格式的框架(在 RFC 中称为“成员”)组成。每个帧都有一个带有一些可选部分的标题块,后面是 DEFLATE 压缩数据和一个 8 字节的页脚。该格式支持标头中可选的“额外数据”块,但大多数实现似乎都忽略了它们。
但是,文件格式不允许将任意数据附加或附加到文件中。通过将数据附加到 gzip 流,您将其更改为 不是 gzip 文件的内容。您创建了一个 gzip 变体,它不适用于合规的实现,并且在不合规的实现上具有未定义的行为。
根据您的需要,还有其他可能更适合的压缩格式。如果它是供内部使用的,那么您可能想要创建自己的格式来封装 gzip 或 deflate 数据。如果您绝对必须生成一个 gzip 文件,那么您需要找到一个允许您在 gzip 标头中读取/写入额外数据的库。
(希望我可以标记人 - Mark Adler 是 SO 上这些东西的权威来源。)
【讨论】:
【参考方案2】:看起来像 GzipStream
中的错误。它直到四个字节之后才识别垃圾。正如 Corey 所指出的,gzip 成员之后的任何内容如果不是另一个完整的 gzip 成员,则表示无效的 gzip 流。该类应该识别出是否有五个、四个或一个字节的垃圾。
如果您想在一个 gzip 成员之后停止解压缩,您可以改用 DeflateStream
来解码 gzip 成员内的压缩数据。然后您只需要自己解码 gzip 标头和预告片,并计算解压缩数据的 CRC 以与预告片中的 CRC 进行比较。见RFC 1952。
【讨论】:
以上是关于在压缩数据字节数组的末尾添加一些垃圾字节后,是不是可以使用 GZIP 解压缩数据?的主要内容,如果未能解决你的问题,请参考以下文章