为什么 SHA256withRSA 签名在逐字节计算和一次计算时不同?
Why is SHA256withRSA Signature Different when Computed Byte-by-Byte versus All at Once?
我有两段代码使用 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 问题中找到链接),但我不认为我会完全理解它;为什么这两种签名方法(逐字节签名与一次全部签名)会产生不同的签名?
您没有说明您的 SigningInputStream
是如何使用的。因此,让我们假设它在没有任何重置的情况下被完全读取,例如像这样:
SigningInputStream sigIS = new SigningInputStream(...);
while (sigIS.read() != -1);
在这种情况下,上面的循环已经暗示了问题:如果因为已经到达流的末尾而没有可用字节,read
returns 值 -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;
}
我有两段代码使用 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 问题中找到链接),但我不认为我会完全理解它;为什么这两种签名方法(逐字节签名与一次全部签名)会产生不同的签名?
您没有说明您的 SigningInputStream
是如何使用的。因此,让我们假设它在没有任何重置的情况下被完全读取,例如像这样:
SigningInputStream sigIS = new SigningInputStream(...);
while (sigIS.read() != -1);
在这种情况下,上面的循环已经暗示了问题:如果因为已经到达流的末尾而没有可用字节,read
returns 值 -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;
}