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。
我需要根据 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。