UTILIZANDO PINS (Personal Identification Number)

Hoje explicarei como utilizar o PIN Number (Personal Identification Number), trata-se da velha e conhecida Senha que inserimos ao pagar uma conta no caixa do mercado, sacar dinheiro nos caixas eletrônicos, habilitar o SIM Card em um celular, etc.

Java Cards possuem seus próprios mecanismos para armazenar e validar PIN's, você poderá utilizar a classe javacard.framework.OwnerPIN para gerenciar todo processo, desde armazenamento, checagem, bloqueio e desbloqueio, ou se preferir poderá desenvolver uma classe só sua implementando a Interface javacard.framework.PIN.
Vamos ao Código:
  1. package pin_test;  
  2.   
  3. import javacard.framework.*;  
  4.   
  5. public class PinTest extends Applet {  
  6.  /** Número de Tentativas antes do Bloqueio */  
  7.  static private final byte TRY_LIMIT = 0x03;  
  8.  /** Tamanho Máximo do PIN (16 Caracteres) */  
  9.  static private final byte MAX_PIN_SIZE = 0x10;  
  10.    
  11.  /** Instrução para Definição do PIN */  
  12.  static private final byte INS_UPDATE_PIN =  (byte)0x02;  
  13.  /** Instrução para Validação do PIN */  
  14.  static private final byte INS_CHECK_PIN =  (byte)0x04;  
  15.  /** Instrução que Verifica o PIN foi autenticado */  
  16.  static private final byte INS_IS_VALIDATE = (byte)0x06;  
  17.  /** Instrução que Reseta uma Autenticação */  
  18.  static private final byte INS_RESET_PIN =  (byte)0x08;  
  19.  /** Instrução para Desbloqueio do PIN */  
  20.  static private final byte INS_UNLOCK_PIN =  (byte)0x0A;  
  21.  /** Instrução que retorna quantidades de Tentativas */  
  22.  static private final byte INS_GET_REMAIN =  (byte)0x0C;  
  23.    
  24.  /** PIN Number */  
  25.  private OwnerPIN pin;  
  26.    
  27.  /** 
  28.   * Construtor 
  29.   */  
  30.  private PinTest() {  
  31.   //Objeto Persistente  
  32.   this.pin = new OwnerPIN( TRY_LIMIT, MAX_PIN_SIZE );  
  33.  }  
  34.   
  35.  /** 
  36.   * Installer 
  37.   * @param bArray 
  38.   * @param bOffset 
  39.   * @param bLength 
  40.   * @throws ISOException 
  41.   */  
  42.  public static void install  
  43.      (byte bArray[], short bOffset, byte bLength)  
  44.          throws ISOException{  
  45.   new PinTest().register();  
  46.  }  
  47.   
  48.  /** 
  49.   * Processa APDU 
  50.   */  
  51.  public void process(APDU apdu){  
  52.     
  53.   //Acquire Reference IN/OUT  
  54.   byte buffer[] = apdu.getBuffer();  
  55.     
  56.   //On Select  
  57.   if (selectingApplet())  
  58.       ISOException.throwIt(ISO7816.SW_NO_ERROR);  
  59.     
  60.   switch ( buffer[ISO7816.OFFSET_INS] ){  
  61.   //Define um PIN Number  
  62.   case INS_UPDATE_PIN :  
  63.   {  
  64.    //Adquire tamanho do novo PIN  
  65.    byte pinLen = (byte)apdu.setIncomingAndReceive();  
  66.      
  67.    if ( pinLen < (byte)1 || pinLen > MAX_PIN_SIZE )  
  68.     ISOException.throwIt(ISO7816.SW_DATA_INVALID);  
  69.      
  70.    //Redefine PIN  
  71.    pin.update(buffer, ISO7816.OFFSET_CDATA, pinLen);  
  72.      
  73.    ISOException.throwIt(ISO7816.SW_NO_ERROR);  
  74.   }  
  75.   //Autentica um PIN  
  76.   case INS_CHECK_PIN :  
  77.   {  
  78.    //Adquire tamanho do PIN  
  79.    byte pinLen = (byte)apdu.setIncomingAndReceive();  
  80.      
  81.    if ( pinLen < (byte)1 )  
  82.     ISOException.throwIt(ISO7816.SW_DATA_INVALID);  
  83.      
  84.    //Checa PIN  
  85.    if ( !pin.check(buffer, ISO7816.OFFSET_CDATA, pinLen) )  
  86.     ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);  
  87.      
  88.    ISOException.throwIt(ISO7816.SW_NO_ERROR);  
  89.   }  
  90.   //Verifica se Autenticado  
  91.   case INS_IS_VALIDATE :  
  92.   {  
  93.    //Verifica Validade do PIN  
  94.    if ( pin.isValidated() )  
  95.     ISOException.throwIt(ISO7816.SW_NO_ERROR);  
  96.    else  
  97.     ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);  
  98.   }  
  99.   //Reseta Autenticação  
  100.   case INS_RESET_PIN :  
  101.   {  
  102.    pin.reset();  
  103.    ISOException.throwIt(ISO7816.SW_NO_ERROR);  
  104.   }  
  105.   //Desbloqueia um PIN  
  106.   case INS_UNLOCK_PIN :  
  107.   {  
  108.    pin.resetAndUnblock();  
  109.    ISOException.throwIt(ISO7816.SW_NO_ERROR);  
  110.   }  
  111.   //Adquire Quantidades de Erros Remanescentes  
  112.   case INS_GET_REMAIN :  
  113.   {  
  114.    buffer[0] = pin.getTriesRemaining();  
  115.    apdu.setOutgoing();  
  116.    apdu.setOutgoingLength((short)1);  
  117.    apdu.sendBytes((short)0, (short)1);  
  118.    ISOException.throwIt(ISO7816.SW_NO_ERROR);  
  119.   }  
  120.   }//switch end  
  121.     
  122.   //Instrução Desconhecida  
  123.   ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);  
  124.  }  
  125.   
  126. }  
