2
0

More than 1 year has passed since last update.

libnfc で pn53x-tamashell を使ってみる

Last updated at Posted at 2022-03-20

(Felica/Mifare/NFC チャレンジシリーズ) その他の記事はこちら 「Felica/Mifare/NFC でいろいろ実験」
https://qiita.com/nanbuwks/items/1f416d6e45a87250ee0a


Raspberry Pi で libnfc + PN532 NFC RFID module
https://qiita.com/nanbuwks/items/0c73add503b354774035

にて libnfc を試してみました。これを元に PN532 NFC RFID module を操作するプログラムをかけばいいのですが、なかなか見通しが悪くサンプルプログラム以上のことをしようとしても難しい。

さて、examples の中に pn53x-tamashell というファイルがあり、これは pn53x に直接命令を送れるのかな?

公式のドキュメントなどは見つけることができなかったが、アイスランドの教材らしい pdf が見つかった。

Mifare Ultralight に対してポーリング/読み込み/書き込み/認証/盗聴/エミュレーションを行っています。

ポーリング

pdf で書かれているポーリングのレッスンを試してみます。

コマンド

> 4a0100

と入力すると以下のように待受になります。

4a0100
Tx: 4a  01  00  

Mifare Classic 1K を近づけると以下のように反応がありました。


Rx: 01  01  00  04  08  04  c5  b2  0f  ad  

コマンドの詳細はユーザマニュアル
https://www.nxp.com/docs/en/user-guide/141520.pdf
に記されています。

InListPassiveTarget コマンドとして、4Aを送出、
image.png

ISO/IEC14443 Type A (Mifare) を指定しています。

image.png

返事として以下が返ってきていることがわかります。

  • NbTg 01
  • Tg 01
  • SENS_RES 00 04
  • SEL_RES 08
  • NFCIDLength 04
  • NFCID1 C5 B2 0F AD

AutoColl/AutoPoll

先のコマンドでは FeliCa の検出はできませんでした。FeliCa と Mifare両方対応するために、

「PN532 NFC RFID module + Arduino で FeliCa と Mifare を判別する」
https://qiita.com/nanbuwks/items/a264201dcc0b4e12e72d

の AutoColl/AutoPoll コマンドを試してみます。

に示されています。
image.png

何もない時


6001011011
Tx: 60  01  01  10  11  
Rx: 00  

AutoPoll に Mifair カード が検出された場合


> 6001011011
6001011011
Tx: 60  01  01  10  11  
Rx: 01  10  09  01  00  04  08  04  c5  b2  0f  ad  

01 tg枚
10 カードType:MiFare
09 データ長
01 論理番号
00 04 ATQA (SENS_RES)
08 SAK (SEL_RES)
04 NFCID1 長
c5 b2 0f ad UID (NFCID1)

のカードが検出できています。

AutoPoll に FeliCa カード が検出された場合


> 6001011011
6001011011
Tx: 60  01  01  10  11  
Rx: 01  11  13  01  12  01  01  14  b4  27  6b  11  5a  23  0f  0d  23  04  2f  77  83  ff  
> 
01 Tg枚
11 カードType:FeliCa
13 データ長
01 論理番号
12 POL_RES
01 Response Code
01 14 b4 27 6b 11 5a 23 NFCID2t
0f 0d 23 04 2f 77 83 ff Parameter (PAD)

?? Pad って何かな?

以下のようにすると無限に待ち受けに入ります


60FF011011
Tx: 60  ff  01  10  11  

カードを近づけると返事が返ってきます。


Rx: 01  10  09  01  00  04  08  04  c5  b2  0f  ad  

上記はMifareに反応した場合の返答です。先の返答と同じ値が返ってきてますね。

GetFirmwareVersion

image.png


02
Tx: 02  
Rx: 32  01  06  07  
32 IC:PN532
01 Ver. 1
06 Rev. 6
07 Support ISO18092,ISO/IEC14443 TypeB,ISO/IEC14443 TypeA

データ読んでみる

InDataExchange かな?

image.png

この通り、送ってみます。

最初に鍵を送っておきます。


> 40016004feeffeeffeeff2f3f4f5
40016004feeffeeffeeff2f3f4f5
Tx: 40  01  60  04  fe  ef  fe  ef  fe  ef  f2  f3  f4  f5  
Rx: 00  

次に

> 40013004
40013004
Tx: 40  01  30  04  
Rx: RF Transmission Error

うまくいきません

「ハードウェアハッキングして NFC コントローラの命令を解析する」
https://qiita.com/nanbuwks/items/8baa0408e08812258c95

のようにして、必要なコマンドを調べてみました。
InDataExchange の前に InListPassiveTarget が必要っぽかったので、以下のようにしてみました。


 > 4A0100
4A0100
Tx: 4a  01  00  
Rx: 01  01  00  04  08  04  f2  f3  f4  f5  

このあと鍵 FEEFFEEFFEEFを送ります

