2016-01-12 32 views
2

我想在Java Card上實現ECDSA算法(JCOP 2.4.2)。這是我的源代碼:JCOP上的ECDSA算法2.4.2 Java卡

package hashPack; 

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, true); 
       } 
      catch(CryptoException c) 
      {  
       short reason = c.getReason(); 
       ISOException.throwIt(reason);  // for check 
      }  // for check*/ 
        // objECDSAPubKey = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC,  KeyBuilder.LENGTH_EC_FP_192, true); 

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


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

我正在使用這個腳本腳本代碼此源代碼:

#/term SCComm:2 
/mode trace=on 
/atr 
/card 
/select |ecdsa 
/send 00A4040007D4106509900090 
/send 0046000000 
/send 002E00000A30313233343031323334 

當我簽署了純文本郵件調用/send 0046000000我得到的響應代碼6F00

你能幫我找出這有什麼問題嗎?

如何在JCOP卡上正確實現該算法?

+0

從您選擇ECC參數的位置開始,請參考[NIST](http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf)獲取P-192曲線,似乎你的參數是錯誤的。如果你仍然無法弄清楚,請讓我知道。 –

+0

不要評論此行......「// objECDSAPubKey =(ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC,KeyBuilder.LENGTH_EC_FP_192,true);」否則它將始終爲空,並且您將繼續獲得0x6F00。 –

+0

priyanka給出的答案是否有缺失?如果不是,那麼您是否可以選擇並接受一個問題,否則問題仍然存在。您可以通過點擊答案左側的V標記來接受。 –

回答

2

我不是JCOP專家,但我有經驗的ISO7816:

狀態字0x6F00的意思是「一般錯誤」。我猜想CryptoException被拋出,但「reason」的值在1-5之間(根據documentation)。 無法將任意值作爲ISO7816 statusword返回。

所以我建議發送郵件使用apdu.sendBytes(...)的原因,那麼你就知道什麼是真正的問題是

最好的辦法是到調試代碼

1

既然你表明,您致電KeyBuilder.buildKey(...)失敗,我會假設此調用會拋出CryptoException,原因碼NO_SUCH_ALGORITHM。由於您沒有在代碼中處理該異常,因此會導致狀態字0x6F00被卡重新調用(0x6F00通常會在未處理的異常情況下返回)。

所以CryptoException表示不支持請求的密鑰算法。由於您使用以下參數

KeyBuilder.buildKey(
    KeyBuilder.TYPE_EC_FP_PRIVATE, // key type 
    KeyBuilder.LENGTH_EC_FP_192, // key length 
    true);       // key encryption 

這可能意味着

  • 卡不支持EC_FP密鑰類型/算法(大素數場橢圓曲線),
  • 卡不支持密鑰長度爲192,或者
  • 該卡不支持密鑰加密。

由於FIPS 140-2加密模塊的安全策略兩個JCOP 2.4.2 R2JCOP 2.4.2 R3表明ECDSA密鑰對生成在P-192(除P-224和P-256),我會假設你的卡不支持密鑰加密。因此,你可以代之以

KeyBuilder.buildKey(
    KeyBuilder.TYPE_EC_FP_PRIVATE, // key type 
    KeyBuilder.LENGTH_EC_FP_192, // key length 
    false);       // key encryption 
1

我可以看到兩個不同的問題:

  • JCOP(錯誤地)要求你設置專用密鑰參數爲好;
  • 基點G似乎是壓縮格式,可能不支持,它需要轉換爲49字節的未壓縮點。

此外,應該注意的是:

  • 你確實應該先建立使用KeyBuilder公共密鑰(目前註釋掉);
  • 沒有理由在那裏有一個參數S(種子沒有任何影響 - 至少我認爲它不是一個具有該大小的私鑰);
  • 你應該使用try/catch語句真正包裝密鑰生成,並且(最終)使用有效的狀態字將其轉換爲ISOException;具有可用調試器的
  • 至關重要。