为什么SHA256withRSA签名在按字节计算时与一次性计算时不同?

时间:2015-10-21 23:10:13

标签: java inputstream digital-signature

我有两段代码使用Java" SHA256withRSA" Signature。一种方法是InputStream装饰器,它通过read()方法逐字节地更新签名:

public class SigningInputStream extends InputStream {
    // Removed for brevity: declaration of useful objects

    @Override
    public int read() throws IOException {
        final int nextByte = source.read();
        try {
            sign.update((byte) nextByte);
        } catch (java.security.SignatureException e) {
            throw new IOException("Unknown exception while signing file", e);
        }

        return nextByte;
    }

    // Removed for brevity 
}

另一个一次生成签名:

Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(privateKey);

sign.update(contents);
byte[] signature = sign.sign();
return Base64.getEncoder().encodeToString(signature);

这两种方法给我不同的结果。我仍在阅读spec(我发现从另一个SO问题中链接),但我不认为我完全理解它;为什么这两种签名方法(逐字节与全部一次)会产生不同的签名?

1 个答案:

答案 0 :(得分:1)

您没有展示如何使用SigningInputStream。因此,让我们假设它完全被读取而没有任何重置,例如像这样:

SigningInputStream sigIS = new SigningInputStream(...);
while (sigIS.read() != -1);

在这种情况下,上面的循环已经暗示了问题:如果因为到达流末尾没有可用的字节,read将返回值-1

因此,如果您的final int nextByte = source.read()-1,则必须忽略此值,因为它不属于流内容的一部分:

public int read() throws IOException
{
    final int nextByte = source.read();
    if (nextByte != -1)
    [
        try {
            sign.update((byte) nextByte);
        } catch (java.security.SignatureException e) {
            throw new IOException("Unknown exception while signing file", e);
        }
    }

    return nextByte;
}