> 40016004feeffeeffeeff2f3f4f5
40016004feeffeeffeeff2f3f4f5
Tx: 40  01  60  04  fe  ef  fe  ef  fe  ef  f2  f3  f4  f5  
Rx: 00  

セクタ4を読んでみます


> 40 01 30 04
40 01 30 04
Tx: 40  01  30  04  
Rx: 00  33  30  31  32  33  34  35  36  37  38  00  00  00  00  00  00  

読めました

このRXの中身

00 Status=0x00: terminated successfully
33 30 31 32 33 34 35 36 37 38 00 00 00 00 00 00 DataIn

DataIn はセクターのデータになります

image.png
良く見ると、InDataExchangeの前にInListPassiveTargetを送っている図がありました。
ここでTarget numberを取得しないといけない

なお、一連の操作はタイミングを早くしないとうまくいかなかったです。
カードを置かずに

4A0100
40016004feeffeeffeeff2f3f4f5
40 01 30 04
を連続でコマンド投入して、それからカードを置くと3つ一緒にうまく処理できました。

初期化

32 05 FF 01 FF : RFConfiguration MaxRetries ( MxRtyATR=FF, MxRtyPSL=01, MxRtyPassiveActivation=FF )

14 01 14 01 : SAMConfiguration Mode=Normal mode,TIMEOUT=14, IRQ=driven
4A 01 00 : InListPassiveTarget MaxTg=1,BrTy=106 kbps type A (ISO/IEC14443 Type A)
60 01 01 11 10 : InAutoPoll PollNr =1,Period=1, Type1=0x11 ,Type2=0x10
4A 01 00 E1 00 : InListPassiveTarget MaxTg=1,BrTy=106 kbps type A (ISO/IEC14443 Type A)
40 01 14 06 011606000a1e7703 01 8B 1A 03 80 00 80 02 80 03

スクリプト

見てみると、TAMASHELLはスクリプトエンジンを入っているとかそういうことではなく、単にリダイレクトでパラメータを入れているだけみたいです。
ReadNavigo.sh を元にしてみました。

Mifareを読む

上のものを押し込んでみました。


#!/bin/sh

ID=$(cat << EOF | \
    pn53x-tamashell |\
    grep -A1 "^Tx: 4a  01  00" |\
    sed -e '1d' -e "s/^Rx: 01  ..  ..  ..  ..  ..  \(..  ..  ..  ..\).*/\1/" -e 's/  //g'
# Timeouts
#3205000002
# ListTarget
4a0100
# TypeB' APGEN
#42010b3f80
EOF
)

if [ -z "$ID" ]; then
	echo "Error: can not read ID" >&2
	exit 1
fi
echo $ID



DATA=$(cat << EOF | \
    pn53x-tamashell |\
    grep -A1 "^Tx: 40  01  30" |\
    sed -e '1d' -e "s/^Rx: 00  \(..  ..  ..  ..\).*/\1/" -e 's/  //g'
4A0100
40 01 60 04 FE EF FE EF FE EF $ID
40 01 30 04
EOF
)
if [ -z "$DATA" ]; then
	echo "Error: Can not read sector 4 data" >&2
	exit 1
fi
echo $DATA

実行

$ ReadMifare.sh
f26b7b3e
33303135

TAMASHELLでFeliCa読んでみる

Polling


> 4a  01  01  00  fe  00  01  00 
4a  01  01  00  fe  00  01  00 
Tx: 4a  01  01  00  fe  00  01  00  
Rx: 01  01  14  01  11  16  06  00  0a  1e  77  03  03  32  42  82  82  47  aa  ff  fe  00  

解読すると、

パケット内容 意味
4A 命令:InListPassiveTarget
01 MaxTg = 0x01
01 BrTy = 0x01 : : 212 kbps (FeliCa polling)
00 FE 00 01 00 InitiatorData

となり、InitiatorData は FeliCa のコマンドとなります。

FeliCaコマンドについては、「FeliCa Card User's Manual Excerpted Edition」
を見てみます。
https://www.sony.net/Products/felica/business/tech-support/

00 Polling command
FE00 System Code
01 Request Code=0x01:System code request
00 Time Slot=0x00: Designation of maximum number of slots possible to respond=1

System Code FE00とは何かな?

https://japannfcreader.tret.jp/help-improve-the-app.html
や、
https://gist.github.com/oboenikui/ee9fb0cb07a6690c410b872f64345120
によると、楽天Edy nanaco WAON 大学生協ICプリペイドなどが該当している。
決済機能の付いたものが FE00 になるのかな?

返ってきた返答:


 01  01  14  01  01  01  06  01  67  02  a5  15  03  32  42  82  82  47  aa  ff  fe  00  
パケット内容 意味
01 NbTg
01 Logical number
14 length
01 response code byte
11 16 06 00 0a 1e 77 03 NFCID2t
03 32 42 82 82 47 aa ff PAD
fe 00 System code

