1

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

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 生成一个简单的 SHA-256 哈希MessageDigest,然后将其截断为所需的长度。

我做错了什么还是我误解了这些海绵功能的意义?

带有单元测试的完整代码可在以下位置获得:https ://github.com/steinsag/java-dynamic-hash

4

1 回答 1

2

Nit:SHAKen 实际上是在 Keccak 海绵上构建的可扩展输出函数 (XOF) ,其方式与(固定长度)SHA3 哈希相同;请参阅https://en.wikipedia.org/wiki/SHA-3#Instances

但是您似乎误解的一点是,底层海绵使每个/所有这些都是确定性的——给定的实例(参数化)每次针对相同的输入产生相同的输出,并且不受输出大小本身的影响。因此 SHA3-256(m) 不是 SHA3-512(m) 的前 256 位,因为它具有不同的参数,而 SHAKE128(m,256)SHAKE128(m,512) 的前 256 位但不是SHAKE256(米,256)。

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

于 2021-06-01T18:12:18.557 回答