安全篇之永強繼續教你加解密:對稱篇(三)
- 2019 年 11 月 13 日
- 筆記
篇文中我們已經好像大概似乎看起來貌似搞定了ECB、CBC、CFB、OFB、CTR這五個英文單詞縮寫代表啥意義了,也弄清楚了aes-128-ecb中的128是啥意思了,好像還接觸了一下填充的概念,最後就差那個iv向量到現在還沒搞明白是個什麼鬼玩意了… …
這個章節理論上你可以跳過不看的,不過你一定會錯過這些比較基礎的內容!好了,不廢話不BB,先從ECB開始,複製粘貼一下上篇文中的程式碼:
<?php $ava_methods = openssl_get_cipher_methods(); $my_method = 'aes-128-ecb'; if ( !in_array( $my_method, $ava_methods ) ) { exit( '錯誤的加密方法'.PHP_EOL ); } $key = "1234567812345678"; $data = "12345678abcdxxoo12345678abcdxxooi"; echo "明文:".$data.PHP_EOL; $enc_data = openssl_encrypt( $data, $my_method, $key, OPENSSL_RAW_DATA ); echo "密文:".$enc_data.PHP_EOL; $dec_data = openssl_decrypt( $enc_data, $my_method, $key, OPENSSL_RAW_DATA ); echo "解密:".$dec_data.PHP_EOL;
保存運行一把,結果如下圖:

那麼這個ECB是如何對分組明文進行處理的呢?看下圖:

也就是說:ECB模式就是簡單地利用密鑰為了每個明文分組進行加密;解密地時候做相反操作即可。如果說ECB模式這樣的模式,我們做個大膽的測試,就是我們將加密後的密文分組交換順序,是不是也會改變明文順序?
<?php $ava_methods = openssl_get_cipher_methods(); $my_method = 'aes-128-ecb'; if ( !in_array( $my_method, $ava_methods ) ) { exit( '錯誤的加密方法'.PHP_EOL ); } $key = "1234567812345678"; $data = "12345678abcdxxooxxooabcd12345678i"; echo "明文:".$data.PHP_EOL; $enc_data = openssl_encrypt( $data, $my_method, $key, OPENSSL_RAW_DATA ); $hex = bin2hex( $enc_data ); $pre = substr( $hex, 0, 32 ); $mid = substr( $hex, 32, 32 ); $suf = substr( $hex, 64, 32 ); $tmp = $mid.$pre.$suf; $dec_data = openssl_decrypt( hex2bin( $tmp ), $my_method, $key, OPENSSL_RAW_DATA ); echo "解密:".$dec_data.PHP_EOL;
上述程式碼的意思主要是說要把第一個密文分組和第二個密文分組交換一下順序,然後再解密,按照我們的猜測如果可以的話,那麼解密成功後的明文就應該是:xxooabcd1234567812345678abcdxxooi,那麼接下來我們執行下程式碼,看看我們篡改的分組數據是否篡改成功了:

卧槽… …

我雖然不知道加解密的密碼是什麼,但是我卻能通過固定位元組長度調整分組順序間接的篡改數據,導致解密後的數據已經不再是原來的明文了
ECB模式存在這麼大缺陷,所以,喜新厭舊的真香人類們發明了一種新的模式叫做CBC模式,那麼CBC模式是怎樣一種流程呢?如下圖:

這個傳說中的iv向量終於出現了!相對於ECB模式,CBC在加密之前多了一個XOR異或運算的環節,但是第一個明文分組和誰做異或呢?所以這個iv向量就是初始化後給第一個明文分組做XOR異或運算用的,第二個明文分組就與第一個密文分組做XOR異或運算,然後再加密得到第二個密文分組…依次重複下去。
然後CBC模式解密的時候與上面就是完全一個相反的過程:

