domingo, 19 de dezembro de 2010

Utilizando PIN's (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:
package pin_test;

import javacard.framework.*;

public class PinTest extends Applet {
 /** Número de Tentativas antes do Bloqueio */
 static private final byte TRY_LIMIT = 0x03;
 /** Tamanho Máximo do PIN (16 Caracteres) */
 static private final byte MAX_PIN_SIZE = 0x10;
 
 /** Instrução para Definição do PIN */
 static private final byte INS_UPDATE_PIN =  (byte)0x02;
 /** Instrução para Validação do PIN */
 static private final byte INS_CHECK_PIN =  (byte)0x04;
 /** Instrução que Verifica o PIN foi autenticado */
 static private final byte INS_IS_VALIDATE = (byte)0x06;
 /** Instrução que Reseta uma Autenticação */
 static private final byte INS_RESET_PIN =  (byte)0x08;
 /** Instrução para Desbloqueio do PIN */
 static private final byte INS_UNLOCK_PIN =  (byte)0x0A;
 /** Instrução que retorna quantidades de Tentativas */
 static private final byte INS_GET_REMAIN =  (byte)0x0C;
 
 /** PIN Number */
 private OwnerPIN pin;
 
 /**
  * Construtor
  */
 private PinTest() {
  //Objeto Persistente
  this.pin = new OwnerPIN( TRY_LIMIT, MAX_PIN_SIZE );
 }

 /**
  * Installer
  * @param bArray
  * @param bOffset
  * @param bLength
  * @throws ISOException
  */
 public static void install
     (byte bArray[], short bOffset, byte bLength)
         throws ISOException{
  new PinTest().register();
 }

 /**
  * Processa APDU
  */
 public void process(APDU apdu){
  
  //Acquire Reference IN/OUT
  byte buffer[] = apdu.getBuffer();
  
  //On Select
  if (selectingApplet())
      ISOException.throwIt(ISO7816.SW_NO_ERROR);
  
  switch ( buffer[ISO7816.OFFSET_INS] ){
  //Define um PIN Number
  case INS_UPDATE_PIN :
  {
   //Adquire tamanho do novo PIN
   byte pinLen = (byte)apdu.setIncomingAndReceive();
   
   if ( pinLen < (byte)1 || pinLen > MAX_PIN_SIZE )
    ISOException.throwIt(ISO7816.SW_DATA_INVALID);
   
   //Redefine PIN
   pin.update(buffer, ISO7816.OFFSET_CDATA, pinLen);
   
   ISOException.throwIt(ISO7816.SW_NO_ERROR);
  }
  //Autentica um PIN
  case INS_CHECK_PIN :
  {
   //Adquire tamanho do PIN
   byte pinLen = (byte)apdu.setIncomingAndReceive();
   
   if ( pinLen < (byte)1 )
    ISOException.throwIt(ISO7816.SW_DATA_INVALID);
   
   //Checa PIN
   if ( !pin.check(buffer, ISO7816.OFFSET_CDATA, pinLen) )
    ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
   
   ISOException.throwIt(ISO7816.SW_NO_ERROR);
  }
  //Verifica se Autenticado
  case INS_IS_VALIDATE :
  {
   //Verifica Validade do PIN
   if ( pin.isValidated() )
    ISOException.throwIt(ISO7816.SW_NO_ERROR);
   else
    ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
  }
  //Reseta Autenticação
  case INS_RESET_PIN :
  {
   pin.reset();
   ISOException.throwIt(ISO7816.SW_NO_ERROR);
  }
  //Desbloqueia um PIN
  case INS_UNLOCK_PIN :
  {
   pin.resetAndUnblock();
   ISOException.throwIt(ISO7816.SW_NO_ERROR);
  }
  //Adquire Quantidades de Erros Remanescentes
  case INS_GET_REMAIN :
  {
   buffer[0] = pin.getTriesRemaining();
   apdu.setOutgoing();
   apdu.setOutgoingLength((short)1);
   apdu.sendBytes((short)0, (short)1);
   ISOException.throwIt(ISO7816.SW_NO_ERROR);
  }
  }//switch end
  
  //Instrução Desconhecida
  ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
 }

}
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:
/** Offset do PUK */
 static private final byte PUK_OFFSET = 0x00;
 /** Offset do PIN */
 static private final byte PIN_OFFSET = 0x01;

 /** PIN Number */
 private OwnerPIN pins[];

  //No Construtor
  this.pins = new OwnerPIN[2];
  this.pins[PUK_OFFSET] = 
   new OwnerPIN( TRY_LIMIT, MAX_PIN_SIZE );
  this.pins[PIN_OFFSET] = 
   new OwnerPIN( TRY_LIMIT, MAX_PIN_SIZE );
Um Grande Abraço, e até a Próxima!

2 comentários:

  1. Massao estou tendo alguns problemas quando eu simulo no JCWDE o comando pin.check funciona apenas quando eu uso um PIN 0x01 0x02 0x03 0x04 0x05, ou seja, sequencias como 1234 ou 12345. Você já passou por isso?

    ResponderExcluir

Observação: somente um membro deste blog pode postar um comentário.