在CTR 模式下,计数器(AES 为 128 位)被加密以生成密钥流,然后与明文或密文进行异或运算。通常,假设 IV 是 64 位或 96 位,其余位实际上设置为 0。最初的 64 位或 96 位称为nonce。
nonce 的大小决定了一次性加密多少数据而无需创建多次填充:nonce 越大,安全消息长度越小,但随机生成的两个 nonce 冲突的概率也更低。由于没有规范 nonce 有多大,许多框架不会将 nonce 的大小限制为特定大小。
您可以在 mcrypt 中使用完整的块大小作为随机数。
你可以
- 取一开始就使用的静脉输液,
- 将该 IV 解析为一个大整数(它不适合 PHP 整数类型),
- 添加一个数字,它表示您想要跳过的块(AES 为 16 字节块) ,
- 将数字转换回二进制表示和
- 从后面的字节开始解密。
步骤 2-4 由add
以下代码中的函数完成。
假设您有一个大文件,但想从字节 512(为简单起见是块大小的倍数)解密。您将在 IV 中添加512/16=32 。
这是一些示例代码:
<?php
$d = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
$k = "k0k1k2k3k4k5k6k7"; // 16 byte AES key
$bs = 16; // 16 byte block size
$iv = mcrypt_create_iv($bs);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'ctr', '');
mcrypt_generic_init($td, $k, $iv);
$ct = mcrypt_generic($td, $d);
$dec_offset = 32;
$ct_slice = substr($ct, $dec_offset);
$iv_slice = add($iv, $dec_offset / $bs);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'ctr', '');
mcrypt_generic_init($td, $k, $iv_slice);
$d_slice = mdecrypt_generic($td, $ct_slice);
var_dump($d_slice);
function add($big_num_str, $to_add){
$big_num = str_split(strrev($big_num_str));
for($i = 0; $i < count($big_num) ; $i++){
$tmp = ord($big_num[$i]) + $to_add;
$big_num[$i] = $tmp % 256;
$to_add = floor( $tmp / 256 );
}
while($to_add){
$big_num[$i++] = $to_add % 256;
$to_add = floor( $to_add / 256 );
}
for($i = 0; $i < count($big_num) ; $i++){
$big_num[$i] = chr($big_num[$i]);
}
return strrev(implode('', $big_num) );
}
输出:
字符串(32)“101112131415161718191a1b1c1d1e1f”
这也同样适用于 PHP 中的 OpenSSL 扩展。这是代码。
当然,如果你想获得一个不在块边界开始的块,这会稍微复杂一些。您必须提前开始一个块并删除多余的字节。