Driver SmartCard VISA Alpha0.1

GTY_EMV_Chip_MEM_150930_12x5_1600

Hola estoy trabajando en este driver para lectura de tarjetas visa, una de las clases principales que compone este programa es la siguiente:

/*
 * Version 2.0 Revision 1
 *
 * 01/03/2014
 *
 * Copyright 2013-2016 gigaDatta, S.A.
 * Julio Francisco Chinchilla Valenzuela - gigadatta@gmail.com
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 */

package com.gd.creditcard.visa;

import com.gd.creditcard.entitys.CreditCard;
import com.gd.creditcard.tlv.utils.EMVTags;
import com.gd.smartcard.SCardConexion;
import com.gd.utils.ByteConverts;
import com.gd.utils.ByteEngine;
import javax.smartcardio.ATR;

import javax.smartcardio.CardException;

/**
 *
 * @author Julio Chinchilla
 */
public final class VisaSCDataRead extends CreditCard {

    public VisaSCDataRead(int pcsc, String protocol) throws CardException, Exception {
        SCardConexion c = new SCardConexion();
        ATR atr = c.connect(pcsc, protocol);
        setAtr(com.gd.utils.ByteConverts.byteToHex(atr.getBytes()));
        VisaCardCheck checkVisa = new VisaCardCheck(atr);
        if (checkVisa.isVisaCard()) {
            setIssuerData(checkVisa.getIssuerData());
            c.transmit(APDU.VISA);
            byte[] visaData = c.transmit(APDU.RECORD0C).getData();
            c.transmit(APDU.PAYSYSDDF01);
            byte[] paySysData = c.transmit(APDU.RECORD0C).getData();
            scannData(visaData, paySysData);
        } else {
            throw new Exception("No es una tarjeta visa");
        }
    }

    public void scannData(byte[] visaData, byte[] paySysData) {
        setNumber(VisaNumberScanner(visaData));
        setDateExpiration(VisaDateExpireScanner(visaData));
        int cardHolderName = ByteEngine.find(visaData, EMVTags.CardHolderName);
        int trackData = ByteEngine.find(visaData, EMVTags.Track1DiscretionaryData);
        setName(ByteConverts.byteToASCII(visaData,cardHolderName+3,(trackData == -1)?visaData.length-1:trackData-3));
        setPaySys(PaySysScanner(paySysData));
    }

    private String PaySysScanner(byte[] paySysData) {
        int trackData = ByteEngine.find(paySysData, EMVTags.ApplicationPreferredName);
        int applIndicator = ByteEngine.find(paySysData, EMVTags.ApplicationPriorityIndicator);
        return ByteConverts.byteToASCII(paySysData,trackData+3,(trackData+3<applIndicator)?applIndicator-1:paySysData.length-1);
    }

    private String VisaNumberScanner (byte[] data) {
        String num = ByteConverts.byteToHex(data,4,11).replace(" ","");
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < num.length(); i++) {
            sb.append(num.charAt(i));
            if( ((i+1) % 4) == 0) {
                sb.append(" ");
            }
        }
        return sb.toString();
    }

    private String VisaDateExpireScanner (byte[] data) {
        String d = ByteConverts.byteToHex(data,12,14).replace(" ","").substring(1, 5);
        String year = d.substring(0, 2);
        String month = d.substring(2,4);
        return month.concat("/").concat(year);
    }

}

Bancos-en-guatemala1

Como veran es una fase alfa aún en desarrollo, el proyecto se encuentra completo en GitHub VISASmartCardDriver0.1A entre las características del driver es que este cuenta con una lista aún en construcción que posee los emisores de tarjetas visa para Guatemala, en este caso los bancos del país. Entre la lista recavada hasta el momento se encuentran:

0x17 0xB1 BANCO INDUSTRIAL
0x06 0x1B BANRURAL
0x18 0x60 BANRURAL
0x18 0x64 BANRURAL
0x08 0x8B G&T CONTINENTAL
0x15 0x19 BANTRAB

 

/*
 * Version 2.0 Revision 1
 *
 * 01/03/2014
 *
 * Copyright 2013-2016 gigaDatta, S.A.
 * Julio Francisco Chinchilla Valenzuela - gigadatta@gmail.com
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 */
package com.gd.creditcard.cardissuer;

import java.nio.ByteBuffer;
import java.util.Map;
import java.util.TreeMap;

/**
 *
 * @author Julio Chinchilla
 */
public class VISAIssuerDataGTM {

    public final Map<Short, String> IssuerData = new TreeMap<>();

    public VISAIssuerDataGTM() {
        IssuerData.put(ByteBuffer.wrap(new byte[] {(byte)0x17,(byte)0xB1}).getShort(), "BANCO INDUSTRIAL");
        IssuerData.put(ByteBuffer.wrap(new byte[] {(byte)0x06,(byte)0x1B}).getShort(), "BANRURAL");
        IssuerData.put(ByteBuffer.wrap(new byte[] {(byte)0x18,(byte)0x60}).getShort(), "BANRURAL");
        IssuerData.put(ByteBuffer.wrap(new byte[] {(byte)0x18,(byte)0x64}).getShort(), "BANRURAL");
        IssuerData.put(ByteBuffer.wrap(new byte[] {(byte)0x08,(byte)0x8B}).getShort(), "BANRURAL");
        IssuerData.put(ByteBuffer.wrap(new byte[] {(byte)0x17,(byte)0xAE}).getShort(), "G&T CONTINENTAL");
        IssuerData.put(ByteBuffer.wrap(new byte[] {(byte)0x15,(byte)0x19}).getShort(), "BANTRAB");
    }

}

