ID TECH
すべての技術記事

技術記事

クレジットカードデータの復号方法 第1回

よくいただく質問の一つに、「ID TECH のカードリーダーから取得したトラックデータが暗号化されているのですが、どのように復号すればよいですか?」というものがあります。

答えは、当該トランザクションに対応する適切なセッションキーを取得し、そのキーを用いてデータペイロードを次の方式で復号する、というものです。 Triple-DES (または AESを、状況に応じて使用します)。

復号処理そのものは、拍子抜けするほどシンプルです。既存のオープンソースの TDES または AES 実装の中から、適切なものを利用すれば十分であり(コア暗号ルーチンを自前で実装する必要はありません)、CBC(暗号ブロック連鎖(Cipher Block Chaining))モードで動作させ、初期ベクトルにはすべてゼロのバイトを既定値として使用します。正しい16バイトの復号キーさえあれば、復号処理は容易です。

難しいのはキーの導出です。これを理解するには、ANSI X9.24-1、別名 DUKPT.

DUKPT の世界へようこそ

理解しておくべき重要な点は、カードリーダーでは各トランザクションごとに異なるキーで暗号化されたデータが生成される、ということです。キーは個々のトランザクションに固有であり(ゆえに DUKPT=Derived Unique Key Per Transaction という頭字語になります)、同じキーが二度使われることはありません。その結果、リプレイ攻撃は事実上不可能となります。

DUKPT の仕組みを理解するには、Key Serial Number(KSN)という概念について少し知っておく必要があります。最も重要なポイントは、KSN は10バイトの値で、各トランザクションごとに変化するということです。なぜなら下位21ビットがカウンタを構成しているからです。

Key Serial Number のレイアウト。

覚えておいてください。暗号化されたカードトランザクションには必ず KSN が伴います。KSN は常に10バイトの長さです。そして KSN は常に平文で送信されます。KSN それ自体は機密情報を一切開示しないにもかかわらず、セッションキーの導出には不可欠だからです。

カードリーダーは工場で暗号化用に設定される際、16バイトのキーと10バイトの初期 KSN が注入されます。注入されるキーは、BDK(Base Derivation Key)と呼ばれる、決して注入されることのない極秘キーから導出されます。(1つの BDK から多数のキーを導出できるため、単一の BDK を起源とする一意のキーを数百、あるいは数千台のカードリーダーに注入することが可能ですし、実際よく行われています。)導出処理そのものに KSN が必要となります。KSN にはデバイスのシリアル番号情報(およびその他の各種「ネームスペース」情報)が含まれているため、ある BDK と KSN の組み合わせから生成されたハッシュ(またはキー)は、本質的にそのデバイス固有のものとなります。さらに、これは暗号学的に安全な一方向ハッシュなので、KSN を知っていても元の BDK を逆算することは決してできません。

トランザクションが発生するたびに、カードリーダーは(DUKPT 対応の場合。今日のカードリーダーはほぼすべて対応しています)、現在の KSN 値と IPEK(Initial PIN Encryption Key)と呼ばれるものから一意のキーを生成します。こうして得られる一回限りのセッションキーで、トランザクションデータの機密部分が暗号化されます。

一度暗号化されたトランザクションデータは、認可された送信先(カードイシュアの場合もあります)に到達するまで復号されることはありません。受信側(例えばイシュア)は自身の保有する BDK のコピーと、当該トランザクションの KSN を用いてセッションキーを再導出し、元の(復号された)トランザクションデータを復元します。これは、暗号化する側と復号する側の双方が同じ秘密(BDK)をあらかじめ知っている必要があるため、いわゆる対称型の処理です。受信側には、互いに復号できるように必要な「秘密」を事前に渡してあるという前提です。

IPEK

DUKPT セッションキーを得るための出発点は、必ず IPEK(初期キー)の導出です。これを行うには、元の BDK と KSN を知っている必要があります。(このステップではカウンタをゼロにするため、対象デバイスの任意の KSN であれば何でも使用できます。)

Initial PIN Encryption Key(IPEK)を導出するには、以下を行う必要があります。

