EMV-NFC-Paycard-Enrollment 项目常见问题解决方案

EMV-NFC-Paycard-Enrollment 项目常见问题解决方案

EMV-NFC-Paycard-Enrollment A Java library used to read and extract data from NFC EMV credit cards (Android/PCSC). EMV-NFC-Paycard-Enrollment 项目地址: https://gitcode.com/gh_mirrors/em/EMV-NFC-Paycard-Enrollment

项目基础介绍

EMV-NFC-Paycard-Enrollment 是一个用于读取和提取 NFC EMV 信用卡数据的 Java 库。该项目支持在 Android 和 PCSC 平台上使用,旨在帮助开发者轻松地从 NFC EMV 信用卡中提取公共数据。项目的主要编程语言是 Java。

新手使用注意事项及解决方案

1. 如何创建自定义 Provider

问题描述: 新手在使用该项目时,可能会遇到如何创建自定义 Provider 的问题。Provider 是与 NFC EMV 信用卡进行 APDU 交换的关键组件。

解决步骤:

  1. 定义 Provider 类: 创建一个实现 IProvider 接口的类。
  2. 实现 transceive 方法: 该方法用于向 NFC EMV 信用卡发送 APDU 命令并接收响应。
  3. 实现 getAt 方法: 该方法用于获取卡的 ATR(Answer To Reset)或 ATS(Answer To Select)。
public class YourProvider implements IProvider {
    @Override
    public byte[] transceive(final byte[] pCommand) {
        // 实现 APDU 交换逻辑
        return new byte[0]; // 返回响应数据
    }

    @Override
    public byte[] getAt() {
        // 返回卡的 ATR 或 ATS
        return new byte[0];
    }
}

2. 如何配置和使用 EmvTemplate

问题描述: 新手可能会对如何配置和使用 EmvTemplate 类感到困惑,这是读取和解析 NFC EMV 信用卡数据的核心类。

解决步骤:

  1. 创建 Provider 实例: 使用自定义 Provider 类创建一个实例。
  2. 配置 Config 对象: 设置读取选项,如是否启用非接触式读取、是否读取所有 AID 等。
  3. 创建 EmvTemplate 实例: 使用 EmvTemplate.Builder 创建 EmvTemplate 实例,并传入 Provider 和 Config。
  4. 读取卡片数据: 调用 readEmvCard 方法读取卡片数据。
// 创建 Provider
IProvider provider = new YourProvider();

// 配置 Config
Config config = EmvTemplate.Config()
    .setContactLess(true) // 启用非接触式读取
    .setReadAllAids(true) // 读取所有 AID
    .setReadTransactions(true) // 读取所有交易
    .setReadCplc(false) // 不读取 CPLC 数据
    .setRemoveDefaultParsers(false) // 不移除默认解析器
    .setReadAt(true); // 读取 ATR/ATS

// 创建 EmvTemplate
EmvTemplate parser = EmvTemplate.Builder()
    .setProvider(provider) // 设置 Provider
    .setConfig(config) // 设置 Config
    .build();

// 读取卡片数据
EMVCard card = parser.readEmvCard();

3. 在 Android 平台上如何使用 IsoDep 类

问题描述: 在 Android 平台上,新手可能会对如何使用 IsoDep 类来创建 Provider 感到困惑。

解决步骤:

  1. 创建 Provider 类: 创建一个实现 IProvider 接口的类,并使用 IsoDep 类进行 APDU 交换。
  2. 实现 transceive 方法: 使用 IsoDeptransceive 方法发送 APDU 命令并接收响应。
  3. 实现 getAt 方法: 根据 NFC 卡的类型(NFC-A 或 NFC-B)返回相应的历史字节或高层响应。
public class Provider implements IProvider {
    private IsoDep mTagCom;

    @Override
    public byte[] transceive(final byte[] pCommand) throws CommunicationException {
        byte[] response;
        try {
            // 发送 APDU 命令
            response = mTagCom.transceive(pCommand);
        } catch (IOException e) {
            throw new CommunicationException(e.getMessage());
        }
        return response;
    }

    @Override
    public byte[] getAt() {
        // 根据 NFC 卡的类型返回历史字节或高层响应
        return mTagCom.getHistoricalBytes(); // 对于 NFC-A
        // return mTagCom.getHiLayerResponse(); // 对于 NFC-B
    }
}

通过以上步骤,新手可以顺利地使用 EMV-NFC-Paycard-Enrollment 项目读取和提取 NFC EMV 信用卡数据。

