世界を動かす技術を、日本語で。

LinuxでのNFCパスポートチップの読み取り

概要

  • Linux環境で パスポートNFCチップ の全データ読取方法を解説
  • pypassport ライブラリを使い、MRZ(機械可読領域)情報の再生成・利用手順を説明
  • キャンセル済みパスポート でもMRZ再構築で読取が可能
  • セキュリティ・ブルートフォースの現実性とリスクを検証
  • 実際の Pythonコード例 とデータ構造、画像保存方法も紹介

LinuxでパスポートNFCチップを読む方法

  • pypassport (https://github.com/roeften/pypassport)を利用したNFCチップ読取手順
  • 必要ライブラリは pyasn1 のみ(pip3 install pyasn1)
  • パスポートの MRZ(Machine Readable Zone) がパスワードとして機能
  • NFCリーダーにパスポートをかざし、Pythonスクリプトで全データ読取
    • pypassportとリーダーの連携方法
    • epassport.EPassportクラスによるデータ取得

キャンセル済みパスポートのMRZ再構築

  • MRZは パスポート番号、誕生日、有効期限 +各チェックサムで構成
    • チェックサム計算は ICAO 9303 規格 Appendix A参照
  • 一部が切り取られていても、 必要情報が分かれば再生成可能
  • PythonによるMRZ生成スクリプト例
def calculateChecksum(value):
    weighting = [7,3,1]
    characterWeight = {'0':0, '1':1, ... 'Z':35, '<':0}
    counter = 0
    result = 0
    for x in value:
        result += characterWeight[str(x)] * weighting[counter%3]
        counter += 1
    return str(result%10)

def calculateMRZ(passportNumber, DOB, expiry):
    passportCheck = calculateChecksum(passportNumber)
    DOBCheck = calculateChecksum(DOB)
    expiryCheck = calculateChecksum(expiry)
    mrzNumber = passportNumber + passportCheck + DOB + DOBCheck + expiry + expiryCheck
    mrzCheck = calculateChecksum(mrzNumber).zfill(2)
    mrz = passportNumber + passportCheck + "XXX" + DOB + DOBCheck + "X" + expiry + expiryCheck + "<<<<<<<<<<<<<<" + mrzCheck
    return mrz

セキュリティ・ブルートフォースの現実性

  • パスポートNFCは 公開鍵暗号 で守られているが、チップ自体にタイマーや試行制限なし
  • MRZの組み合わせは膨大(例:1E24通り以上)で 事実上ブルートフォースは非現実的
  • 誕生日・有効期限などが分かる場合のみ、数日かけてブルートフォースは理論上可能
  • チップは 読み取り回数制限 や自己破壊機能は(仕様上)ないが、証拠は未確認

データ構造とバイオメトリクス

  • チップ内データは Data Group で管理
    • 例:'60'(メタデータ)、'61'(DG1, MRZ情報)、'75'(DG2~DG4, バイオメトリクス)
  • 顔画像や特徴点(Feature Points)、性別、髪色、顔向きなどのメタデータ保存
  • 画像は JPEGまたはJPEG2000 で高圧縮、小容量(例:19KB)

顔画像の保存方法

  • バイトデータを直接ファイル保存
photo = ep["75"]["A1"]["5F2E"]
with open("photo.jpg", "wb") as f:
    f.write(photo)

他ツールの検証と注意点

  • mrtdreader :NFCデバイス認識せず動作不可
  • Jean-Francois Houzard/pyPassport :Python2専用
  • beaujean's pyPassport :脆弱性テストのみ
  • d-Logic ePassport :専用ハードウェア必須
  • Android用tananaev's passport-reader :Androidのみ対応、Linux不可

実用性とリスク

  • MRZが読めれば、 パスポート内情報の取得は迅速かつ容易
  • 取得できる情報は 現物パスポートで目視可能な範囲 とほぼ同等
  • MRZが失われても、印字情報から再構築可能
  • 偽造・無効パスポート検出やブラックリスト照会は不可
  • 長距離リーダーや高出力装置による 盗聴リスク も理論上存在
  • 一般的な個人利用や検証には 十分実用的

まとめ

  • Linuxで pypassport を利用すれば、NFCパスポートの全データ取得が可能
  • MRZが一部欠損しても再構築で問題なし
  • セキュリティ面では ブルートフォースは非現実的、情報取得リスクは限定的
  • パスポートの個人情報確認や検証 用途には最適な手法

Hackerたちの意見

うーん、結局、彼がチェックサムが欠けているパスポートを復号化できたかどうか言ってないし、欠けてるのがどうでもいいのか、残りの情報からチェックサムを計算するのが簡単だからなのか、それにどれくらい時間がかかるのかもわからない。見逃したのかな、それとも役立つ情報が省かれてるの?

OPです。欠けているチェックサムを作るのは簡単です。詳しくはここに書いてあります。https://shkspr.mobi/blog/2025/06/reading-nfc-passport-chips-...

ちょっと待って。じゃあ、何が止めてるの?カスタムの写真とメタデータをランダムなチップにアップロードして、偽のパスポートに埋め込むことを?

良心

こんなに頻繁に行われてることを考えると、あんまり?

データはパスポート発行機関の秘密鍵で署名されてるから、公式のパスポートみたいに反応するチップを作ることはできるよ。国境警備員が署名が無効だって気づいたら、ただのいたずらだって説明すれば、みんなで楽しく笑えるよね。

既に言ったように、データは署名されてるし、プロトコルはインタラクティブでパスポート文書専用だから、どんなプログラム可能なNFCタグにも載せられないよ。パスポートプロトコルを実装したプログラム可能なものを買えるとは思えないけど、プロトコルを実装できる汎用のプログラム可能なものが見つかるかもしれない。さらに、チップが認証されるためのオプションのサブプロトコルもあって(つまり、秘密鍵を知っている証明)、これが有効な署名データを別のチップにコピーするのを防いでるんだ。

イギリスみたいな国は、オンラインAPIを通じて簡単に確認できるeビザ(シェアコード)の公開データベースを持ってるから、少なくともいくつかの外国政府はパスポートデータを相互に検証できるかもしれないね。

パスポートリーダーシステムを壊すチップを作れるかどうか気になるな。それができたら本当に混乱するから、できないことを願ってる。

ボーダーや旅行の職員の前でゼロデイを燃やすなんて、すぐに刑務所行きになるだろうね。

ICAOの文書には完全な仕様が載ってる。まあ、ちょっと複雑で、いろんなビットをいじくる必要があるから、どこかのパスポートリーダーがちゃんとバウンドチェックしてないのは間違いない。でも、ハンマーを使えば似たような効果は得られるよ。

パスポートの読み取りプロセスの特定のステップで、任意のデータを送信できるんだ。妨害の可能性は、読み取りシステムに受信データで悪用できるバグがあるかどうかに依存する。壊れたデータを持つカードを読み取ると、PKCS#11ドライバーがクラッシュするのを見たことがあるから、理論的にはその可能性は常にあるね。

多くのパスポートにはデジタル指紋スキャンも含まれてるけど、アクセスするのはさらに難しいよ。政府だけが持ってるプライベートキーが必要なんだ。

それはかなり理にかなってると思うよ。

政府だけが持ってるものだね :-)

