Package pursejc

Source Code of pursejc.PurseApplet

package pursejc;

import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.OwnerPIN;
import javacard.framework.PINException;
import javacard.framework.Util;

/**
*
* @author C Michoudet, A Vernotte
*
*/

public class PurseApplet extends Applet {
 
  //apdu commands
  public static final byte CLA_PURSEAPPLET = (byte) 0x25;
  public static final byte INS_VERIFY = (byte) 0x01;
  public static final byte INS_CREDIT = (byte) 0x02;
  public static final byte INS_DEBIT = (byte) 0x03;
  public static final byte INS_GET_BALANCE = (byte) 0x04;
  private static final byte INS_GET_STATE = (byte) 0x05;
  private static final byte INS_CONFIGURE = (byte) 0x06;

  // maximum wallet balance
  public static final short maxBalance = 10000;

  // maximum transaction amount
  public static final byte maxTrans = 100;
 
  // maximum number of transaction
  public static final byte maxNbTrans = 3;

  // maximum number of incorrect tries before the
  // PIN is blocked
  public static final byte maxUserTries = (byte) 0x03;
  public static final byte maxBankTries = (byte) 0x03;

  // maximum size PIN
  public static final byte MaxPINSize = (byte) 0x04;

  // Applet-specific status words:
  public static final short SW_VERIFICATION_FAILED = 0x6300;
  public static final short SW_PIN_VERIFICATION_REQUIRED = 0x6301;
  public static final short SW_INVALID_TRANSACTION_AMOUNT = 0x6A83;
  public static final short SW_EXCEED_MAXIMUM_BALANCE = 0x6A84;
  public static final short SW_NEGATIVE_BALANCE = 0x6A85;
  public static final short SW_TOO_MUCH_TRANS = 0x6A86;
  public static final short SW_PIN_VERIF_EXCEEDED = 0x6A87;

  // LifeCycleState
  public static final byte LFC_PRE_PERSO = (byte) 0x50;
  public static final byte LFC_USE = (byte) 0x51;
  public static final byte LFC_INVALID = (byte) 0x52;
  public static final byte LFC_DEAD = (byte) 0x53;
 
  /* Attributs */
  private short balance;
  private byte lifeCycleState;
  private short nbTransLeft;
 
  /* Pins */
  OwnerPIN userPin;
  OwnerPIN bankPin;

  /* Constructeur */
  private PurseApplet(byte bArray[], short bOffset, byte bLength) {
    userPin = new OwnerPIN(maxUserTries, MaxPINSize);

    bankPin = new OwnerPIN(maxBankTries, MaxPINSize);

    this.balance = 0;
    nbTransLeft = PurseApplet.maxNbTrans;
    lifeCycleState = PurseApplet.LFC_PRE_PERSO;
   
    userPin.update(new byte[]{0,0,0,0}, (short) 0, (byte)4);
    bankPin.update(new byte[]{0,0,0,0}, (short) 0, (byte)4);
    this.register();
  }

  public static void install(byte bArray[], short bOffset, byte bLength)
      throws ISOException {

    new PurseApplet(bArray, bOffset, bLength);
  }

  public boolean select() {
    if (userPin.getTriesRemaining() == 0)
      return false;

    return true;
  }

  public void deselect() {

    userPin.reset();
    bankPin.reset();

  }

  public void process(APDU apdu) throws ISOException {
    byte[] buffer = apdu.getBuffer();

    if (this.selectingApplet())
      return;

    if (buffer[ISO7816.OFFSET_CLA] != CLA_PURSEAPPLET) {
      ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
    }

    switch (buffer[ISO7816.OFFSET_INS]) {

    case INS_GET_STATE:
      getState(apdu);
      return;
   
    case INS_GET_BALANCE:
      getBalance(apdu);
      return;

    case INS_DEBIT:
      debit(apdu);
      return;

    case INS_CREDIT:
      credit(apdu);
      return;

    case INS_VERIFY:
      verify(apdu);
      return;
     
    case INS_CONFIGURE:
      configure(apdu);
      return;

    default:
      ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
    }
  }
 
  /**
   * La commande configure permet de personnaliser une carte
   * Les deux pin sont envoy�s dans une seule commande
   * les 4 premiers indices correspondent au pin user
   * les 4 derniers indices correspondent au pin bank
   * @param apdu
   */
  private void configure(APDU apdu) {
    byte[] buffer = apdu.getBuffer();

    //verification longueur des pin
    if (buffer[ISO7816.OFFSET_LC] != 8)
      ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
   
    //on verifie qu'il s'agit bien d'un chiffre
    for (byte i = ISO7816.OFFSET_CDATA; i< (ISO7816.OFFSET_CDATA + ISO7816.OFFSET_LC);i++) {
      if (buffer[i] < 0 || buffer[i] > 9)
        ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
    }
   
    lifeCycleState = PurseApplet.LFC_USE;
   
    userPin.update(buffer, (short) ISO7816.OFFSET_CDATA, (byte)4);
    bankPin.update(buffer, (short) (ISO7816.OFFSET_CDATA+4), (byte)4);
  }

