検証環境 : 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()
