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


            }

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

In the above link :

the data on the left is the actual data which im supposed to read from the smartcard and the other side one is the data which i read from the card. im able to read only 255 bytes out of 326 bytes ::::

from 00-255 data and 2 bytes status word

how can i read the remaining bytes.

======================================================================== The below is the output of my code:

Selected terminal Connected to card. 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 --- command to open session
ResponseAPDU: 2 bytes, SW=9000 (Nr:0 SW:36864 SW1:144 SW2:0)Bytes received: {-112 0 } (90 00 )Data received: {} () Received data.

command ::: 00 a4 04 00 01 11 ---command to select header id : 11
ResponseAPDU: 25 bytes, SW=9000 (Nr:23 SW:36864 SW1:144 SW2:0)Bytes received: {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 )Data received: {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 ) Received data.

command ::: 00 b0 00 00 00 00 ff --- command to read
ResponseAPDU: 257 bytes, SW=9000 (Nr:255 SW:36864 SW1:144 SW2:0)

06 5e is the max data to receive and 01 46 is the available data. i already read 255 bytes i just need to read remaining 44 bytes. what would be the next offset to retrieve the remaining bytes.

akhil tccsa
  • 69
  • 1
  • 5

2 Answers2

1

Extended APDU allows large amounts of data to be sent to the card, processed appropriately, and sent back to the terminal, in a more efficient way. Instead of having to re-issue multiple APDU messages to complete an operation requiring large volumes of data, and requiring the developer to code the application to keep a state across such multiple APDU commands, extended APDU allows applets to perform this function more efficiently with one large APDU exchange.

Use this reference for more information.

UPDATE:

In this Reference there's a step by step guid to write an applet that takes advantage of extended length. Note that the applet should implements javacardx.apdu.ExtendedLength interface.

Also you can use C0 00 00 XX which XX is usually the SW2 of the prevoious answer. That's because the card is using T=0 protocol.

For example if the response is 61 09 then send 00 C0 00 00 09 until the response become 90 00. of course each time you should replace XX with the previous response.

Hana Bzh
  • 2,212
  • 3
  • 18
  • 38
  • 1
    Hey! You okay Mrs BzH? :) --- The APDU command that the questioner sent to card to read is an Extended form APDU command, and as he/she successfully received 255 bytes, it doesn't mean that he/she implemented Extended interface in the applet? Does regular applets accept Extended form APDU commands that read/write short data? – Ebrahim Ghasemi Jan 01 '16 at 12:19
  • @Abraham thanks for the comment – Hana Bzh Jan 01 '16 at 13:22
-1

To read large binary data > 255 bytes, you have to implement chaining protocol. Please check below links:

Reading big file from a javacard applet

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

Community
  • 1
  • 1
Bill
  • 172
  • 8
  • >255 is different from large; simply specifying the offset in P1/P2 will do, no extended length necessary – guidot Jan 03 '16 at 13:34
  • who said extended ?? I said chaining NOT extended. Which will require specifying P1/P2 and also some code in Javacard to handle incoming data. – Bill Jan 03 '16 at 13:40
  • If you don't have further confusion on this, please remove -ive point. – Bill Jan 06 '16 at 11:44
  • I see no point in implementing chaining if extended length was not intended. Admittedly *chaining* is used in lot of different contexts, but in my accepted answer to the question of your first link it is **not** used. I fail to see, which benefit the second link provides to the question. – guidot Jan 06 '16 at 12:35