Read without Encryption


> 40 01 14 06 01 01 06 01 67 02 a5  15 01 8B 1A 03 80 00 80 02 80 03
40 01 14 06 01 01 06 01 67 02 a5 15 01 8B 1A 03 80 00 80 02 80 03
Tx: 40  01  14  06  01  01  06  01  67  02  a5  15  01  8b  1a  03  80  00  80  02  80  03  
Rx: 00  0c  07  01  01  06  01  67  02  a5  15  01  a6  

40 InDataExchange
01 Tg=01
14 06 01 01 06 01 67 02 a5 15 01 8b 1a 03 80 00 80 02 80 03 Felica DataOut

Felica DataOutの中身

14 Len
06 Cmd:Read without Encryption
01 01 06 01 67 02 a5 15 IDm
01 Number of Service
8b 1A Service Code List
03 Number of Block
80 00 Block List 1
80 02 Block List 2
80 03 Block List 3

Responce

00 Status:successflly?
0c Len
07 01 01 06 01 67 02 a5 15 01 a6 DataIn

DataIn の中身

07 Responce Code
01 01 06 01 67 02 a5 15 Idm
01 Status Flag 1:最初のブロック処理でエラー発生
a6 Status Flag 2:Illegal Service Code List

うーん、エラーで読めてないですね

ここのところだけやり直して

Rx: 00  3d  07  01  01  06  01  67  02  a5  15  00  00  03  30  31  31  30  31  33  30  32  30  39  36  31  00  00  31  31  33  36  30  31  30  30  36  34  32  30  31  33  30  34  30  31  32  30  32  31  30  33  33  31  39  39  39  39  39  39  39  39  

Responce

00 Status:successflly?
3d ?
07 01 01 06 01 67 02 a5 15 00 00 03 30 31 31 30 31 33 30 32 30 39 36 31 00 00 31 31 33 36 30 31 30 30 36 34 32 30 31 33 30 34 30 31 32 30 32 31 30 33 33 31 39 39 39 39 39 39 39 39 DataIn

DataIn の中身

07 Responce Code
01 01 06 01 67 02 a5 15 Idm
00 Status Flag 1
00 Status Flag 2
03 Block num
30 31 32 33 34 35 36 37 38 39 30 31 00 00 31 31 Block1 :"012345678901\0\011"
33 36 30 31 30 30 36 34 32 30 31 33 30 34 30 31 Block2:"3601006420130401"
32 30 32 32 30 33 33 31 39 39 39 39 39 39 39 39 Block3:"20220331999999999"

スクリプト

上のものを押し込んで


#!/bin/sh

ID=$(cat << EOF | \
    pn53x-tamashell |\
    grep -A1 "^Tx: 4a  01  01" |\
    sed -e '1d' -e "s/^Rx: 01  ..  ..  ..  \(..  ..  ..  ..  ..  ..  ..  ..\).*/\1/" -e 's/  //g'
# FeliCa polling
4a010100FE000100
EOF
)

if [ -z "$ID" ]; then
        echo "Error: can not read ID" >&2
        exit 1
fi
echo $ID



DATA=$(cat << EOF | \
    pn53x-tamashell |\
    grep -A1 "^Tx: 40  01  ..  06" |\
    sed -e '1d' -e "s/^Rx: 00  ..  07  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  \(..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..\).*/\1/" -e 's/  //g'
# FeliCa polling
4a010100FE000100
# FeliCa read
40 01 14 06 $ID 01 8b 1a 03 80 00 80 02 80 03
EOF
)
if [ -z "$DATA" ]; then
        echo "Error: Can not read sector 4 data" >&2
        exit 1
fi
echo $DATA

FeliCa polling して、Idmを取得します。
取得したIdm を使って、 8b1a の 8000のブロックを読み込みます。

プログラムでは FeliCa polling で Idm を取得したら pn53x-tamashell が一旦終了して再度呼び出すことになってしまいます。そのときにセッションぽいものが切れてしまい、パラメータエラーとなるので、わざわざ 再度 FeliCa polling をムダにかけています。

また、内部では8000,8002,8003 の3つのブロックを読んでますが表示は8000のみを行っています。

感想

pn53x-tamashell を使うと、直接 pn532 とやりとりができます。
SPI/I2C/シリアル どれに対しても同じ操作でやりとりができます。
チップマニュアルとプロトコルマニュアルを見ながら直接パケットを書けるので、ライブラリの処理がチップのどの処理にあたるのかなどに悩まなくても良くなります。

しかしながら思ったより透過的ではなかったです。エラー時に、エラーパケットを返さずにメッセージだけしか出なかったりするので、はてなーと悩んでしまいます。
結局他の手法でエラーパケットの中身を調べて、マニュアルでエラー番号を参照することも必要になってきます。
結局命令バイト数やチェックサム、プリアンプルなどを計算したり付加したりするのが自動になっているだけのメリットしか無いような。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0