CORDEA blog

Android applications engineer

EMV Contactless 対応のクレジットカードから情報を読み取る

クレジットカードやデビットカードには EMV Contactless という非接触決済に対応しているものがあります。

EMV Contactless は NFC を使用しているため、手持ちの Android 端末でカードの情報を読み取る事ができます。
ということでここではカードからカード番号及び有効期限を読み取ってみます。

なお、触れると長くなるのであまり具体的な実装には触れません。Android での実装は下部に Repository の URL を貼っておくので興味があればそちらを見てください。

はじめに

情報を読み取るために、ISO/IEC 14443-4 に定義されている通信プロトコルを介して通信を行います。データへのアクセスには ISO/IEC 7816-4 で定義されている Application Protocol Data Unit (APDU) という通信フォーマットを使用します。

雑に Android での実装の話をすると、IsoDep を使って connect で操作を開始し、transceive でやり取りし、close で終了します。

APDU Commands

Command は以下のように構成されます。

| CLA | INS | P1 | P2 | Lc | Data | Le |

Lc には Data length、Le には Response length を入れます。Response length は Response をすべて取りたい場合は 0 にします。
例えばこのあと出てくる SELECT FILE command の場合

| 00 | A4 | 04 | 00 | Lc | Data | Le |

となります。
P1/P2 は Parameter です。P1 の 04 (00000100) はこの場合 Dedicated File (DF) をその名前によって選択するということになります。詳しくは以下の Table 58 を見てください。

また、Response は以下のように構成されます。

| Data | SW1 | SW2 |

SW1-SW2 で Status を表します。90 00 が成功ステータスです。詳しくは以下の Table 17,18 を見てください。

読み取り

本編です

PSE を選択する

SELECT FILE Command を送信し、Payment System Environment (PSE) を選択します。
PSE の DF Name は "1PAY.SYS.DDF01"、PPSE の場合は "2PAY.SYS.DDF01" です。
サポートしていれば PSE の File Control Information (FCI) が返却されます。これに Application Elementary Files (AEF) の Short File Identifier (SFI) が含まれています。

AEF のレコードを読む

PSE をサポートしているカードのみの手順です。

SFI を使用して READ RECORD Command を送信し、Application Identifier (AID) を取得します。

AID でファイルを選択する

PSE をサポートしていた場合は先に取得した AID を、していなかった場合は直接 AID を指定し選択します。

例えば、Visa のクレジットカード・デビットカードは A0 00 00 00 03 10 10 です。

以下のように SELECT FILE Command を送信します。

| 00 | A4 | 04 | 00 | 07 | A0 00 00 00 03 10 10 | 00 |

Response として Processing Options Data Object List (PDOL) が返却されます。

PDOL を Parse する

返却された PDOL を Parse します。
PDOL は概ね以下のようになります。

 ... 01 01 9F 38 18 9F 66 04 9F 02 06 9F 03 06 9F 1A 02 95 05 5F 2A 02 9A 03 9C 01 9F 37 04 ...

PDOL の開始 Tag は 9F 38 なので、それを探します。

また、開始 Tag の直後は length です。9F 38 18 であれば length は 24 となります。
このことから PDOL は以下のようになります。

9F 66 04 9F 02 06 9F 03 06 9F 1A 02 95 05 5F 2A 02 9A 03 9C 01 9F 37 04

この PDOL は次に送る Command に request として何をどの length で送ればよいかを示しています。

  • 9F 66
    • Terminal Transaction Qualifiers (TTQ)
  • 9F 02
    • Amount, Authorised
  • 9F 03
    • Amount, Other
  • 9F 1A
    • Terminal Country Code
  • 95
    • Terminal Verification Results (TVR)
  • 5F 2A
    • Transaction Currency Code
  • 9A
    • Transaction Date
  • 9C
    • Transaction Type
  • 9F 37
    • Unpredictable Number

以上の Data を指定された length で構築します。
以下はそれぞれの例です。実際はそれぞれの要件等に合わせて構築します。

できたらこれらをくっつけます。

GPO Command を送信する

GET PROCESSING OPTIONS (GPO) Command を送信します。
先程の Data の length を先頭に付けます。

21 28 00 00 ...

Tag (83) をつけます。

83 21 28 00 00 ...

以下のように送信します。

| 80 | A8 | 00 | 00 | 23 | 83 21 28 00 ... | 00 |
Track2 Equivalent Data を Parse する

カード情報が含まれている Data を Parse します。Response として Track2 Equivalent Data が返却されている場合、開始 Tag は 57 です。
返却されていない場合はこちらではなく次を見てください。
57 の直後は length で、delimiter は 'd' です。

以下のようにデータが含まれています。

xx xx ... xx dy yy ...
  • x = カード番号
  • y = 有効期限
AFL を Parse する

ここから最後までは Track2 Equivalent Data ではなく Application File Locator (AFL) が返却された場合の手順です。

AFL の開始 Tag は 94 です。
Data から SFI と start, end の 3 bytes を取得します。

レコードを読む

さきほどの SFI をもとにすべてのレコードを読みます。
P1 として index (start から end まで), P2 として下位 3 bits を 1 0 0 とした SFI をセットします。これは P1 のレコードを読むという意味です。以下の Table 36 を見てください。

Track2 Data を Parse する

返却された Track2 Data を Parse します。開始 Tag は 9F 6B です。
あとは Track2 Equivalent Data と同じです。

終わりに

以上で読み取りまでの流れは終わりです。
結構端折った部分や私自身の知識が甘い部分もあり、調べながらでないとこの記事を読んで実装することは難しいと思いますが、私が実装するときに情報が散らばっていたりしてかなり苦労したので書いておきました。
以下に参考にしたリンクを貼っておきます。すべて非常に参考になるので読んでみてください。

あと実装した Repository も置いておきます。EMV Contactless 対応の Visa と Mastercard 3 枚で動作を確認していますので興味があれば。

github.com