我有两段代码使用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问题中链接),但我不认为我完全理解它;为什么这两种签名方法(逐字节与全部一次)会产生不同的签名?
答案 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;
}