SHA-3 可变长度哈希与使用 BouncyCastle 在 Java 中截断普通哈希相同

SHA-3 variable length hash same as truncating normal hash in Java using BouncyCastle

我需要根据 Java 中的一些输入数据(如客户电子邮件地址)生成 30 个字符的固定长度散列。经过一番搜索,我发现了 SHA-3 海绵函数,我可以在其中指定所需的长度。我使用 Bouncy Castle SHAKEDigest class.

实现了以下内容
public class App {
    public static void main(String[] args) {
        final String message = "Hello World!";
        System.out.println(getHash(message, 64));
        System.out.println(getHash(message, 30));
        System.out.println(getHash(message, 20));
    }

    static String getHash(final String message, final int lengthInCharacters) {
        final byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);

        final SHAKEDigest digest = new SHAKEDigest(128);

        final byte[] hashBytes = new byte[lengthInCharacters / 2];
        digest.update(messageBytes, 0, messageBytes.length);
        digest.doOutput(hashBytes, 0, hashBytes.length);

        return Hex.toHexString(hashBytes);
    }
}

如果我执行它,我会得到以下输出:

aacfe6ebd3737d9f195c837c5281d3f87646ecd7e43864e1a40456e40f264046
aacfe6ebd3737d9f195c837c5281d3
aacfe6ebd3737d9f195c

我预计哈希值会因请求的长度而完全不同。现在看来,我还可以使用 JDK MessageDigest 生成一个简单的 SHA-256 哈希,然后将其截断到所需的长度。

我是做错了什么还是误解了那些海绵函数的意义?

包含单元测试的完整代码位于:https://github.com/steinsag/java-dynamic-hash

尼特:SHAKEn 实际上是可扩展输出函数 (XOF) 建立在 Keccak 海绵上,其方式与(固定长度)SHA3 哈希相同;见 https://en.wikipedia.org/wiki/SHA-3#Instances .

但是您似乎误解了这一点,即底层海绵使 each/all 这些确定性——一个给定的实例(参数化)每次为相同的输入产生相同的输出,并且不受这样的输出大小。因此 SHA3-256(m) 不是 SHA3-512(m) 的前 256 位,因为它有不同的参数,而 SHAKE128(m,256) SHAKE128 的前 256 位(m,512) 但 不是 SHAKE256(m,256).

是的,您可以将任何 SHA3 散列(或 SHA2 散列)截断为小于其正常大小的大小,并获得更小但其他方面同样好的加密散列(伪随机、不可逆和非碰撞的真实数据),事实上,人们几十年来一直在这样做。但是你不能安全地增加它,你可以使用像 SHAKE 这样的 XOF。