繁体   English   中英

JCOP 2.4.2 Java卡上的ECDSA算法

[英]ECDSA algorithm on JCOP 2.4.2 Java Card

我想在Java Card(JCOP 2.4.2)上实现ECDSA算法。 这是我的源代码:

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卡上正确实现此算法?

我不是JCOP的专家,但是我具有ISO7816的经验:

状态字0x6F00表示“常规错误”。 我想抛出了CryptoException,但是“ reason”的值在1-5之间(根据文档 )。 无法返回任意值作为ISO7816 statusword。

因此,我建议使用apdu.sendBytes(...)发送原因,然后您知道真正的问题是什么

最好的方法是调试代码

由于您指示对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,或者
  • 该卡不支持密钥加密。

由于同时针对JCOP 2.4.2 R2JCOP 2.4.2 R3的FIPS 140-2加密模块安全策略表明P-192支持ECDSA密钥对生成(P-224和P-256除外),因此我认为您的卡不支持密钥加密。 因此,您可以尝试

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

我可以看到两个不同的问题:

  • JCOP(错误地)要求您也设置私钥参数;
  • 基点G似乎是压缩格式,可能不受支持,因此需要将其转换为49字节未压缩点。

此外,应注意:

  • 实际上,您应该首先使用KeyBuilder构建公共密钥(当前已注释掉);
  • 没有理由在那里有一个参数S(种子没有关系-至少我认为它不是具有该大小的私钥);
  • 您实际上应该使用try / catch语句包装密钥生成,并(最后)将其转换为带有有效状态字的ISOException
  • 拥有调试器至关重要。

暂无
暂无

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

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