  /**
   * Commande qui retourne l'�tat (lifeCycleState)
   * @param apdu
   */
  private void getState(APDU apdu) {
    byte[] buffer = apdu.getBuffer();
    buffer[0] = lifeCycleState;
    apdu.setOutgoingAndSend((short) 0, (short) 1);
  }
 
  /**
   * permet de v�rifier le code pin de l'utilisateur ou de la banque
   * L'utilisateur poss�de 3 essais
   * la banque poss�de 4 essais
   * @param apdu
   */
  private void verify(APDU apdu) {
    byte[] buffer = apdu.getBuffer();

    // receive the PIN data for validation.
    byte byteRead = (byte) (apdu.setIncomingAndReceive());

    // check pin
    // the PIN data is read into the APDU buffer
    // starting at the offset ISO7816.OFFSET_CDATA
    // the PIN data length = byteRead
    if (userPin.check(buffer, ISO7816.OFFSET_CDATA, byteRead) == false)
      ISOException.throwIt(SW_VERIFICATION_FAILED);
  }

  /**
   * permet de cr�diter le solde de la carte
   * verifie d'abord que le nombre de transactions max n'est pas depasse.
   * verifie aussi que le code pin est valide.
   *
   * @param apdu
   */
  private void credit(APDU apdu) {
   
    if (checkNbTrans()) {
   
      if (!userPin.isValidated()) {
        if (userPin.getTriesRemaining() == 0) {
          lifeCycleState = LFC_INVALID;
          ISOException.throwIt(SW_PIN_VERIF_EXCEEDED);
        }
        ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
      }
     
      byte[] buffer = apdu.getBuffer();
 
      // get the number of bytes in the
      // data field of the command APDU
      byte numBytes = buffer[ISO7816.OFFSET_LC];
 
      // recieve data
      // data are read into the apdu buffer
      // at the offset ISO7816.OFFSET_CDATA
      byte byteRead = (byte) (apdu.setIncomingAndReceive());
 
      // error if the number of data bytes
      // read does not match the number in the Lc byte
      if ((numBytes != 1) || (byteRead != 1))
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
 
      // get the credit amount
      byte creditAmount = buffer[ISO7816.OFFSET_CDATA];
 
      // check the credit amount
      if ((creditAmount > maxTrans) || (creditAmount < 0))
        ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
 
      // check the new balance
      if ((short) (balance + creditAmount) > maxBalance)
        ISOException.throwIt(SW_EXCEED_MAXIMUM_BALANCE);
 
      // credit the amount
      balance = (short) (balance + creditAmount);
      nbTransLeft--;
 
      return;

    } else {
      ISOException.throwIt(SW_TOO_MUCH_TRANS);
    }
  }

  /**
   * permet de debiter de l'argent stocke dans la carte
   * verifie d'abord que le nombre de transactions max n'est pas depasse.
   *
   * @param apdu
   */
  private void debit(APDU apdu) {
   
    if (checkNbTrans()) {
   
      byte[] buffer = apdu.getBuffer();
      byte numBytes = (byte) (buffer[ISO7816.OFFSET_LC]);
      byte byteRead = (byte) (apdu.setIncomingAndReceive());
 
      if ((numBytes != 1) || (byteRead != 1))
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
 
      // get debit amount
      byte debitAmount = buffer[ISO7816.OFFSET_CDATA];
 
      // check debit amount
 
      if ((debitAmount > maxTrans) || (debitAmount < 0))
        ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
 
      // check the new balance
      if ((short) (balance - debitAmount) < (short) 0)
        ISOException.throwIt(SW_NEGATIVE_BALANCE);
 
      balance = (short) (balance - debitAmount);
      nbTransLeft--;
   
    }

  }

  /**
   * verifie si le nombre de transition n'est pas maximal
   * si c'est le cas, changement du statut de la carte en DEAD
   *
   * @return resultat test
   */
  private boolean checkNbTrans() {
    if (nbTransLeft < 0) {
      lifeCycleState = LFC_DEAD;
      ISOException.throwIt(SW_TOO_MUCH_TRANS);
      return false;
    } else return true;
  }

 
  /**
   * Pour visualiser le solde de la carte
   * @param apdu
   */
  private void getBalance(APDU apdu) {
   
    byte[] buffer = apdu.getBuffer();
    // inform system that the applet has finished
    // processing the command and the system should
    // now prepare to construct a response APDU
    // which contains data field
    short le = apdu.setOutgoing();
    if ( le < 2 ) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    //informs the CAD the actual number of bytes
    //returned
    apdu.setOutgoingLength((byte)2);
    // move the balance data into the APDU buffer
    // starting at the offset 0
    buffer[0] = (byte)(balance >> 8);
    buffer[1] = (byte)(balance & 0xFF);
    // send the 2-balance byte at the offset
    // 0 in the apdu buffer
    apdu.sendBytes((short)0, (short)2);
   
  }

}
TOP

Related Classes of pursejc.PurseApplet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.