Невозможно расшифровать AES с помощью OpenSSL

3729
robert

Я работаю над игрой в ctf:

Зашифровано с помощью AES в режиме ECB. Все значения base64 закодированы

ciphertext = 8LBUVZfDfI6wnggG1uUYuQsRoGd08pGwHCN++R5rabMW9PJmWHWcSrjy5Tfffj6L key = 3q1FxGhuZ5fQYbjzDxgQ35== 

Я попытался расшифровать его в своем терминале, оставив зашифрованный текст в base64 и используя -base64флаг, но безуспешно. Затем я пошел на http://extranet.cryptomathic.com/aescalc, где после преобразования значений в шестнадцатеричные я смог расшифровать:

key: DEAD45C4686E6797D061B8F30F1810DF  text: F0B0545597C37C8EB09E0806D6E518B90B11A06774F291B01C237EF91E6B69B316F4F26658759C4AB8F2E537DF7E3E8B out: 7B796F755F73686F756C645F6E6F745F706F73745F7468655F61637475616C5F6374665F76616C75657D5F5F5F5F5F5F 

Затем я вернулся в свой терминал, пытаясь:

echo -n F0B0545597C37C8EB09E0806D6E518B90B11A06774F291B01C237EF91E6B69B316F4F26658759C4AB8F2E537DF7E3E8B | openssl enc -d -K DEAD45C4686E6797D061B8F30F1810DF -aes-128-ecb -nosalt 

но я получил ту же ошибку:

bad decrypt 140735124906848:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:531: 

Я пробовал это на Ubuntu 17.04, а теперь на моем MacOSX с использованием OpenSSL 1.0.2l. Почему я не могу расшифровать в моем собственном терминале?

3
Так как это для CTF, я заменил фактические значения рабочими заполнителями. ;) Lery 7 лет назад 0

3 ответа на вопрос

5
Maarten Bodewes

Потому что opensslпо умолчанию используется заполнение PKCS # 7, а ваш открытый текст не содержит заполнения PKCS # 7. Если ваш открытый текст был дополнен, то он был дополнен байтами значения 5F. -nopadВместо этого используйте опцию, заполнение значением 5Fне является какой-либо схемой заполнения, известной мне; если это необходимо удалить, вам нужно будет удалить его самостоятельно.

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

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