いつも思ってたんだけど、こういう仕様にはパスポート発行者のデジタル署名とかも入ってるんじゃないの?そうじゃないと、他の国はどうやって偽造じゃないって確認するの?この記事を読んだけど、その情報はなんか省かれてるみたい。

パスポートにはデジタル署名とDSC(文書署名証明書)が含まれてる。このDSCは、ICAOの公開鍵ディレクトリからダウンロードできるCSCA証明書によって署名されてるよ。リンクはこちら: https://pkddownloadsg.icao.int/

そうだよ。パスポートが実際にプライベートキーを含んでいるか確認するために、任意のビットに署名するアクティブな機能もあるんだ。そうじゃないと、政府が署名したデータを再生するだけでパスポートを偽造できちゃうからね。ソースとしては、過去にNFCパスポートの暗号機能と互換性のあるブロックチェーン実装に取り組んでたんだ。基本的には、標準のNFCパスポートをコールドウォレットとして使う感じ。面白い事実として、暗号システムは国ごとに異なるんだよ。例えば、オランダはNISTの楕円曲線を信用してないから、代わりにブレインプール曲線を使ってる。確か他の国はまだRSAを使ってるはず。

機械可読旅行文書の仕様は残念ながらあまり簡潔じゃないけど、文書を検証する方法やデータを読み取る詳細に興味があるなら、ICAO 9303を見てみてね。https://www.icao.int/publications/documents/9303_p10_cons_en... https://www.icao.int/publications/documents/9303_p11_cons_en... ただし、これは実装されるべき仕様に過ぎないことを忘れないで。実際の実装は、仕様のクリエイティブな解釈やバグがたくさんあるから、いろんな政府が発行したさまざまな文書と連携するソフトウェアを書くなら、楽しいデバッグセッションが待ってるよ :)

電子旅行認証に移行する国は、みんなこの方法でパスポートを確認するアプリが必要みたい。最近発行された新しいパスポートと最近のスマホがあるのに、このプロセスがめっちゃ面倒なんだ。パスポートをスマホで1分くらいかけて調整して、やっと反応があったら、じっと持って…あ、やり直し…もう一回…はい、今度はパートナーの顔認証サービスを使って…うわ、最悪だ。パスポートのチップがすごく低電力なのか、何か損傷があるのか…でも、これをやるたびに憂鬱になる。

パスポートデータからMRZを生成するためのPythonコードの整理版をここに載せるよ。パディングエラーも修正してある。 https://pastebin.com/k0Tty22a 私のオランダの運転免許証には、下にMRZっぽい1行があるんだけど、国と免許番号をエンコードしているみたいだけど、残りの部分は全然わからない。誰か手がかりある?

オランダ版のドキュメントは見つからなかったけど、この記事にはフランスの運転免許証のMRZの内容が載ってる。オランダのものとも一致するみたいだよ。 https://trustdochub.com/en/mrz-strip-french-driving-licence/...

日付がY2Kセーフじゃないのは変だね(2025年にこれを打ってるなんて信じられない)。

そうだね。実際、1歳の娘のためにUKのETAを記入したばかりなんだけど、MRZの写真を撮った後、申請が「彼女は1924年に生まれたのか2024年に生まれたのか確認してくれ」って聞いてきたよ :-)

これってLinux特有のことなの?WindowsやmacOSでも動きそうに見えるけど。