На прошлых выходных была проведена криптографическая задача, в которой шифртекст представлял собой следующее шестнадцатеричное число:
FC 89 BF C2 B0 5F 1C 2E 64 B8 78 43 92 78 3A C9
Я точно знаю, что это зашифровано с помощью AES/Rijndael 128-бит ECB, ключ — REDRYDER, и решение для этого уже было опубликовано, чтобы подтвердить это. Открытый текст — FLAG=DAISY. Я написал простой скрипт PHP mcrypt, который расшифровывает это без соли или без строки IV, и он расшифровывает правильно. Однако, когда я попытался использовать openssl, я не получил открытый текст:
echo "0: FC 89 BF C2 B0 5F 1C 2E 64 B8 78 43 92 78 3A C9" | xxd -r | openssl aes-128-ecb -d -k REDRYDER -nosalt -nopad ; echo
Это просто выводит некоторые двоичные данные. Я также пробовал передавать входные данные через dd conv=swab, чтобы сделать обмен байтами.
Что я делаю не так?
решение1
Инструмент openssl
командной строки — это демонстрационная версия библиотеки OpenSSL. У него довольно бессистемный интерфейс и плохая документация. Я не рекомендую использовать его ни для чего, кроме тестирования библиотеки OpenSSL. (Да, есть люди, которые управляют CA с помощью openssl
. Я опасаюсь за их рассудок.)
АЕСработает с ключом, а не с паролем. Ключ AES-128 составляет ровно 16 байт.
Опция -k
не принимает ключ в качестве входных данных, она принимает пароль. Этот пароль хэшируется для получения ключа; по умолчанию используется MD5, и его можно переопределить с помощью опции командной строки -md
. Насколько я могу судить, это не документировано в руководстве, вам просто нужно прочитать исходный код ( apps/enc.c
, вызов EVP_BytesToKey
). Дайджест MD5 создает 16-байтовое значение из любой строки, но это не то, что использовалось здесь. В этом случае ключ на самом деле находится REDRYDER\0\0\0\0\0\0\0\0
там, где \0
находятся нулевые байты.
Опция -K
позволяет вам передавать ключ в шестнадцатеричном формате. Если вы передаете меньше байтов, чем размер ключа, OpenSSL завершается нулевыми байтами. Таким образом, чтобы передать ключ REDRYDER\0\0\0\0\0\0\0\0
, вы можете передать , $(echo REDRYDER | od -An -tx1 | tr -d ' ')
который является 5245445259444552
.
Операция расшифровки AES-128-ECB блока зашифрованного текста FC89BFC2B05F1C2E64B8784392783AC9 с ключом 524544525944455200000000000000000 дает 464c41473d44414953590000000000000 (используя шестнадцатеричное представление для представления последовательностей байтов). Это FLAG=DAISY\0\0\0\0\0\0
.
Для таких небольших криптографических манипуляций мне нравится верхний уровень Python сPycryptoбиблиотека.
>>> from binascii import hexlify, unhexlify
>>> from Crypto.Cipher import AES
>>> ciphertext = unhexlify('FC 89 BF C2 B0 5F 1C 2E 64 B8 78 43 92 78 3A C9'.replace(' ', ''))
>>> key = 'REDRYDER'.ljust(16, '\0')
>>> AES.new(key, AES.MODE_ECB).decrypt(ciphertext)
'FLAG=DAISY\x00\x00\x00\x00\x00\x00'
решение2
Это работает:
echo '0: FC89BFC2B05F1C2E64B8784392783AC9' | xxd -r | openssl enc -aes-128-ecb -d -nopad -nosalt -K 5245445259444552
Я не понимаю, как вводить данные для опции -k, но если преобразовать ключ из обычного текста в шестнадцатеричный формат (с правильным порядком байтов) и использовать вместо этого опцию -K, то это сработает.
openssl — это вуду!