上週末有密碼挑戰,密文是以下十六進位:
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使用密鑰進行操作,而不是使用密碼。 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 將以空位元組完成。所以要傳遞key REDRYDER\0\0\0\0\0\0\0\0
,就可以傳遞$(echo REDRYDER | od -An -tx1 | tr -d ' ')
which is 5245445259444552
。
使用金鑰 52454452594445520000000000000000 對密文區塊 FC89BFC2B05F1C2E64B8784392783AC9 進行 AES-128-ECB 解密操作,得到1 46404050制來表示位元組序列)。那是FLAG=DAISY\0\0\0\0\0\0
。
對於像這樣的小加密操作,我喜歡使用 Python 頂層加密貨幣圖書館.
>>> 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 是巫毒!