Как читать большие двоичные данные с смарт-карты iso7816
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.smartcardio.ATR;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CardTerminals;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;
@SuppressWarnings("restriction")
public class APDu {
static FileOutputStream fos = null;
private static byte[] SELECT = {
(byte) 0x00, ////CLA
(byte) 0xA4, ////INS
(byte) 0x04, ////P1
(byte) 0x00, ////P2
(byte) 0x07, ////Length of AID
(byte) 0xA0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x34, (byte) 0x49, (byte) 0x44, (byte) 0x43};
private static byte[] select_dataSet = {
(byte) 0x00, ////CLA
(byte) 0xA4, ////INS
(byte) 0x04, ////P1
(byte) 0x00, ////P2
(byte) 0x01, ////Length of AID
(byte) 0x11 }; ///////////worked
private static byte[] read_dataSet = {
(byte) 0x00, ////CLA
(byte) 0xB0, ////INS
(byte) 0x00, ////P1
(byte) 0x00, ////P2 this is the offset
(byte) 0x00, ////
(byte) 0x00,
(byte) 0xFF
};
private static CommandAPDU SELECT_APDU = new CommandAPDU(SELECT);
private static CommandAPDU select_dataSetAPDU = new CommandAPDU(select_dataSet);
private static CommandAPDU read_dataSetAPDU = new CommandAPDU(read_dataSet);
private static CardTerminal cardTerminal = null;
private static void arrayPrint(byte[] data) {
System.out.print("{");
arrayPrintBytes(data);
System.out.print("} (");
arrayPrintHex(data);
System.out.print(")");
}
private static void arrayPrintHex(byte[] data) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < data.length; i++) {
String bs = Integer.toHexString(data[i] & 0xFF);
if (bs.length() == 1)
sb.append(0);
sb.append(bs).append(" ");
}
System.out.print( sb.toString() );
}
private static void arrayPrintBytes(byte[] data) {
for(int i=0; i < data.length; i++)
System.out.print(data[i]+ " ");
}
public static boolean sendAPDU(CardChannel ch, CommandAPDU apdu,boolean write) throws CardException {
System.out.println("sent these ::: ");arrayPrintHex(apdu.getBytes());
ResponseAPDU responseAPDU = ch.transmit(apdu);
byte[] response = responseAPDU.getBytes();
System.out.print("\n"+responseAPDU.toString()+" (Nr:"+responseAPDU.getNr() +" SW:"+responseAPDU.getSW()+" SW1:"+responseAPDU.getSW1() +" SW2:"+responseAPDU.getSW2()+")");
System.out.print("Bytes received: "); arrayPrint( responseAPDU.getBytes());
System.out.print("Data received: "); arrayPrint( responseAPDU.getData());
if(write){
}
if(write){
try {
System.out.println("\n\nbytes ::: ");arrayPrintHex(responseAPDU.getData());
fos.write(responseAPDU.getData());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//Check if response is 0x9000 (code for success)
return (response[response.length - 2] == (byte) 0x90 && response[response.length - 1] == (byte) 0x00);
}
public APDu() {
}
public static void main(String[] args) throws Exception {
File f = new File("dataBytes.dat");
fos = new FileOutputStream(f,true);
TerminalFactory tf = TerminalFactory.getDefault();
CardTerminals ct = tf.terminals();
cardTerminal = ct.list().get(0);
System.out.println("Selected terminal");
if(cardTerminal==null)
throw new Exception("ERROR: No cardterminal available to communicate.");
try {
while (cardTerminal.isCardPresent()) {
Card card = null;
if ((card = cardTerminal.connect("*")) != null){
System.out.println("Connected to card.");
} else {
System.out.println("ERROR: Failed to connect to card!");
return;
}
System.out.print("ATR: "); arrayPrint(((ATR) card.getATR()).getBytes()); System.out.println();
CardChannel ch = card.getBasicChannel();
//open session
if (sendAPDU(ch, SELECT_APDU,false)){
System.out.println("\nReceived data.");
} else {
System.out.println("\nERROR: Unable to get data!");
return;
}
//select data set
if (sendAPDU(ch, select_dataSetAPDU,false)){
System.out.println("\nReceived data.");
} else {
System.out.println("\nERROR: Unable to get data!");
return;
}
//select read data set
if (sendAPDU(ch, read_dataSetAPDU,true)){
System.out.println("\nReceived data.");
} else {
System.out.println("\nERROR: Unable to get data!");
return;
}
fos.close();
return;
}
} catch (CardException e) {
System.out.println("Error isCardPresent()" + e.getCause());
}
}
}
В приведенной выше ссылке:
данные слева - это фактические данные, которые я должен прочитать со смарт-карты, а другая сторона - это данные, которые я прочитал с карты. я могу читать только 255 байтов из 326 байтов::::
от 00-255 данных и 2 байта слова состояния
Как я могу прочитать оставшиеся байты.
================================================== ====================== Ниже приведен вывод моего кода:
Выбранный терминал подключен к карте. ATR: {59 -1 -107 0 -1 -64 10 49 -2 77 -128 49 -32 107 4 32 5 2 82 85 85 85 85 85 85 -106 } (3b ff 95 00 ff c0 0a 31 fe 4d 80 31 e0 6b 04 20 05 02 52 55 55 55 55 55 55 96)
Команда::: 00 a4 04 00 07 a0 00 00 00 34 49 44 43 --- команда на открытие сессии
ResponseAPDU: 2 байта, SW=9000 (Nr:0 SW:36864 SW1:144 SW2:0) Получено байтов: {-112 0 } (90 00) Получено данных: {} () Получено данных.
команда::: 00 a4 04 00 01 11 --- команда для выбора идентификатора заголовка: 11
ResponseAPDU: 25 байтов, SW=9000 (Nr:23 SW:36864 SW1:144 SW2:0) Получено байтов: {1 17 6 94 1 70 1 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 -112 0 } (01 11 06 5e 01 46 01 0a 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00 90 00) Полученные данные: {1 17 6 94 1 70 1 10 0 0 0 0 0 0 0 10 0 0 0 0 0 0 0 } (01 11 06 5e 01 46 01 0a 00 00 00 00 00 00 00 0a 00 00 00 00 00 00 00) Полученные данные.
команда::: 00 b0 00 00 00 00 ff --- команда для чтения
ResponseAPDU: 257 байтов, SW = 9000 (Nr: 255 SW: 36864 SW1: 144 SW2: 0)
06 5e - максимальное количество данных, которое нужно получить, а 01 46 - доступные данные. Я уже прочитал 255 байтов, мне просто нужно прочитать остальные 44 байта. каким будет следующее смещение для извлечения оставшихся байтов.
2 ответа
Расширенный APDU позволяет отправлять большие объемы данных на карту, обрабатывать их надлежащим образом и отправлять обратно в терминал более эффективным способом. Вместо того, чтобы повторно выдавать несколько сообщений APDU для завершения операции, требующей больших объемов данных, и требовать от разработчика кодирования приложения для сохранения состояния в таких множественных командах APDU, расширенный APDU позволяет апплетам выполнять эту функцию более эффективно с помощью одного большой обмен APDU.
Используйте эту ссылку для получения дополнительной информации.
ОБНОВИТЬ:
В этом справочнике есть пошаговое руководство по написанию апплета, который использует преимущества расширенной длины. Обратите внимание, что апплет должен реализовывать javacardx.apdu.ExtendedLength
интерфейс.
Также вы можете использовать C0 00 00 XX
какой XX обычно SW2
из предыдущего ответа. Это потому, что карта использует T=0
протокол.
Например, если ответ 61 09
затем отправьте 00 C0 00 00 09
пока ответ не станет 90 00
, конечно каждый раз, когда вы должны заменить XX
с предыдущим ответом.
Чтобы прочитать большие двоичные данные> 255 байтов, вы должны реализовать протокол цепочки. Пожалуйста, проверьте ниже ссылки: