在充气城堡上验证javacard签名ALG_ECDSA_SHA

时间:2015-03-03 22:37:55

标签: java cryptography digital-signature bouncycastle javacard

我的问题看起来像这样:我在javaCard上生成一个签名(jcdk 2.2.2),当我想在终端上使用BouncyCastle验证它时,签名并不总是被验证 - 3,66中的1(100次尝试中的平均值) )签名被验证,其余的返回false。当我验证卡上的签名时,它总是返回true,但是在终端上它通常返回false,但有时是真的。因为终端有时给出一个肯定的答案我认为代码是好的,原因是其他地方,但我可能是错的。

在javacard上使用了Signature.ALG_ECDSA_SHA,在终端Signature.getInstance(“SHA1withECDSA”,“BC”)上我也尝试了SHA1withDetECDSA,但我的行为相似。

请帮忙。

2 个答案:

答案 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]

希望我会有用