Java的SHA-256有时会返回255位

时间:2012-10-16 22:05:39

标签: 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");
    } 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());
    }
}

(是的,我正在使用JUnit 4)。此测试在第三个测试编号上失败,其中第二个断言失败并显示“预期256但是为255”。

我将BigIntegers转换为字节数组的方式有什么问题吗?我可以为Java的MessageDigest找到的所有示例都使用它来散列字符串,而不是BigIntegers,所以我不知道是否有一种“标准”方式将BigIntegers与MessageDigest一起使用。或者,这是Java执行SHA-256的方式的错误或边缘情况,并且有一些东西与7153293421609183203421127438153268(我随机生成的数字)导致散列中的一个一个错误?

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

2 个答案:

答案 0 :(得分:7)

忽略前导零

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

打印

1

不像你期望的那样16岁。


我应该阅读Javadoc,因为它在BigInteger.bitLength()

中说明
  

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

答案 1 :(得分:0)

如果你要运行足够数量的随机测试,你会看到大约一半的结果是256位长,四分之一255位长,八位长254位长等等。原因是每个散列的位有效地是随机的,因此高位(或者,确切地说,您需要注意的任何其他特定位)为1和50%的概率为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]);
        }
    }        
}

制备:

位: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人数:657 6.57% 位:254数:1238 12.38% 比特:255数:2510 25.1% 位:256计数:4992 49.92%