Сохранить значение CRC в файле, не изменяя фактическую контрольную сумму CRC? - PullRequest
5 голосов
/ 22 декабря 2011

Я сохраняю некоторые объекты, которые я определил из моих собственных классов, в файл. (сохранение данных потока).

Это нормально, но я бы хотел сохранить в файле контрольную сумму CRC этого файла.

Затем, когда мое приложение пытается открыть файл, оно может прочитать внутренне сохраненное значение CRC.

Затем выполните проверку действительного файла, если CRC файла соответствует внутренне сохраненному значению CRC, я могу нормально обработать файл, в противном случае выдается сообщение об ошибке, в котором говорится, что файл недействителен.

Мне нужен какой-то совет о том, как это сделать, я думал, что смогу сделать что-то вроде этого:

  • Сохраните файл из моего приложения.
  • Рассчитать CRC сохраненного файла.
  • Редактирование сохраненного файла с сохранением значения CRC.
  • При каждом открытии файла проверьте, соответствует ли CRC внутреннему значению CRC.

Проблема в том, что, как только в файле изменяется один байт данных, контрольная сумма CRC будет совершенно другой - как и ожидалось.

Ответы [ 4 ]

10 голосов
/ 22 декабря 2011

Я бы вообще предпочел подход, при котором CRC исключается из проверки.Но если по какой-то причине это невозможно, есть обходной путь:

Вам необходимо зарезервировать 8 байтов, 4 для CRC и 4 для данных компенсации.Сначала заполните зарезервированные байты определенным фиктивным значением (скажем, 0x00).Затем вычислите CRC в первые 4 байта и, наконец, измените остальные 4 байта, чтобы CRC файла остался прежним.

Подробнее о выполнении этого вычисления: Реверсивный CRC32


Я фактически использовал это в одном из моих проектов :

Я разрабатывал формат файла на основе zip.Первый файл в архиве хранится в несжатом виде и служит заголовочным файлом.Это также означает, что он хранится с фиксированным смещением в файле.Пока что довольно стандартный и похожий, например, на ePub.

Теперь я решил включить в заголовок хэш sha1, чтобы дать каждому файлу уникальный идентификатор на основе контента и для проверки целостности.Поскольку заголовок и, следовательно, хэш sha1 находятся в известном смещении в файле, маскировать его при хешировании тривиально.Поэтому я вставил фиктивный хеш и создал zip-файл, затем хешировал файл и заполнил реальный хеш.

Но теперь возникает проблема: Zip сохраняет CRC всех содержащихся файлов.И не только в одном месте, которое было бы легко замаскировать при хешировании sha1, но и во втором месте с переменным смещением в конце файла.Поэтому я решил пойти с подделкой CRC, чтобы получить сильный хеш, а zip получил действительный CRC32.

И так как я уже подделывал CRC для окончательного файла, я решил подделать его для исходного заголовкафайл тоже не повредит.Таким образом, все файлы в этом формате теперь начинаются с заголовочного файла, который имеет CRC 0xD1CE0DD5.

8 голосов
/ 22 декабря 2011

Проще говоря, вам нужно исключить байты, используемые для хранения контрольной суммы, из расчета контрольной суммы.

Запишите контрольную сумму как последнюю вещь в файле. Рассчитайте его на основе содержимого файла, кроме контрольной суммы. Когда вы приходите, чтобы прочитать файл, рассчитайте контрольную сумму на основе содержимого до контрольной суммы. Или вы можете написать контрольную сумму в качестве первых байтов файла с произвольным доступом. Пока вы знаете, где это.

6 голосов
/ 22 декабря 2011

Сохраните CRC как часть самого файла, но не включайте данные для него в расчет CRC. Если у вас есть какой-то фиксированный заголовок, обнулите поле CRC, прежде чем передавать его в функцию CRC. Если нет, просто добавьте его в конец файла и передайте все, кроме последних 4 байтов, в функцию CRC.


В качестве альтернативы, если файлы хранятся на диске NTFS и вам не нужно переносить их на другой компьютер, вы можете использовать Альтернативные потоки данных NTFS для хранения CRC. По сути, вы открываете файл с именем ADS, отделенным от имени файла двоеточием (например, C:\file.txt:CRC). Windows обрабатывает разницу внутренне, поэтому вы можете использовать простые функции TFileStream для управления ими.

Альтернативные потоки данных хранятся отдельно от стандартного файлового потока, поэтому открытие или изменение только C:\file.txt не повлияет на него.

Итак, код будет выглядеть так:

procedure UpdateCRC(const aFileName: string);
var
  FileStream, ADSStream: TStream;
  CRC: LongWord;
begin
  FileStream := TFileStream.Create(aFileName, fmOpenRead);
  try
    CRC := CrcOf(FileStream);
  finally
    FileStream.Free;
  end;

  ADSStream := TFileStream.Create(aFileName + ':CRC', fmCreate);
  try
    ADSStream.WriteBuffer(CRC, SizeOf(CRC));
  finally
    ADSStream.Free;
  end;
end;

Если вам нужно найти все альтернативные потоки данных, прикрепленные к файлу (их может быть больше одного), вы можете перебрать по ним, используя BackupRead . Internet Explorer использует ADS для поддержки «Этот файл был загружен из Интернета. Вы уверены, что хотите открыть его?» проворная.

1 голос
/ 22 декабря 2011

Я бы порекомендовал сохранить контрольную сумму в другом файле, возможно, в файле .ini.Или для действительно странной идеи, вы можете включить контрольную сумму как часть имени файла.
т.е. MyFile_checksum_digits_here.dat

...