Recovering an ECPublicKey from Java to JavaCard

581 views Asked by At

This question is related to the one I asked yesterday : Recovering an ECPublicKey from JavaCard to Java

I have the same problem but in the opposite way : After sending the public key from my card to my computer (the point is represented as an octet string in uncompressed form as per ANSI X9.62) I can recover the corresponding key.

But I can't recover it on my card if I send it from my computer, I get a CryptoException (ILLEGAL_VALUE) which means that the form isn't correct or the point doesn't match with the curve parameter.

I verified, my parameters are well defined and I send the point in the right form...

To debug it, I try to send the public key from my card to my computer, and resend it to my card to try to recover it (so I'm sure that parameters are fine). Whatever, I still get the same error...

To illustrate my problem, I post the corresponding code:

On the card side - to send the public key :

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);

The response sent is:

APDU <<<: 04C2B28FBE96C5EAC1E81750E9B288B0BD8357D3AED4EA39413197D734B145EBC92F3FD7489B9A7EF4C8A956427668851F0BB3A55D5C7B9033A533F21463E1A2139000

So the first coordinate is x = C2B28FBE96C5EAC1E81750E9B288B0BD8357D3AED4EA39413197D734B145EBC9 and the second one, y = 2F3FD7489B9A7EF4C8A956427668851F0BB3A55D5C7B9033A533F21463E1A213

On the computer side - to recover the key and resend it:

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);

The APDU sent is:

APDU >>>: 802000004104C2B28FBE96C5EAC1E81750E9B288B0BD8357D3AED4EA39413197D734B145EBC92F3FD7489B9A7EF4C8A956427668851F0BB3A55D5C7B9033A533F21463E1A213

So we can easily see that the data which is sent is exactly the same that the one received before.

And, finally, on the card side, I have the following code to recover the key:

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

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

But I get APDU >>>: 0401

Which means CryptoException.ILLEGAL_VALUE that is raised at the instruction

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

How can it raises an Exception knowing that I send the same thing that I get by pubKey.getW()?

1

There are 1 answers

4
Maarten Bodewes On BEST ANSWER

The problem is likely:

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

First of all, you should not use ISO7816.OFFSET_CDATA and ISO7816.OFFSET_LC directly. Use APDU.getOffsetCData for the location of the command data and use APDU.setIncomingAndReceive to get the Nc value (Lc is the encoding of the Nc value).

Currently your code is failing as you use ISO7816.OFFSET_LC instead of the output of setIncomingAndReceive. ISO7816.OFFSET_LC is a constant set to the value 4. Your public point is bigger than that.