问题
I'm implementing the signing code using ECDSA in Javacard.
My code outputs 0x0003(NO_SUCH_ALGORITHM) in exception part which means this card does not support the algorithm. I don't understand that because my vendor told me that it supports ECC. I concluded I don't know how to sign with ECDSA and I want to know that.
Here is my full source code
package MyECDSA;
import javacard.framework.*;
import javacard.security.*;
import javacardx.crypto.*;
public class MyECDSA extends Applet{
private byte[] PLAINTEXT ;
private ECPrivateKey objECDSAPriKey=null; // Object for ECDSA Private Key
private ECPublicKey objECDSAPubKey=null; // Object for ECDSA Public Key
private KeyPair objECDSAKeyPair=null; // Object for ECDSA Key Pair
private Signature objECDSASign=null; // Object for ECDSA Signature
final static short BAS = 0;
public static void install(byte[] bArray, short bOffset, byte bLength){
new MyECDSA(bArray, bOffset, bLength);
}
private MyECDSA(byte bArray[], short bOffset, byte bLength){
PLAINTEXT = new byte[0x100] ; // Data file
Util.arrayFillNonAtomic(PLAINTEXT, BAS, (short)0x100, (byte)0);
register();
}
//======================================================================================
public void process(APDU apdu){
byte buf[] = apdu.getBuffer();
switch(buf[1])
{
//--------------------------------------------------------
case (byte)0xA4: break;
case (byte)0x46:
// Create ECDSA Keys and Pair
try {
// <<<<<<<<<<<<<<<< Here is the problem >>>>>>>>>>>>>>>>>
objECDSAKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_192);
//objECDSAKeyPair = new KeyPair(KeyPair.ALG_EC_F2M, KeyBuilder.LENGTH_EC_F2M_193);
}
catch(CryptoException c)
{
short reason = c.getReason();
ISOException.throwIt(reason);
}
ISOException.throwIt((short)0x9999); // for check
// Generate Key pair
objECDSAKeyPair.genKeyPair();
// Create Signature Object
objECDSASign = Signature.getInstance(Signature.ALG_ECDSA_SHA, false);
objECDSAPriKey = (ECPrivateKey)objECDSAKeyPair.getPrivate();
objECDSAPubKey = (ECPublicKey)objECDSAKeyPair.getPublic();
break;
case (byte)0x2E:
short Le = apdu.setOutgoing();
short sSignLen=0 ;
// Init with Private Key
objECDSASign.init(objECDSAPriKey, Signature.MODE_SIGN);
// Sign Data
sSignLen = objECDSASign.sign(PLAINTEXT, BAS, Le, buf, BAS);
apdu.setOutgoingLength(sSignLen);
apdu.sendBytes(BAS, sSignLen);
break;
//--------------------------------------------------------
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
return;
}
}
And APDU Command is as follows
[ Card ] <== 00A4040007D4106509900090
[ Card ] ==> 9000
[ Card ] <== 0046000000
[ Card ] ==> 0003
My Development Environment is as follows.
- OS : Windows 7
- JCDK Ver 2.2.1
- JDK Ver 1.4.2
- Chip : NXP
- Terminal : ACR122 NFC Contactless Smart Card Reader
I've changed my code to set domain parameters. But the card still outputs the same result(0x0003). Here is my full source code.
package MyECDSA;
import javacard.framework.*;
import javacard.security.*;
import javacardx.crypto.*;
public class MyECDSA extends Applet{
private byte[] PLAINTEXT ;
private ECPrivateKey objECDSAPriKey=null; // Object for ECDSA Private Key
private ECPublicKey objECDSAPubKey=null; // Object for ECDSA Public Key
private KeyPair objECDSAKeyPair=null; // Object for ECDSA Key Pair
private Signature objECDSASign=null; // Object for ECDSA Signature
final static short BAS = 0;
final static byte[] SecP192r1_P = { // 24
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xFE,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF};
final static byte[] SecP192r1_A = { // 24
(byte)0xFC,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xFE,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF};
final static byte[] SecP192r1_B = { // 24
(byte)0xB1,(byte)0xB9,(byte)0x46,(byte)0xC1,(byte)0xEC,(byte)0xDE,(byte)0xB8,(byte)0xFE,
(byte)0x49,(byte)0x30,(byte)0x24,(byte)0x72,(byte)0xAB,(byte)0xE9,(byte)0xA7,(byte)0x0F,
(byte)0xE7,(byte)0x80,(byte)0x9C,(byte)0xE5,(byte)0x19,(byte)0x05,(byte)0x21,(byte)0x64};
final static byte[] SecP192r1_S = { // 20
(byte)0xD5,(byte)0x96,(byte)0x21,(byte)0xE1,(byte)0xEA,(byte)0x20,(byte)0x81,(byte)0xD3,
(byte)0x28,(byte)0x95,(byte)0x57,(byte)0xED,(byte)0x64,(byte)0x2F,(byte)0x42,(byte)0xC8,
(byte)0x6F,(byte)0xAE,(byte)0x45,(byte)0x30};
final static byte[] SecP192r1_G = { // 25
(byte)0x12,(byte)0x10,(byte)0xFF,(byte)0x82,(byte)0xFD,(byte)0x0A,(byte)0xFF,(byte)0xF4,
(byte)0x00,(byte)0x88,(byte)0xA1,(byte)0x43,(byte)0xEB,(byte)0x20,(byte)0xBF,(byte)0x7C,
(byte)0xF6,(byte)0x90,(byte)0x30,(byte)0xB0,(byte)0x0E,(byte)0xA8,(byte)0x8D,(byte)0x18,(byte)0x03};
final static byte[] SecP192r1_N = { // 24
(byte)0x31,(byte)0x28,(byte)0xD2,(byte)0xB4,(byte)0xB1,(byte)0xC9,(byte)0x6B,(byte)0x14,
(byte)0x36,(byte)0xF8,(byte)0xDE,(byte)0x99,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF};
final static short SecP192r1_H = 1;
//======================================================================================
public static void install(byte[] bArray, short bOffset, byte bLength){
new MyECDSA(bArray, bOffset, bLength);
}
private MyECDSA(byte bArray[], short bOffset, byte bLength){
PLAINTEXT = new byte[0x100] ; // Data file
Util.arrayFillNonAtomic(PLAINTEXT, BAS, (short)0x100, (byte)0);
register();
}
//======================================================================================
public void process(APDU apdu){
byte buf[] = apdu.getBuffer();
switch(buf[1])
{
//--------------------------------------------------------
case (byte)0xA4: break;
case (byte)0x46:
// Create ECDSA Keys and Pair
try {
// <<<<<<<<<<<<<<<< Here is the problem >>>>>>>>>>>>>>>>>
objECDSAPriKey = (ECPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, KeyBuilder.LENGTH_EC_FP_192, false);
ISOException.throwIt((short)0x8888); // for check
objECDSAPubKey = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, KeyBuilder.LENGTH_EC_FP_192, false);
// set EC Domain Parameters
objECDSAPubKey.setFieldFP(SecP192r1_P, BAS, (short)24);
objECDSAPubKey.setA(SecP192r1_A, BAS, (short)24);
objECDSAPubKey.setB(SecP192r1_B, BAS, (short)24);
objECDSAPubKey.setG(SecP192r1_G, BAS, (short)25);
objECDSAPubKey.setK(SecP192r1_H);
objECDSAPubKey.setR(SecP192r1_N, BAS, (short)24);
objECDSAKeyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_192);
}
catch(CryptoException c)
{
short reason = c.getReason();
ISOException.throwIt(reason); // for check
}
// On-Card Key Generation Process
objECDSAKeyPair.genKeyPair();
// Obtain Key References
objECDSAPriKey = (ECPrivateKey)objECDSAKeyPair.getPrivate();
objECDSAPubKey = (ECPublicKey)objECDSAKeyPair.getPublic();
// Create Signature Object
objECDSASign = Signature.getInstance(Signature.ALG_ECDSA_SHA, false);
break;
case (byte)0x2E:
short Le = apdu.setOutgoing();
short sSignLen=0 ;
// Init with Private Key
objECDSASign.init(objECDSAPriKey, Signature.MODE_SIGN);
// Sign Data
sSignLen = objECDSASign.sign(PLAINTEXT, BAS, Le, buf, BAS);
apdu.setOutgoingLength(sSignLen);
apdu.sendBytes(BAS, sSignLen);
break;
//--------------------------------------------------------
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
return;
}
}
回答1:
There are no default EC domain parameters in Java Card. It is required to create the KeyPair
using an ECPublicKey
and a ECPrivateKey
for which the domain parameters are set (so the point W and secret S may be kept empty). After that it is possible to call genKeyPair()
, at least if the card has support for F(2m) or F(p) Elliptic Curve cryptography and the key size that is specified.
ADDED
Note that NXP JCOP chips may require these parameters set for the public and the private key. The parameters should have either the key size (for separate values) or an uncompressed Elliptic Curve point. The value of G in the question seems to be a compressed point. Only the cofactor (for setH
) should just have the value 1.
Note that only the chips with an asymmetric coprocessor may support elliptic curves; not all cards are created / configured equally. Contact your vendor for details.
回答2:
If an attempt to create instance of the particular algorithm (KeyPair.ALG_EC_FP & KeyBuilder.LENGTH_EC_FP_192 in your case) fails with NO_SUCH_ALGORITHM, it is either not supported by your card completely (e.g., old hardware) or disabled.
Project JCAlgTester allows you to obtain complete list of the supported algorithms for your particular card. Database of results for multiple different cards is also available (but is better to check your particular card directly by uploading JCAlgTester applet).
来源:https://stackoverflow.com/questions/24467612/ecdsa-signature-in-javacard