当前位置: 首页 > 面试题库 >

Java:有效地计算大文件的SHA-256哈希

从经略
2023-03-14
问题内容

我需要计算大文件(或其一部分)的SHA-256哈希。我的实现工作正常,但比C 的CryptoPP计算要慢得多(25分钟vs. 30
GB文件的10分钟)。我需要的是在C
和Java中执行时间相似,因此散列几乎可以同时准备好。我也尝试了Bouncy
Castle的实现,但是它给了我相同的结果。这是我如何计算哈希值:

int buff = 16384;
try {
    RandomAccessFile file = new RandomAccessFile("T:\\someLargeFile.m2v", "r");

    long startTime = System.nanoTime();
    MessageDigest hashSum = MessageDigest.getInstance("SHA-256");

    byte[] buffer = new byte[buff];
    byte[] partialHash = null;

    long read = 0;

    // calculate the hash of the hole file for the test
    long offset = file.length();
    int unitsize;
    while (read < offset) {
        unitsize = (int) (((offset - read) >= buff) ? buff : (offset - read));
        file.read(buffer, 0, unitsize);

        hashSum.update(buffer, 0, unitsize);

        read += unitsize;
    }

    file.close();
    partialHash = new byte[hashSum.getDigestLength()];
    partialHash = hashSum.digest();

    long endTime = System.nanoTime();

    System.out.println(endTime - startTime);

} catch (FileNotFoundException e) {
    e.printStackTrace();
}

问题答案:

我的解释可能无法解决您的问题,因为它很大程度上取决于您的实际运行时环境,但是当我在系统上运行您的代码时,吞吐量受磁盘I /
O限制,而不是哈希计算。通过切换到NIO并不能解决问题,而仅仅是由于您以很小的片段(16kB)读取文件的事实而引起的。将系统上的缓冲区大小(buff)增加到1MB而不是16kB会使吞吐量增加一倍以上,但是以>
50MB / s的速度,我仍然受到磁盘速度的限制,无法完全加载单个CPU内核。

顺便说一句:您可以通过将DigestInputStream包裹在FileInputStream周围,通读文件并从DigestInputStream获取计算得出的哈希值,而不是像代码中那样将数据从RandomAccessFile手动改组为MessageDigest,来大大简化实现。

我使用较旧的Java版本进行了一些性能测试,这里的Java 5和Java
6之间似乎存在相关差异。我不确定是否优化了SHA实施,或者VM是否以更快的速度执行代码。我使用不同的Java版本(1MB缓冲区)获得的吞吐量为:

  • Sun JDK 1.5.0_15(客户端):28MB / s,受CPU限制
  • Sun JDK 1.5.0_15(服务器):45MB / s,受CPU限制
  • Sun JDK 1.6.0_16(客户端):42MB / s,受CPU限制
  • Sun JDK 1.6.0_16(服务器):52MB / s,受磁盘I / O限制(85-90%CPU负载)

我对CryptoPP
SHA实现中的汇编程序部分的影响有些好奇,因为基准测试结果表明SHA-256算法在Opteron上仅需要15.8个CPU周期/字节。不幸的是,我无法在cygwin上用gcc构建CryptoPP(构建成功,但是生成的exe立即失败),但是在VS2005(默认发行版配置)下建立了性能基准,并在CryptoPP中支持汇编器和不使用汇编器,并与Java
SHA进行了比较。在内存缓冲区中实现,不考虑任何磁盘I / O,我在2.5GHz Phenom上获得以下结果:

  • Sun JDK1.6.0_13(服务器):26.2个周期/字节
  • CryptoPP(仅C ++):21.8个周期/字节
  • CryptoPP(汇编器):13.3周/字节

这两个基准测试都计算一个4GB空字节数组的SHA哈希,以1MB的块对其进行迭代,然后将其传递到MessageDigest#update(Java)或CryptoPP的SHA256.Update函数(C
++)。

我能够在运行Linux的虚拟机中使用gcc 4.4.1(-O3)构建和基准测试CryptoPP。与VS
exe的结果相比,吞吐量提高了一半。我不确定对虚拟机造成的差异有多少,以及由VS通常产生比gcc更好的代码所导致的差异,但是我现在无法从gcc获得任何更准确的结果。



 类似资料:
  • 我正在尝试使用亚马逊的弹性代码转换器。这里我需要sha-256散列一个字符串;http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html 我已经尝试了我在网上找到的任何方法,但我找不到与页面和一些在线哈希网站提供的相同的结果。 下面是要散列的字符串,您可以从上面的链接中找到; 以下是预期结果: 3

  • 问题内容: 我一直在使用CryptoJS(即)库在前端进行SHA-3哈希处理。(请参阅http://crypto- js.googlecode.com/svn/tags/3.1.2/build/rollups/sha3.js ) 我想知道是否有任何Java库等效项?但是到目前为止,我还没有找到任何东西。Java SHA-3示例也不是很多。 具有SHA-3,但在Eclipse下不可见。另外,我不确定

  • 2)获取第一部分的输出散列,将其与第二部分一起输入,并计算第二部分的散列 3)获得2)点的输出散列,将其与第三部分一起输入,并计算第三部分的散列 4)获得3)点的输出哈希值,将其与第四部分一起输入,并计算整个文件的哈希值。 我在google上搜索了很多,但没有找到类似的东西。我在MessageDigest中读到,通过使用方法update,我可以读取文件块,直到整个文件加载完毕,然后计算哈希值,但我

  • 问题内容: 我正在尝试在Android中获取字符串的SHA256。 这是我要匹配的PHP代码: 现在,在Java中,我正在尝试执行以下操作: 但这会打印出来:“ a42yzk3axdv3k4yh98g8” 我在这里做错了什么? 归功于erickson: 问题答案: PHP函数意味着它需要一个字节字符串并将其编码为十六进制数字。 在Java代码中,您尝试获取一堆随机字节,并使用平台的默认字符编码将它

  • 因此,我试图找出如何在ios上进行hmacshad256哈希,因为这是我为wcf服务api所做的哈希。我一直试图寻找一些关于它的信息,但通常只是最终得到一个SHA-256哈希。

  • 我已经在诺基亚开发者论坛上发布了这个问题,所以请原谅我。 我正在编写一个应用程序,它需要查找一个URL的SHA-256哈希,该URL以唯一的值键控,即。在Java ME/J2ME中最好的方法是什么?