Java';SHA-256有时返回255位

Java';SHA-256有时返回255位,java,hash,biginteger,sha,Java,Hash,Biginteger,Sha,当我使用Java的MessageDigest计算BigInteger的SHA-256散列时,我遇到了一些奇怪的行为。看起来哈希值有时有256位,但有时只有255位。这是我用来测试BigInteger哈希的代码: @Test public void testSHA256LengthConsistent() { MessageDigest sha256 = null; try { sha256 = MessageDigest.getInstance("SHA-256"

当我使用Java的
MessageDigest
计算
BigInteger
的SHA-256散列时,我遇到了一些奇怪的行为。看起来哈希值有时有256位,但有时只有255位。这是我用来测试BigInteger哈希的代码:

@Test
public void testSHA256LengthConsistent() {
    MessageDigest sha256 = null;
    try {
        sha256 = MessageDigest.getInstance("SHA-256");
    } catch (NoSuchAlgorithmException e) {
        Assert.fail("NoSuchAlgorithmException. Can't construct the MessageDigest.");
    }
    BigInteger[] tests = {new BigInteger("15902493"), new BigInteger("5189087324092341824"), new BigInteger("7153293421609183203421127438153268")};
    for(BigInteger testNum : tests) {
        byte[] hash = sha256.digest(testNum.toByteArray());
        Assert.assertEquals(32, hash.length); //256 bits is 32 bytes
        BigInteger hashedInt = new BigInteger(1, hash);
        Assert.assertEquals(256, hashedInt.bitLength());
    }
}
(是的,我正在使用JUnit4)。此测试在第三个测试编号上失败,其中第二个断言以“预期为256,但为255”失败

我将大整数转换成字节数组和从字节数组转换成大整数的方式是否有问题?我能找到的所有关于Java的MessageDigest的示例都使用它来散列字符串,而不是大整数,所以我不知道是否有一种“标准”的方法可以将大整数与MessageDigest一起使用。或者,这是Java执行SHA-256的方式中的一个bug还是边缘情况,并且7153293421609183203421127438153268(我随机生成的一个数字)会导致散列中的off-by-one错误


顺便说一句,我已经尝试过将散列转换为负的BigInteger(使用
new BigInteger(-1,hash)
),以查看是否符号位有问题,但我得到了完全相同的结果

忽略前导零

byte[] bytes = {0x0, 0x1};
System.out.println(new BigInteger(1, bytes).bitLength());
印刷品

1
不像你想象的那样16岁


我应该读一下Javadoc,因为它在

此BigInteger的最小补码表示中的位数,不包括符号位


忽略前导零

byte[] bytes = {0x0, 0x1};
System.out.println(new BigInteger(1, bytes).bitLength());
印刷品

1
不像你想象的那样16岁


我应该读一下Javadoc,因为它在

此BigInteger的最小补码表示中的位数,不包括符号位


如果要运行足够数量的随机测试,您会看到大约一半的结果是256位长、四分之一的255位长、八分之一的254位长等。原因是散列的每个位实际上都是随机的,因此高阶位(或者,更准确地说,您想要查看的任何其他特定位)是1,50%是0,25%的概率是两个高阶位(或者您想要查看的任何其他两个特定位)是00(或者您想要测试的任何其他值),依此类推

 public static void main(final String[] args) throws Exception {
    final Random random = new Random();
    final int[] bits = new int[257];
    for (int i = 0; i < 10000; i++) {
        final MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
        final BigInteger testNum = new BigInteger(100, random);
        final byte[] hash = sha256.digest(testNum.toByteArray());
        final BigInteger hashedInt = new BigInteger(1, hash);
        bits[hashedInt.bitLength()]++;
    }

    for (int i = 0; i < bits.length; i++) {
        if (bits[i] > 0) {
            System.out.println(i + " / " + bits[i]);
        }
    }        
}
publicstaticvoidmain(最终字符串[]args)引发异常{
最终随机数=新随机数();
最终整数[]位=新整数[257];
对于(int i=0;i<10000;i++){
final MessageDigest sha256=MessageDigest.getInstance(“SHA-256”);
final BigInteger testNum=新的BigInteger(100,随机);
最后一个字节[]hash=sha256.digest(testNum.toByteArray());
final BigInteger hashedit=新的BigInteger(1,散列);
位[hashedInt.bitLength()]+;
}
for(int i=0;i0){
系统输出println(i+“/”+位[i]);
}
}        
}
制作:

