Мне нужно прочитать номер счета из Maestro / Mastercard с помощью устройства чтения смарт-карт. Я использую Java 1.6 и ее пакет javax.smartcardio. Мне нужно отправить команду APDU, которая запросит у приложения EMV, хранящегося на чипе карты, номер PAN. Проблема в том, что я не могу найти обычный байтовый массив для создания команды APDU, которая будет возвращать необходимые данные где угодно ...




Вам нужно создать объект CommandAPDU и передать его команде transfer ().
Вы сможете найти точную команду в документации к вашей смарт-карте, но вот один пример:
byte[] readFile(CardChannel channel) throws CardException {
CommandAPDU command = new CommandAPDU(0xB0, 0x60, 0x10, 0x00);
ResponseAPDU response = channel.transmit(command);
return response.getData();
}
Вы пытались найти в документации значение 0x6D00? Похоже, это может означать, что команда ENVELOPE не поддерживается. Вы пробовали использовать протокол T = 0 вместо T = 1?
Я не ожидал, что мой пример сработает на вашей карте. Я не знаю, какие APDU поддерживает Maestro / MasterCard, поэтому не могу привести рабочий пример.
Попробуйте указать команде явную ожидаемую длину, например:
byte[] readPan(CardChannel channel) throws CardException {
CommandAPDU command = new CommandAPDU(0x00, 0xB2, 0x5a, 0x14, 250);
ResponseAPDU response = channel.transmit(command);
return response.getData();
}
Вам не нужно дополнительно оборачивать APDU. Об этом должен позаботиться уровень API.
Похоже, что ответ 0x6D00 просто означает, что приложение не поддерживает INS.
Сейчас просто устранение неполадок, но вы же начали с выбора приложения MasterCard, верно?
Т.е. что-то вроде этого:
void selectApplication(CardChannel channel) throws CardException {
byte[] masterCardRid = new byte[]{0xA0, 0x00, 0x00, 0x00, 0x04};
CommandAPDU command = new CommandAPDU(0x00, 0xA4, 0x04, 0x00, masterCardRid);
ResponseAPDU response = channel.transmit(command);
return response.getData();
}
вот рабочий пример:
CardChannel channel = card.getBasicChannel();
byte[] selectMaestro = {(byte)0x00, (byte)0xA4,(byte)0x04,(byte)0x00 ,(byte)0x07 ,(byte)0xA0 ,(byte)0x00 ,(byte)0x00 ,(byte)0x00 ,(byte)0x04 ,(byte)0x30 ,(byte)0x60 ,(byte)0x00};
byte[] getProcessingOptions = {(byte)0x80,(byte)0xA8,(byte)0x00,(byte)0x00,(byte)0x02,(byte)0x83,(byte)0x00,(byte)0x00};
byte[] readRecord = {(byte)0x00,(byte)0xB2,(byte)0x02,(byte)0x0C,(byte)0x00};
ResponseAPDU r=null;
try {
ATR atr = card.getATR(); //reset kartice
CommandAPDU capdu=new CommandAPDU( selectMaestro );
r=card.getBasicChannel().transmit( capdu );
capdu=new CommandAPDU(getProcessingOptions);
r=card.getBasicChannel().transmit( capdu );
capdu=new CommandAPDU(readRecord);
r=card.getBasicChannel().transmit( capdu );
Это работает с картой Maestro, я могу прочитать номер PAN, но теперь мне нужно прочитать номер PAN MasterCard. Я не знаю, следует ли мне изменить APDU записи чтения или выбрать APDU приложения. Кто-нибудь знаком с APDU?
Это команда выбора приложения, которую вам нужно изменить. Последняя часть этой команды - это AID приложения, которое вы хотите выбрать. Изменение этого на MasterCard AID должно сработать. Или вы можете просто сократить AID. Если вы поставляете A400000004, ...
... он должен соответствовать всем AID, начинающимся с A400000004.
atr = open();
prints(atr);
prints("[Step 1] Select 1PAY.SYS.DDF01 to get the PSE directory");
cmd = new ISOSelect(ISOSelect.SELECT_AID, EMV4_1.AID_1PAY_SYS_DDF01);
card_response = execute(cmd);
prints(card_response);
SFI = NumUtil.hex2String((byte)((1 < < 3) | 4));
// try SFI 1 record 1
prints("[Step 2] Send READ RECORD with 0 to find out where the record is");
read = new EMVReadRecord(SFI, "01", "00");
card_response = execute(read);
prints(card_response);
byte_size = NumUtil.hex2String(card_response.getStatusWord().getSw2());
prints("[Step 3] Send READ RECORD with 1C to get the PSE data");
read = new EMVReadRecord(SFI, "01", byte_size);
card_response = execute(read);
prints(card_response);
// the AID is A0000000031010
prints("[Step 4] Now that we know the AID, select the application");
cmd = new ISOSelect(ISOSelect.SELECT_AID, "A0000000031010");
card_response = execute(cmd);
prints(card_response);
prints("[Step 5] Send GET PROCESSING OPTIONS command");
cmd = new EMVGetProcessingOptions();
card_response = execute(cmd);
prints(card_response);
// SFI for the first group of AFL is 0C
prints("[Step 6] Send READ RECORD with 0 to find out where the record is");
read = new EMVReadRecord("0C", "01", "00");
card_response = execute(read);
prints(card_response);
byte_size = NumUtil.hex2String(card_response.getStatusWord().getSw2());
prints("[Step 7] Use READ RECORD with the given number of bytes to retrieve the data");
read = new EMVReadRecord("0C", "01", byte_size);
card_response = execute(read);
prints(card_response);
data = new TLV(card_response.getData());
close();
Привет, Гранди, ты можешь добавить сюда класс TLV?
как насчет использования сканера, получения изображения карты, сканирования содержимого изображения с помощью хорошей библиотеки java ocr (например, http://ocr4j.sourceforge.net/) и поиска (обычно) 16-значной последовательности XXXX-XXXX-XXXX-XXXX, затем вы получите PAN с любой карты EMV, используя java.
Я не совсем понимаю твой ответ. мой ответ всегда попадает в 0x6D00. что мне делать, если моя карта не поддерживает INS, как вы сказали?