Погуглил и получил один из моих собственных ответов :) Maarten Bodewes 7 лет назад 1
5Fs появляются в расшифрованном сообщении. robert 7 лет назад 1
Да, заполнение выполняется до шифрования блочным шифром / режимом работы и, следовательно, после дешифрования. Maarten Bodewes 7 лет назад 1
Хорошо, сейчас я понимаю. При использовании `-nopad` больше нет сообщений об ошибках, но вывод неправильный, что-то вроде мусора. robert 7 лет назад 1
AES - это блочный шифр 128 бит / 16 байт, и поэтому [невозможно использовать PKCS # 5-совместимое заполнение, так как он определен только для блочных шифров 64 бит / 8 байт] (https://crypto.stackexchange.com/ д / 9043/1172). Если выходные данные выглядят как мусор, то это, вероятно, потому, что выходные данные интерпретируются как US-ASCII / UTF-8 (или любой другой набор символов в вашей системе). Направьте вывод в файл, используя `>`, а затем откройте его в шестнадцатеричном редакторе, * затем * сравните результаты, не раньше. Maarten Bodewes 7 лет назад 1
@robert На самом деле вы получаете мусор, потому что Openssl ожидает байты в качестве входных данных, а не шестнадцатеричную строку, как вы ее кормите. Вы можете использовать `echo -n DEADC0DE | xxd -r -p | openssl ... `чтобы получить фактические данные. Lery 7 лет назад 1
@Lery интегрировал это в мой ответ, забыл про ввод. D'о. Maarten Bodewes 7 лет назад 0
3
Lery

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

Преимущества выполнения этого программно:

  • Всякий раз, когда вам нужно будет повторить что-то подобное, ваш код будет готов.
  • Вы можете написать комментарии, чтобы объяснить, что происходит, поэтому, если вам когда-то понадобится понять, что вы делали ранее, надеюсь, код и комментарии позволят вам это сделать.
  • Многие вещи, такие как кодирование, обработка байтов и т. Д., Проще, чем в консоли
  • Большинство языков являются кроссплатформенными, поэтому они легко будут работать на Windows, Linux, Android, если вы однажды переключите свое устройство.

Что касается вашей проблемы, она может быть решена с помощью Python, чтобы сделать все:

# we import the function we need from common librairies from base64 import b64decode from Crypto.Cipher import AES from binascii import hexlify, unhexlify   # First we decode the message and the key from base64 into bytes: msg = b64decode("8LBUVZfDfI6wnggG1uUYuQsRoGd08pGwHCN++R5rabMW9PJmWHWcSrjy5Tfffj6L") key = b64decode("3q1FxGhuZ5fQYbjzDxgQ35==")  # We then instantiate a cipher_suite using AES with the provided key, in ECB mode cipher_suite = AES.new(key, AES.MODE_ECB)  # We can decrypt the message using our cipher_suite: recovered = cipher_suite.decrypt(msg)  # We can print it: print ("plaintext: ", recovered)  # There is some garbage at the end, but if we display it in hexadecimal form: print ("in hex:", hexlify(recovered)) # We can see it's just padding using '5f', so let's create a function to remove such padding: def unpad(padded): # we declare the value of our padding: paddingByte = unhexlify('5f') # we do a loop, while the last byte is padding while padded[-1:]==paddingByte: # we remove the last byte padded = padded[:-1] # once it's done, we return return padded  # We can now use our function to remove padding: print ("unpadded: ", unpad(recovered)) 

Теперь, если вы не хотите изучать Python или любой другой язык и / или если вы действительно хотите делать все это в своем терминале, это также возможно: тогда вы можете делать все напрямую, используя каналы для передачи данных из одного команду другому, команду подстановки для подачи правой клавиши в openssl и команды base64для обработки base64 plus xxdдля преобразования двоичных данных в шестнадцатеричные (для ключа в openssl) и, наконец, sedдля удаления 5fотступов:

echo "8LBUVZfDfI6wnggG1uUYuQsRoGd08pGwHCN++R5rabMW9PJmWHWcSrjy5Tfffj6L" | base64 --decode | openssl enc -d -K $(echo "3q1FxGhuZ5fQYbjzDxgQ35==" | base64 --decode | xxd -c 16 -ps) -aes-128-ecb -nosalt -nopad | sed 's/_*$//g' 

Я не знаю почему, но лично я считаю, что подход к Python чище.


Вы также упомянули, что получили мусор, как указал вам Мартен Бодьюс, это связано с тем, что вы подаете шестнадцатеричные значения в OpenSSL, в то время как вы должны предоставить двоичные данные (а не шестнадцатеричное значение) для сообщения, пока вы должен предоставить ключ в шестнадцатеричном виде:

echo -n f0b0545597c37c8eb09e0806d6e518b90b11a06774f291b01c237ef91e6b69b316f4f26658759c4ab8f2e537df7e3e8b | xxd -r -p | openssl ... 

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

2
Henno

декодировать base64

echo 8LBUVZfDfI6wnggG1uUYuQsRoGd08pGwHCN++R5rabMW9PJmWHWcSrjy5Tfffj6L | base64 -D > aesdata.dat

( -Dэто особенность Mac OS. Linux имеет тенденцию использовать -dили --decodeвместо).

Так же:

echo 3q1FxGhuZ5fQYbjzDxgQ35== | base64 -D > aeskey.dat

но openssl ожидает шестнадцатеричные значения в параметрах (но двоичные в зашифрованных файлах):

xxd -p < aeskey.datдает dead45c4686e6797d061b8f30f1810df. Или по каналу из предыдущей команды, если вы хотите избежать беспорядка.

В заключение:

openssl enc -d -nopad -aes-128-ecb -K dead45c4686e6797d061b8f30f1810df -in aesdata.dat -out plain

расшифрую это. -Nopad позволяет избежать ошибки дешифрования, так как используется нестандартное заполнение.

Теперь, hd plainчтобы проверить результат, который действительно то, что вы искали.

Похожие вопросы