安全篇之永强继续教你加解密:对称篇(三)

2019-11-13 16:25:27 浏览数 (3)

篇文中我们已经好像大概似乎看起来貌似搞定了ECB、CBC、CFB、OFB、CTR这五个英文单词缩写代表啥意义了,也弄清楚了aes-128-ecb中的128是啥意思了,好像还接触了一下填充的概念,最后就差那个iv向量到现在还没搞明白是个什么鬼玩意了… …

这个章节理论上你可以跳过不看的,不过你一定会错过这些比较基础的内容!好了,不废话不BB,先从ECB开始,复制粘贴一下上篇文中的代码:

代码语言:javascript复制
<?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模式这样的模式,我们做个大胆的测试,就是我们将加密后的密文分组交换顺序,是不是也会改变明文顺序?

代码语言:javascript复制
<?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模式解密的时候与上面就是完全一个相反的过程:

图纸都是苍白的,理论都是无力的,唯有代码才能说明一切:

代码语言:javascript复制
<?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方法,保存代码后运行,报错了:

还记得这个错误吗?记性好的泥腿子应该想起来了,在《加解密开篇》中就是这个错误,我在此复制粘贴过来:

代码语言:javascript复制
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向量出来,非常的简单,我们只需要简单修改一下上面的代码:

代码语言:javascript复制
<?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已经完全对我屏蔽了这些底层运算,所以从接受度以及实用性角度出发,这些可能会写,也可能不会写,写的话就会放到最后附录中作为体现。

0 人点赞