🦁

DUKPT暗号とAmazon Payment Cryptograhpy

に公開

みなさんはDUKPT暗号は聞いたことがありますでしょうか?聞いたことがなくてもモバイル系クレジットカード決済の裏側でクレジットカード番号を暗号化しているもの、といわれるとなんとなく身近に感じます。(そんなことないか💦)

AWSではその暗号計算をAPI/CLIベースで行うためのサービスである、Amazon Cryptographyなるものを提供しています。今日はそれを触っていきます。

DUKPT とは

Derived Unique Key Per Transaction の略です。日本語にするとトランザクションごとに派生した固有のカギを使うという意味で、毎回トランザクションごとに異なる暗号鍵でクレジットカード番号が暗号化されるため、万が一鍵が漏洩してもすぐさま暗号通信が覗かれるという攻撃を防ぐことができます。
派生と言っている通り、ベースとなる暗号鍵から特定ロジックをもとに鍵を毎回派生させています。
https://en.wikipedia.org/wiki/Derived_unique_key_per_transaction

本来非常に汎用性の高いアルゴリズムで、クレジット決済以外にも様々な領域での転用が期待できる、と最初聞いたときは感じたのですがそれから10年以上経過しあまりほかの領域で使われるとは聞いていなので寂しいところです。ブロックチェーンの根幹をなすハッシュツリー技術もそうですが、広がりそうで広がらない技術(まぁこれは電子認証局が発行するCertificate Transparencyなんかには使われていますが、まだまだ局地的です)はなぜそうなるのか、なんかについては飲みながら語るにはよいネタです。

Amazon Payment Cryptography とは

前述のDUKPTに限らずクレジット決済では様々な暗号技術が使われています。
https://docs.aws.amazon.com/ja_jp/payment-cryptography/latest/userguide/what-is.html
そのさまざまな暗号アルゴリズムをコーディングすることなく利用できるようになっているサービスです。

さっそくやってみる

まずはチュートリアルをやっていきます。
https://docs.aws.amazon.com/ja_jp/payment-cryptography/latest/userguide/getting-started.html
CVVの生成です。

CVV と CVV2の違い

クレジットカード番号の裏側には3桁の数字が印刷されています。(AMEXなどは4桁)あれを一般的にCVVと呼んでいますが、正確にはCVV2が正しい名称です。CVVというのは今はほとんど利用されていませんが、ICチップではなく磁気ストライプカードに埋め込まれていた数字です。それとほぼ同じ仕組みがICチップ決済でも利用されておりそれがCVV2です。いずれもカード番号と有効期間から暗号処理に基づいて生成されるものになります。カード番号と有効期間の漏洩だけでは決済が行えないようにしている工夫です。

1. 暗号鍵の生成

まずはCVV2生成用の暗号鍵を生成します。なおPayment CryptographyサービスはCLIからのみ操作可能でありマネージメントコンソールからは確認のみが可能です。

aws payment-cryptography create-key --exportable --key-attributes KeyAlgorithm=TDES_2KEY,KeyUsage=TR31_C0_CARD_VERIFICATION_KEY,KeyClass=SYMMETRIC_KEY,KeyModesOfUse='{Generate=true,Verify=true}'

鍵が生成されると鍵単位でARNが作成されます。この辺りはKMSに似ています。

{
    "Key": {
        "KeyArn": "arn:aws:payment-cryptography:us-east-2:111122223333:key/tqv5yij6wtxx64pi",
        "KeyAttributes": {
            "KeyUsage": "TR31_C0_CARD_VERIFICATION_KEY",
            "KeyClass": "SYMMETRIC_KEY",
            "KeyAlgorithm": "TDES_2KEY",
            "KeyModesOfUse": {
                "Encrypt": false,
                "Decrypt": false,
                "Wrap": false,
                "Unwrap": false,
                "Generate": true,
                "Sign": false,
                "Verify": true,
                "DeriveKey": false,
                "NoRestrictions": false
            }
        },
        "KeyCheckValue": "CADDA1",
        "KeyCheckValueAlgorithm": "ANSI_X9_24",
        "Enabled": true,
        "Exportable": true,
        "KeyState": "CREATE_COMPLETE",
        "KeyOrigin": "AWS_PAYMENT_CRYPTOGRAPHY",
        "CreateTimestamp": "2023-06-05T06:41:46.648000-07:00",
        "UsageStartTimestamp": "2023-06-05T06:41:46.626000-07:00"
    }
}

2. CVV2の生成

今度はそのarnを用いてCVV2の生成を行います。

 aws payment-cryptography-data generate-card-validation-data \
    --key-identifier arn:aws:payment-cryptography:ap-northeast-1:917561075114:key/t3nu2trperav7wy \
    --primary-account-number=171234567890123 \
    --generation-attributes CardVerificationValue2={CardExpiryDate=0123}

試しにお使いのクレジットカード番号と有効期限(MMYY)を入力してみてください。お持ちのカードに印刷されているCVV2と異なる番号が生成されます。当然暗号鍵が違うためです。

{
    "KeyArn": "arn:aws:payment-cryptography:ap-northeast-1:917561075114:key/e6bmb477a76rr6e6",
    "KeyCheckValue": "9C5B24",
    "ValidationData": "381"
}

この381がカードに印刷されるわけです。
https://docs.aws.amazon.com/ja_jp/payment-cryptography/latest/userguide/use-cases-issuers.networkfunctions.amex.html
AMEXの4桁の生成やブランド固有のコマンドもそろっています。

3. 決済時における CVV2 の検証

今度は決済時のシミュレーションです。

 aws payment-cryptography-data  verify-card-validation-data \
    --key-identifier arn:aws:payment-cryptography:ap-northeast-1:917561075114:key/t3nu2trperav7wy \
    --primary-account-number=171234567890123 \
    --verification-attributes CardVerificationValue2={CardExpiryDate=0123} \
    --validation-data 381

381があっていると以下がレスポンスとして戻ります。

{
    "KeyArn": "arn:aws:payment-cryptography:ap-northeast-1:917561075114:key/e6bmb477a76rr6e6",
    "KeyCheckValue": "9C5B24"
}

間違っている場合レスポンスは以下となります。

An error occurred (VerificationFailedException) when calling the VerifyCardValidationData operation: Card validation data verification failed.

4. DUKPT暗号鍵生成

では次にDUKPT用暗号鍵生成を行います。

aws payment-cryptography create-key \
    --exportable \
    --key-attributes KeyAlgorithm=TDES_2KEY,KeyUsage=TR31_B0_BASE_DERIVATION_KEY,KeyClass=SYMMETRIC_KEY,KeyModesOfUse={DeriveKey=true}

KeyModesOfUse={DeriveKey=true}となっています。つまりこの鍵から暗号鍵を派生させることを許可する、という意味です。

5. DUKPTによる暗号と復号計算

では最後に派生した鍵で暗号と復号を行います。

aws payment-cryptography-data encrypt-data \
     --key-identifier arn:aws:payment-cryptography:ap-northeast-1:917561075114:key/t3nu2trperav7wyn \
     --plain-text "<クレジットカード番号>" \
     --encryption-attributes 'Dukpt={KeySerialNumber=<16桁の数字>,Mode=ECB}'
{
    "KeyArn": "arn:aws:payment-cryptography:ap-northeast-1:917561075114:key/t3nu2trperav7wyn",
    "KeyCheckValue": "12707F",
    "CipherText": "22D2B0DC1881FCFB"
}

22D2B0DC1881FCFBが暗号化された値です。暗号に用いた鍵はarnで指定したものをベースにKeySerialNumber=<16桁の数字>,Mode=ECBで派生しています。
最後に復号です。派生に用いたシリアル番号とアルゴリズムを入れればまず鍵が復号化されます。次にその復号化された鍵を用いて暗号化された文字列(CipherText)を復号化する。

 aws payment-cryptography-data decrypt-data \
>     --key-identifier arn:aws:payment-cryptography:ap-northeast-1:917561075114:key/t3nu2trperav7wyn \
>     --cipher-text "22D2B0DC1881FCFB" \
>     --decryption-attributes 'Dukpt={KeySerialNumber=1234567890123456,Mode=ECB}'
{
    "KeyArn": "arn:aws:payment-cryptography:ap-northeast-1:917561075114:key/t3nu2trperav7wyn",
    "KeyCheckValue": "12707F",
    "PlainText": "<カード番号>"
}

どうでしょうか?DUKPTを知らない方には複雑に見えますが、DUKPT処理を行ったことがある方には驚くほど簡単なことがわかると思います。

Discussion