【问题标题】:Recovering an ECPublicKey from Java to JavaCard将 ECPublicKey 从 Java 恢复到 JavaCard
【发布时间】:2015-06-10 09:39:13
【问题描述】:

这个问题和我昨天问的那个问题有关:Recovering an ECPublicKey from JavaCard to Java

我有同样的问题,但方式相反: 将公钥从我的卡发送到我的计算机后(根据 ANSI X9.62,该点表示为未压缩形式的八位字节字符串)我可以恢复相应的密钥。

但是如果我从我的计算机发送它,我无法在我的卡上恢复它,我收到一个CryptoException (ILLEGAL_VALUE),这意味着表格不正确或点与曲线参数。

我已验证,我的参数定义明确,我以正确的形式发送点...

为了调试它,我尝试将公钥从我的卡发送到我的计算机,然后将其重新发送到我的卡以尝试恢复它(所以我确定参数没问题)。无论如何,我仍然得到同样的错误......

为了说明我的问题,我贴出相应的代码:

在卡端 - 发送公钥

pubKey = (ECPublicKey) KeyBuilder.buildKey(
            KeyBuilder.TYPE_EC_FP_PUBLIC, (short) 0x0100, false);
pubKey.setFieldFP(p, (short) 0x0001, (short) 0x0020);
pubKey.setA(a, (short) 0x0001, (short) 0x0020);
pubKey.setB(b, (short) 0x0000, (short) 0x0020);
pubKey.setR(r, (short) 0x0001, (short) 0x0020);
pubKey.setG(g, (short) 0x0000, (short) g.length);

privKey = (ECPrivateKey) KeyBuilder.buildKey(
        KeyBuilder.TYPE_EC_FP_PRIVATE, (short) 0x0100, false);

KeyPair keypair = new KeyPair(pubKey, privKey);
    keypair.genKeyPair();

short len = pubKey.getW(apduBuffer, (short) 0x0000);
setOutgoingAndSend((short) 0x0000, len);

发送的响应是:

APDU <<<: 04C2B28FBE96C5EAC1E81750E9B288B0BD8357D3AED4EA39413197D734B145EBC92F3FD7489B9A7EF4C8A956427668851F0BB3A55D5C7B9033A533F21463E1A2139000

所以第一个坐标是x = C2B28FBE96C5EAC1E81750E9B288B0BD8357D3AED4EA39413197D734B145EBC9,第二个坐标是y = 2F3FD7489B9A7EF4C8A956427668851F0BB3A55D5C7B9033A533F21463E1A213

在计算机端 - 恢复密钥并重新发送它

byte[] x = new byte[32];
byte[] y = new byte[32];
System.arraycopy(W, 1, x, 0, x.length);
System.arraycopy(W, 1 + x.length, y, 0, y.length);

ECPublicKeySpec pub = new ECPublicKeySpec(new ECPoint(new BigInteger(1,x), new BigInteger(1,y)), ecParamSpec);

ECPublicKey ecPubKey = (ECPublicKey) kf.generatePublic(pub);

byte[] k_x = ecPubKey.getEncoded();

byte[] tmp = new byte[70];
tmp[0] = (byte) 0x80;
tmp[1] = (byte) 0x20;
tmp[2] = (byte) 0x00;
tmp[3] = (byte) 0x00;
tmp[4] = (byte) (65);
System.arraycopy(k_x, k_x.length - 65, tmp, 5,65);

sendApdu(cardChan, tmp);

发送的APDU是:

APDU >>>: 802000004104C2B28FBE96C5EAC1E81750E9B288B0BD8357D3AED4EA39413197D734B145EBC92F3FD7489B9A7EF4C8A956427668851F0BB3A55D5C7B9033A533F21463E1A213

因此我们可以很容易地看到发送的数据与之前收到的数据完全相同

最后,在卡方面,我有以下代码来恢复密钥:

pubKey.setW(apduBuffer, ISO7816.OFFSET_CDATA,
            ISO7816.OFFSET_LC);

len = pubKey.getW(apduBuffer, (short) 0x0000);
setOutgoingAndSend((short) 0x0000, len);

但我得到APDU &gt;&gt;&gt;: 0401

这意味着CryptoException.ILLEGAL_VALUE 在指令中引发

pubKey.setW(apduBuffer, ISO7816.OFFSET_CDATA,
                ISO7816.OFFSET_LC);

知道我发送了与pubKey.getW() 相同的东西,它怎么会引发异常?

【问题讨论】:

  • 请问“04 在响应的开头是什么意思”?
  • 在对应于卡片公钥的响应中:APDU &lt;&lt;&lt;: 04C2B28FBE96C5EAC1E81750E9B288B0BD8357D3AED4EA39413197D734B145EBC92F3FD7489B9A7EF4C8A956427668851F0BB3A55D5C7B9033A533F21463E1A213900004表示该点没有被压缩,然后你有该点的2个坐标,你可以检查我在开头提到的链接帖子。关于APDU &gt;&gt;&gt;: 0401,这是一个自制的例外(CryptoException 为 04,ILLEGAL_VALUE 为 01)。

标签: java cryptography javacard apdu elliptic-curve


【解决方案1】:

问题很可能:

pubKey.setW(apduBuffer, ISO7816.OFFSET_CDATA, ISO7816.OFFSET_LC);

首先,你不应该直接使用ISO7816.OFFSET_CDATAISO7816.OFFSET_LC。命令数据的位置使用APDU.getOffsetCData,使用APDU.setIncomingAndReceive获取Nc值(Lc是Nc值的编码)。

当前您的代码失败,因为您使用 ISO7816.OFFSET_LC 而不是 setIncomingAndReceive 的输出。 ISO7816.OFFSET_LC 是一个设置为值 4 的常量。您的公共点比这更大。

【讨论】:

  • 这是我的一个答案发生接受的新记录。可惜没有徽章:)
  • 好吧,我现在肯定是瞎了,事实上它需要超过 4 个字节 :) ty
  • 第一条评论是什么意思?我想答案在发布后立即被接受。我对吗? :)
  • @Abraham 是的,几分钟后。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-27
  • 2021-10-05
  • 2013-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-22
相关资源
最近更新 更多