ACR1251にAndroid端末を乗せるとFeliCaカードと認識される問題を解決する


はじめに

NFCに興味を持ったので、Androidに搭載されているHost-based Card Emulation機能でなにかしてみようかなと思った。
ハローワールド的なものを作り終わって、さあ動かしてみようとACR1251CL-NTTComに乗せてみたら、TypeA/TypeBカードじゃなくてFeliCaと認識されてしまって、なんかうまく動かない!

という問題の解決を目指します。

この現象は、ちょっと型番忘れちゃったんですがAQUOS Phoneの何かで発生しました。
手持ちのXperiaZ/Z3/XZでは起きていません。
※ただ、XperiaはFeliCaとして認識されてほしい場合は困るかもしれません。TypeBカードとして認識されるので。
※しかしXperiaZ/Z3/XZはNFC-Fに対応してないので、FeliCaとしてACR1251に乗せたい場面が少ないかもしれません。

結論

ACR1251に「E0h 00h 00h 20h 01h 13h」のバイト列を送ると、設定が変わってFeliCaに反応しなくなります。
「E0h 00h 00h 20h 01h 1Fh」を送ると元に戻ります。

何が起きているのか

PCSCのWindCard系APIを使ってNFCカードを触っていると、ATR(Answer To Reset)という値を取得できます。
こいつが、Android端末を乗せたときに「僕FeliCaカードだよー」と叫びます。
具体的には下みたいな値が返ってきます。

3B-8F-80-01-80-4F-0C-A0-00-00-03-06-11-00-3B-00-00-00-00-42

まんなかちょっと後ろのほうに00-3Bと書いてありますが、これがFeliCaカードの証です。
今回は、こうなって欲しくありません。

詳細は不明ですが、なんとなく日本仕様なのかなと思います。

設定変更で解決

http://www.acs-japan.jp/products/258/acr1251-nfc のダウンロードページ最下部にApplication Programming InterfaceというPDFがあります。

これがACR1251の仕様書でして、この中のセクション5.4.12. Set PICC Operating Parameterに書いてあるコマンドを送信することで、反応するカードを選択することができます。

仕様に沿って、FeliCaのみ反応しないように設定すると「E0h 00h 00h 20h 01h 13h」です。
元に戻すには、すべてに反応する「E0h 00h 00h 20h 01h 1Fh」です。

ソースコード全文

ということで、設定変更のソースコード全文は以下です。
前半部分はeternalwindowsさんからお借りしました。(元ネタは参照セクションで)
ありがとうございます。

Visual Studio 2017 15.8.9で動くことを確認しています。

#include <windows.h>
#include <winscard.h>
#include <iostream>

#pragma comment (lib, "winscard.lib")

#define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500) 

int main()
{
    SCARDCONTEXT hContext;
    SCARDHANDLE  hCard;
    LPTSTR       lpszReaderName;
    LONG         lResult;
    DWORD        dwAutoAllocate = SCARD_AUTOALLOCATE;
    DWORD        dwActiveProtocol;
    BYTE bGetFirmwareCommand[] = { 0xE0, 0x00, 0x00, 0x20, 0x01, 0x13 };
    BYTE bOutBuffer[256] = { 0 };
    DWORD dwOutBufferLen = 0;

    lResult = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hContext);
    if (lResult != SCARD_S_SUCCESS) {
        if (lResult == SCARD_E_NO_SERVICE)
            MessageBox(NULL, TEXT("Smart Cardサービスが起動されていません。"), NULL, MB_ICONWARNING);
        return 0;
    }

    lResult = SCardListReaders(hContext, SCARD_ALL_READERS, (LPTSTR)&lpszReaderName, &dwAutoAllocate);
    if (lResult != SCARD_S_SUCCESS) {
        if (lResult == SCARD_E_NO_READERS_AVAILABLE)
            MessageBox(NULL, TEXT("カードリーダが接続されていません。"), NULL, MB_ICONWARNING);
        return 0;
    }

    lResult = SCardConnect(hContext, lpszReaderName, SCARD_SHARE_DIRECT, SCARD_PROTOCOL_UNDEFINED,&hCard, &dwActiveProtocol);
    if (lResult != 
        SCARD_S_SUCCESS) {
        MessageBox(NULL, TEXT("カードリーダへの接続に失敗しました。"), NULL, MB_ICONWARNING);
        return 0;
    }

    lResult = SCardControl(hCard, IOCTL_CCID_ESCAPE_SCARD_CTL_CODE, bGetFirmwareCommand,sizeof(bGetFirmwareCommand), bOutBuffer, sizeof(bOutBuffer), &dwOutBufferLen);
    if (lResult != SCARD_S_SUCCESS) {
        MessageBox(NULL, TEXT("カードリーダへの送信が失敗しました。"), NULL, MB_ICONWARNING);
        return 0;
    }

    SCardDisconnect(hCard, SCARD_LEAVE_CARD);
    SCardFreeMemory(hContext, lpszReaderName);
    SCardReleaseContext(hContext);

    return 0;
}

最後に

TypeAだけ、TypeBだけ、FeliCaだけに、それぞれ反応するように設定を変えると、
今使っているXperia XZだと以下みたいなATRが返ってきます。

TypeA

3B-80-80-01-01

TypeB

3B-F5-91-00-FF-91-81-71-FE-40-00-42-00-01-00-71-76

FeliCa

3B-8F-80-01-80-4F-0C-A0-00-00-03-06-11-00-3B-00-00-00-00-42

みなさんも、設定を変えてLet's HCE Life!!

参照

http://eternalwindows.jp/security/scard/scard02.html
https://tipszone.jp/20140902_introduction-to-nfc/
http://www.acs-japan.jp/products/258/acr1251-nfc