https://cryptohack.org/courses/symmetric/ecb_oracle/
ECB 是最簡單的加密模式,每個明文區塊會獨立加密。在這裡,你的flag 會被加到所輸入的內容後面,然後再一起加密。
點入題目給的網址後,先來看一下原始碼。
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
KEY = ?
FLAG = ?
@chal.route('/ecb_oracle/encrypt/<plaintext>/')
def encrypt(plaintext):
plaintext = bytes.fromhex(plaintext)
#這裡的 plaintext 與 FLAG 的編碼形式進行串接後,使用 pad 函數來填充,使其長度成為AES的區塊大小(16 bytes)的倍數。
padded = pad(plaintext + FLAG.encode(), 16)
cipher = AES.new(KEY, AES.MODE_ECB)
try:
encrypted = cipher.encrypt(padded)
except ValueError as e:
return {"error": str(e)}
return {"ciphertext": encrypted.hex()}
這題中很重要的概念是填充模式(Padding),也就是在區塊加密中,當明文的長度不是區塊大小的整數倍時,用額外的資料填滿最後一個不完整的區塊,以確保所有區塊的大小一致。關於填充模式晚點寫一篇小介紹。
從原始碼中我們可以知道區塊大小為16bytes。
1 bytes = 8bits = 2個hex字符(因為 2^4=16,所以一個hex字符4bits)
16 bytes = 32個hex字符
需要注意的是這題中不管是加密後還是解密後的字元格式都是hex
從原始碼中的
@chal.route('/ecb_oracle/encrypt/<plaintext>/')
得出進行加密的網址為"https://aes.cryptohack.org/ecb_oracle/encrypt/"
再加上我們要加密的hex字串
使用request的方法就可以向網頁端發送請求了。
上面提到plaintext與FLAG的編碼形式進行串接後,會使用pad函數來填充使長度成為16 bytes的倍數。
所以接下來簡單寫個程式碼來判斷flag的長度。
從程式運行的結果可以看到當str從 6 bytes 變成 7 bytes時, block 從 32 bytes 變成 48 bytes。
所以flag的長度為32-6=26bytes,而因為byte顯示時會有一個b'的前綴,所以實際的flag為25bytes。
(因為當 str=7 bytes時,plaintext+FLAG > 32 bytes,所以被填充為48bytes)
接下來內容有點太多分兩部分發好了,今天先這樣,明天再補剩下的。