next up previous contents
Next: Schemat hierarchii klas Up: Wykorzystanie kart procesorowych w systemie Previous: Zakończenie   Spis tresci


Przykład kardletu

Specyfikacja JavaCard zawiera przykładową aplikację przeznaczoną do uruchamiania na kartach procesorowych zgodnych z tą specyfikacją. Jest to implementacja prostego elektronicznego portfela. Firma Schlumberger dokonała niewielkich modyfikacji tej aplikacji mających na celu przystosowanie jej do działania na karcie cyberflex. W niniejszym dodatku prezentujemy opatrzony komentarzami kod tej wersji aplikacji.

//
//
// Wallet.java
//
// Ten kod został stworzony przez firmę Schlumberger na podstawie 
// przykładu o nazwie ,,Wallet'' zaprezentowanego przez firmę 
// JavaSoft w dokumentacji specyfikacji Javacard 2.0.
//
//
import javacard.framework.*;
import javacardx.framework.*;

public class Wallet extends javacard.framework.Applet 
{

  /* deklaracje stałych */
  // klasa instrukcji kardletu

  final byte Wallet_CLA =(byte)0x03;

  // kody instrukcji kardletu

  final byte Deposit  = (byte) 0x10; 
  final byte Debit    = (byte) 0x20;
  final byte Balance  = (byte) 0x30; 
  final byte Validate = (byte) 0x40;
  final byte Select   = (byte) 0xA4;

  // maksymalna dozwolona liczba nieudanych prób podania numeru PIN 

  final byte PinTryLimit = (byte) 0x03;

  // maksymalna długość numeru PIN

  final byte MaxPinSize  = (byte) 0x04;

  // kody zakończenia operacji: ujemne saldo oraz błędny numer PIN 

  final short SW_NEGATIVE_BALANCE = (short) 0x6910;
  final short SW_WRONG_PIN        = (short) 0x6BBB;


  /* deklaracje składowych kardletu */ 
  OwnerPIN pin;
  byte balance;
  byte base_balance = 0x20;

  // bufor APDU

  byte buffer[]; 

  // konstruktor kardletu
  
  private Wallet () 
  { 

    // wszystkie obszary pamięci, które kiedykolwiek kardlet będzie 
    // wykorzystywał należy zaalokować w konstruktorze
    
    pin = new OwnerPIN (PinTryLimit, MaxPinSize);
    balance = base_balance; 

    // rejestruje instancję w systemie operacyjnym

    register(); 

  }

  // metoda służąca do tworzenia instancji kardletu
 
  public static void install (APDU apdu) 
  {
    // tworzy instancję kardletu 
    
    new Wallet();

  }

  // metoda służąca do wyboru aktywnej instancji
  
  public boolean select () 
  { 

    // podany wcześniej numer PIN traci ważność, użytkownik będzie musiał 
    // podać go ponownie
   
    pin.reset(); 
  
    // przekazuje wartość TRUE, aby poinformować system operacyjny karty, 
    // że instancja gotowa jest do wykonywania poleceń APDU

    return true; 

  }

  // metoda służąca do wykonania polecenia APDU
  
  public void process (APDU apdu) 
  { 

    // obiekt APDU posiada bufor służący do przechowywania przychodzących 
    // poleceń i wysyłanych odpowiedzi APDU 
   
    buffer = apdu.getBuffer(); 

    // polecenie wybierające aktualny kardlet należy pozostawić systemowi 
    // operacyjnemu karty

    if((buffer[ISO.OFFSET_CLA] == (byte)0) && 
       (buffer[ISO.OFFSET_INS ]== Select))
    {	

      // zgłoszenie wyjątku powoduje wysłanie podanej wartości jako wyniku 
      // polecenia (SW)
   
      ISOException.throwIt(ISO.SW_NO_ERROR);

    }

    // sprawdza, czy polecenie jest odpowiedniej klasy
   
    else if (buffer[ISO.OFFSET_CLA] != Wallet_CLA)  
      ISOException.throwIt(ISO.SW_CLA_NOT_SUPPORTED);

    // na podstawie kodu polecenia wywołuje odpowiednią metodę kardletu
 
    switch (buffer[ISO.OFFSET_INS]) 
    {
      case Balance:   getBalance(apdu); 
                      return; 
      case Debit:     debit(apdu); 
                      return; 
      case Deposit:   deposit(apdu);
                      return;
      case Validate:  validate(apdu);
                      return; 
      default:        ISOException.throwIt (ISO.SW_INS_NOT_SUPPORTED); 
    
    } 

  }

