Java 中的 SHA-256 和 SHA3-256 哈希算法

289 阅读4分钟

1. 概述

SHA(安全哈希算法)是一种流行的加密哈希函数。加密哈希可用于为文本或数据文件制作签名。

在本教程中,让我们了解如何使用各种 Java 库执行 SHA-256 和 SHA3-256 哈希操作。

SHA-256算法会生成几乎独一无二的固定大小 256 位(32 字节)哈希值。这是一个单向函数,因此无法将结果解密回原始值。

目前,SHA-2 哈希算法被广泛使用,因为它被认为是加密领域最安全的哈希算法。

SHA-3是继 SHA-2 之后的最新安全哈希标准。与 SHA-2 相比,SHA-3 提供了一种不同的方法来生成唯一的单向哈希,并且在某些硬件实现上可以更快。与 SHA-256 类似,SHA3-256 是 SHA-3 中的 256 位固定长度算法。

NIST于 2015 年发布了 SHA-3,因此目前 SHA-3 库的数量不如 SHA-2 多。直到 JDK 9,内置默认提供程序中才提供 SHA-3 算法。

现在让我们从 SHA-256 开始。

进一步阅读:

使用 Java-LSH 在 Java 中进行局部敏感哈希处理

使用 java-lsh 库在 Java 中应用局部敏感哈希算法的快速实用指南。

阅读更多

Java 中的 MD5 哈希算法

快速书写向您展示如何在 Java 中处理 MD5 散列。

阅读更多

Java 中的 HashSet 指南

快速但全面地介绍 Java 中的 HashSet。

阅读更多

2. Java中的MessageDigest类

Java为 SHA-256 哈希算法提供了内置的MessageDigest类:

MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] encodedhash = digest.digest(
  originalString.getBytes(StandardCharsets.UTF_8));

但是,这里我们必须使用自定义的字节到十六进制转换器来获取十六进制的哈希值:

private static String bytesToHex(byte[] hash) {
    StringBuilder hexString = new StringBuilder(2 * hash.length);
    for (int i = 0; i < hash.length; i++) {
        String hex = Integer.toHexString(0xff & hash[i]);
        if(hex.length() == 1) {
            hexString.append('0');
        }
        hexString.append(hex);
    }
    return hexString.toString();
}

我们需要注意的是,MessageDigest 不是线程安全的。 因此,我们应该为每个线程使用一个新实例。

3. Guava 库

Google Guava 库还提供了用于散列的实用程序类。

首先,让我们定义依赖关系:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>32.1.3-jre</version>
</dependency>

接下来,我们来看看如何使用 Guava 对字符串进行哈希处理:

String sha256hex = Hashing.sha256()
  .hashString(originalString, StandardCharsets.UTF_8)
  .toString();

4. Apache Commons 编解码器

类似地,我们也可以使用Apache Commons Codecs:

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.16.0</version>
</dependency>

以下是支持 SHA-256 哈希算法的实用程序类 - DigestUtils :

String sha256hex = DigestUtils.sha256Hex(originalString);

5. Bouncy Castle库

5.1. Maven 依赖

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk18on</artifactId>
    <version>1.76</version>
</dependency>

5.2. 使用 Bouncy Castle 库进行哈希处理

Bouncy Castle API 提供了一个实用程序类,用于将十六进制数据转换为字节并转回。

但是,我们需要首先使用内置的 Java API 来填充摘要:

MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(
  originalString.getBytes(StandardCharsets.UTF_8));
String sha256hex = new String(Hex.encode(hash));

6. SHA3-256

现在让我们继续讨论 SHA3-256。Java 中的 SHA3-256 哈希与 SHA-256 并没有什么不同。

6.1. Java 中的MessageDigest类

从 JDK 9 开始,我们可以简单地使用内置的 SHA3-256 算法:

final MessageDigest digest = MessageDigest.getInstance("SHA3-256");
final byte[] hashbytes = digest.digest(
  originalString.getBytes(StandardCharsets.UTF_8));
String sha3Hex = bytesToHex(hashbytes);

6.2. Apache 通用编解码器

Apache Commons Codecs为MessageDigest类提供了一个方便的 DigestUtils包装器。**

该库从1.11版本开始支持 SHA3-256 ,并且也需要 JDK 9+ :

String sha3Hex = new DigestUtils("SHA3-256").digestAsHex(originalString);

6.3. Keccak-256

Keccak-256 是另一种流行的 SHA3-256 哈希算法。目前,它是标准 SHA3-256 的替代方案。Keccak-256 提供与标准 SHA3-256 相同的安全级别,并且仅在填充规则上与 SHA3-256 不同。它已在多个区块链项目中使用,例如Monero

再次,我们需要导入 Bouncy Castle 库来使用 Keccak-256 哈希:

Security.addProvider(new BouncyCastleProvider());
final MessageDigest digest = MessageDigest.getInstance("Keccak-256");
final byte[] encodedhash = digest.digest(
  originalString.getBytes(StandardCharsets.UTF_8));
String sha3Hex = bytesToHex(encodedhash);

我们还可以利用 Bouncy Castle API 来进行散列:

Keccak.Digest256 digest256 = new Keccak.Digest256();
byte[] hashbytes = digest256.digest(
  originalString.getBytes(StandardCharsets.UTF_8));
String sha3Hex = new String(Hex.encode(hashbytes));

7. 结论

在这篇简短的文章中,我们研究了在 Java 中实现 SHA-256 和 SHA3-256 散列的几种方法,包括使用内置库和第三方库。