圖紙都是蒼白的,理論都是無力的,唯有程式碼才能說明一切:
<?php $ava_methods = openssl_get_cipher_methods(); // ⚠️⚠️⚠️ 我們將方法改為aes-128-cbc! $my_method = 'aes-128-cbc'; if ( !in_array( $my_method, $ava_methods ) ) { exit( '錯誤的加密方法'.PHP_EOL ); } // 密鑰 和 明文 $key = "1234567812345678"; $data = "12345678abcdxxooxxooabcd12345678i"; echo "明文:".$data.PHP_EOL; $enc_data = openssl_encrypt( $data, $my_method, $key, OPENSSL_RAW_DATA ); $dec_data = openssl_decrypt( $enc_data, $my_method, $key, OPENSSL_RAW_DATA ); echo "解密:".$dec_data.PHP_EOL;
注意上述程式碼中第4行,我們採用aes-128-cbc方法,保存程式碼後運行,報錯了:

還記得這個錯誤嗎?記性好的泥腿子應該想起來了,在《加解密開篇》中就是這個錯誤,我在此複製粘貼過來:
HP Warning: openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended in /home/ubuntu/lab/test.php on line 10 PHP警告:openssl_encrypt():iv向量最好別是空的,不推薦這麼用,而且這樣並不安全~
CBC模式的原理我們也看到了,說明我們確實需要在使用CBC模式前初始化一個iv向量出來,非常的簡單,我們只需要簡單修改一下上面的程式碼:
<?php $ava_methods = openssl_get_cipher_methods(); $my_method = 'aes-128-cbc'; if ( !in_array( $my_method, $ava_methods ) ) { exit( '錯誤的加密方法'.PHP_EOL ); } // 密鑰 和 明文 $key = "1234567812345678"; $data = "12345678abcdxxooxxooabcd12345678i"; // 每種方法都有自己需要的iv向量的長度 $iv_length = openssl_cipher_iv_length( $my_method ); // 根據長度生成相應iv $iv = openssl_random_pseudo_bytes( $iv_length, $cstrong ); echo "明文:".$data.PHP_EOL; $enc_data = openssl_encrypt( $data, $my_method, $key, OPENSSL_RAW_DATA, $iv ); $dec_data = openssl_decrypt( $enc_data, $my_method, $key, OPENSSL_RAW_DATA, $iv ); echo "解密:".$dec_data.PHP_EOL;
程式碼的11行表示獲取這個模式的iv向量的長度;13行表示根據這個長度生成一個iv向量。可能有泥腿子糾結於這個iv向量都是是啥玩意,至於你知不知道,反正我不知道。。。我就是一直把這玩意當成一個隨機的字元串看待的。還有泥腿子問這個玩意和高中數學老師講的向量是不是一樣,這個至於你知不知道,反正我不知道。
保存運行,結果如下圖:

完美!
說了ECB和CBC模式的處理流程,其實後面的CFB和OFB其實也就那樣了,我就不再自己拼湊了。總之,加密就是各種花式分塊;然後,解密也是各種花式分塊。其他的分塊模式,大家可以去網上搜索一下。
理論上講,要是上面的流程和程式碼都走一遍的話,CFB和OFB你們可以自己嘗試查資料完成就可以了,弄不好你們搜索到的資料比我這裡還上檔次顯難度!
截止到目前為止,三篇文章已經闡述了對稱加解密中如下的概念:
- iv向量
- 分組
- 分組模式
- 對稱密鑰的概念以及對稱密鑰長度的概念
- PHP中openssl關於對稱加密的一些用法
截止到目前為止,已經過去的三篇文章沒有說明闡述的內容有如下:
- DES、3DES、AES在對明文進行分組後,是如何對明文分組執行加密的
- DES和AES在對明文分組進行加密的時候到底哪兒不一樣
這些基本上都是屬於黑盒子概念了,說真的,至於你們知不知道,反正我是就知道一點兒,我並不打算在第四篇中講解這些,因為openssl-encrypt已經完全對我屏蔽了這些底層運算,所以從接受度以及實用性角度出發,這些可能會寫,也可能不會寫,寫的話就會放到最後附錄中作為體現。