1

我有一个 1MB 的测试文件,我想从 500KB 开始解密它,而不是从头开始。它不需要完全从文件的 500KB 开始,它可以从任何块的开头开始,只要它不是第一个,我只是想学习如何去做。

有了这个脚本,我就可以解密文件,只要它从 0KB 开始。

$file = file_get_contents("file.dat");
$aeskey = base64_decode("sVv2g7boc/pzCDepDfV1VA==");
$iv = base64_decode("A5chWWE3D4cAAAAAAAAAAA==");

$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'ctr', '');
mcrypt_generic_init($td, $aeskey, $iv);

echo mdecrypt_generic($td, $file);

如果至少有可能,有人可以解释一下吗?

4

1 回答 1

2

CTR 模式下,计数器(AES 为 128 位)被加密以生成密钥流,然后与明文或密文进行异或运算。通常,假设 IV 是 64 位或 96 位,其余位实际上设置为 0。最初的 64 位或 96 位称为nonce

nonce 的大小决定了一次性加密多少数据而无需创建多次填充:nonce 越大,安全消息长度越小,但随机生成的两个 nonce 冲突的概率也更低。由于没有规范 nonce 有多大,许多框架不会将 nonce 的大小限制为特定大小。

您可以在 mcrypt 中使用完整的块大小作为随机数。

你可以

  1. 取一开始就使用的静脉输液,
  2. 将该 IV 解析为一个大整数(它不适合 PHP 整数类型),
  3. 添加一个数字,它表示您想要跳过的块(AES 为 16 字节块) ,
  4. 将数字转换回二进制表示和
  5. 从后面的字节开始解密。

步骤 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 扩展。是代码。


当然,如果你想获得一个不在块边界开始的块,这会稍微复杂一些。您必须提前开始一个块并删除多余的字节。

于 2016-03-14T20:57:00.477 回答