Отправить буфер прямо на смарт-карту
Мне нужно отправить сообщение на смарт-карту. Прежде всего, я отправил его с помощью gpshell, чтобы проверить правильность и получить ответ:
send_apdu_nostop -sc 0 -APDU 802A80B05F87410061DA7A1E2F02602A255063713FD657797063C6C7ACC12072F5340B1C0126A616BC66C65F49132EED10AE071DC661AA1333BEA92F67A5BEFFDFA7A0F31FC8B3D981105D1EF96B000FD90098C7FF031906A1018E0897C5DA580059AD2900 Command --> 802A80B05F87410061DA7A1E2F02602A255063713FD657797063C6C7ACC12072F5340B1C0126A616BC66C65F49132EED10AE071DC661AA1333BEA92F67A5BEFFDFA7A0F31FC8B3D981105D1EF96B000FD90098C7FF031906A1018E0897C5DA580059AD2900
Wrapped command --> 802A80B05F87410061DA7A1E2F02602A255063713FD657797063C6C7ACC12072F5340B1C0126A616BC66C65F49132EED10AE071DC661AA1333BEA92F67A5BEFFDFA7A0F31FC8B3D981105D1EF96B000FD90098C7FF031906A1018E0897C5DA580059AD2900
Response <-- 604001544F50434F4E31392020202020000000FF00FF0000FF00020000000000000000FF5D11DCAD000000005D11DCAD005D1EF96B9000
Благодаря этому результату я был уверен, что смог повторить поведение в java с помощью smartcardio. Вот код, который я написал:
void testCard()
{
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals;
try {
terminals = factory.terminals().list();
} catch (CardException ex) {
return;
}
CardTerminal cardTerm = terminals.get(0);
Card card;
try {
card = cardTerm.connect("T=0");
} catch (CardException ex) {
return;
}
CardChannel cach = card.getBasicChannel();
ResponseAPDU r;
try {
CommandAPDU ca = new CommandAPDU(new byte[]{(byte)0x80,(byte)0x2A,(byte)0x80,(byte)0xB0,(byte)0x5F,(byte)0x87,(byte)0x41,(byte)0x00,(byte)0x61,(byte)0xDA,(byte)0x7A,(byte)0x1E,(byte)0x2F,(byte)0x02,(byte)0x60,(byte)0x2A,(byte)0x25,(byte)0x50,(byte)0x63,(byte)0x71,(byte)0x3F,(byte)0xD6,(byte)0x57,(byte)0x79,(byte)0x70,(byte)0x63,(byte)0xC6,(byte)0xC7,(byte)0xAC,(byte)0xC1,(byte)0x20,(byte)0x72,(byte)0xF5,(byte)0x34,(byte)0x0B,(byte)0x1C,(byte)0x01,(byte)0x26,(byte)0xA6,(byte)0x16,(byte)0xBC,(byte)0x66,(byte)0xC6,(byte)0x5F,(byte)0x49,(byte)0x13,(byte)0x2E,(byte)0xED,(byte)0x10,(byte)0xAE,(byte)0x07,(byte)0x1D,(byte)0xC6,(byte)0x61,(byte)0xAA,(byte)0x13,(byte)0x33,(byte)0xBE,(byte)0xA9,(byte)0x2F,(byte)0x67,(byte)0xA5,(byte)0xBE,(byte)0xFF,(byte)0xDF,(byte)0xA7,(byte)0xA0,(byte)0xF3,(byte)0x1F,(byte)0xC8,(byte)0xB3,(byte)0xD9,(byte)0x81,(byte)0x10,(byte)0x5D,(byte)0x1E,(byte)0xF9,(byte)0x6B,(byte)0x00,(byte)0x0F,(byte)0xD9,(byte)0x00,(byte)0x98,(byte)0xC7,(byte)0xFF,(byte)0x03,(byte)0x19,(byte)0x06,(byte)0xA1,(byte)0x01,(byte)0x8E,(byte)0x08,(byte)0x97,(byte)0xC5,(byte)0xDA,(byte)0x58,(byte)0x00,(byte)0x59,(byte)0xAD,(byte)0x29,(byte)0x00});
r = cach.transmit(ca);
} catch (CardException ex) {
return;
}
}
Когда код запускается, я всегда получаю ошибку 0x6E00, которая означает: "Класс не поддерживается".
Читая Javadoc для передачи, я понимаю, что "Байт CLA команды APDU автоматически настраивается в соответствии с номером канала этого CardChannel".
Я подозреваю, что по каким-то причинам байт класса был каким-то образом изменен, и по этой причине карта отвечает с ошибкой.
Есть ли способ отправить напрямую сообщение на карту в java?
2 ответа
Я нашел решение. Кажется, использование "T=0" не является подходящим способом для отправки второй команды. Использование "T=1" или "*" решит проблему. Исправление следующее:
card = cardTerm.connect("T=1");
ПРИМЕЧАНИЕ. Я не работал со смарт-картами и не могу подтвердить этот ответ. Но это может указать вам в правильном направлении
Если вы посмотрите на исходный код gshell
, Для отправки APDU
это читается как ниже
else if (_tcscmp(token, _T("-APDU")) == 0)
{
token = strtokCheckComment(NULL);
if (token == NULL)
{
_tprintf(_T("Error: option -APDU not followed by data\n"));
rv = EXIT_FAILURE;
goto end;
}
else
{
pOptionStr->APDULen = ConvertStringToByteArray(token, APDULEN, pOptionStr->APDU);
}
}
Итак, что вы прошли, это полная команда APDU
if (platform_mode == PLATFORM_MODE_OP_201)
{
status = OP201_send_APDU(cardContext, cardInfo,
(optionStr.secureChannel == 0 ? NULL : &securityInfo201),
(PBYTE)(optionStr.APDU), optionStr.APDULen,
recvAPDU, &recvAPDULen);
}
Который в свою очередь идет к
OPGP_ERROR_STATUS OPGP_send_APDU(OPGP_CARD_CONTEXT cardContext, OPGP_CARD_INFO cardInfo, GP211_SECURITY_INFO *secInfo, PBYTE capdu, DWORD capduLength, PBYTE rapdu, PDWORD rapduLength) {
OPGP_ERROR_STATUS errorStatus;
OPGP_ERROR_STATUS securityStatus;
OPGP_ERROR_STATUS(*plugin_sendAPDUFunction) (OPGP_CARD_CONTEXT, OPGP_CARD_INFO, PBYTE, DWORD, PBYTE, PDWORD);
BYTE apduCommand[261];
DWORD apduCommandLength = 261;
int i=0;
OPGP_LOG_START(_T("OPGP_send_APDU"));
plugin_sendAPDUFunction = (OPGP_ERROR_STATUS(*)(OPGP_CARD_CONTEXT, OPGP_CARD_INFO, PBYTE, DWORD, PBYTE, PDWORD)) cardContext.connectionFunctions.sendAPDU;
Так что я думаю, что дополнительный cardContext
требуется добавить в вашу команду, которой сейчас нет
Смотрите также несколько реализаций и посмотрите, сможете ли вы разобрать байты
https://www.javaworld.com/article/2076450/how-to-write-a-java-card-applet--a-developer-s-guide.html