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

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

2025年6月25日原文(shkspr.mobi)

概要

  • 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ドライバーがクラッシュするのを見たことがあるから、理論的にはその可能性は常にあるね。

Hacker Newsで議論の続きを見る