我的问题看起来像这样:我在javaCard上生成一个签名(jcdk 2.2.2),当我想在终端上使用BouncyCastle验证它时,签名并不总是被验证 - 3,66中的1(100次尝试中的平均值) )签名被验证,其余的返回false。当我验证卡上的签名时,它总是返回true,但是在终端上它通常返回false,但有时是真的。因为终端有时给出一个肯定的答案我认为代码是好的,原因是其他地方,但我可能是错的。
在javacard上使用了Signature.ALG_ECDSA_SHA,在终端Signature.getInstance(“SHA1withECDSA”,“BC”)上我也尝试了SHA1withDetECDSA,但我的行为相似。
请帮忙。
答案 0 :(得分:5)
问题是JavaCard和BouncyCastle使用不同格式的结果签名。例如,对于Prime192v1曲线,生成的JavaCard签名总是56字节长,但Bouncy Castle签名有时更短,因为它省略了EC点坐标中的前导零。
JavaCard签名(对于Prime192v1,再次)看起来像十六进制格式:
30 36 02 19 [25 bytes of the first coord] 02 19 [25 bytes of the second coord]
(它是DER编码结构:两个INTEGER的SEQUENCE)
然而,BouncyCastle并不期望在EC coords中引领这些零。所以你必须删除它们并修复DER结构,例如
30 36 02 19 **00 00** [the rest 23 bytes of the first coord] 02 19 **00** [24 bytes of the second coord]
必须将来自JavaCard的转换为Bouncy Castle:
30 **33** 02 **17** [23 bytes of the first coord] 02 **18** [24 bytes of the second coord]
您有时正确验证签名的原因很简单:有时您的JavaCard签名坐标中没有前导零。
编辑:受到TajnosAgentos观察的启发:
BouncyCastle将coords编码为有符号整数,JavaCard始终为无符号整数。这就是为什么只要第一个字节的最高位为1,BouncyCastle就会添加一个特殊的前导零(尽管它会修正其他前导零),因为coord总是一个正数。
答案 1 :(得分:1)
我有一个解决方案。我不知道为什么会这样,它确实...... 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);
}
ist a&#34; prototype&#34;功能。它工作所以我先分享它,以后也许我会改善它一点。 scratch是在其他地方声明的字节数组。
像之前发布的VOJTA一样,签名(在我的例子中)看起来像这样:30 34 02 18 [24字节NO1] 02 18 [24字节NO2] [SW - 90 00]
不需要SW。所以[24字节NO1]的FIRST字节的SHORT值和[24字节NO2]的第一个字节的SHORT值不能是负的。我不知道为什么会这样。我打印了经过验证和未经验证的签名,我正在寻找任何差异,我发现了这一点。我做了1000多次尝试并且验证总是返回TRUE。这两个字节将成为负的概率是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字节NO1]和[24字节NO2]的第一次咬合为正,则对签名不做任何处理。 如果[24字节NO1]的第一个字节的SHORT值为负,那么我们必须将一个加到X(现在x = 35),在[24字节NO1]的第一个字节旁边的18加一个并插入一个值18在18(现在19)旁边签名。如果[24字节NO2]的第一个字节的SHORT值为负,那么我们必须将一个加到X(现在x = 36),在[24字节NO2]的第一个字节旁边的18加一个并插入00在18(现在19)旁边。如果两个第一个字节都是负数,则签名应如下所示:
30 36 02 19 00 [24字节NO1] 02 19 00 [24字节NO2]
如果只有[24字节NO1]的第一个字节为负,而[24字节NO2]的第一个字节为正,则签名应该像这样看起来像
30 35 02 19 00 [24字节NO1] 02 18 [24字节NO2]
和最后一个案例: 如果只有[24字节NO1]的第一个字节为正,而[24字节NO2]的第一个字节为负,则签名应该像这样看起来像
30 35 02 18 [24字节NO1] 02 19 00 [24字节NO2]
希望我会有用