简体   繁体   English

JCOP 2.4.2 Java卡上的ECDSA算法

[英]ECDSA algorithm on JCOP 2.4.2 Java Card

I want to implement ECDSA algorithm on Java Card (JCOP 2.4.2). 我想在Java Card(JCOP 2.4.2)上实现ECDSA算法。 This is my source code: 这是我的源代码:

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

I am running this source code using this script script code: 我正在使用以下脚本脚本代码运行此源代码:

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

When I am calling /send 0046000000 for signing the plain text message I get the response code 6F00 . 当我致电/send 0046000000签署纯文本消息时,我得到响应代码6F00

Could you help me to find out what is wrong with this? 您能帮我找出问题所在吗?

How to properly implement this algorithm on a JCOP card? 如何在JCOP卡上正确实现此算法?

I'm not an expert on JCOP but I have experience with ISO7816: 我不是JCOP的专家,但是我具有ISO7816的经验:

Statusword 0x6F00 means "General Error". 状态字0x6F00表示“常规错误”。 I suppose a CryptoException is thrown, but the value of "reason" is between 1-5 (according to the documentation ). 我想抛出了CryptoException,但是“ reason”的值在1-5之间(根据文档 )。 It's not possible to return arbitrary values as ISO7816 statusword. 无法返回任意值作为ISO7816 statusword。

Therefore I would suggest to send the reason using apdu.sendBytes(...), then you know what really is the problem 因此,我建议使用apdu.sendBytes(...)发送原因,然后您知道真正的问题是什么

Best way would be to debug the code 最好的方法是调试代码

Since you indicate that your call to KeyBuilder.buildKey(...) fails, I would assume that this call throws a CryptoException with reason code NO_SUCH_ALGORITHM . 由于您指示对KeyBuilder.buildKey(...)调用失败,因此,我假定此调用将引发CryptoException ,原因码为NO_SUCH_ALGORITHM As you do not handle that exception in your code, this results in the status word 0x6F00 being retuned by the card ( 0x6F00 is typically returned in case of unhandled exceptions). 由于您未在代码中处理该异常,因此会导致状态字0x6F00被卡重新调整(如果未处理异常,通常会返回0x6F00 )。

So the CryptoException indicates that the requested key algorithm is not supported. 因此CryptoException指示不支持请求的密钥算法。 Since you use the following parameters 由于您使用以下参数

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

this could mean that 这可能意味着

  • the card does not support the EC_FP (elliptic curve over large prime field) key type / algorithm, 该卡不支持EC_FP(大素数字段上的椭圆曲线)密钥类型/算法,
  • the card does not support a key length of 192, or 卡不支持密钥长度192,或者
  • the card does not support key encryption. 该卡不支持密钥加密。

As the FIPS 140-2 Cryptographic Module Security Policy for both JCOP 2.4.2 R2 and JCOP 2.4.2 R3 indicate that ECDSA key pair generation is supported for P-192 (besides P-224 and P-256), I would assume that your card does not support key encryption. 由于同时针对JCOP 2.4.2 R2JCOP 2.4.2 R3的FIPS 140-2加密模块安全策略表明P-192支持ECDSA密钥对生成(P-224和P-256除外),因此我认为您的卡不支持密钥加密。 Hence, you could instead try 因此,您可以尝试

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

I can see two different issues: 我可以看到两个不同的问题:

  • JCOP (mistakenly) requires you to set the private key parameters as well; JCOP(错误地)要求您也设置私钥参数;
  • base point G seems to be in compressed format, which may not be supported, it is required to convert to a 49 byte uncompressed point instead. 基点G似乎是压缩格式,可能不受支持,因此需要将其转换为49字节未压缩点。

Furthermore it should be noted that: 此外,应注意:

  • you should indeed first build the public key using KeyBuilder (currently commented out); 实际上,您应该首先使用KeyBuilder构建公共密钥(当前已注释掉);
  • there is no reason to have a parameter S in there (the seed is of no consequence - at least I presume it's not a private key with that size); 没有理由在那里有一个参数S(种子没有关系-至少我认为它不是具有该大小的私钥);
  • you should really wrap key generation with a try / catch statement and (in the end) convert to an ISOException with a valid status word; 您实际上应该使用try / catch语句包装密钥生成,并(最后)将其转换为带有有效状态字的ISOException
  • having a debugger available is of vital importance. 拥有调试器至关重要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM