ReadRND.java
// ReadRND
// Demo for reading and displaying the random numbers from a smart card
// using the OCF 1.2 with PC/SC to transmit the data
//
// File: ReadRND.java
//
// This program uses the PassThruCardService from OCF opencard.opt.util package.
// Additional informations and reference implementation: www.opencard.org.
// Testet with Towitoko Chipdrive micro on USB port and the appropriate PC/SC drivers
// from Towitoko on Windows 98. Testet with Omnikey CardMan Dongle 6020 on USB port
// and the appropriate PC/SC drivers from Omnikey on Windows 2000. Testet with
// JBuilder 6 and JDK 1.3.1. Uses a ISO/IEC 7816-4 smart card.
//
// Uses OCFPCSC1.DLL, OCFPCSC1.DLL, pcsc-wrapper-src.jar, base-core.jar, base-opt.jar
// from OCF 1.2
// The content of the file "opencard.properties" must be changed to:
// OpenCard.terminals = com.ibm.opencard.terminal.pcsc10.Pcsc10CardTerminalFactory
//
// For understanding the mechanisms of OCF it is useful to look first into the
// SimpleOCF example.
//
// This programm fetches n 8 byte long random numbers from an ISO/IEC 7816-4 smart card
// and displays the decimal formated random numbers in such a form that they could
// with copy and paste easily imported in a spreadsheet programm for further analisis.
//
// This source code is under GNU general public license (see www.opensource.org for details).
// Please send corrections and ideas for extensions to Wolfgang Rankl (www.wrankl.de)
// Copyright 2003 by Wolfgang Rankl, Munich
//
//  9. Dez. 2003 - V 5, rw: minor clarifications, add GPL statement
//                      3rd published version
// 23. Jan. 2003 - V 4, rw: simplifications byte to int conversion, test with new
//                          card reader, review of the source code, 2nd published version
// 17. Oct. 2002 - V 3, rw: minor changes for UI and GET CHALLENGE parameters additional test
// 15. Oct. 2002 - V 2, rw: improved documentation, 1st published version
// 14. Oct. 2002 - V 1, rw: initial runnable version
//---------------------------------------------------------------------------------------

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import opencard.core.service.*;
import opencard.core.terminal.*;
import opencard.opt.util.*;

public class ReadRND implements ActionListener {

  static final int IFD_TIMEOUT = 0;       // unit: seconds
  static final int MAX_APDU_SIZE = 250;   // unit: byte
  static final int NO_OF_RNDCMDS = 30;    // number of requests (commands) for random numbers
  static final int RND_PER_ROW = 10;      // random numbers in a row
  static final int RND_PER_CMD = 8;       // random numbers per command form the card
  static final boolean DEBUG = false;     // true -> show the APDUs when reading random numbers

  // command GET CHALLENGE, according to ISO/IEC 7816-4
  // CLA || INS || P1 || P2 || Le
  static final byte[] CMD_GET_CHALLENGE = {(byte)0x00, (byte)0x84,
                                           (byte)0x00, (byte)0x00, (byte)0x08 };

  static private int n, k, rcount;
  static private byte[] i;
  private Frame f;
  private Panel p;
  private TextArea t;
  private Button b;
  static private ResponseAPDU response;
  static private CommandAPDU command;

  public ReadRND() {      // build the UI
    f = new Frame();
    f.setTitle("Message Window for ReadRND");
    p = new Panel();
    p.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
    t = new TextArea(40, 100);
    t.setFont(new Font("Monospaced", 0, 12));   // Courier, 12 point size
    t.setBackground(new Color(0, 0, 0));        // black
    t.setForeground(new Color(200, 255, 100));  // yellowgreen
    p.add(t);
    b = new Button("Exit");
    b.addActionListener(this);
    p.add(b);
    f.add(p);
    f.pack();
    f.show();
  }  // ReadRND

  public void actionPerformed(ActionEvent evt) {
  // exit programm if exit button is pressed
    if (evt.getSource() == b) System.exit(0);
  } // actionPerformed

  public void showText(String Text) {
    t.append(Text);
  } // showText

