什么是较便宜的哈希算法?

时间:2013-10-03 10:51:02

标签: java encryption hash

我对哈希算法知之甚少。

我需要在将文件转发到远程系统(有点像S3)之前计算Java中的传入文件的哈希值,这需要MD2 / MD5 / SHA-X中的文件哈希。 出于安全原因,不会计算此哈希,而只是为了一致性校验和。

我可以使用Java标准库的DigestInputStream在转发文件时实时计算此哈希,但是想知道哪种算法最好用来避免使用DigestInputStream的性能问题?

我的一位前同事测试并告诉我们,与unix命令行或文件相比,计算hash实时可能非常昂贵。


编辑过早优化: 我在一家公司工作,目的是帮助其他公司取消他们的文件。 这意味着我们有一个处理来自其他公司的文件传输的批次。我们将来每天定位数百万份文档,实际上,此批次的执行时间对我们的业务非常敏感。

每天100万份文档的散列优化10毫秒是每天执行时间减少3小时,这是非常巨大的。

3 个答案:

答案 0 :(得分:5)

如果您只是想在传输过程中检测意外损坏等,那么一个简单的(非加密)校验和应该就足够了。但请注意(例如)16位校验和将无法在2 16 中检测到一次随机损坏。而且无法防止有人故意修改数据。

Checksums上的维基百科页面列出了各种选项,包括Adler-32和CRC等常用(和便宜)的选项。

但是,我同意@ppeterka。这有点“过早优化”。

答案 1 :(得分:1)

我知道很多人不相信微基准,但让我发布我得到的结果。

输入:

bigFile.txt = appx 143MB size

hashAlgorithm = MD2, MD5, SHA-1

测试代码:

       while (true){
            long l = System.currentTimeMillis();
            MessageDigest md = MessageDigest.getInstance(hashAlgorithm);
            try (InputStream is = new BufferedInputStream(Files.newInputStream(Paths.get("bigFile.txt")))) {
                DigestInputStream dis = new DigestInputStream(is, md);
                int b;
                while ((b = dis.read()) != -1){
                }
            }
            byte[] digest = md.digest();
            System.out.println(System.currentTimeMillis() - l);
        }

结果:

MD5
------
22030
10356
9434
9310
11332
9976
9575
16076
-----

SHA-1
-----
18379
10139
10049
10071
10894
10635
11346
10342
10117
9930
-----

MD2
-----
45290
34232
34601
34319
-----

似乎MD2慢了MD5SHA-1

答案 2 :(得分:0)

像NKukhar一样,我试图做一个微基准测试,但代码不同,效果更好:

public static void main(String[] args) throws Exception {
    String bigFile = "100mbfile";


    // We put the file bytes in memory, we don't want to mesure the time it takes to read from the disk
    byte[] bigArray = IOUtils.toByteArray(Files.newInputStream(Paths.get(bigFile)));
    byte[] buffer = new byte[50_000]; // the byte buffer we will use to consume the stream

    // we prepare the algos to test
    Set<String> algos = ImmutableSet.of(
            "no_hash", // no hashing
            MessageDigestAlgorithms.MD5,
            MessageDigestAlgorithms.SHA_1,
            MessageDigestAlgorithms.SHA_256,
            MessageDigestAlgorithms.SHA_384,
            MessageDigestAlgorithms.SHA_512
    );

    int executionNumber = 20;

    for ( String algo : algos ) {
      long totalExecutionDuration = 0;
      for ( int i = 0 ; i < 20 ; i++ ) {
        long beforeTime = System.currentTimeMillis();
        InputStream is = new ByteArrayInputStream(bigArray);
        if ( !"no_hash".equals(algo) ) {
          is = new DigestInputStream(is, MessageDigest.getInstance(algo));
        }
        while ((is.read(buffer)) != -1) {  }
        long executionDuration = System.currentTimeMillis() - beforeTime;
        totalExecutionDuration += executionDuration;
      }
      System.out.println(algo + " -> average of " + totalExecutionDuration/executionNumber + " millies per execution");
    }
  }

这会在一台优秀的i7开发者机器上为100mb文件生成以下输出:

no_hash -> average of 6 millies per execution
MD5 -> average of 201 millies per execution
SHA-1 -> average of 335 millies per execution
SHA-256 -> average of 576 millies per execution
SHA-384 -> average of 481 millies per execution
SHA-512 -> average of 464 millies per execution