1. BDK のサイズが16バイトの場合、いわゆる EDE3 方式で24バイトに拡張します。これは単純に、キーの最初の8バイトをキーの末尾にコピーし、最初と最後の8バイトが同じである24バイトのキーを作る、ということです。

元のキー(16進表記)が次のような場合:

最終的に次のようになるようにします:

2. 10バイトの初期 KSN を、16進値 0xFFFFFFFFFFFFFFE00000 と AND 演算してマスクします。この結果を「マスク済み KSN」と呼びます。

3. 10バイトのマスク済み KSN のうち、最初(つまり左端)の8バイトのみを残して、8バイトの値を作成します。言い換えると、右端の2バイトを切り捨てます。

4. 拡張した24バイトの BDK をキーとして用い、ステップ3で得た8バイトのマスク済み KSN を TDES で暗号化します。初期ベクトルはすべてゼロを使用します。(なお、ここでのデータは8バイトという1ブロック分だけなので、Cipher Block Chaining は意味を持ちません。)このステップで得られる8バイトの暗号文を保持してください。これが16バイト IPEK の左半分になります。

5. IPEK の右半分を得るには、まず元の16バイトの BDK を16進値 0xC0C0C0C000000000C0C0C0C000000000 と XOR 演算します。(多倍長整数演算をサポートするプログラミング言語を使用していれば、これは1行のコードで可能です。そうでなければ、2つの値を断片ごとに段階的に XOR する必要があります。)

6. ステップ5で得た16バイトの値を EDE3 で拡張し、24バイトのキー値を取得します。

7. ステップ6の24バイトのキー値を用いて、ステップ3で得た8バイトのマスク済み KSN を TDES で暗号化します。これが IPEK の右半分になります。

8. IPEK の左半分と右半分を連結します。これで最終的な16バイト IPEK が得られます。

ご自身でコードを実装する場合は、テスト用キー値 0123456789ABCDEFFEDCBA9876543210 と KSN 62994900000000000001 から IPEK を生成してみてください。得られる IPEK は B5610650EBC24CA3CACDD08DDAFE8CE3 となるはずです。

キー管理と暗号化アルゴリズムの違い

ところで、DUKPT では Triple-DES(TDES)が多用されていることにお気づきでしょう。AES が使われることは一切ありません(カードリーダーが暗号化に AES を使う設定であっても同様です)。X9.24 規格では TDES、場合によっては通常の DES を使用すると定められています。DUKPT のキー導出処理は、トランザクションデータの暗号化/復号処理とは完全に独立していることを、明確に理解しておいてください。一方ではキーを導出し、他方ではそのキーを使って TDES または AES のエンコーディングを行うわけです。暗号化ルーチンは、キーがどこから来たのか、どのアルゴリズムで構築されたのかを知らないし気にもしません。重要なのは、キーそのものが正しく機能するかどうかだけです。したがって、解除すべきデータが AES で暗号化されていたとしても、それを解除するために使うキーは DUKPT(内部的には TDES を使用)で導出されることになります。

コードはどこに?

本記事の第2回では、IPEK と KSN を使って実際の DUKPT セッションキーを導出する方法を、かなり詳しく解説します。実際のソースコードもお見せしますので、すべて自分で実装することができます。次回まで待ちきれない方は、当社で人気の 暗号化/復号ツールをぜひご覧ください。これには、第2回で取り上げる DUKPT アルゴリズムの完全に動作する JavaScript 実装が含まれています(オープンソースの TDES および AES 実装も付属)。この Encrypt/Decrypt Tool を使えば、DUKPT キーの導出(PIN、Data、MAC の3バリアントすべて)、データの暗号化/復号(TDES または AES)、各種ハッシュの生成など、さまざまなことが可能です。何より、このツールは単なる Web ページなので、JavaScript をサポートする任意のブラウザ(任意のプラットフォーム)で動作します。

KSNとIPEKからデータバリアントのDUKPTセッションキーを導出したいですか? パートIIへ進む (本記事の続き)