GZipStream не обнаруживает поврежденные данные (даже проходы CRC32)? - PullRequest
5 голосов
/ 26 февраля 2012

Я использую GZipStream для сжатия / распаковки данных.Я выбрал это вместо DeflateStream, так как в документации говорится, что GZipStream также добавляет CRC для обнаружения поврежденных данных, что является еще одной функцией, которую я хотел.Мои «положительные» модульные тесты работают хорошо: я могу сжать некоторые данные, сохранить сжатый байтовый массив и затем снова успешно распаковать его.Пост .NET GZipStream о проблеме сжатия и распаковки помог мне понять, что мне нужно закрыть GZipStream перед доступом к сжатым или распакованным данным.

Далее я продолжил писать «отрицательный» блокпроверить, чтобы убедиться, что поврежденные данные могут быть обнаружены.Ранее я использовал пример для класса GZipStream из MSDN , чтобы сжать файл, открыть сжатый файл в текстовом редакторе, изменить байт, чтобы испортить его (как будто его не открывали в текстовом редакторе).достаточно плохо!), сохраните его, а затем распакуйте, чтобы убедиться, что я получил InvalidDataException, как и ожидалось.

Когда я написал модульный тест, я выбрал произвольный байт для повреждения (например, compressDataBytes [50] = 0x99) и получил исключение InvalidDataException.Все идет нормально.Мне было любопытно, поэтому я выбрал другой байт, но, к своему удивлению, я не получил исключения.Это может быть хорошо (например, я случайно ударил неиспользуемый байт в блоке данных), если данные все еще могут быть успешно восстановлены.Тем не менее, я также не получил верные данные!

Чтобы быть уверенным, что «это был не я», я взял очищенный код из нижней части .NET GZipStream проблема сжатия и распаковки и изменил его, чтобы последовательно повредить каждый байт сжатых данных, пока он не сможет распаковать должным образом.Вот изменения (обратите внимание, что я использую тестовую среду Visual Studio 2010):

// successful compress / decompress example code from:
//    https://stackoverflow.com/questions/1590846/net-gzipstream-compress-and-decompress-problem
[TestMethod]
public void Test_zipping_with_memorystream_and_corrupting_compressed_data()
{
   const string sample = "This is a compression test of microsoft .net gzip compression method and decompression methods";
   var encoding = new ASCIIEncoding();
   var data = encoding.GetBytes(sample);
   string sampleOut = null;
   byte[] cmpData;

   // Compress 
   using (var cmpStream = new MemoryStream())
   {
      using (var hgs = new GZipStream(cmpStream, CompressionMode.Compress))
      {
         hgs.Write(data, 0, data.Length);
      }
      cmpData = cmpStream.ToArray();
   }

   int corruptBytesNotDetected = 0;

   // corrupt data byte by byte
   for (var byteToCorrupt = 0; byteToCorrupt < cmpData.Length; byteToCorrupt++)
   {
      // corrupt the data
      cmpData[byteToCorrupt]++;

      using (var decomStream = new MemoryStream(cmpData))
      {
         using (var hgs = new GZipStream(decomStream, CompressionMode.Decompress))
         {
            using (var reader = new StreamReader(hgs))
            {
               try
               {
                  sampleOut = reader.ReadToEnd();

                  // if we get here, the corrupt data was not detected by GZipStream
                  // ... okay so long as the correct data is extracted
                  corruptBytesNotDetected++;

                  var message = string.Format("ByteCorrupted = {0}, CorruptBytesNotDetected = {1}",
                     byteToCorrupt, corruptBytesNotDetected);

                  Assert.IsNotNull(sampleOut, message);
                  Assert.AreEqual(sample, sampleOut, message);
               }
               catch(InvalidDataException)
               {
                  // data was corrupted, so we expect to get here
               }
            }
         }
      }

      // restore the data
      cmpData[byteToCorrupt]--;
   }
}

Когда я запускаю этот тест, я получаю:

Assert.AreEqual failed. Expected:<This is a compression test of microsoft .net gzip compression method and decompression methods>. Actual:<>. ByteCorrupted = 11, CorruptBytesNotDetected = 8

Итак, это означает, что тамв действительности было 7 случаев, когда повреждение данных не имело никакого значения (строка была успешно восстановлена), но повреждение байта 11 не вызвало исключение и не восстановило данные.

Я что-то упустил или сделал что-то не так?Кто-нибудь может понять, почему поврежденные сжатые данные не обнаруживаются?

1 Ответ

6 голосов
/ 27 февраля 2012

Имеется 10-байтовый заголовок в формате gzip, для которого последние семь байтов могут быть изменены, не приводя к ошибке распаковки. Таким образом, ожидаются семь случаев, которые вы отметили без коррупции.

Должно быть крайне редко не обнаруживать ошибку с повреждением где-либо еще в потоке. В большинстве случаев декомпрессор обнаруживает ошибку в формате сжатых данных, даже не доходя до точки проверки crc. Если он доходит до точки проверки crc, эта проверка должна почти всегда завершаться неудачно с поврежденным входным потоком. («Почти все время» означает вероятность около 1 - 2 ^ -32.)

Я только что попробовал это (в C с zlib), используя вашу примерную строку, которая создает поток gzip размером 84 байта. Увеличение каждого из 84 байтов, оставляя остаток таким же, как вы, привело к: двум неправильным проверкам заголовка, одному неверному методу сжатия, семи успешным попыткам, одному неверному типу блока, четырем установленным неверным расстояниям, семи неверным длинам кода, четырем отсутствующим конец блока, 11 недопустимых повторов битовой длины, три недопустимых повторения битовой длины, два недопустимых повторения битовой длины, два неожиданных конца потока, 36 неверных проверок данных (это фактическая ошибка CRC) и четыре неверных проверки длины (еще одна проверка в формате gzip для правильной длины несжатых данных). Ни в одном случае поврежденный сжатый поток не был обнаружен.

Так что где-то должна быть ошибка, либо в вашем коде, либо в классе.

Обновление:

Похоже, что в классе есть ошибка.

Примечательно (или, может быть, не замечательно), что Microsoft пришла к выводу, что они не исправят эту ошибку!

...