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()
?
The problem is likely:
First of all, you should not use
ISO7816.OFFSET_CDATA
andISO7816.OFFSET_LC
directly. UseAPDU.getOffsetCData
for the location of the command data and useAPDU.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 ofsetIncomingAndReceive
.ISO7816.OFFSET_LC
is a constant set to the value 4. Your public point is bigger than that.