Как подписать апплет javacard и вернуть подпись в хост-приложение - PullRequest
0 голосов
/ 26 мая 2018

У меня есть следующая функция в апплете javacard, которая должна принимать вызов от хост-приложения, подписывать его и возвращать на хост через связь apdu command-response.

private void sign(APDU apdu) {

        if(!pin.isValidated())ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
        else{

            byte[] buffer = apdu.getBuffer();
            byte [] output = new byte [20];
            short length = 20;
            short x =0;

            Signature signature =Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false);
            signature.init(privKey, Signature.MODE_SIGN);
            short sigLength = signature.sign(buffer, offset,length, output, x);
            //This sequence of three methods sends the data contained in
            //'serial' with offset '0' and length 'serial.length'
            //to the host application.
            apdu.setOutgoing();
            apdu.setOutgoingLength((short)output.length);
            apdu.sendBytesLong(output,(short)0,(short)output.length);
        }


    }

хост вычисляет запрос следующим образом и отправляет его в апплет javacard для подписи:

//produce challenge


            SecureRandom random = SecureRandom . getInstance( "SHA1PRNG" ) ;
            byte [ ]bytes = new byte [ 20 ] ;
            random . nextBytes ( bytes) ;
            CommandAPDU challenge;
            ResponseAPDU resp3;
            challenge =  new CommandAPDU(IDENTITY_CARD_CLA,SIGN_CHALLENGE, 0x00, 0x00,bytes ,20 );
            resp3= c.transmit(challenge);
            if(resp3.getSW()==0x9000) {
                card_signature = resp2.getData();
                String s = new String(card_signature);
                System.out.println("signature " + s);
            }else System.out.println("Challenge signature error: " + resp3.getSW());

Как видите, я проверяю как успешное, так и неудачное подписание, но распечатываю следующее:

Challenge signature error:28416

Где именно я ошибаюсь?Могу ли я получить вызов ошибочным способом с помощью `byte [] buffer = apdu.getBuffer ();или моя подпись не так?

1 Ответ

0 голосов
/ 26 мая 2018

Вы пытаетесь подписать, используя ключ RSA.Однако размер подписи сгенерированной RSA подписи идентичен размеру ключа (размеру модуля), закодированному в минимальном количестве байтов.Так, например, 2048-битный ключ приводит к подписи с размером ceil(2028D / 8D) = 256 байт (максимальный размер ответа, если вы не используете APDU расширенной длины).

Вы должны никогда создавать байтовые массивы в Javaкроме случаев создания класса или персонализации апплета.Любой массив, созданный в постоянной памяти с использованием new byte[], вероятно, останется до запуска сборщика мусора и может изнашивать EEPROM или флэш-память.А для подписей вам не нужна постоянная память.

Если вы посмотрите на метод Signature.sign:

Входные и выходные данные буфера могут перекрываться.

Таким образом, вы можете просто сгенерировать подпись в буфер APDU.В противном случае вы можете сгенерировать его в JCSystem.makeTransientByteArray созданном буфере, но если вы хотите передать его клиенту, вам все равно придется скопировать его в буфер APDU.


Пожалуйста, никогда невыполните следующие действия:

String s = new String(card_signature);

Сигнатура практически неотличима от случайных байтов, поэтому ее распечатка приведет к просто мусору.Если вам нужен вывод текста, попробуйте шестнадцатеричное или базовое 64 кодирование подписи.Или выведите его как десятичное число (но учтите, что это может привести к потере старших байтов со значением 00).

...