Na Linha 62, iniciamos ou definimos um PIN number, o método update também reseta a quantidade de tentativas do PIN, você pode testar isso com o seguinte APDU:
0x00 0x02 0x00 0x00 0x05 0x01 0x02 0x03 0x04 0x05 (0x7F - Caso esteja no JCWDE).
Esse APDU cria um PIN de 5 números "12345".

Na Linha 76 validamos um PIN, esse procedimento também é conhecido como "Match on Card", pois uma vez definido o PIN ele nunca é exposto e a validação é realizada internamente pelo cartão, utilize o seguinte APDU para testar:
0x00 0x04 0x00 0x00 0x05 0x01 0x02 0x03 0x04 0x05 (0x7F - Caso esteja no JCWDE).
Esse APDU requisita a validação de um PIN de 5 números "12345", caso o PIN seja validado  com sucesso 0x9000 será retornado pelo cartão, do contrário 0x6985 será retornado e o número de tentativas será decrementada em 1.

Na Linha 91 verificamos seu o PIN já foi validado no sistema, utilize o seguinte APDU para testar:
0x00 0x06 0x00 0x00 0x00 (0x7F - Caso esteja no JCWDE).
Caso o PIN já esteja validado o cartão retornará 0x9000, caso contrário 0x6985.

Na Linha 100 resetamos a validação do PIN, utilize o seguinte APDU para testar:
0x00 0x08 0x00 0x00 0x00 (0x7F - Caso esteja no JCWDE).
Esse comando sempre retornará 0x9000.

Na Linha 106 desbloqueamos um PIN, isso reseta o contador de tentativas, geralmente utilizamos esse comando após o usuário efetuar uma validação de PUK (Personal Unlock Key), como nos SIM Cards GSM ou Cartões com Certificados Digitais, utilize o seguinte APDU para testar:
0x00 0x0A 0x00 0x00 0x00 (0x7F - Caso esteja no JCWDE).
Esse comando sempre retornará 0x9000.

Na Linha 112 adquirimos a quantidade de tentativas restantes antes do bloqueio do PIN, utilize o seguinte APDU para testar:
0x00 0x0C 0x00 0x00 0x00 (0x7F - Caso esteja no JCWDE).
Esse comando retornará a quantidade de tentativas restantes seguido do 0x9000, por exemplo 0x03 0x90 0x00 (3 tentativas restantes).

Caso esteja testando no JCWDE, os recursos de persistencia não funcionarão, no caso você não conseguirá testar o recurso de contador de tentativas antes de bloqueio, armanzenamento do número PIN caso feche a aplicação APDU Tool ou resete a simulação. Mais uma vez um cartão Físico ajuda bastante nos teste.
 
Isso foi um artigo curto de como utilizar com eficiencia o recurso de PIN's em suas aplicações Java Card caso esteja se perguntando onde o PUK entra na história:
  1. /** Offset do PUK */  
  2.  static private final byte PUK_OFFSET = 0x00;  
  3.  /** Offset do PIN */  
  4.  static private final byte PIN_OFFSET = 0x01;  
  5.   
  6.  /** PIN Number */  
  7.  private OwnerPIN pins[];  
  8.   
  9.   //No Construtor  
  10.   this.pins = new OwnerPIN[2];  
  11.   this.pins[PUK_OFFSET] =   
  12.    new OwnerPIN( TRY_LIMIT, MAX_PIN_SIZE );  
  13.   this.pins[PIN_OFFSET] =   
  14.    new OwnerPIN( TRY_LIMIT, MAX_PIN_SIZE );  

0 comments:

Post a Comment