我有一个解决方案。我不知道为什么会这样,但确实如此... javacard 上的签名函数应该如下所示:
byte[] buffer = apdu.getBuffer();
signature.init(ecPrivateKey, Signature.MODE_SIGN);
short sLen = signature.sign(helloWorld, (short) 0, (short)helloWorld.length, scratch, (short) 0);
if((short)scratch[4] < 0 || (short)scratch[30] < 0)
{
sign(apdu);
}
else
{
Util.arrayCopyNonAtomic(scratch, (short)0, buffer, (short)0, (short) sLen);
apdu.setOutgoingAndSend((short)0, (short)sLen);
}
是一个“原型”函数。它有效,所以我先分享它,稍后也许我会改进它。 scratch 是在其他地方声明的字节数组。
就像 VOJTA 之前发布的那样,签名(在我的示例中)看起来像这样:
30 34 02 18 [24 字节 NO1] 02 18 [24 字节 NO2] [SW - 90 00]
不需要软件。所以[24 bytes NO1]的第一个字节的SHORT值和[24 bytes NO2]的第一个字节的SHORT值不能为负数。我不知道为什么会这样。我打印了已验证和未验证的签名,我正在寻找任何差异,我发现了这一点。我进行了 1000 多次尝试,验证始终返回 TRUE。这 2 个字节为负数的概率是 1/4((-128,127),0 变为正数,半负数,半正数 -> 1/2 * 1/2 = 1/4)所以可能这就是为什么前面只有 1对 3,66 个签名进行了验证。如果有人知道它为什么起作用,我会很高兴阅读他的帖子
编辑
现在我知道它是如何工作的了。这个问题有解决办法。一种是上面的解决方案——生成签名直到数组的 2 个元素的 SHORT 值为正数,第二种解决方案:
签名看起来像这样:
30 34 02 18 [24 字节 NO1] 02 18 [24 字节 NO2]
现在是 VOJTA 所写的算法(如果需要,粗体值将被更改)
lex x=34(符号的第二个字节——这可能会有所不同,在我的签名中是 34)。
如果 [24 byte NO1] 和 [24 byte NO2] 的第一个字节是肯定的,则对签名不做任何事情。
如果 [24 bytes NO1] 的第一个字节的 SHORT 值为负,那么我们必须将 ONE 添加到 X(现在 x=35),将 ONE 添加到 [24 bytes NO1] 的第一个字节旁边的 18 并插入一个签名的 18(现在是 19)旁边的值 00。如果 [24 bytes NO2] 的第一个字节的 SHORT 值为负,那么我们必须将 ONE 添加到 X(现在 x=36),将 ONE 添加到 [24 bytes NO2] 的第一个字节旁边的 18 并插入 00在 18 岁(现在是 19 岁)旁边。如果两个第一个字节都是负数,那么签名应该是这样的:
30 36 02 19 00 [24 字节 NO1] 02 19 00 [24 字节 NO2]
如果只有 [24 bytes NO1] 的第一个字节为负,而 [24 bytes NO2] 的第一个字节为正,则签名应该看起来像这样
30 35 02 19 00 [24 字节 NO1] 02 18 [24 字节 NO2]
最后一种情况:
如果只有 [24 bytes NO1] 的第一个字节为正,而 [24 bytes NO2] 的第一个字节为负,则签名应该看起来像这样
30 35 02 18 [24 字节 NO1] 02 19 00 [24 字节 NO2]
希望对你有用