Java - 哈希算法 - 最快的实现

时间:2011-03-26 23:21:02

标签: java hash md5 sha2

我想知道什么是Java的哈希算法的最佳和最快的实现,特别是MD5和SHA-2 512(SHA512)或256.我想要一个函数来获取字符串作为参数并返回哈希作为结果。亲爱的。

编辑:这是为了将每个URL映射到唯一的哈希。由于MD5在这个领域并不可靠,我更感兴趣的是找到最好的& SHA-2算法的最快实现。请注意,我知道即使SHA-2可能会为某些URL生成相同的哈希值,但我可以接受它。

6 个答案:

答案 0 :(得分:49)

首先要做的事:速度被高估了。在声明给定算法“太慢”之前,您应该采取措施。大多数情况下,哈希函数速度无论如何都没有明显的差异。如果您对安全性有疑虑,那么首先选择足够安全的哈希函数,然后只关心性能。

此外,您想要散列“字符串”。 Java String在内部是来自char值数组的块,表示Unicode代码点(实际上是使用UTF-16编码代码点的Unicode 16位代码单元)。散列函数将位或字节序列作为输入。因此,您必须进行转换步骤,例如str.getBytes("UTF-8"),将字符串作为一堆字节获取。与散列本身相比,转换步骤可能具有不可忽略的成本。

注意:注意URL编码!在URL中,某些字节可以替换为以“%”符号开头的序列;这是为了支持不可打印的字符,但也可以在“标准”字符上使用(例如,将“a”替换为“%61”)。这意味着两个不同的字符串(在String.equals()意义上)实际上可能代表相同的URL(就URL处理而言)。根据您的情况,这可能是也可能不是问题。

您应首先尝试将Java MessageDigest API与标准(已安装)JCE提供程序(即您调用MessageDigest.getInstance("SHA-256"))一起使用,并对结果进行评分。从理论上讲,JCE可以将调用映射到具有“本机”代码(用C或汇编语言编写)的实现,这将比使用Java获得的更快。

有人说......

sphlib是许多加密哈希函数的开源实现,在C和Java中。代码已针对速度进行了优化,实际上,Java版本比Sun / Oracle提供的标准JRE更快。如果上一个链接失败,请使用this link(主要主机服务器有时会停机进行维护,现在似乎就是这种情况)(警告:10 MB下载)。该档案还包含一份报告(在2010年的second SHA-3 candidate conference上提供),该报告在几个平台上提供了一些测量的性能数据,SHA-2和即将到来的SHA-3的14个“第二轮”候选人。 / p>

但你真的应该制定情况基准。例如,对L1缓存的影响会对性能产生严重影响,并且无法通过获取功能代码并单独运行来准确预测。

答案 1 :(得分:21)

编辑:我最初将这个问题视为“最快的哈希算法”,并且已经澄清为“每个算法的最快实现”。这是一个有效的问题,其他人已指出更快的实施。但是,除非你在很短的时间内散列大量数据,否则它根本不重要。我怀疑使用标准JCE提供的内容以外的其他东西通常是值得花时间和复杂性的。

对于URL地址,您需要在现代硬件上使用SHA-256进行散列,每秒百万以更快地需要更快的速度。我无法想象大多数应用程序每秒需要超过一千(每天超过8600万),这意味着用于散列的总CPU时间远远小于1%。因此,即使你有一个无限快速的哈希算法,你也只能将整体性能提高1%。

原始答案:获得最好和最快的两者是相互矛盾的。更好的哈希值通常较慢。如果真的需要速度和安全性并不是一个问题,那么使用MD5。如果您需要最好的安全性,那么请使用SHA-256甚至SHA-512。你没有提到你正在使用它的是什么,所以很难推荐其中一个。你可能最安全的使用SHA-256,因为无论如何它应该足够快速用于现代硬件上的大多数用例。这是你如何做到的:

String input = "your string";
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(input.getBytes("UTF-8"));
byte[] hash = digest.digest();

如果您出于安全目的使用它,例如散列密码,那么您也应该在摘要中添加salt。如果你想要一个可打印的字符串,你可以将它编码回十六进制字符串:

static char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();

StringBuilder sb = new StringBuilder(hash.length * 2);
for (byte b : hash) {
    sb.append(HEX_CHARS[(b & 0xF0) >> 4]);
    sb.append(HEX_CHARS[b & 0x0F]);
}
String hex = sb.toString();

答案 2 :(得分:2)

检查这些:Lots of SHA / MD5 examples

此外: From same thread: Fast MD5

String hash = MD5.asHex(MD5.getHash(new File(filename)));

答案 3 :(得分:2)

另一件需要考虑的事情是使用MD4。它不如MD5安全,但计算速度更快。 Windows XP最常用于在MD4中存储和交换密码,因此我们使用此哈希,因为它仍允许我们为此平台提供身份验证服务。

答案 4 :(得分:1)

考虑BLAKE2,它比上面提到的哈希更快,更安全。

MD5,SHA-1,SHA256和SHA-512易受长度扩展影响。

MD5和SHA-1容易受到冲突。

MD5容易受到选择前缀冲突的影响。

SHA-3和BLAKE2没有已知的安全问题,可以生成不同长度的摘要。

SHA-3在硬件中实现最快; BLAKE2在使用软件实现时速度最快。

BLAKE2b针对64位平台进行了优化,可生成1到64字节之间任意大小的摘要。

BLAKE2s针对8到32位平台进行了优化,可生成1到32个字节之间任意大小的摘要。

以下是AES,MD5,SHA-256和BLAKE2b的基准测试。

https://blake2.net/

https://www.cryptopp.com/benchmarks.html

在第一个链路中,BLAKE2b(947 Mbits)比SHA-256(413 Mbits)和MD5(632 Mbits)快得多。

在第二个链路中,AES-256 CBC(805 Mbits)和BLAKE2b(776 Mbits)的速度大致相同,比SHA-256(275 Mbits)和MD5(602)Mbits快。

答案 5 :(得分:0)

对于字符串,只需调用hashCode(),因为内存开销更便宜。

否则我推荐这段代码用于私有哈希:

public static int hash8(String val) throws UnsupportedEncodingException {
    return hash8(val.getBytes("UTF-8"));
}

public static int hash8(byte[] val) {
    int h = 1, i = 0;
    for (; i + 7 < val.length; i += 8) {
        h = 31 * 31 * 31 * 31 * 31 * 31 * 31 * 31 * h + 31 * 31 * 31 * 31
                * 31 * 31 * 31 * val[i] + 31 * 31 * 31 * 31 * 31 * 31
                * val[i + 1] + 31 * 31 * 31 * 31 * 31 * val[i + 2] + 31
                * 31 * 31 * 31 * val[i + 3] + 31 * 31 * 31 * val[i + 4]
                + 31 * 31 * val[i + 5] + 31 * val[i + 6] + val[i + 7];
    }
    for (; i + 3 < val.length; i += 4) {
        h = 31 * 31 * 31 * 31 * h + 31 * 31 * 31 * val[i] + 31 * 31
                * val[i + 1] + 31 * val[i + 2] + val[i + 3];
    }
    for (; i < val.length; i++) {
        h = 31 * h + val[i];
    }
    return h;
}

供参考: http://lemire.me/blog/2015/10/22/faster-hashing-without-effort/