Расшифровка AES в iOS: заполнение PKCS5 и CBC - PullRequest
9 голосов
/ 10 февраля 2011

Я внедряю для iOS некоторый код дешифрования для сообщения, отправляемого на сервер, который я не могу контролировать.Предыдущая реализация на другой платформе документирует требования к расшифровке AES256, определяет ключ и вектор инициализации, а также говорит:

 * Cipher Mode: CBC
 * Padding: PKCS5Padding

Опции для создания объекта CCCryptor включают только kCCOptionPKCS7Padding и kCCOptionECBMode, отмечая, что CBCпо умолчанию.Из того, что я понимаю о дополнении для шифрования, я не понимаю, как можно использовать оба;Я думал, что они были взаимоисключающими.При создании CCCryptor для дешифрования я попытался использовать как 0 для параметров, так и kCCOptionPKCS7Padding, но оба дают мне бессмысленное значение после расшифровки.

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

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

Ответы [ 4 ]

6 голосов
/ 29 апреля 2011

Заполнение PKCS # 5 и заполнение PKCS # 7 практически одинаковы (добавление байтов 01, или 0202, или 0303 и т. Д. До длины блока размера алгоритма, в данном случае 16 байтов)).Официально заполнение PKCS # 5 должно использоваться только для 8-байтовых блоков, но во многих средах выполнения они могут взаимозаменяться без проблем.Заполнение всегда происходит в конце зашифрованного текста, поэтому, если вы получаете просто тарабарщину, это не заполнение.ECB - это блочный режим работы (его не следует использовать для шифрования данных, которые можно отличить от случайных чисел): для этого потребуется заполнение, поэтому эти два не являются взаимоисключающими.

Наконец, если вы просто выполняете дешифрование (не MAC-адреса или другие формы контроля целостности) и возвращаете результат отмены заполнения на сервер (дешифрование не удалось), ваши обычные текстовые данные небезопасны, посколькунабивочных оракулов.

4 голосов
/ 10 февраля 2011

Сначала вы можете позаботиться о заполнении позже. Предоставление 0, как вы сделали, означает AES CBC без заполнения, и с этой конфигурацией вы должны видеть свое сообщение очень хорошо. Albiet потенциально с некоторыми байтами заполнения в конце. Так что выходит:

  1. Вы неправильно загружаете ключ.
  2. Вы неправильно загружаете IV.
  3. Вы неправильно загружаете данные.
  4. Сервер делает что-то, чего вы не ожидаете.

Чтобы отладить это, вам нужно изолировать вашу систему. Вы можете сделать это, выполнив тест обратной петли, в котором вы оба шифруете, а затем дешифруете данные, чтобы убедиться, что вы загружаете все правильно. Но это может вводить в заблуждение. Даже если вы делаете что-то не так (например, загружаете ключ назад), вы все равно сможете расшифровать то, что вы зашифровали, потому что вы делаете это одинаково неправильно с обеих сторон.

Так что вам нужно проверить против Known Answer Tests (KATs). Вы можете посмотреть официальные KAT-файлы в AES википедии . Но так получилось, что я разместил другой ответ здесь, на SO, который мы можем использовать.

С учетом этого ввода:

KEY: 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
     0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
IV:  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
PLAIN TEXT:   encrypt me
CIPHER TEXT:  338d2a9e28208cad84c457eb9bd91c81

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

$ echo -n "encrypt me" > to_encrypt
$ openssl enc -in to_encrypt -out encrypted -e -aes-256-cbc \
> -K 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \
> -iv 0000000000000000
$ hexdump -C encrypted
00000000  33 8d 2a 9e 28 20 8c ad  84 c4 57 eb 9b d9 1c 81  |3.*.( ....W.....|
00000010
$ openssl enc -in encrypted -out plain_text -d -aes-256-cbc \
> -K 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \
> -iv 0000000000000000
$ hexdump -C plain_text 
00000000  65 6e 63 72 79 70 74 20  6d 65                    |encrypt me|
0000000a

Так что теперь попробуйте расшифровать этот тест с известным ответом в вашей программе. Обязательно включите заполнение PKCS7, потому что это то, что я использовал в этом примере. В качестве упражнения расшифруйте его без заполнения и убедитесь, что результат такой же, за исключением того, что у вас есть байты заполнения после текста «encrypt me».

Внедрение KAT - большой шаг. Это говорит о том, что ваша реализация верна, но ваши предположения о поведении сервера неверны. И тогда пришло время начать подвергать сомнению эти предположения ...

(И P.S., те опции, которые вы упомянули, не являются взаимоисключающими. ECB означает отсутствие IV, а CBC означает, что вы имеете IV. Никакого отношения к заполнению.)

Хорошо, я знаю, что сказал, что это упражнение, но я хочу доказать это, даже если вы шифруете с отступом и расшифровывать без заполнения, вы не получите мусор. Поэтому, учитывая KAT, который использовал заполнение PKCS7, мы расшифровываем его с помощью опции no padding и получаем читаемое сообщение, за которым следует 06, используемый в качестве байта заполнения.

$ openssl enc -in encrypted -out plain_text -d -aes-256-cbc \
-K 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \
-iv 0000000000000000 -nopad
$ hexdump -C plain_text
00000000  65 6e 63 72 79 70 74 20  6d 65 06 06 06 06 06 06  |encrypt me......|
00000010
$ 
3 голосов
/ 15 августа 2012

Пол
Заполнение PKCS # 5 необходимо для идентификации заполнения в дешифрованных данных. Для CBC входной буфер должен быть кратным размеру блока шифра (16 для AES). По этой причине буфер для шифрования расширяется дополнительными байтами. Обратите внимание, что после шифрования первоначальный размер данных теряется. PKCS # 5 padding позволяет получить этот размер. Это делается путем заполнения расширенного буфера данных повторяющимися байтами со значением, равным размеру заполнения. например, если ваш буфер открытого текста был 12 байтов, чтобы сделать его кратным 16, вам нужно будет добавить еще 4 байта. (Если данных было 16, вы добавите еще 16, чтобы сделать их 32). Затем вы заполняете эти 4 байта '0x4', чтобы соответствовать заполнению PKCS # 5. Когда вы расшифровываете, просто ищите последний байт в расшифрованных данных и вычтите это число из длины расшифрованного буфера.

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

0 голосов
/ 10 февраля 2011

Оказывается, объяснение того, что я испытывал, было смущающе простым: я неправильно истолковал то, что прочитал в предыдущей реализации, чтобы показать, что он использовал 256-битный ключ, но на самом деле он использовал 128-бит ключ. Сделайте это изменение, и все неожиданное станет ясным текстом. : -)

0 для аргумента options, для вызова CBC, было действительно правильным. То, что ссылка на заполнение PKCS5 в предыдущей реализации все еще загадочна, но это не имеет значения, потому что то, что у меня теперь есть, работает.

Спасибо за выстрел, индивид.

...