如何从智能卡iso7816读取大型二进制数据

时间:2015-12-31 14:47:20

标签: smartcard javacard apdu

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


            }
  

http://i.stack.imgur.com/IvQHZ.png

在上面的链接中:

左边的数据是我应该从智能卡读取的实际数据,另一边是我从卡上读取的数据。 我只能读取326字节中的255个字节::::

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

Command ::: 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)收到的数据:{}() 收到的数据。

command ::: 00 a4 04 00 01 11 ---命令选择标题id: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 00 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) 收到的数据。

command ::: 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 个答案:

答案 0 :(得分:1)

扩展APDU允许以更有效的方式将大量数据发送到卡,进行适当处理并发送回终端。无需重新发出多个APDU消息来完成需要大量数据的操作,并要求开发人员对应用程序进行编码以保持跨多个APDU命令的状态,扩展APDU允许applet更有效地执行此功能。大型APDU交换。

使用this reference获取更多信息。

<强>更新

在本参考文献中,我们逐步编写了一个利用扩展长度的applet。请注意,applet应该实现defaultHtmlAttributesObject接口。

此外,您可以使用javacardx.apdu.ExtendedLength,其中XX通常是早期答案的C0 00 00 XX。这是因为该卡正在使用SW2协议。

例如,如果回复为T=0,则发送61 09,直到回复变为00 C0 00 00 09。当然,每次你应该用之前的回复取代90 00

答案 1 :(得分:-1)

读取大型二进制数据&gt; 255字节,你必须实现链接协议。 请查看以下链接:

Reading big file from a javacard applet

https://community.oracle.com/thread/2207556?tstart=0