Расшифровка AES в iOS: заполнение PKCS5 и CBC

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

 * Cipher Mode: CBC
 * Padding: PKCS5Padding

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

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

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


person Paul Mailman    schedule 09.02.2011    source источник


Ответы (3)


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

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

person Maarten Bodewes    schedule 28.04.2011
comment
Заполнение PKCS#5 не совпадает с заполнением PKCS#7. В то время как оба дополняются до длины блока, заполнение PKCS#5 подходит только для алгоритмов шифрования с 8-байтовыми блоками, PKCS#7 расширяет это до произвольной длины блока. Они могут вести себя одинаково, если требуется менее 8 байтов заполнения, а в библиотеках Java PKCS они используют заполнение PKCS#7 и вызывают его PKCS#5, но они разные. - person Dave Durbin; 19.08.2013
comment
@DaveDurbin Да, я знаю, но в Java, где используется точная строка "PKCS5Padding", указанная для конфигурации сервера, это фактически идентичен заполнению PKCS # 7. Это относится к большинству приложений, допускающих заполнение PKCS#5 для различных блочных шифров. Уточнил это в ответе... - person Maarten Bodewes; 19.08.2013

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

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

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

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

Учитывая этот ввод:

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, потому что это то, что я использовал в этом примере. В качестве упражнения расшифруйте его без заполнения и убедитесь, что результат тот же, за исключением того, что у вас есть байты заполнения после текста «зашифровать меня».

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

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

Хорошо, я знаю, что сказал, что это упражнение, но я хочу доказать, что даже если вы шифруете с дополнением и расшифровываете без заполнения, вы не получаете мусора. Таким образом, учитывая KAT, который использовал заполнение PKCS7, мы расшифровываем его с опцией без заполнения и получаем читаемое сообщение, за которым следует 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
$ 
person indiv    schedule 09.02.2011

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

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

Спасибо за кадр, инд.

person Paul Mailman    schedule 10.02.2011