如何从Java中读取EMV SmartCard中的PAN

时间:2022-09-25 10:36:55

I need to read account number from Maestro/Mastercard with smart card reader. I am using Java 1.6 and its javax.smartcardio package. I need to send APDU command which will ask EMV application stored on card's chip for PAN number. Problem is, I cannot find regular byte array to construct APDU command which will return needed data anywhere...

我需要通过智能卡读卡器读取Maestro / Mastercard的帐号。我正在使用Java 1.6及其javax.smartcardio包。我需要发送APDU命令,它会询问存储在卡芯片上的EMV应用程序的PAN号。问题是,我找不到常规的字节数组来构造APDU命令,它会在任何地方返回所需的数据......

6 个解决方案

#1


6  

You shouldn't need to wrap the APDU further. The API layer should take care of that.

您不应该进一步包装APDU。 API层应该处理这个问题。

It looks like the 0x6D00 response just means that the application did not support the INS.

看起来0x6D00响应只是意味着应用程序不支持INS。

Just troubleshooting now, but you did start out by selecting the MasterCard application, right?

现在就进行故障排除,但是你确实选择了MasterCard应用程序,对吗?

I.e. something like this:

即像这样的东西:

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();
}

#2


3  

here is some working example:

这是一些工作示例:

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 );

This works with Maestro card, I can read PAN number, yet now I need to read MasterCard's PAN number. I do not know should I change the read record APDU or select application APDU. Anyone familiar with APDUs?

这适用于Maestro卡,我可以读取PAN编号,但现在我需要读取MasterCard的PAN编号。我不知道应该更改读取记录APDU还是选择应用程序APDU。有熟悉APDU的人吗?

#3


1  

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();

#4


0  

You need to do construct a CommandAPDU object and pass it to the transmit()-command.

您需要构造一个CommandAPDU对象并将其传递给transmit() - 命令。

You should be able to find the precise command in the documentation for your smartcard, but here is one example:

您应该能够在智能卡的文档中找到精确的命令,但这是一个示例:

byte[] readFile(CardChannel channel) throws CardException {
  CommandAPDU command = new CommandAPDU(0xB0, 0x60, 0x10, 0x00);
  ResponseAPDU response = channel.transmit(command);
  return response.getData();
}

#5


0  

Did you try looking up in your documentation what 0x6D00 means? It looks like it might mean that the ENVELOPE command is not supported. Have you tried using T=0 protocol instead of T=1?

您是否尝试在文档中查找0x6D00的含义?看起来它可能意味着不支持ENVELOPE命令。您是否尝试使用T = 0协议而不是T = 1?

I would not expect my example to work on your card. I don't know which APDUs the Maestro/MasterCard-supports, so I couldn't give you a working example.

我不希望我的例子在你的卡上工作。我不知道Maestro / MasterCard支持哪些APDU,所以我不能给你一个有效的例子。

Try giving the command an explicit expected length like this:

尝试给命令一个明确的预期长度,如下所示:

byte[] readPan(CardChannel channel) throws CardException {
  CommandAPDU command = new CommandAPDU(0x00, 0xB2, 0x5a, 0x14, 250);
  ResponseAPDU response = channel.transmit(command);
  return response.getData();
}

#6


-2  

what about using a scanner, getting a picture of the card, scanning the content of the picture with a good java ocr library ( like http://ocr4j.sourceforge.net/ for example ) and search for a (usually) 16 digit sequence XXXX-XXXX-XXXX-XXXX , then you will get the PAN from any EMV card using java.

怎么样使用扫描仪,获取卡片的图片,用一个好的java ocr库扫描图片的内容(例如http://ocr4j.sourceforge.net/)并搜索(通常)16位数序列XXXX-XXXX-XXXX-XXXX,然后您将使用java从任何EMV卡获取PAN。

#1


6  

You shouldn't need to wrap the APDU further. The API layer should take care of that.

您不应该进一步包装APDU。 API层应该处理这个问题。

It looks like the 0x6D00 response just means that the application did not support the INS.

看起来0x6D00响应只是意味着应用程序不支持INS。

Just troubleshooting now, but you did start out by selecting the MasterCard application, right?

现在就进行故障排除,但是你确实选择了MasterCard应用程序,对吗?

I.e. something like this:

即像这样的东西:

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();
}

#2


3  

here is some working example:

这是一些工作示例:

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 );

This works with Maestro card, I can read PAN number, yet now I need to read MasterCard's PAN number. I do not know should I change the read record APDU or select application APDU. Anyone familiar with APDUs?

这适用于Maestro卡,我可以读取PAN编号,但现在我需要读取MasterCard的PAN编号。我不知道应该更改读取记录APDU还是选择应用程序APDU。有熟悉APDU的人吗?

#3


1  

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();

#4


0  

You need to do construct a CommandAPDU object and pass it to the transmit()-command.

您需要构造一个CommandAPDU对象并将其传递给transmit() - 命令。

You should be able to find the precise command in the documentation for your smartcard, but here is one example:

您应该能够在智能卡的文档中找到精确的命令,但这是一个示例:

byte[] readFile(CardChannel channel) throws CardException {
  CommandAPDU command = new CommandAPDU(0xB0, 0x60, 0x10, 0x00);
  ResponseAPDU response = channel.transmit(command);
  return response.getData();
}

#5


0  

Did you try looking up in your documentation what 0x6D00 means? It looks like it might mean that the ENVELOPE command is not supported. Have you tried using T=0 protocol instead of T=1?

您是否尝试在文档中查找0x6D00的含义?看起来它可能意味着不支持ENVELOPE命令。您是否尝试使用T = 0协议而不是T = 1?

I would not expect my example to work on your card. I don't know which APDUs the Maestro/MasterCard-supports, so I couldn't give you a working example.

我不希望我的例子在你的卡上工作。我不知道Maestro / MasterCard支持哪些APDU,所以我不能给你一个有效的例子。

Try giving the command an explicit expected length like this:

尝试给命令一个明确的预期长度,如下所示:

byte[] readPan(CardChannel channel) throws CardException {
  CommandAPDU command = new CommandAPDU(0x00, 0xB2, 0x5a, 0x14, 250);
  ResponseAPDU response = channel.transmit(command);
  return response.getData();
}

#6


-2  

what about using a scanner, getting a picture of the card, scanning the content of the picture with a good java ocr library ( like http://ocr4j.sourceforge.net/ for example ) and search for a (usually) 16 digit sequence XXXX-XXXX-XXXX-XXXX , then you will get the PAN from any EMV card using java.

怎么样使用扫描仪,获取卡片的图片,用一个好的java ocr库扫描图片的内容(例如http://ocr4j.sourceforge.net/)并搜索(通常)16位数序列XXXX-XXXX-XXXX-XXXX,然后您将使用java从任何EMV卡获取PAN。