Estos bytes asociados corresponden al ATR de la tarjeta, específicamente a los bytes en las posiciones 9 y 10, los cuales son conocidos como “Issuer Data”, en fín el driver solo lee los datos mas importantes o que he considerado hasta el momento, ya que la data que se recava es mucho más extensa, si quisieran determinar a exactitud los records extraidos en la data, les recomiendo esta herramienta: TLV Utilities. La cual sirve para parsear los extraído en las aplicaciones que posee el chip regidos bajo el estándar EMV.

Este driver recoge información de los AID’s principales de las tarjetas Visa:

card_large

00 A4 04 00 07 A0 00 00 00 03 10 10

00 A4 04 00 0E 31 50 41 59 2E 53 59 53 2E 44 44 46 30 31

 

Y por si se lo preguntan, el código CVV no viene en los records del chip,  ya que por estandar este se genera en base al número de la tarjeta, el emisor y un algoritmo propio del emisor, esto se hace por seguridad.

Java [Twitter4J]: Creación de APP y consumo desde java (Actualización de estado)

Sin título-1-01

Para esta gúia rápida usaremos la api Twitter4J

Paso 1: Dirígete a https://apps.twitter.com/

01

Paso 2: Crea la aplicación y llena los datos solicitados *

02

03

Paso 3: Dirígete a “Keys and Access Tokens”

04

Paso 4: En la sección “Your Access Token” genera los tokens de acceso a la aplicación “Create my access token”. Lo que haces aquí es generar un acceso hacia tu cuenta desde la aplicación.

05

Paso 6: Revisa que tengas tanto como el Key y Secret que son los consumidores de la aplicación, asi como tus tokens de acceso, Access Token y Access Token Secret

06

Una vez hecho esto, utiliza tu ide de confianza, aplicando el siguiente código:

import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.OAuthAuthorization;
import twitter4j.conf.ConfigurationBuilder;


/**
 * @version 1.0
 * Clase que inicia una sesión en Twitter a través de una app, y actualiza
 * el estado con un mensaje deseado
 * @author Julio Chinchilla
 */
public class UpdateStatus {
    private static final String CONSUMER_KEY = "xxx";
    private static final String CONSUMER_SECRET = "xxx";    
    private static final String ACCESS_TOKEN = "xxx";
    private static final String ACCESS_TOKEN_SECRET = "xxx";
	
    public static void main(String[] args) throws TwitterException {
    	ConfigurationBuilder builder = new ConfigurationBuilder();
        builder.setOAuthAccessToken(ACCESS_TOKEN);
        builder.setOAuthAccessTokenSecret(ACCESS_TOKEN_SECRET);
        builder.setOAuthConsumerKey(CONSUMER_KEY);
        builder.setOAuthConsumerSecret(CONSUMER_SECRET);
        OAuthAuthorization auth = new OAuthAuthorization(builder.build());
    	Twitter twitter = new TwitterFactory().getInstance(auth);
        twitter.updateStatus("Hola mundo desde java");
       
    }
}

Obviamente tendrás que llenar las variables: CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET. Con los que generaste cuando configuraste la aplicación.

Y listo, la ejecución del código no deberá traerte ningún problema.

07

JavaScript: Fade In/Out Script After Effects

after-effects-865x505

 

Utiliza este Script para hacer un fadeIn y fadeOut homogenio en todas tus capas. El siguiente Script se usa sobre la propiedad de Opacidad de la capa.

fadeINTime=1; // Tiempo de entrada
fadeOUTTime=1; // Tiempo de salida
if ((fadeIn=(time-inPoint)*(100/fadeINTime)) < 100) {
	transform.opacity=fadeIn;
} else {
	outStart=outPoint-fadeOUTTime;
	if (outStart <= time) {
		transform.opacity=100-(time-outStart)*(100/fadeOUTTime);
	} else {
		transform.opacity=100;
	}
}

JavaScript: Fade Out Script After Effects

after-effects-865x505

Utiliza este Script para hacer un fadeOut homogenio en todas tus capas. El siguiente Script se usa sobre la propiedad de Opacidad de la capa.

fadeOUTTime=1;
velFO=100/fadeOUTTime;
outStart=outPoint-fadeOUTTime;
if (outStart <= time) {
	transform.opacity=100-(time-outStart)*velFO;
} else {
	transform.opacity=100;
}

Utilizando fadeOUTTime con valor “1”, la capa tardará en aparecer “1 segundo”

JavaScript: Fade In Script After Effects

after-effects-865x505Utiliza este Script para hacer un fade un homogenio en todas tus capas. El siguiente Script se usa sobre la propiedad de Opacidad de la capa.

fadeINTime=1; // Tiempo de entrada
velFI=100/fadeINTime;
if ((fadeIn=(time-inPoint)*velFI) < 100) {
	transform.opacity=fadeIn;
} else {
	transform.opacity=100;
}

Utilizando fadeTime con valor “1”, la capa tardará en aparecer “1 segundo”

Contador con expresion After Effects

Sin títuloPara hacer un contador sobre una capa de texto, utilizando únicamente una simple expresión, coloca la siguiente expresión en la capa de texto deseada, específicamente sobre la propiedad “Texto origen”.

contador=parseInt(time);
text.sourceText=contador;

La expresión únicamente obtiene el valor del tiempo, y luego se utiliza la función “parseInt()” para convertir dicho valor a un entero, el cual se representa sobre la variable “contador” y luego esto se aplica a la propiedad “text.sourceText”