2014-06-28 297 views
1

我在Javacard中使用ECDSA实现签名代码。JavaCard中的ECDSA签名

我的代码在异常部分输出0x0003(NO_SUCH_ALGORITHM),这意味着此卡不支持该算法。我不明白,因为我的供应商告诉我它支持ECC。我得出结论,我不知道如何与ECDSA签约,我想知道这一点。

这里是我的全部源代码

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

} 

而且APDU命令如下

[ Card ] <== 00A4040007D4106509900090 
[ Card ] ==> 9000 

[ Card ] <== 0046000000 
[ Card ] ==> 0003 

我的开发环境如下。

  • 操作系统:Windows 7
  • JCDK版本2.2.1
  • JDK版本1.4.2
  • 芯片:NXP
  • 终端:ACR122 NFC非接触式智能卡读写器

我已更改我的代码以设置域参数。但卡仍输出相同的结果(0x0003)。这是我的完整源代码。

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

} 
+0

你的问题是什么/你不明白哪一部分?如果您遇到问题,请说明具体问题。如果你想让某些人看看你的代码来发表意见,可以在这里发帖:http://codereview.stackexchange.com –

+0

@VinceEmigh这个问题对我来说确实足够清晰。 –

+0

除了EC支持的问题:请注意,您的参数的大小不正确。您似乎混合了224和192个参数,并且我认为G点应该是密钥大小的两倍左右的无压缩点,从'04'开始, –

回答

2

Java Card中没有默认的EC域参数。需要使用设置域参数的ECPublicKeyECPrivateKey来创建KeyPair(因此点W和秘密S可以保持为空)。之后可以拨打genKeyPair(),至少该卡是否支持F(2m)或F(p)椭圆曲线加密以及指定的密钥大小。


ADDED

需要注意的是NXP的芯片JCOP可能需要这些参数为公众和私营键即可。参数应具有密钥大小(对于单独的值)或非压缩的椭圆曲线点。 G在这个问题上的价值似乎是一个压缩点。只有辅助因子(对于setH)应该具有值1.

请注意,只有具有不对称协处理器的芯片才可以支持椭圆曲线;并非所有的卡都是平等创建/配置的。详情请联系您的供应商。

+0

我改变了我的源代码,但结果是一样的。我可以在javacard中获得ECDSA的示例代码,或者我可以获取它的代码。 – user2642459

+0

是的,在尝试的第一行{...}(objECDSAPriKey = ...) – user2642459

+0

我已经添加到相当大的答案,并删除了现在虚假的评论。 –

2

如果尝试创建特定的算法(KeyPair.ALG_EC_FP & KeyBuilder.LENGTH_EC_FP_192你的情况)的情况下失败,NO_SUCH_ALGORITHM,它要么是没有被你的卡完全(例如,旧的硬件)或禁用支持。

项目JCAlgTester允许您获取特定卡所支持算法的完整列表。也可以使用多个不同卡片的结果数据库(但最好通过上传JCAlgTester小程序直接检查您的特定卡片)。