Генерация ключа шифрования
Генерация ключа шифрования осуществляется многостадийным образом, который мы сейчас рассмотрим, что называется "на пальцах". Подробное изложение алгоритма шифрования можно найти в спецификации на PDF, ссылку на которую мы уже давали, так что не будем повторяться и описывать то, что уже описано задолго до нас. Короче, делаем свой первый шаг.
- берем U-пароль (обычно пустой) и дополняем его до 32 байт, используя следующую строку, жестко прописанную (hardcoded) в теле Acrobat'а: 28h BFh 4Eh 5Eh 4Eh 75h 8Ah 41h 64h 00h 4Eh 56h FFh FAh 01h 08h 2Eh 2Eh 00h B6h D0h 68h 3Eh 80h 2Fh 0Ch A9h FEh 64h 53h 69h 7Ah, соединяя пароль со строкой операцией конкатенации (объединения);
- к полученной последовательности дописываем хэш O-пароля (/O поле);
- дописываем P-флаг, интерпретируемый как 4-байтовая целочисленная переменная типа LSB (Less Significant Bellow – наименее значимый байт лежит по меньшему адресу как в x86), если бы пункта 3 не существовало, мы бы могли свободно менять атрибуты P-флага в HEX-редакторе, а так… увы…
- дописываем идентификатор (поле /ID), если он есть (это необязательное поле);
- пропускаем полученную последовательность через алгоритм MD5 и на выходе получаем хэш-сумму первые 5 байт которой и будут ключом шифрования (encryption key) для 40-битного алгоритма (примечание: в ревизии 3 полученный хэш пропускается через MD5-алгоритм 50 раз, и от финальной хэш-последовательности берется столько байт, сколько нужно для ключа);
Хэш-сумма пользовательского пароля, хранящаяся в /U-поле это всего лишь 32-байтовая последовательность, дополненная вышеуказанной hardcoded-строкой, зашифрованная по алгоритму RC4 с использованием 5-байтового ключа шифрования (encryption key).
Проверка пароля, введенного пользователем, осуществляется выполнения пунктов 1-5 с последующий сравнением полученного результата со значением /U-поля. Если обе последовательности совпадают по последнего бита, пароль считается истинным и наоборот.
Проверка пароля владельца осуществляется по аналогичной схеме.
Выполняем пункты 1- 5 используя либо пароль пользователя, либо жестко кодированную последовательность, если этого пароля нет. Полученным ключом шифрования encryption key расшифровываем O-поле по алгоритму RC4 и трактуем образовавшуюся последовательность как U-пароль, проверяя его по вышеописанной схеме. Очевидно, если мы знаем U-пароль (или содержимое документа незашифрованно), мы можем модифицировать P-флаг и регенерировать /O-поле, рассчитав его новое значение, которое Acrobat воспримет как правильное.
С расшифровкой содержимого, зашифрованного непустым U-паролем, все обстоит намного сложнее. Да, мы можем рассчитать новое /U-поле для пустого пароля и Acrobat подумает, что никакого пароля здесь нет, но открыть файл он все равно не сможет. Прежде его необходимо расшифровать. Это делается так:
- выполняем шаги 1-5, получая 5-байтовый ключ шифрования (или более длинный);
- дописываем 3-байтовый номер строки/объекта (string/object number) и 2 байтовый номер поколения (generation number) см. рис. 10; Примечание: в фильтре ревизии 3 номер объекта и поколения пропускаются через скрамблер и к ним еще добавляется случайная привязка в лице SALT-строки (см. рис. 11);
- вычисляем MD5 хэш для данной 10-байтовой строки;
- используем первые 10 или более байт хэш-суммы в качестве ключа шифрования по RC4, расшифровывая содержимое строки/объекта.
Хуже, если O-пароль не пустой и при открытии файла выскакивает противное диалоговое окно, требующее его ввода. Ничего другого не остается кроме как перебирать…