  // metoda służąca do zdeponowania pieniędzy na karcie

  private void deposit (APDU apdu) 
  { 

    // sprawdza, czy podano właściwy numer PIN
    if (!pin.isValidated())
      ISOException.throwIt (ISO.SW_PIN_REQUIRED); 

    // pole Lc nagłówka APDU określa ilość danych znajdujących się w treści 
    // polecenia
   
    byte numBytes = (byte) (buffer[ISO.OFFSET_LC]); 

    // odczytuje dane z bufora APDU, zaczynając od pozycji ISO.OFFSET_CDATA

    byte byteRead = (byte)(apdu.setIncomingAndReceive()); 

    // ilość odczytanych danych powinna pokrywać się z wartością pola Lc 
    // nagłówka APDU
 
    if (byteRead != numBytes) 
      ISOException.throwIt(ISO.SW_WRONG_LENGTH); 

    // zwiększamy saldo o kwotę wyszczególnioną w treści polecenia APDU
   
    balance = (byte)(balance + buffer[ISO.OFFSET_CDATA]); 

    // metoda wykonana poprawnie

    return; 

  }

  // metoda służąca do pobrania pieniędzy z karty

  private void debit (APDU apdu) 
  { 
    // sprawdza, czy podano właściwy numer PIN

    if (!pin.isValidated())
      ISOException.throwIt(ISO.SW_PIN_REQUIRED); 

    // znaczenie instrukcji takie jak w metodzie deposit
    
    byte numBytes = (byte)(buffer[ISO.OFFSET_LC]);
    byte byteRead = (byte)(apdu.setIncomingAndReceive()); 

    if (byteRead != 1) 
      ISOException.throwIt(ISO.SW_WRONG_LENGTH); 

    // jeżeli saldo wychodzi ujemne, to zgłasza wyjątek

    if ((byte)((byte)balance - (byte)buffer[ISO.OFFSET_CDATA]) < (byte)0) 
      ISOException.throwIt(SW_NEGATIVE_BALANCE); 

    // zmniejsza saldo o podaną kwotę
    balance = (byte)(balance - buffer[ISO.OFFSET_CDATA]);

  }

  // metoda służąca do odczytania salda
  
  private void getBalance (APDU apdu) 
  { 
  
    // sprawdza, czy podano właściwy numer PIN

    if (!pin.isValidated())
      ISOException.throwIt(ISO.SW_PIN_REQUIRED); 

    // informuje system operacyjny, że metoda gotowa jest wysłania 
    // odpowiedzi APDU

    apdu.setOutgoing(); 

    // określa ilość danych do wysłania

    apdu.setOutgoingLength((byte)1); 

    // kopiuje dane do wysłania do bufora APDU

    buffer[0] = (byte) balance; 
 
    // wysyła 1 bajt zaczynając od pozycji 0 bufora APDU

    apdu.sendBytes((short)0, (short)1); 
 
  }

  // metoda służąca do weryfikacji numeru PIN

  private void validate (APDU apdu) 
  { 

    // podany przez użytkownika numer PIN znajduje się w treści 
    // polecenia APDU 
   
    byte byteRead = (byte)(apdu.setIncomingAndReceive()); 

    // sprawdza, czy podany numer PIN jest poprawny, jeżeli nie, to 
    // zgłasza odpowiedni wyjątek 
   
    if (!pin.check(buffer, ISO.OFFSET_CDATA, byteRead)) 
      ISOException.throwIt(SW_WRONG_PIN); 

    // w przypadku poprawnego zakończenia metody pole SW odpowiedzi APDU 
    // ma wartość 0x9000

  }

}



Janina Mincer-Daszkiewicz 2001-11-21