AES 5种加密模式 && 初始向量的影响
- 引言
- AES的工作模式
- ECB模式(电子密码本模式:Electronic codebook)
- CBC模式(密码分组链接:Cipher-block chaining)
- CFB模式(密文反馈:Cipher feedback)
- OFB模式(输出反馈:Output feedback)
- CTR模式 (计数器:Counter)
引言
写这篇文章是由于,关于如何使用AES的文章很多,大多都是API调用,但是关于IV初始向量
的作用好像没几个文章有写,IV初始向量
在CBC
,CFB
模式下,仅影响前16字节(128位加密方式)
的块,推荐使用CTR
模式。
AES的工作模式
AES
的工作模式(ECB
、CBC
、CFB
、OFB
、CTR
)。
-
OPENSSL_ZERO_PADDING
你可以使用OPENSSL_ZERO_PADDING
的flag
,让它自动填充0x00
(使用自动填充
返回的内容就直接是base64
编码过的了,并不是二进制数据
),虽然也可以再base64Decode
变会二进制数据
,但是这样做感觉像是多此一举,但是由于php
不建议使用OPENSSL_ZERO_PADDING
,实际上会无效,还是需要你手动补齐
,它唯一的作用就是直接返回base64
格式的编码。 -
OPENSSL_NO_PADDING
推荐使用OPENSSL_NO_PADDING
手动填充,我们可以自写填充函数
,好处是我们可以自己选择需要二进制数据
还是base64
数据。 -
OPENSSL_RAW_DATA
OPENSSL_RAW_DATA
不填充数据。
ECB模式(电子密码本模式:Electronic codebook)
加密前根据加密块大小分成若干块,之后将每块使用相同的密钥
单独加密
,解密同理。
<?php
$data = '0123456789abcdefghijklmnopqrstuvwxyz';
$key = "0123456789abcdef";
$encode = base64_encode(openssl_encrypt($data,"AES-128-ECB",$key,OPENSSL_RAW_DATA));
$decode = openssl_decrypt(base64_decode($encode),"AES-128-ECB",$key,OPENSSL_RAW_DATA);
echo $encode.PHP_EOL;
echo $data.PHP_EOL;
echo $decode.PHP_EOL;
?>
输出内容:
shellcnJ+iB7c/QEApxhoeQm1ZcZmX1z/d7UC1tQtnJD7Dk38io1fHY85My7I/tQPjI3b
0123456789abcdefghijklmnopqrstuvwxyz
0123456789abcdefghijklmnopqrstuvwxyz
CBC模式(密码分组链接:Cipher-block chaining)
CBC模式
对于每个待加密的密码块在加密前会先与前一个密码块的密文异或
然后再用加密器加密
。第一个明文块
与初始向量
的数据块异或
。
这里的初始向量
是第二重保障
,让开头的16字节(128位加密方式)
与初始向量
异或具体看下面的栗子。
这里正好演示一下flag,手动补齐0x00之类的。
<?php
function PadZero($data, $blocksize = 16)
{
$pad = $blocksize - (strlen($data) % $blocksize);
return $data . str_repeat("\0", $pad);
}
$data = '0123456789abcdefghijklmnopqrstuvwxyz';
$key = "0123456789abcdef";
$iv = '8NONwyJtHesysWpM';
$iv2 = 'gergergertqqwerw';
$encode = base64_encode(openssl_encrypt(PadZero($data),"AES-128-CBC",$key,OPENSSL_NO_PADDING,$iv));
//OPENSSL_ZERO_PADDING自动填充,由于php的问题,还是需要手动补齐,但是返回的直接是base64编码
$encode2 = openssl_encrypt(PadZero($data),"AES-128-CBC",$key,OPENSSL_ZERO_PADDING,$iv);
// 解密
$decode = openssl_decrypt(base64_decode($encode),"AES-128-CBC",$key,OPENSSL_NO_PADDING,$iv2);
//解密还是需要OPENSSL_NO_PADDING
$decode2 = openssl_decrypt(base64_decode($encode2),"AES-128-CBC",$key,OPENSSL_NO_PADDING,$iv2);
echo $encode.PHP_EOL;
echo $encode2.PHP_EOL;
echo $data.PHP_EOL;
echo $decode.PHP_EOL;
echo $decode2.PHP_EOL;
?>
输出内容:
最后那十二个方框实际上是0x00,因为我们加密时补齐了0,我只是写出来让你们看的更明白。
k2GXq52ijs28l14F1JOBFDB2YiEX0BmKpES8bsce9JXpL4FtfHsYldzVt1w3UbSb
k2GXq52ijs28l14F1JOBFDB2YiEX0BmKpES8bsce9JXpL4FtfHsYldzVt1w3UbSb
0123456789abcdefghijklmnopqrstuvwxyz
o&>&(cjgVg\ghijklmnopqrstuvwxyz□□□□□□□□□□□□
o&>&(cjgVg\ghijklmnopqrstuvwxyz□□□□□□□□□□□□
结论,CBC的初始向量
只影响数据头部16字节(128位加密方式)
,所以也没有特别安全。只是加密过程更安全,但是在得知密钥
的情况下,IV初始向量
的作用不大
。
CFB模式(密文反馈:Cipher feedback)
将前一段加密得到的密文再加密,将第一步加密得到的数据与当前段的明文异或。不要求与16字节
(128位加密方式)对齐
。
<?php
$data = '0123456789abcdefghijklmnopqrstuvwxyz';
$key = "0123456789abcdef";
$iv = '8NONwyJtHesysWpM';
$iv2 = 'gergergertqqwerw';
$encode = base64_encode(openssl_encrypt($data,"AES-128-CFB",$key,OPENSSL_RAW_DATA,$iv));
// 解密
$decode = openssl_decrypt(base64_decode($encode),"AES-128-CFB",$key,OPENSSL_RAW_DATA,$iv2);
echo $encode.PHP_EOL;
echo $data.PHP_EOL;
echo $decode.PHP_EOL;
?>
输出内容:
5MuwKWvcGaXaKfenTlK9IX2GpGr3AtFW9qPB8L0ZtOwZ6lPm
0123456789abcdefghijklmnopqrstuvwxyz
KB�����Ǻ�w ~&@ghijklmnopqrstuvwxyz
结论,CFB的初始向量
只影响数据头部16字节(128位加密方式)
,所以同样没有特别安全。同样在得知密钥
的情况下,IV初始向量
的作用不大
。
OFB模式(输出反馈:Output feedback)
OFB
是先用块加密器
生成密钥流(Keystream)
,然后再将密钥流与明文流异或
得到密文流
,解密
是先用块加密器
生成密钥流
,再将密钥流与密文流异或
得到明文
,由于异或操作
的对称性
所以加密
和解密
的流程一样
。
<?php
$data = '0123456789abcdefghijklmnopqrstuvwxyz';
$key = "0123456789abcdef";
$iv = '8NONwyJtHesysWpM';
$iv2 = 'gergergertqqwerw';
$encode = base64_encode(openssl_encrypt($data,"AES-128-OFB",$key,OPENSSL_RAW_DATA,$iv));
// 解密
$decode = openssl_decrypt(base64_decode($encode),"AES-128-OFB",$key,OPENSSL_RAW_DATA,$iv2);
echo $encode.PHP_EOL;
echo $data.PHP_EOL;
echo $decode.PHP_EOL;
?>
输出内容:
shell5MuwKWvcGaXaKfenTlK9Ibkd7J6mqD8+YTkratN3B5RNyZfF
0123456789abcdefghijklmnopqrstuvwxyz
KB�����Ǻ�w ~&@b)��2A��8]�cȐQ�A
结论,OFB的初始向量
影响整个数据
,是因为他的加密机制,利用密钥流与明文流整体异或,哪怕初始向量
只有一个字节不同
,结果都会差很多。
CTR模式 (计数器:Counter)
它和OFB
有些类似,但是有一个counter计数器
,每次加密就+1,用这个值使用加密器加密
,然后与明文分组异或
。
<?php
$data = '0123456789abcdefghijklmnopqrstuvwxyz';
$key = "0123456789abcdef";
$iv = '8NONwyJtHesysWpM';
$iv2 = 'gergergertqqwerw';
$encode = base64_encode(openssl_encrypt($data,"AES-128-CTR",$key,OPENSSL_RAW_DATA,$iv));
// 解密
$decode = openssl_decrypt(base64_decode($encode),"AES-128-CTR",$key,OPENSSL_RAW_DATA,$iv2);
echo $encode.PHP_EOL;
echo $data.PHP_EOL;
echo $decode.PHP_EOL;
?>
输出内容:
5MuwKWvcGaXaKfenTlK9IVbSSYBHiHol+Ye3qJBeRdPgfY8h
0123456789abcdefghijklmnopqrstuvwxyz
�Z��Iڱ9���aUX�w鳴��I�(k�iZ&[�
结论,CTR的初始向量
影响整个数据
,也是因为他的加密机制,哪怕初始向量
只有一个字节不同
,结果都会差很多。