検証環境 : Ubuntu 22.04, ICカードリーダー ACR1251DI / SCM3310
データ読み出しAPI
ACR128U Dual- Interface Reader , API reference
Perlを使う場合
Perlモジュール リファレンス
Chipcard::PCSC - Smart card reader interface library
Chipcard::PCSC::Card - Smart card communication library
ソースコード
#!/usr/bin/perl # Smart Card(MIFARE)よりUIDを / Smart Card(FeliCa)よりIDm PMmを読み出す # サンプルスクリプト # # libpcsc_perl パッケージが必要(Ubuntu 22.04で動作確認済み) # # 次の4種類の読み込み方法サンプル # (01) UID を Transmit で読取り、(02) UID を TransmitWithCheck で読取り # (03) ATS を Transmit で読取り、(04) ATS を TransmitWithCheck で読取り # # 読み出しデータ(APDUフォーマット)の例 ### FeliCaの IDm 8 byte Recv UID = 01 02 03 04 05 06 07 08 90 00 ### FeliCaの PMm 8 byte Recv ATS = 09 0A 0B 0C 0D 0E 0F 10 90 00 ### MIFARE UID 4 byte Recv UID = 01 02 03 04 90 00 ### MIFARE UID 7 byte Recv UID = 01 02 03 04 05 06 07 90 00 use warnings; use strict; use Chipcard::PCSC; print "Read UID/ATS from smart card ( use Chipcard::PCSC::Card )\n"; my $hContext = new Chipcard::PCSC(); die("Can't create the PCSC object\n") unless defined $hContext; # カードリーダーの一覧を得る my @ReadersList = $hContext->ListReaders(); die("Can't get readers' list: $Chipcard::PCSC::errno\n") unless ( defined( $ReadersList[0] ) ); print $#ReadersList + 1 . " reader detected."; if ( $#ReadersList > 0 ) { print "this script use first reader .\n"; } else { print "\n"; } print "target reader = " . $ReadersList[0] . "\n"; # 最初のカードリーダーを開く my $hCard = new Chipcard::PCSC::Card( $hContext, $ReadersList[0] ); die("Can't connect: $Chipcard::PCSC::errno\n") unless defined $hCard; # PICC command : Get Data # 送信データ (APDU format) = Class : 0xff, INS : 0xca, P1 : 0x00(UID)/0x01(ATS), P2 : 0x00, Length : 0x00 # 受信データ (APDU format) = DATA bytes + 0x90 0x00 (読取成功), DATA bytes + 0x63 0x00/0x6a 0x81 (読取エラー) ### (01) # 読取り成功/エラーのリザルトコードも含めて、UIDのバイト配列を取得する方法 my $APDU_Array = $hCard->Transmit( [ 0xff, 0xca, 0x00, 0x00, 0x00 ] ); print " Recv UID = "; foreach my $tmpVal ( @{$APDU_Array} ) { printf( "%02X ", $tmpVal ); } print " : " . ( $#{$APDU_Array} + 1 ) . " byte "; if ( $#{$APDU_Array} < 2 ) { print " : NO DATA "; } print "\n"; ### (02) # 読取り成功/エラーのリザルトコードをチェックした後、UIDのバイト列をテキスト変換した文字列を得る方法 # (リザルトコードは出力されない) ( my $sw, my $APDU_Str ) = $hCard->TransmitWithCheck( "FF CA 00 00 00", "90 00" ); # リザルトコードが [0x90, 0x00] の場合に、$APDU_Str にUIDデータが格納される if ( defined $APDU_Str ) { print " Recv UID = " . $APDU_Str . "\n"; # テキスト形式のUIDをそのまま表示 $APDU_Array = (); $APDU_Array = Chipcard::PCSC::ascii_to_array($APDU_Str); # UIDのバイト列を配列に一旦格納 print " Recv UID = "; foreach my $tmpVal ( @{$APDU_Array} ) { printf( "%02X ", $tmpVal ); } print "\n"; } else { print " Recv UID : NO DATA\n"; } ### (03) # 読取り成功/エラーのリザルトコードも含めて、UID(ATS)のバイト配列を取得する方法 $APDU_Array = $hCard->Transmit( [ 0xff, 0xca, 0x01, 0x00, 0x00 ] ); print " Recv ATS = "; foreach my $tmpVal ( @{$APDU_Array} ) { printf( "%02X ", $tmpVal ); } print " : " . ( $#{$APDU_Array} + 1 ) . " byte "; if ( $#{$APDU_Array} < 2 ) { print " : NO DATA "; } print "\n"; ### (04) # 読取り成功/エラーのリザルトコードをチェックした後、UID(ATS)のバイト列をテキスト変換した文字列を得る方法 # (リザルトコードは出力されない) ( $sw, $APDU_Str ) = $hCard->TransmitWithCheck( "FF CA 01 00 00", "90 00" ); # リザルトコードが [0x90, 0x00] の場合に、$APDU_Str にATSデータが格納される if ( defined $APDU_Str ) { print " Recv ATS = " . $APDU_Str . "\n"; # テキスト形式のUIDをそのまま表示 $APDU_Array = (); $APDU_Array = Chipcard::PCSC::ascii_to_array($APDU_Str); # UIDのバイト列を配列に一旦格納 print " Recv ATS = "; foreach my $tmpVal ( @{$APDU_Array} ) { printf( "%02X ", $tmpVal ); } print "\n"; } else { print " Recv ATS : NO DATA\n"; } $hCard->Disconnect(); $hContext = undef;
Pythonを使う場合
#!/usr/bin/python # sudo apt install python3-pyscard from smartcard.util import toHexString from smartcard.System import readers def main(): print("Read UID/ATS from smart card ( use smartcard.System )") ReaderList = readers() if len(ReaderList) < 1: print("Can't get readers' list\n") return print(str(len(ReaderList)) + " reader detected . ", end="") if len(ReaderList) > 1: print("this script use first reader .") else: print("\n") print("target reader : " + str(ReaderList[0])) try: conn = ReaderList[0].createConnection() conn.connect() except Exception as message: print("Exception : " + str(message)) return try: SendApduList = [0xFF, 0xCA, 0x00, 0x00, 0x00] RecvApduList, sw1, sw2 = conn.transmit(SendApduList) print("Recv UID = " + toHexString(RecvApduList) + " " + hex(sw1)[2:] + " " + hex(sw2)[2:]) SendApduList = [0xFF, 0xCA, 0x01, 0x00, 0x00] RecvApduList, sw1, sw2 = conn.transmit(SendApduList) print("Recv ATS = " + toHexString(RecvApduList) + " " + hex(sw1)[2:] + " " + hex(sw2)[2:]) except Exception as message: print("Exception : " + str(message)) finally: conn.disconnect() main()