Hashing Algorithm in Java

2025年5月10日 | 阅读 9 分钟

将数据映射到固定大小哈希的算法称为哈希算法。Java 中的哈希算法是一种加密哈希函数。哈希算法或哈希函数的设计方式使其表现得像一个单向函数。单向意味着无法进行逆运算,即无法从哈希值恢复原始值。

哈希算法的特性

一个好的哈希算法必须具备以下特性

  • 哈希算法必须足够快,能够哈希任何类型的数据。
  • 算法应避免从其生成的哈希值重新生成消息(单向)。
  • 在任何时候,两个消息都不得具有相同的哈希值。换句话说,哈希算法必须避免冲突。
  • 当消息发生任何微小变化时,消息的哈希值都必须改变。这称为雪崩效应。

哈希算法的特性

一个好的哈希算法必须具备以下特性

  • 哈希算法必须足够快,能够哈希任何数据。
  • 算法应避免从其生成的哈希值重新生成消息(单向)。
  • 在任何时候,两个消息都不得具有相同的哈希值。换句话说,哈希算法必须避免冲突。
  • 当消息发生任何微小变化时,消息的哈希值都必须改变。这称为雪崩效应

哈希算法的类型

以下是一些哈希算法的类型。

  1. MD5 算法
  2. SHA 算法
  3. PBKDF2WithHmacSHA1 算法

MD5 算法

消息摘要算法(MD5)是一种广泛使用的加密哈希函数,它生成一个 16 字节(128 位)的哈希值。它非常简单易懂。主要概念是将可变长度的数据集映射到固定长度的数据集。

为了实现这一点,输入消息被分成 512 位块。在末尾添加填充,使其大小可被 512 整除。然后,使用 MD5 算法处理这些块,该算法在 128 位状态下运行,结果是 128 位哈希值。应用 MD5 算法后,生成的哈希通常是一个 32 位的十六进制数字。在这里,要编码的字符串通常称为“消息”,哈希后生成的哈希值称为“摘要”或“消息摘要”。

文件名:MD5.java

输出

The HashCode Generated for 'JavaTpoint' is: 9e0a53565bd3ad4997fe16d35e085ffc

MD5 算法的异常

MD5 算法是一种流行的哈希算法。因为它生成哈希值速度快且易于实现。然而,该算法存在安全问题。该算法生成的哈希值相当弱。此外,该算法容易发生冲突。因此,两个不同的密码很可能生成相同的哈希值。

为了使 MD5 算法更安全,建议使用盐(salt)。

带盐的 MD5 算法

盐使 MD5 算法更强大、更安全。盐就是一些随机生成的文本,在字符串被 MD5 算法处理之前添加到字符串中。请注意,盐并不是 MD5 算法特有的。它也可以应用于其他哈希算法。以下示例显示了 MD5 算法中盐的使用。

文件名:MD5SaltedExample.java

输出

The HashCode Generated for JavaTpoint is: 3bd3b836b49f0b0b0b3bfd137768b6de
The HashCode Generated for JavaTpoint is: 3bd3b836b49f0b0b0b3bfd137768b6de

注意:需要为每个哈希的密码保留盐值。因为当用户再次登录系统时,用户必须使用原始盐,这样创建的哈希才能与存储的哈希匹配。如果用户不使用原始盐,则生成的哈希将不匹配存储的哈希,并且可能会出现登录问题。

SHA 算法

安全哈希算法(SHA)是加密哈希函数的成员。该算法与 MD5 算法类似。然而,与 MD5 算法不同,SHA 算法生成的哈希值更强。有时,SHA 算法生成的哈希值不总是唯一的,这意味着存在冲突的可能性。但是,SHA 中的冲突比 MD5 少得多。在 Java 中,有四种 SHA 算法的实现。

  1. SHA-1 - 这是最简单的 SHA。它生成 20 字节或 160 位。
  2. SHA-256 - 它比 SHA-1 更安全。它生成一个包含 256 位的哈希。
  3. SHA-384 - SHA-384 比 SHA-256 高一个级别,并生成一个 384 位的哈希。
  4. SHA-512 - 它是所有提到的 SHA 中最强的。它生成一个 512 位的哈希。

因此,我们看到哈希的大小越大,哈希就越强。这意味着不容易破解大尺寸的哈希。

以下示例显示了 SHA-256 的实现。

文件名:SHAExample.java

输出

The HashCode produced by SHA-256 algorithm for strings: 

JavaTpoint : f9142e5ca706378c1c7f9daf6782dcff8197ef1ecfd4075b63dae2f40186afa6

India is a great country. : e28335e1124e47ebf4c0b6cb87a34737b70d539241641c60c1969602a7b46cf9

注意:要使用其他 SHA 实现生成哈希,可以在上述代码中进行少量修改。

MessageDigest msgDgst = MessageDigest.getInstance("SHA-1"); // for SHA -1

MessageDigest msgDgst = MessageDigest.getInstance("SHA-384"); // for SHA -384

MessageDigest msgDgst = MessageDigest.getInstance("SHA-512"); // for SHA -512

PBKDF2WithHmacSHA1 算法

我们已经学习了如何生成安全的哈希,甚至如何通过盐来提高其安全性。如今,硬件的速度比任何密码破解速度都快,即使使用暴力攻击,也可能在短时间内被破解。

为了解决这个问题,一个常见的概念是确保暴力攻击更慢,这样可以最大限度地减少损害。PBKDF2WithHmacSHA1 算法就是基于这个概念工作的。目的是使哈希方法足够慢,以延迟攻击。然而,同时它必须足够快,以便不会给用户生成哈希带来显著延迟。该算法有一个安全因子(也称为工作因子)或迭代计数作为其参数。工作计数决定了哈希函数的慢速程度。硬件效率越高,迭代计数或工作因子的值就应该越高。

文件名:SHAExample.java

输出

500: d38932f8037b1a2740aad31de8765b25:c6c9c5005e0e421f47cd862bc612e9061fe7a393923af3a9984e8f5d8d4141113f8b8969f17f81bb1f47c81dbb100a071ce3218e509dc2b9371148fee0da7765

哈希的应用

  • 查找重复项:哈希的基本规则是相同的输入生成相同的哈希。因此,如果两个哈希相同,则意味着输入也相同(假设哈希方法是抗冲突的)。
  • 消息摘要:消息摘要用于保护数据。例如,如果我们把文件存储在云端,我们还需要确保存储的文件没有被别人篡改。为此,找到存储在云端的文件使用哈希算法生成的哈希值,并保存它。当文件再次从云端下载时,再次计算其哈希值。如果生成的哈希值与之前保存的哈希值匹配,则文件未被篡改。
  • 编译器操作:关键字(while、for、int、if、else、switch 等)的处理方式与其他标识符不同。编译器通过将这些关键字存储在集合(set)中来区分其他标识符和关键字。集合是通过哈希表实现的。
  • 数据结构:哈希表在数据结构中得到广泛应用。几乎所有支持键值对的数据结构都使用哈希表。例如,Java 中的 HashMap 和 HashSet,C++ 中的 map 和 unordered_map 都使用哈希表。

注意:哈希表使用哈希函数来存储键值对。