问题是关于在Java中创建哈希的正确方法:
让我们假设我有一个正BigInteger
值,我想创建一个哈希值。让我们假设下面messageDigest
的实例是(SHA-256)
public static final BigInteger B = new BigInteger("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC996C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAEEB4012B7D7665238A8E3FB004B117B58", 16);
byte[] byteArrayBBigInt = B.toByteArray();
this.printArray(byteArrayBBigInt);
messageDigest.reset();
messageDigest.update(byteArrayBBigInt);
byte[] outputBBigInt = messageDigest.digest();
现在我只假设下面的代码是正确的,因为根据测试,我生成的哈希值与下面的代码匹配:
但是我不确定为什么我们这样做,即 因为在digest()调用之后返回的字节数组是有符号的,在这种情况下它是负数,我怀疑我们确实需要将它转换为正数,即我们可以使用这样的函数。
public static String byteArrayToHexString(byte[] b) {
String result = "";
for (int i=0; i < b.length; i++) {
result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
}
return result;
}
因此:
String hex = byteArrayToHexString(outputBBigInt)
BigInteger unsignedBigInteger = new BigInteger(hex, 16);
当我从新的十六进制字符串构造BigInteger
并将其转换回字节数组时,我看到符号位,即最高位,即最左边的位,设置为0,这意味着number为正,而且整个字节由零(00000000)构成。
我的问题是:是否有任何RFC描述我们为什么需要将哈希始终转换为“正”无符号字节数组。我的意思是即使摘要调用后生成的数字是负数,它仍然是一个有效的散列,对吧?那么为什么我们需要这个额外的程序。基本上,我正在寻找一篇论文:标准或rfc描述我们需要这样做。
答案 0 :(得分:1)
哈希由八位字符串组成(在Java中称为字节数组)。如何将其转换为大数(或Java中的BigInteger
),这完全超出了加密哈希算法的范围。所以不,没有RFC来描述它,因为(通常)没有理由将哈希视为数字。从这个意义上讲,加密哈希与Object.hashCode()
非常不同。
你只能将十六进制视为无符号是一个问题,但是如果你真的想要那么你可以先将它转换回一个字节数组,然后执行new BigInteger(result)
。该构造函数会对结果中的编码进行威胁威胁。请注意,在协议中,通常不需要来回转换为十六进制;十六进制主要供人类使用,计算机可以使用字节。