比特数:244计数:2 0.02% 比特数:245计数:3 0.03% 比特数:246计数:4 0.04% 比特数:247计数:7 0.07% 比特数:248计数:20 0.2% 比特数:249计数:33 0.33% 位数:250计数:70 0.7% 位数:251计数:168 1.68% 位数:252计数:296 2.96% 比特数:253计数:6576.57% 位数:254计数:123812.38% 位数:255计数:2510 25.1%
位:256 Count:4992 49.92%

如果要运行足够数量的随机测试,您会看到大约一半的结果是256位长、四分之一的255位长、八分之一的254位长等。原因是散列的每个位实际上是随机的,因此高阶位有50%的概率(或者,更准确地说,您想要查看的任何其他特定位)是1,50%是0,25%的概率是两个高阶位(或者您想要查看的任何其他两个特定位)是00(或者您想要测试的任何其他值),依此类推

 public static void main(final String[] args) throws Exception {
    final Random random = new Random();
    final int[] bits = new int[257];
    for (int i = 0; i < 10000; i++) {
        final MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
        final BigInteger testNum = new BigInteger(100, random);
        final byte[] hash = sha256.digest(testNum.toByteArray());
        final BigInteger hashedInt = new BigInteger(1, hash);
        bits[hashedInt.bitLength()]++;
    }

    for (int i = 0; i < bits.length; i++) {
        if (bits[i] > 0) {
            System.out.println(i + " / " + bits[i]);
        }
    }        
}
publicstaticvoidmain(最终字符串[]args)引发异常{
最终随机数=新随机数();
最终整数[]位=新整数[257];
对于(int i=0;i<10000;i++){
final MessageDigest sha256=MessageDigest.getInstance(“SHA-256”);
final BigInteger testNum=新的BigInteger(100,随机);
最后一个字节[]hash=sha256.digest(testNum.toByteArray());
final BigInteger hashedit=新的BigInteger(1,散列);
位[hashedInt.bitLength()]+;
}
for(int i=0;i0){
系统输出println(i+“/”+位[i]);
}
}        
}
制作:

比特数:244计数:2 0.02% 比特数:245计数:3 0.03% 比特数:246计数:4 0.04% 比特数:247计数:7 0.07% 比特数:248计数:20 0.2% 比特数:249计数:33 0.33% 位数:250计数:70 0.7% 位数:251计数:168 1.68% 位数:252计数:296 2.96% 比特数:253计数:6576.57% 位数:254计数:123812.38% 位数:255计数:2510 25.1%
位:256计数:4992 49.92%

如果顶部位是0,它仍然计数吗?您是否尝试打印有问题的哈希以查看是否提供了任何细节?@NullUserException是的,但我看不到任何差异。这是我得到的:
5189087324092341824的哈希是10949622034786168613655900561035489570474747444851370767764711534787201110;256位
7153293421609183203421127438153268的哈希值是3946906047895465475068776231416937199935884942218059502044137508701079982846;255位
如果顶部位是0,它仍然被计算吗?您是否尝试打印有问题的哈希值以查看是否提供任何细节?@NullUserException是的,但我看不到任何区别。这s是我得到的:
5189087324092341824的散列是109496220347861686136559005610354895701474744851370567677647115347473787201110;256位
7153293421609183203421127438153268的散列是39469060478954654750687262316937199935894221805950445041375041378787846;255位是的,我建议删除此测试。不要测试如果你不相信哈希算法能给你正确的位数,你怎么能