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

2022-09-01 05:46:33

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

编辑:这是为了获取每个URL映射到唯一的哈希。由于MD5在这方面并不那么可靠,我更感兴趣的是找到SHA-2算法的最佳和最快的实现。请注意,我知道即使SHA-2也可能为某些URL产生相同的哈希值,但我可以忍受这一点。


答案 1

首先:速度被高估了。您应该在声明给定算法“太慢”之前进行度量。大多数时候,哈希函数速度无论如何都没有明显的区别。如果您对安全性有疑问,请首先选择足够安全的哈希函数,然后只担心性能。

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

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

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

话虽如此...

sphlib是许多加密哈希函数的开源实现,在C和Java中。该代码已针对速度进行了优化,在实践中,Java版本比Sun / Oracle提供的标准JRE版本更快。使用此链接以防上一个链接失败(主主机服务器有时会因维护而关闭,就像现在的情况一样)(警告:10 MB下载)。该档案还包含一份报告(在2010年第二届SHA-3候选人会议上发表),该报告提供了几个平台上的一些衡量绩效数据,包括SHA-2和即将到来的SHA-3的14个“第二轮”候选人。

但你真的应该做情境基准。例如,对 L1 缓存的影响可能会对性能产生巨大影响,并且无法通过获取函数代码并单独运行它来准确预测。


答案 2

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

对于URL地址,您需要在现代硬件上使用SHA-256每秒超过100万次进行哈希处理,以需要更快的速度。我无法想象大多数应用程序每秒需要超过一千(每天超过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();

如果您出于安全目的使用它,例如散列密码,那么您也应该在摘要中添加盐。如果要从哈希中取出可打印的字符串,可以将其编码回字符串为十六进制:

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();

推荐