【问题标题】:Hash file in chunk with Crypto++ FileSource使用 Crypto++ FileSource 在块中散列文件
【发布时间】:2019-03-31 21:36:43
【问题描述】:

我有一个大文件需要散列,但如果我直接从文件中散列它,我的内存是有限的。我想分 2 步而不是 1 步进行散列。例如,我首先使用算法CRC32 将文件散列在块中并存储在字符串中。并执行第二步再次哈希到SHA256

目前我成功地在 1 步中散列文件。但它会吃掉内存,如果内存不足,最终会返回错误或崩溃。

为了在循环while中使用cpu不会太高。我决定选择 1048576 Bytes(1MB) 作为块。在这个测试中,我的控制台不返回 crc32 哈希。

CRC32 hash;
std::string str;
FileSource file("D:/1.exe", false, new HashFilter(hash, new HexEncoder(new StringSink(str))), true);
while (!file.SourceExhausted())
{
    file.Pump(1048576);
}
std::cout << str;
getchar();
return 0;

【问题讨论】:

  • 您正在耗尽内存,因为您将整个文件存储在字符串中。只需删除 new CryptoPP::HexEncoder(new CryptoPP::StringSink(str)) 即可解决问题。
  • @zett42 否,如果使用默认的 true 别名 PumpAll。它只返回 8 个长度的字符。真正的问题是在散列之前它需要将整个字节加载到内存而不是散列。所以我选择假第二个参数。但我不知道如何将值从文件源传递到 while 并进行缓冲区转换
  • @zett42 进行测试,我选择了一个 2MB 大小的文件 1.exe。因此它将循环两次并生成 2 个 crc32 哈希并组合成 1 个字符串。这就是我想要的。但文档如此泄漏示例。
  • 首先散列到 CRC32,然后将结果散列到 SHA-256 是不安全的,所以我不确定你在这里尝试完成什么。
  • @kelalaka 那是关于 NaCl,一个完全不同的库。请仔细检查一个骗子是否真的是一个骗子:你不能指望有人因为一个功能而切换库;应该可以在不使用 Crypto++ 将所有内容加载到内存的情况下对文件进行 SHA-256 处理。

标签: c++ hash cryptography crypto++


【解决方案1】:

我有一个大文件需要散列,但如果我直接从文件中散列它,我的内存是有限的。所以我想分两步而不是一步进行散列。前任。我首先使用算法 CRC32 将文件散列在块中并存储在字符串中。并执行第二步再次散列到 SHA256...

我认为您应该使用 ChannelSwitch 并让库提供过滤器。该库默认使用 4KB 块,它应该使您远远低于内存上限。

ChannelSwitch 可以将源数据提供给多个过滤器,因此您只需读取一次数据。您不必担心自己编写"tee"-like filter

首先,修改您的程序以使用ChannelSwitch 并使用名为data.bin 的文件。您将在下面创建文件:

$ cat test.cxx

#include "cryptlib.h"
#include "channels.h"
#include "filters.h"
#include "files.h"
#include "sha.h"
#include "crc.h"
#include "hex.h"

#include <string>
#include <iostream>

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    try
    {
        std::string s1, s2;
        CRC32 crc;
        SHA1 sha1;

        HashFilter f1(crc, new HexEncoder(new StringSink(s1)));
        HashFilter f2(sha1, new HexEncoder(new StringSink(s2)));

        ChannelSwitch cs;
        cs.AddDefaultRoute(f1);
        cs.AddDefaultRoute(f2);

        FileSource("data.bin", true /*pumpAll*/, new Redirector(cs));

        std::cout << "Filename: " << "data.bin" << std::endl;
        std::cout << "   CRC32: " << s1 << std::endl;
        std::cout << "    SHA1: " << s2 << std::endl;
    }
    catch(const Exception& ex)
    {
        std::cerr << ex.what() << std::endl;
    }

  return 0;
}

接下来,创建一个非常大的文件:

$ dd if=/dev/urandom of=data.bin bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 5.48884 s, 196 MB/s

接下来,编译运行程序:

$ g++ -g2 -O3 test.cxx ./libcryptopp.a -o test.exe
$

$ time ./test.exe
Filename: data.bin
   CRC32: 20F45F3E
    SHA1: F0857F8E46112BB08A04D5CE51BDBEA0C4539032

real    0m4.430s
user    0m4.269s
sys     0m0.156s

最后,如Pumping Data | Low Memory 所述,使用 Bash shell 模拟内存不足的情况。请注意,我们需要 12 MB 来运行可执行文件;否则libc.so.6 无法被链接加载器映射。剩下大约 4 MB 的 RAM 用于程序和数据。

$ (ulimit -v 16368; ./test.exe)
Filename: data.bin
   CRC32: 20F45F3E
    SHA1: F0857F8E46112BB08A04D5CE51BDBEA0C4539032

【讨论】:

    猜你喜欢
    • 2014-06-17
    • 1970-01-01
    • 2020-11-04
    • 1970-01-01
    • 2019-10-26
    • 2018-09-03
    • 2018-01-13
    • 2014-03-30
    • 1970-01-01
    相关资源
    最近更新 更多