java smart card_如何从Java中读取EMV SmartCard中的PAN

我需要通过智能卡读卡器读取Maestro / Mastercard的帐号.我正在使用Java 1.6及其javax.smartcardio包.我需要发送APDU命令,它会询问存储在卡芯片上的EMV应用程序的PAN号.问题是,我找不到常规的字节数组来构造APDU命令,它会在任何地方返回所需的数据……

解决方法:

您不应该进一步包装APDU. API层应该处理这个问题.

看起来0x6D00响应只是意味着应用程序不支持INS.

现在只是进行故障排除,但您确实是通过选择万事达卡应用程序开始的,对吧?

即这样的事情:

void selectApplication(CardChannel channel) throws CardException {

byte[] masterCardRid = new byte[]{0xA0, 0x00, 0x00, 0x00, 0x04};

CommandAPDU command = new CommandAPDU(0x00, 0xA4, 0x04, 0x00, masterCardRid);

ResponseAPDU response = channel.transmit(command);

return response.getData();

}

标签:apdu,emv,smartcard,java

来源: https://codeday.me/bug/20191004/1852158.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值