EMV-NFC-Paycard-Enrollment A Java library used to read and extract data from NFC EMV credit cards (Android/PCSC). EMV-NFC-Paycard-Enrollment 项目地址: https://gitcode.com/gh_mirrors/em/EMV-NFC-Paycard-Enrollment

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

package br.com.paysmart; import java.util.List; import javax.smartcardio.*; import java.util.*; import java.text.SimpleDateFormat; public class paySmartTest { private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray(); public static String toHexString(byte[] buf) { char[] chars = new char[2 * buf.length]; for (int i = 0; i < buf.length; ++i) { chars[2 * i] = HEX_CHARS[(buf[i] & 0xF0) >>> 4]; chars[2 * i + 1] = HEX_CHARS[buf[i] & 0x0F]; } return new String(chars); } public static byte[] hexStringToByteArray(String s) { s = s.replaceAll("\\W+",""); int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16)); } return data; } public static byte[] concat( byte[]...arrays ) { // Determine the length of the result array int totalLength = 0; for (int i = 0; i < arrays.length; i++) { totalLength += arrays[i].length; } // create the result array byte[] result = new byte[totalLength]; // copy the source arrays into the result array int currentIndex = 0; for (int i = 0; i < arrays.length; i++) { System.arraycopy(arrays[i], 0, result, currentIndex, arrays[i].length); currentIndex += arrays[i].length; } return result; } public static byte[] getCurrentDateAsByteArray( String sFormat ) { SimpleDateFormat sdfDateFormatted = new SimpleDateFormat( sFormat ); Date now = new Date(); String sDate = sdfDateFormatted.format(now); return hexStringToByteArray ( sDate ); } public static byte[] extractTLVFromBuffer( int iTag, byte[] buf ) { //@todo: check size, check 77, etc int i; byte[] bufExtracted = buf; TLV tlvBuf = new TLV( buf, 0 ); if ( iTag <= 0xFF ) { //System.out.println("iTag= "+ iTag + " tlvBuf.type= " + tlvBuf.type + " buf= "+ toHexString( buf ) ); if ( tlvBuf.type == iTag ) { //System.out.println("Found tag = "+ iTag + " " + toHexString( tlvBuf.getValue() ) ); return tlvBuf.getValue(); } else { /* TLV tlvNext = tlvBuf.next; if ( tlvNext != null ) System.out.println( "next = " + toHexString( tlvNext.getDERData() ) ); else System.out.println( "next = NULL" ); while ( tlvNext != null ) { System.out.println("traversing next, looking for "+ iTag ); return extractTLVFromBuffer( iTag, tlvBuf.next.getDERData() ); } */ return extractTLVFromBuffer( iTag, tlvBuf.getValue() ); } } // lookup for iTag else { //@todo double tags /* byte bTag1 = (byte) ( iTag & 0x00FF ); byte bTag2 = (byte) (( iTag & 0xFF00 ) >> 2 ); */ } return buf; } public static String TLVListToString( byte[] bufTLV ) { String sList = ""; int iOffset = 0; int iTLV= 0; System.out.println("[TLVListToString]"); while ( iOffset < bufTLV.length ) { TLV tlvCurrent = new TLV( bufTLV, iOffset ); iTLV++; System.out.println(" TLV[" + iTLV + "].tag = " + tlvCurrent.type ); System.out.println(" TLV[" + iTLV + "].size = " + tlvCurrent.length ); System.out.println(" TLV[" + iTLV + "].value = " + toHexString(tlvCurrent.getValue() ) ); iOffset+= tlvCurrent.getDERData().length; //System.out.println(" TLV["+iTLV+"].DER = " + toHexString(tlvCurrent.getDERData() ) ); System.out.println( iOffset ); System.out.println(); sList += toHexString( tlvCurrent.getValue() ) + "\n"; } return sList; } public static String printAPDU( ResponseAPDU apdu ) { String sAux = apdu.toString() + " data=" + toHexString( apdu.getData() ); return sAux; } public static void main( String[] args ) { try { boolean boolEverythingAsTLV = true; int i; Random RandomNumberGenerator = new Random(); System.out.println("_______________________________________________________"); System.out.println("paySmart EMV Minimalist Terminal v1.0"); System.out.println("www.paySmart.com.br"); System.out.println("_______________________________________________________"); System.out.println(""); for (i=0; i<args.length; i++) System.out.println( "Param " + i + ": "+args[i] ); System.out.println(); if ( args.length < 2 ) { System.out.println(""); System.out.println("usage: paySmartTest #reader AID [Host Port]"); System.out.println(" example1> paySmartTest 0 A0000005551010"); System.out.println(" example2> paySmartTest 1 A000000555E010"); System.out.println(" example3> paySmartTest 1 A0000000041010"); System.out.println(" example4> paySmartTest 1 A0000000041010 10.2.1.1 887"); System.out.println(""); System.out.println("#ERROR# Invalid Params"); System.exit(1); // throw new Exception( "Invalid params" ); } TerminalFactory factory = TerminalFactory.getDefault(); List<CardTerminal> terminals = null; // Display the list of terminals try { terminals = factory.terminals().list(); System.out.println("Smart card readers: "); System.out.println( terminals ); } catch(Exception e) { System.out.println("#ERROR# No readers found"); System.exit(2); //throw new Exception( "No readers found" ); } int iReader=0; // Use the first terminal try { iReader = Integer.parseInt( args[0] ); } catch( Exception e ) { System.out.println("#ERROR# Invalid reader index format '"+args[0]+"'" ); System.exit(3);// throw new Exception( "Invalid reader index '"+args[0]+"'" ); } if ( iReader >= terminals.size() ) { System.out.println("#ERROR# Invalid reader index '"+args[0]+"'. Last valid index is " + (terminals.size()-1) ); System.exit(3); // throw new Exception( "Invalid reader index '"+iReader+"'. Last valid index is "+(terminals.size()-1) ); } CardTerminal terminal = terminals.get( iReader ); // Connect with the card Card card = null; CardChannel channel = null; try { card = terminal.connect("*"); System.out.println(" card: " + card ); channel = card.getBasicChannel(); System.out.println(" ATR=" + toHexString( card.getATR().getBytes() ) ); System.out.println( "" ); } catch( Exception e ) { System.out.println("#ERROR# Cannot connect to card"); System.exit(4); // throw new Exception( "Cannot connect to card" ); } // Send Select Application command //String sAID = "A000000555E010"; // MAIS ACEITO //String sAID = "A0 00 00 05 55 10 10"; String sAID = args[1]; byte[] bufAID = hexStringToByteArray( sAID ); System.out.println( "SELECT (AID = " + toHexString( bufAID ) + ")" ); ResponseAPDU answer = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x04, 0x00, bufAID )); System.out.println( " FCI = "+ toHexString( answer.getData() ) ); System.out.println( "" ); if ( answer.getSW() != 0x9000 ) { System.out.println("#ERROR# Invalid AID '"+sAID+"'" ); System.exit(5); //throw new Exception( "Invalid AID '"+sAID+"'" ); } //Open MEL Application byte[] bufMEL = {(byte) 0x83, 0x00 }; System.out.println( "MEL (MEL = " + toHexString( bufMEL ) + ")" ); answer = channel.transmit( new CommandAPDU(0xBE, 0x12, 0x00, 0x00, bufMEL, 0x00 ) ); System.out.println( " " + printAPDU( answer ) ); //Send GPO byte[] bufPDOL = {(byte) 0x83, 0x00 }; System.out.println( "GPO (PDOL = " + toHexString( bufPDOL ) + ")" ); answer = channel.transmit( new CommandAPDU(0x80, 0xA8, 0x00, 0x00, bufPDOL ) ); System.out.println( " " + printAPDU( answer ) ); byte[] bufAIP = extractTLVFromBuffer( 0x82, answer.getData() ); //byte[] bufAFL = extractTLVFromBuffer( 0x94, answer.getData() ); System.out.println( " AIP = " + toHexString( bufAIP ) ); //System.out.println( " AFL = " + toHexString( bufAIP ) ); System.out.println( "" ); //Send ReadRecord 2 System.out.println( "READ RECORD (SFI=1, REC=2)" ); answer = channel.transmit( new CommandAPDU(0x00, 0xB2, 0x02, 0x0C, 0x3D ) ); //fixed :-( @todo GetResponse System.out.println( printAPDU( answer ) ); byte[] bufExpiryDate = {0x17, 0x01, 0x01}; //Arrays.copyOfRange( answer.getData(), 11, 03 ); System.out.println( " ExpiryDate= " + toHexString( bufExpiryDate ) ); byte [] bufSlice = Arrays.copyOfRange( answer.getData(), 14, answer.getData().length-14 ); byte[] bufPAN = extractTLVFromBuffer( 0x5A, bufSlice ); System.out.println( " PAN = " + toHexString(bufPAN) ); byte[] bufPANSequence = { 0x00 }; // @todo extractTLVFromBuffer( 0x5F34, ... ); System.out.println( " PANSequence = " + toHexString(bufPANSequence) ); System.out.println( "" ); //Send ReadRecord 3 System.out.println( "READ RECORD (SFI=1, REC=3)" ); answer = channel.transmit( new CommandAPDU(0x00, 0xB2, 0x03, 0x0C, 0x43 ) ); //fixed :-( @todo GetResponse System.out.println( printAPDU( answer ) ); byte[] bufSlice2 = Arrays.copyOfRange( answer.getData(), 2, answer.getData().length-2 ); byte[] bufTrack2 = extractTLVFromBuffer( 0x57, bufSlice2 ); System.out.println( " Track2= " + toHexString( bufTrack2 ) ); System.out.println( ); byte[] bufAmountAuthorized = hexStringToByteArray ("00 00 00 00 00 00"); // 9F02 06 ;$0.00 (assuming currency exponent = 2) byte[] bufAmountOther = hexStringToByteArray ("00 00 00 00 00 00"); // 9F03 06 ;$0.00 (assuming currency exponent = 2) byte[] bufTermCountryCode = hexStringToByteArray ("00 76"); // 9F1A 02 ;Brazil byte[] bufTVR = hexStringToByteArray ("00 00 00 08 00"); // 95 05 ;Merchant forced transaction to go online byte[] bufTxCurrencyCode = hexStringToByteArray ("09 86"); // 5F2A 02 ;Brazilian Reals (BRL) byte[] bufTxDate = getCurrentDateAsByteArray("yyMMdd"); // 9A 03 ;04.SET.2014 byte[] bufTxType = hexStringToByteArray ("00"); // 9C 01 ;Goods & services byte[] bufUN = new byte[4]; RandomNumberGenerator.nextBytes(bufUN); // 9F37 04 ;Unpredictable Number System.out.println( " [Transaction Parameters]"); System.out.println( " AmountAuthorized= "+ toHexString( bufAmountAuthorized ) ); System.out.println( " AmountOther= "+ toHexString( bufAmountOther ) ); System.out.println( " TCC= "+ toHexString( bufTermCountryCode ) ); System.out.println( " TVR= "+ toHexString( bufTVR ) ); System.out.println( " TxDate= "+ toHexString( bufTxDate ) ); System.out.println( " TxType= "+ toHexString( bufTxType ) ); System.out.println( " UN= "+ toHexString( bufUN ) ); System.out.println( ""); byte[] bufTxData = concat ( bufAmountAuthorized, bufAmountOther, bufTermCountryCode, bufTVR, bufTxCurrencyCode, bufTxDate, bufTxType, bufUN ); System.out.println( "GenerateAC (TxData= " + toHexString( bufTxData ) + ")" ); answer = channel.transmit( new CommandAPDU( 0x80, 0xAE, 0x40, 0x00, bufTxData ) ); System.out.println( printAPDU( answer ) ); System.out.println( "" ); // get 9F27, 9F36, 9F10, 9F26 byte[] bufResponse = Arrays.copyOfRange( answer.getData(), 2, answer.getData().length ); byte[] bufBit55 = concat( hexStringToByteArray ("82 02"), bufAIP, hexStringToByteArray ("84 07"), bufAID, hexStringToByteArray ("9F1A 02"), bufTermCountryCode, hexStringToByteArray ("95 05"), bufTVR, hexStringToByteArray ("9C 01"), bufTxType, hexStringToByteArray ("9F37 04"), bufUN, bufResponse ); if ( boolEverythingAsTLV ) { bufBit55 = concat( hexStringToByteArray ("5F34 01"), bufPANSequence, hexStringToByteArray ( "5A 08"), bufPAN, //hexStringToByteArray ("5F34 01"), bufPANSequence, hexStringToByteArray ("9F02 06"), bufAmountAuthorized, hexStringToByteArray ("9F03 06"), bufAmountOther, hexStringToByteArray ("5F2A 02"), bufTxCurrencyCode, hexStringToByteArray ( "9A 03"), bufTxDate, bufBit55 ); } System.out.println( "Bit55 = "); System.out.println( toHexString( bufBit55 ) ); System.out.println( ); // Disconnect the card card.disconnect(false); /* // Send to host if ( args.length >= 4 ) { String sHost = args[2]; int iPort = Integer.parseInt( args[3] ); SendISOPacket( sHost, iPort, bufPAN, bufAmountAuthorized, bufAmountOther, bufTxCurrencyCode, bufTxDate, bufExpiryDate, bufTermCountryCode, bufTrack2, bufBit55 ); } */ System.exit(0); } catch(Exception e) { System.out.println( "#ERROR#: " + e.toString() ); System.exit(6); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霍曙柏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值