AES的基本知識
AES(Advanced Encryption Standard)是一種對稱式(symmetric)的加密演算法,是透過對每個固定大小的4x4位元矩陣區塊(block = 128 bits = 16 bytes),對其每一個元素進行多次交互置換和XOR運算。簡單來說,就是用同一把 secret key 進行Encrypt和Decrypt的動作。優點是對於資料大的檔案加解密的速度較快,而且容易透過硬體實作,運算所需要的記憶體較少,但是缺點是在資料交換的過程中,雙方必須取得這把相同的secret key。否則,接收到加密檔案的接收者,無法解開加密後的檔案。而它的安全性強度取決於金鑰(secret key)的長度,目前美國國防安全局審核認定的AES標準演算法secret key長度有128 bits, 192 bits和256 bits 三種。secret key的長度越長就越安全,但是相對的加密所需的時間就越多,然而實際上secret key長度對於加密時間的影響並不大,主要還是取決於所選擇的 Block Cipher Mode以及需要加密的資料大小。AES演算法中常見的專有名詞
在AES演算法中,不管是網路上的文章或是API文件中,常見到以下這些名詞:Initialization vector (IV)
"初始化向量"或稱"起始變數",它的用途主要在於避免相同的資料加密多次都產生相同的密文(Cipher Text)。因此,使用上必須要注意的是,相同的一把金鑰(secret key)在加密的時候,不可以使用相同的 IV,否則就破壞了AES的安全性。此外 IV 本身並不需要保護,它是可以被公開的。而IV的最大長度必須是 16 bytes,而且產生IV的方式必須是無法預測的,也就是隨機產生即可。
以下是關於幾種常見的IV類型:
(1) Fixed IV
顧名思義就是,在使用同一把金鑰(secret key)在加密的時候,所使用的IV都是固定的。這會造成兩個相同的 plain-text 的區塊,產生的 cipher-text 區塊是相同的。
(2) Counter IV
是指在使用同一把金鑰(secret key)在加密的時候,每次加密一個訊息時,都將 IV 累加 1。
(3) Random IV
是指隨機產生一個亂數當作 IV。建議的作法是將第一個 IV 當作密文的第一個 cipher-text 區塊。從第二個 cipher-text 區塊才是真正的加密資料。
(4) Nonce-Generated IV
是指使用相同的一把金鑰(secret key)在加密的時候,用一個 nonce 來產生 IV 。nonce 是指 number used once 的意思,主要的精神在於同一把金鑰(secret key)不可以使用相同的 nonce。例如:假設選擇 nonce = 0 開始後,使用相同的一把金鑰(secret key)在加密的時候,不可以出現使用 nonce = 0 第 2 次。
以下是關於幾種常見的IV類型:
(1) Fixed IV
顧名思義就是,在使用同一把金鑰(secret key)在加密的時候,所使用的IV都是固定的。這會造成兩個相同的 plain-text 的區塊,產生的 cipher-text 區塊是相同的。
(2) Counter IV
是指在使用同一把金鑰(secret key)在加密的時候,每次加密一個訊息時,都將 IV 累加 1。
(3) Random IV
是指隨機產生一個亂數當作 IV。建議的作法是將第一個 IV 當作密文的第一個 cipher-text 區塊。從第二個 cipher-text 區塊才是真正的加密資料。
(4) Nonce-Generated IV
是指使用相同的一把金鑰(secret key)在加密的時候,用一個 nonce 來產生 IV 。nonce 是指 number used once 的意思,主要的精神在於同一把金鑰(secret key)不可以使用相同的 nonce。例如:假設選擇 nonce = 0 開始後,使用相同的一把金鑰(secret key)在加密的時候,不可以出現使用 nonce = 0 第 2 次。
Padding
由於AES加密過程,是針對每個固定大小的區塊(16 bytes),進行多次的交互置換和XOR運算,因此當需要被加密的資料小於矩陣區塊16 bytes 的時候,或是資料的size 不是 16 bytes的倍數時,為了讓加密能夠順利進行,必須將資料的 size 補齊到能夠被 16 bytes 整除的大小。舉例來說,假設需要保護的資料總長度只有 5 bytes,那在進行AES加密之前,必須補齊資料長度達到16 bytes。至於,不同補齊的方式可以參考 Use Padding in Encryption 這篇文章。
特別註記,以下的圖出自於維基百科 (https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation)
特別註記,以下的圖出自於維基百科 (https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation)
Block cipher mode
- ECB (Electronic codebook,ECB)
ECB是對於每一個資料區塊都用同一把金鑰(secret key)去加密,而且沒有使用 IV。缺點是在於相同的資料區塊,加密後的密文(Cipher Text)會是相同的。優點是每個區塊都可以獨立進行加密,因此可同時對每個區塊進行加密。 - CBC (Cipher-block chaining)
CBC是一種串鏈的加密方式,第一個資料區塊必須加入IV和金鑰(secret key)進行加密,之後將加密後的密文(Cipher Text)作為第二個資料區塊的IV再加上金鑰進行加密,以此類推下去,直到所有區塊都被加密完成。這種方式在加密過程當中,下一個區塊必須依賴這個區塊加密後的結果才能夠得到IV,因此無法同時進行。但是在解密的時候,可以同時對所有區塊進行解密,因為前後兩個密文(Cipher Text)區塊,後面的密文區塊要解密時候所需要的IV就是前一個密文區塊。 - CFB (Cipher feedback)
CFB 則是將 IV 和金鑰(secret key) 產生出 密文(Cipher Text)區塊,然後把密文(Cipher Text)區塊和明文資料區塊進行XOR運算後的值,當做下一個資料區塊的IV再和金鑰(secret key)產生出下一個密文區塊,以此類推下去做相同的運算,直到所有區塊都被加密完成。 - OFB (Output feedback)
OFB 則是將 IV 和 金鑰 (secret key) 產生密文區塊(Cipher Block),然後將Cipher Block和明文區塊 PlainText 進行 XOR 運算。而這個區塊產生的 Cipher Block 則當作下一個資料區塊加密處理所需的 IV。
- CTR (Counter)
CTR 則是先透過所謂的 nonce (其實就是IV) 加上可以在長時間內每次都產生不重復 sequence 整數的 counter 所組合出來的一個整數值, 接著用同一把金鑰 (secret key) 對這個整數值加密後的產生一個密文區塊 (Cipher Block), 最後把這個密文區塊和明文區塊(PlainText)進行XOR運算。這種做法每個區塊都可以獨立地進行加密或是解密,因此可運用在平行處理的加解密運算。
AES Encrypt / Decrypt 基礎範例程式解說
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import M2Crypto.EVP as EVP import cStringIO ENCRYPT_OP = 1 DECRYPT_OP = 0 def aes_encrypt(iv, secret_key, plain_text): cipher = EVP.Cipher(alg='aes_128_cbc', key=secret_key, iv=iv, op=ENCRYPT_OP) input_buffer = cStringIO.StringIO(plain_text) cipher_data1 = cipher.update(input_buffer.read()) cipher_data2 = cipher.final() input_buffer.close() output_buffer = cStringIO.StringIO() output_buffer.write(cipher_data1) output_buffer.write(cipher_data2) cipher_text = output_buffer.getvalue() output_buffer.close() return cipher_text def aes_decrypt(iv, secret_key, cipher_text): cipher = EVP.Cipher(alg='aes_128_cbc', key=secret_key, iv=iv, op=DECRYPT_OP) input_buffer = cStringIO.StringIO(cipher_text) plain_text1 = cipher.update(input_buffer.read()) plain_text2 = cipher.final() input_buffer.close() output_buffer = cStringIO.StringIO() output_buffer.write(plain_text1) output_buffer.write(plain_text2) plain_text = output_buffer.getvalue() output_buffer.close() return plain_text if __name__ == '__main__': IV = 'c782dc4c098c66cb' # 16 bytes secrect_key = 'c286696d887c9aa0' # 16 bytes data = 'This is a 48-byte message (exactly 3 AES blocks)' cipher_text = aes_encrypt(IV, secrect_key, data) plain_text = aes_decrypt(IV, secrect_key, cipher_text) print('Cipher Text length is %d bytes'% len(cipher_text)) print('Cipher Text is as following') print('####################') print(cipher_text) print('####################') print('Plain Text=%s'% plain_text) |
EVP是OpenSSL針對對稱式加密所提供的模組,它針對某些對稱式(Symmetric)密碼學演算法在處理加密或是解密時,所需要的API規格。
- 因此在加密或是解密之前,需要產生一個Cipher的物件來負責加密或是解密。
- 初始化Cipher物件時,第 8 和 27 行程式的 alg 參數指定使用 128-bits 長度的 AES-CBC模式的演算法。這個 alg 參數在AES演算法的使用上,可以指定以下幾種分別代表不同長度和模式:
- ECB
- aes_128_ecb
- aes_192_ecb
- aes_256_ecb
- CBC
- aes_128_cbc
- aes_192_cbc
- aes_256_cbc
- CFB
- aes_128_cfb
- aes_192_cfb
- aes_256_cfb
- OFB
- aes_128_ofb
- aes_192_ofb
- aes_256_ofb
- 初始化Cipher物件時,第 9 和 28 行程式的 key 參數是用來指定加密或是解密時,所需要用到的金鑰(secret key)。它的長度至少需要128 bits 也就是16 bytes。若你是使用aes_256_cbc模式,則金鑰長度必須為256 bits 等於 32 bytes長度。
- 初始化Cipher物件時,第 10 和 29 行程式的 iv 參數是用來指定初始向量(Initialization vector),它的最大長度為 16 bytes。
- 初始化Cipher物件時,根據要做加密或是解密來決定 op的參數。若是用於加密,則 op 參數要設定為 1 。反之,用於解密時,則 op 參數必須指定為 0。
- 在程式碼的的 第 47 行,我們選定的 IV 長度為 16 bytes 。根據我的實驗結果,在M2Crypto API 使用上,即使所給的 IV不足 16 bytes,它還是可以執行。在 secret key不變的情況下,每次執行後的密文都會改變。但是,如果指定的 IV 剛好是 16 bytes長度時,執行多次後的密文是相同的。如果指定的 IV 長度大於 16 bytes,則超過16 bytes後的資料將不會被當做 IV 使用。然而,演算法上 IV 的長度應該要取決於你所使用的 AES mode 與金鑰長度來決定。
- 在程式碼的第 48 行,我們選定的 secret key 長度為 16 bytes 。因為這個範例程式指定的 AES模式為 aes_128_cbc,就 AES 128 bits 加密所需要的長度就是16 bytes 。但是,在 M2Crypto API 使用上,它的行為和 IV 有類似的狀況。以這個範例來說,如果 secret key 少於 16 bytes 而 IV 不變的情況下,對相同的資料加密後所產生的密文,對相同的資料執行多次後的密文都會不同。但是,如果 secret key 剛好指定 16 bytes 時候,對相同資料執行多次加密後所得到的密文是相同的。如果指定的 secret key 超過 16 bytes 時候,超過16 bytes 後的資料不會被當作 secret key來使用。
Important warring: You should select the correct cipher mode, for example: CCM or GCM mode. (Update 2022/03/04) The reason is the CBC mode is vulnerable to padding oracle attacks.
Reference:
- M2Crypto https://pypi.python.org/pypi/M2Crypto
- OpenSSL http://www.openssl.org
- AES CBC和CTR加解密實例 http://www.metsky.com/archives/585.html
- Block Cipher mode of operation https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
- Use Padding in Encryption http://www.di-mgt.com.au/cryptopad.html
學習了一課。給讚!
回覆刪除