Подпись ECDSA в Javacard

#java #javacard #ecdsa

#java #javacard #ecdsa

Вопрос:

Я реализую код подписи с использованием ECDSA в Javacard.

Мой код выводит 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; 
}

}
 

Комментарии:

1. В чем ваша проблема / Какую часть вы не понимаете? Если у вас возникли проблемы, пожалуйста, укажите конкретные проблемы. Если вы хотите, чтобы кто-то взглянул на ваш код и высказал свое мнение, разместите его здесь: codereview.stackexchange.com

2. @VinceEmigh Вопрос на самом деле достаточно ясен для меня.

3. Помимо проблемы с поддержкой ЕС: обратите внимание, что ваши параметры имеют неправильный размер. Кажется, вы смешиваете параметры 224 и 192, и точка G, я думаю, должна быть несжатой точкой примерно в два раза больше размера ключа, начиная с 04 ,

4. @owlstead Теперь я сотрудничаю с поставщиком по поводу ECC. Похоже, что в карте есть какая-то проблема. В любом случае, спасибо.

Ответ №1:

В Java Card нет параметров домена EC по умолчанию. Требуется создать с KeyPair помощью an ECPublicKey и a ECPrivateKey , для которых заданы параметры домена (так что точка W и секрет S могут быть оставлены пустыми). После этого можно вызвать genKeyPair() , по крайней мере, если карта поддерживает криптографию с эллиптической кривой F (2m) или F (p) и указанный размер ключа.


ДОБАВЛЕНО

Обратите внимание, что чипы NXP JCOP могут требовать установки этих параметров для открытого и закрытого ключей. Параметры должны иметь либо размер ключа (для отдельных значений), либо несжатую точку эллиптической кривой. Значение G в вопросе, по-видимому, является сжатой точкой. Только кофактор (for setH ) должен иметь значение 1.

Обратите внимание, что только микросхемы с асимметричным сопроцессором могут поддерживать эллиптические кривые; не все карты создаются / настраиваются одинаково. Обратитесь к своему поставщику за подробной информацией.

Ответ №2:

Если попытка создать экземпляр определенного алгоритма (KeyPair.ALG_EC_FP и KeyBuilder.LENGTH_EC_FP_192 в вашем случае) завершается с ошибкой NO_SUCH_ALGORITHM, она либо не поддерживается вашей картой полностью (например, старое оборудование), либо отключена.

Проект JCAlgTester позволяет получить полный список поддерживаемых алгоритмов для вашей конкретной карты. Также доступна база данных результатов для нескольких разных карт (но лучше проверить вашу конкретную карту напрямую, загрузив апплет JCAlgTester).