  public void showATR(byte[] ATR) {
    int n, x;
    String s = new String();

    t.append("ATR: ");
    for (n=0; n<i.length; n++) {
      x = (int) (0x000000FF & ATR[n]); // conversion byte to int
      s = Integer.toHexString(x).toUpperCase();
      if (s.length()== 1) s = "0" + s;
      t.append(s + " ");
    } // for
    t.append("\n");
  } // showATR

  public void showCmdAPDU(byte[] CmdAPDU, int LenCmdAPDU) {
    int n, x;
    String s = new String();

    t.append("IFD->ICC: ");
    for (n=0; n<LenCmdAPDU; n++) {
      x = (int) (0x000000FF & CmdAPDU[n]); // conversion byte to int
      s = Integer.toHexString(x).toUpperCase();
      if (s.length() == 1) s = "0" + s;
      t.append(s + " ");
    } // for
    t.append("\n");
   } // showCmdAPDU

  public void showRspAPDU(byte[] RspAPDU, int LenRspAPDU) {
    int n, x;
    String s = new String();

    t.append("ICC->IFD: ");
    for (n=0; n<LenRspAPDU; n++) {
      x = (int) (0x000000FF & RspAPDU[n]);  // conversion byte to int
      s = Integer.toHexString(x).toUpperCase();
      if (s.length()== 1) s = "0" + s;
      t.append(s + " ");
    } // for
    t.append("\n");
  } // showRspAPDU

  public static void main( String [] args ){
    ReadRND rrnd = new ReadRND();
    rrnd.showText("Start Program: ReadRND\n\n");
    // get and set system properties for OCF, PC/SC and PassThruCardServce
    Properties sysProps = System.getProperties();
    sysProps.put ("OpenCard.terminals", "com.ibm.opencard.terminal.pcsc10.Pcsc10CardTerminalFactory");
    sysProps.put ("OpenCard.services", "opencard.opt.util.PassThruCardServiceFactory");

    try {
      SmartCard.start();
      CardRequest cr = new CardRequest(CardRequest.ANYCARD, null, PassThruCardService.class);
      cr.setTimeout(IFD_TIMEOUT);  // set timeout for IFD
      SmartCard sc = SmartCard.waitForCard(cr); // wait  for ICC in the IFD
      rrnd.showText("activate smart card\n\n");

      if (sc != null) {  // no error occur, a smart card is in the terminal
        PassThruCardService ptcs = (PassThruCardService) sc.getCardService(PassThruCardService.class, true);
        command = new CommandAPDU(MAX_APDU_SIZE); // set APDU buffer size

        // get ATR
        CardID cardID = sc.getCardID ();
        i = cardID.getATR();
        rrnd.showATR(i);

        // main loop for reading the random numbers
        rcount = 0;
        rrnd.showText("\nThis are " + RND_PER_CMD * NO_OF_RNDCMDS);
        rrnd.showText(" random numbers in decimal notation:\n");
        for (n=0; n < NO_OF_RNDCMDS; n++) {
          command.setLength(0);
          command.append(CMD_GET_CHALLENGE);
          if (DEBUG == true) rrnd.showCmdAPDU(command.getBytes(), command.getLength());
          response = ptcs.sendCommandAPDU(command);
          if (DEBUG == true) rrnd.showRspAPDU(response.getBytes(),response.getLength());
          if (DEBUG == false) {  // display only the random numbers
            for (k=0; k < RND_PER_CMD; k++) {
              rrnd.showText(response.getByte(k) + "\t");
              rcount++;
              if (rcount % RND_PER_ROW == 0) rrnd.showText("\n");
            }  // for
          }  // if
        }  // for

        rrnd.showText("\ndeactivate smart card\n");
        SmartCard.shutdown();
      } // if
      else
        rrnd.showText("\n\ncould not create smart card object (e.g. no ICC in IFD)\n");
    } // try
    catch (Exception except) {
      rrnd.showText("\n\nCaught exception '" + except.getClass() + "' - " + except.getMessage() );
    } // catch
  } // main
} // class




ReadRND.java