マイナンバーカードのパスワード残り試行回数を調べる


最近話題のマイナンバーカード。マイナポータルを用いた申請等で必要なカードで、このカード1つに4つのパスワードがそれぞれ設定されています。
パスワードの設定は各々がマイナンバーカードを受け取る際に設定したはずですが…
これらのパスワードはそれぞれ規定回数以上連続で間違えてしまうとロックされ、このロック解除のために役所へ行かないといけなくなります。

そしてこの度、Japan NFC Reader では Ver 1.0.5 で「マイナンバーカードのパスワードの残り試行回数」を確認できるようになりました。
また、それに伴い Japan NFC Reader のコア部分を MIT Licence で公開しているライブラリ、treastrain/TRETJapanNFCReader でもマイナンバーカードへの対応作業を開始し、このパスワードの残り試行回数を取得する機能も提供しています。

今回はこちらを使って、実際にマイナンバーカードからパスワードの残り試行回数を取得するところまでを試してみます。

なお、この記事を書くために作成したプロジェクトはまるごと GitHub 上で公開しています。もしよろしければ参考にしてください。
treastrain/MyNumberPINRemainingChecker

実機の用意

実際のマイナンバーカードからデータを読み取るので、シミュレーターでは動作しません。iOS 13.0 以降を搭載した「リーダーモード対応NFC」が使える iPhone が必要です。

Swift Package Manager でライブラリを導入する

treastrain/TRETJapanNFCReader はマイナンバーカードの他にも、Suica、PASMO といった交通系ICカード、各種電子マネー、運転免許証の読み取りにも対応しており、少しずつ大きなライブラリとなっています。
今回はマイナンバーカードの読み取り機能のみ利用できればよいので、Swift Package Manager を用いて部分的にライブラリを導入します。

Xcode で iOS App のプロジェクトを作成したら、「File」>「Swift Packages」>「Add Package Dependency...」に進みます。

「Search or enter package repository URL」に「TRETJapanNFCReader」と入力します。

記事執筆時点ではマイナンバーカードに関する機能は Release version に含まれていないので、master ブランチを選択します。

本来であれば、マイナンバーカードの読み取りに関する Product のみにチェックを入れればよいのですが名称が長くて全て表示されないので、どれにもチェックを入れずに「Finish」します。

Target の「Frameworks, Libraries, and Embedded Content」にて、「TRETJapanNFCReader-MIFARE-IndividualNumber」を「Add」します。

※個人番号カード(マイナンバーカード)は英語で「Individual Number Card」となっています。

これで正しくマイナンバーカードに関する Product のみを取り込めました。

Capability と Entitlements の設定

これ以降は基本的に treastrain/TRETJapanNFCReader の README に示されたとおり進めていくだけです。
まず、Signing & Capabilities で「Near Field Communication Tag Reading」を有効にします。これにより、「Near Field Communication Tag Reader Session Formats」が entitlements ファイルに含まれます。

Info.plist の設定

Info.plist に「Privacy - NFC Scan Usage Description」と「ISO7816 application identifiers for NFC Tag Reader Session」を追加します。
「Privacy - NFC Scan Usage Description」には NFC を何のために使用するのかについての説明を、「ISO7816 application identifiers for NFC Tag Reader Session」の配下には以下の AID を記述します。

  • Item 0: D392F000260100000001
  • Item 1: D3921000310001010408
  • Item 2: D3921000310001010100
  • Item 3: D3921000310001010401

コーディング

以上でもろもろの設定はおしまいです。続いてコーディングしていきます。
すべて ViewController.swift に記述します。全文を見たい場合は GitHub 上の treastrain/MyNumberPINRemainingChecker を見たほうが便利かもしれません。

ライブラリをインポートする

まずはライブラリをインポートします。

import UIKit
import TRETJapanNFCReader_MIFARE_IndividualNumber

IndividualNumberReaderSessionDelegate に準拠させる

IndividualNumberReaderSessionDelegate プロトコルに準拠させます。

individualNumberReaderSession(didRead:) はマイナンバーカードからの情報の読み取りが終わると呼ばれるものになります。しかし、今回の目的である「パスワードの残り試行回数を調べる」際には特に使用しません。

japanNFCReaderSession(didInvalidateWithError:) は NFC 通信でのエラーハンドリングに使用します。今回は省略します。

class ViewController: UIViewController, IndividualNumberReaderSessionDelegate {
    // ...

    func individualNumberReaderSession(didRead individualNumberCardData: IndividualNumberCardData) {
        // ...
    }

    func japanNFCReaderSession(didInvalidateWithError error: Error) {
        // ...
    }

    // ...
}

IndividualNumberReader を初期化する

マイナンバーカードの読み取りには IndividualNumberReader を使用します。

var reader: IndividualNumberReader!

override func viewDidLoad() {
    super.viewDidLoad()

    self.reader = IndividualNumberReader(delegate: self)
    // ...
}

パスワードの種別を指定する

treastrain/TRETJapanNFCReader では、マイナンバーカードの4つのパスワードの残り試行回数の取得に対応しています。それは IndividualNumberCardPINType に次のように定義されています。

TRETJapanNFCReader/Sources/MIFARE/IndividualNumber/IndividualNumberCardPINType.swift
public enum IndividualNumberCardPINType {
    /// 署名用電子証明書(公的個人認証 署名用)
    case digitalSignature
    /// 利用者証明用電子証明書(公的個人認証 利用者証明用)
    case userAuthentication
    /// 券面事項入力補助用
    case cardInfoInputSupport
    /// 個人番号カード用(住民基本台帳事務用)
    case individualNumber
}

ここでは、署名用電子証明書のパスワードを取得します。

// ...
self.reader = IndividualNumberReader(delegate: self)
let pinType = IndividualNumberCardPINType.digitalSignature
// ...

IndividualNumberReader.lookupRemainingPIN(pinType:completion:) を呼び出す

以上の準備ができたら、IndividualNumberReader.lookupRemainingPIN(pinType:completion:) を呼び出します。completionInt? に残り試行回数が含まれています。エラーが発生した場合は nil となり、NFC 通信に起因するエラーの場合は先述の japanNFCReaderSession(didInvalidateWithError:) にエラー内容が送られてきます。

// ...
self.reader = IndividualNumberReader(delegate: self)
let pinType = IndividualNumberCardPINType.digitalSignature

self.reader.lookupRemainingPIN(pinType: pinType) { (remaining) in
    if let remaining = remaining {
        print(pinType.description, "残り試行回数:", remaining)
    } else {
        // 取得エラー
    }
}

実行結果

それでは実行してみましょう。以下のように残り試行回数がコンソールに表示されれば成功です。

もしよろしければ GitHub にて Star をしていただけると嬉しいです…!
- treastrain/TRETJapanNFCReader : 今回使用したライブラリ
- treastrain/MyNumberPINRemainingChecker : 今回の記事のために作成したサンプルプロジェクト

環境

  • 開発
    • Xcode Version 11.4.1 (11E503a)
    • Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)
    • macOS Catalina 10.15.4 (19E287)
  • 実機
    • iPhone X (A1902、MQAY2J/A)
    • iOS 13.3.1 (17D50)
    • iPhone 11 Pro (A2215、MWCC2J/A)
    • iOS 13.5 (17F5065a)