رمزنگاری داده‌های پرداخت برای بازرگانان

API گوگل پی، روش‌های پرداخت را در یک payload امضا شده و رمزگذاری شده PaymentMethodToken برمی‌گرداند. روش‌های پرداخت برگردانده شده یا کارت‌هایی هستند که شامل PAN می‌شوند، یا کارت‌های توکنیزه شده‌ای هستند که شامل PAN دستگاه و رمزنگاری‌ها می‌شوند.

این payload حاوی فیلدی به نام protocolVersion است که به گیرنده‌ی payload می‌گوید کدام اصول رمزنگاری در حال استفاده هستند و فرمت مورد انتظار چیست.

این راهنما اطلاعاتی در مورد نحوه تولید کلید عمومی برای درخواست توکن روش پرداخت رمزگذاری شده و امضا شده توسط گوگل ارائه می‌دهد و مراحل لازم برای تأیید و رمزگشایی توکن را به تفصیل شرح می‌دهد.

این راهنما فقط برای protocolVersion = ECv2 اعمال می‌شود.

از آنجا که اطلاعات کارت پرداخت را مستقیماً دریافت می‌کنید، قبل از ادامه، مطمئن شوید که برنامه شما با PCI DSS سازگار است و سرورهای شما زیرساخت لازم برای مدیریت ایمن اعتبارنامه‌های پرداخت کاربر را دارند.

مراحل زیر مشخص می‌کند که یک یکپارچه‌ساز برای استفاده از بار داده‌ی Google Pay API ECv2 PaymentMethodToken چه کاری باید انجام دهد:

  1. کلیدهای امضای روت گوگل را دریافت کنید.
  2. تأیید کنید که امضای کلید امضای میانی توسط هر یک از کلیدهای امضای ریشه که منقضی نشده‌اند، معتبر است.
  3. تأیید کنید که کلید امضای میانیِ پیلود منقضی نشده باشد.
  4. تأیید کنید که امضای محموله توسط کلید امضای میانی معتبر است.
  5. پس از تأیید امضا، محتویات payload را رمزگشایی کنید.
  6. تأیید کنید که پیام منقضی نشده باشد. برای این کار لازم است بررسی کنید که زمان فعلی کمتر از فیلد messageExpiration در محتوای رمزگشایی شده باشد.
  7. از روش پرداخت موجود در محتوای رمزگشایی شده استفاده کنید و آن را شارژ کنید.

کد نمونه موجود در کتابخانه Tink ما مراحل ۱ تا ۶ را انجام می‌دهد.

ساختار توکن روش پرداخت

پیامی که توسط گوگل در پاسخ PaymentData برگردانده می‌شود، یک شیء JSON سریالی شده و کدگذاری شده با UTF-8 است که کلیدهای آن در جدول زیر مشخص شده است:

نام نوع توضیحات
protocolVersion رشته طرح رمزگذاری یا امضایی را که پیام تحت آن ایجاد شده است، شناسایی می‌کند. این امر به پروتکل اجازه می‌دهد تا در صورت نیاز، با گذشت زمان تکامل یابد.
signature رشته تأیید می‌کند که پیام از گوگل آمده است. این پیام با کد پایه 64 رمزگذاری شده و با ECDSA توسط کلید امضای میانی ایجاد شده است.
intermediateSigningKey شیء یک شیء JSON که شامل کلید امضای میانی از گوگل است. این شیء شامل signedKey به همراه keyValue ، keyExpiration و signatures است. این شیء برای ساده‌سازی فرآیند تأیید امضای کلید امضای میانی، سریال‌سازی شده است.
signedMessage رشته یک شیء JSON که به صورت یک رشته HTML-safe سریالی شده است و شامل encryptedMessage ، ephemeralPublicKey و tag است. این شیء برای ساده‌سازی فرآیند تأیید امضا سریالی شده است.

مثال

در زیر پاسخ توکن روش پرداخت در قالب JSON آمده است:

{
  "protocolVersion":"ECv2",
  "signature":"MEQCIH6Q4OwQ0jAceFEkGF0JID6sJNXxOEi4r+mA7biRxqBQAiAondqoUpU/bdsrAOpZIsrHQS9nwiiNwOrr24RyPeHA0Q\u003d\u003d",
  "intermediateSigningKey":{
    "signedKey": "{\"keyExpiration\":\"1542323393147\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\\u003d\\u003d\"}",
    "signatures": ["MEYCIQCO2EIi48s8VTH+ilMEpoXLFfkxAwHjfPSCVED/QDSHmQIhALLJmrUlNAY8hDQRV/y1iKZGsWpeNmIP+z+tCQHQxP0v"]
  },
  "signedMessage":"{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\\u003d\",\"ephemeralPublicKey\":\"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\\u003d\",\"encryptedMessage\":\"mKOoXwi8OavZ\"}"
}

کلید امضای میانی

کلید intermediateSigningKey یک شیء JSON سریالی شده و کدگذاری شده با UTF-8 است که شامل مقادیر زیر است:

نام نوع توضیحات
signedKey رشته یک پیام کدگذاری شده با base64 که حاوی توضیحات پرداخت کلید است.
signatures رشته تأیید می‌کند که کلید امضای میانی از گوگل آمده است. این کلید با کد base64 رمزگذاری شده و با ECDSA ایجاد شده است.

کلید امضا شده

کلید signedKey یک شیء JSON سریالی شده و کدگذاری شده با UTF-8 است که شامل مقادیر زیر است:

نام نوع توضیحات
keyValue رشته یک نسخه base64 از کلید که در نوع ASN.1 کدگذاری شده است. SubjectPublicKeyInfo در استاندارد X.509 تعریف شده است.
keyExpiration رشته تاریخ و زمان انقضای کلید میانی بر اساس میلی‌ثانیه UTC از زمان شروع. انتگرال‌گیرها هر کلیدی را که منقضی شده باشد، رد می‌کنند.

پیام امضا شده

signedMessage یک شیء JSON سریالی شده و کدگذاری شده با UTF-8 است که شامل مقادیر زیر است:

نام نوع توضیحات
encryptedMessage رشته یک پیام رمزگذاری شده با کد پایه ۶۴ که حاوی اطلاعات پرداخت و برخی فیلدهای امنیتی اضافی است.
ephemeralPublicKey رشته یک کلید عمومی موقت کدگذاری شده با پایه ۶۴ که با کلید خصوصی برای رمزگذاری پیام در قالب نقطه‌ای غیرفشرده مرتبط است. برای اطلاعات بیشتر، به قالب کلید عمومی رمزگذاری مراجعه کنید.
tag رشته یک MAC رمزگذاری شده با پایه 64 از encryptedMessage .

پیام رمزگذاری شده

encryptedMessage رمزگشایی‌شده یک شیء JSON سریالی‌شده و کدگذاری‌شده با UTF-8 است. این JSON شامل دو سطح است. سطح بیرونی شامل فراداده‌ها و فیلدهایی است که برای امنیت گنجانده شده‌اند، در حالی که سطح درونی یک شیء JSON دیگر است که نشان‌دهنده‌ی اعتبارنامه‌ی پرداخت واقعی است.

برای جزئیات بیشتر در مورد encryptedMessage ، به جداول زیر و نمونه‌های شیء JSON مراجعه کنید:

نام نوع توضیحات
messageExpiration رشته تاریخ و زمانی که پیام از زمان epoch به میلی‌ثانیه UTC منقضی می‌شود. یکپارچه‌سازان باید هر پیامی را که منقضی شده است، رد کنند.
messageId رشته یک شناسه منحصر به فرد که پیام را در صورت نیاز به لغو یا یافتن آن در زمان بعدی، شناسایی می‌کند.
paymentMethod رشته نوع اعتبارنامه پرداخت. در حال حاضر، فقط CARD پشتیبانی می‌شود.
paymentMethodDetails شیء خودِ اعتبارنامه‌ی پرداخت. قالب این شیء توسط paymentMethod تعیین می‌شود و در جداول زیر شرح داده شده است.

کارت

ویژگی‌های زیر، اعتبارنامه پرداخت برای روش پرداخت CARD را تشکیل می‌دهند:

نام نوع توضیحات
pan رشته شماره حساب شخصی که از آن برداشت شده است. این رشته فقط شامل ارقام است.
expirationMonth شماره ماه انقضای کارت، که در آن ۱ نشان دهنده ژانویه، ۲ نشان دهنده فوریه و غیره است.
expirationYear شماره سال انقضای چهار رقمی کارت، مانند ۲۰۲۰.
authMethod رشته روش احراز هویت تراکنش کارت.

PAN_ONLY

قطعه کد JSON زیر نمونه‌ای از encryptedMessage کامل برای paymentMethod CARD است. با یک PAN_ONLY authMethod .

{
  "paymentMethod": "CARD",
  "paymentMethodDetails": {
    "authMethod": "PAN_ONLY",
    "pan": "1111222233334444",
    "expirationMonth": 10,
    "expirationYear": 2025
  },
  "gatewayMerchantId": "some-merchant-id",
  "messageId": "some-message-id",
  "messageExpiration": "1759309000000"
}

CRYPTOGRAM_3DS

CARD با استفاده از رمزنگاری امن سه‌بعدی، CRYPTOGRAM_3DS authMethod احراز هویت شده است. این شامل فیلدهای اضافی زیر است:

نام نوع توضیحات
cryptogram رشته یک رمزنگاری امن سه‌بعدی.
eciIndicator رشته این رشته همیشه وجود ندارد. فقط برای تراکنش‌های توکن‌های دستگاه احراز هویت شده در اندروید (CRYPTOGRAM_3DS) مقدار را برمی‌گرداند. این مقدار باید در جریان پردازش پرداخت منتقل شود.

قطعه کد JSON زیر نمونه‌ای از encryptedMessage کامل برای paymentMethod CARD با authMethod CRYPTOGRAM_3DS است:

{
  "paymentMethod": "CARD",
  "paymentMethodDetails": {
    "authMethod": "CRYPTOGRAM_3DS",
    "pan": "1111222233334444",
    "expirationMonth": 10,
    "expirationYear": 2025,
    "cryptogram": "AAAAAA...",
    "eciIndicator": "eci indicator"
    
  },
  
  "messageId": "some-message-id",
  "messageExpiration": "1759309000000"
}

شاخص eci

شبکه کارت ممکن است eciIndicator برای تراکنش‌های توکن‌های دستگاه احراز هویت شده (CRYPTOGRAM_3DS) ارائه دهد.

شما باید مقدار eciIndicator را بدون تغییر یا کدگذاری مجدد، به تراکنش مجوز ارسال کنید؛ در غیر این صورت، تراکنش با شکست مواجه می‌شود. جدول زیر جزئیات مقادیر eciIndicator را نشان می‌دهد.

مقدار eciIndicator شبکه کارت طرف مسئول متد احراز هویت
""(empty) مسترکارت تاجر/خریدار کریپتوگرام_3DS
02 مسترکارت صادرکننده کارت کریپتوگرام_3DS
06 مسترکارت تاجر/خریدار کریپتوگرام_3DS
05 ویزا صادرکننده کارت کریپتوگرام_3DS
07 ویزا تاجر/خریدار کریپتوگرام_3DS
""(empty) شبکه‌های دیگر تاجر/خریدار کریپتوگرام_3DS

هر مقدار ECI دیگری برای VISA و Mastercard که در این جدول وجود ندارد، بازگردانده نخواهد شد.

تأیید امضا

برای تأیید امضاها، که شامل کلید میانی و امضاهای پیام است، موارد زیر مورد نیاز است:

  • الگوریتم مورد استفاده برای ایجاد امضا
  • رشته بایتی که برای ایجاد امضا استفاده می‌شود
  • کلید عمومی که با کلید خصوصی مورد استفاده برای ایجاد امضا مطابقت دارد
  • خود امضا

الگوریتم امضا

گوگل از الگوریتم امضای دیجیتال منحنی بیضوی ( ECDSA ) برای امضای پیام‌ها با پارامترهای زیر استفاده می‌کند: ECDSA روی NIST P-256 با تابع درهم‌سازی SHA-256، همانطور که در FIPS 186-4 تعریف شده است.

امضا

امضا در بیرونی‌ترین سطح پیام گنجانده شده است. این امضا با base64 در قالب بایت ASN.1 کدگذاری شده است. برای اطلاعات بیشتر در مورد ASN.1، به ضمیمه A ابزارهای IETF مراجعه کنید. امضا شامل اعداد صحیح ECDSA r و s است. برای اطلاعات بیشتر، به الگوریتم تولید امضا مراجعه کنید.

در ادامه مثالی از فرمت بایت ASN.1 مشخص شده آمده است که فرمت استاندارد تولید شده توسط پیاده‌سازی‌های ECDSA افزونه رمزنگاری جاوا (JCE) است.

ECDSA-Sig-Value :: = SEQUENCE {
 r INTEGER,
 s INTEGER
}

نحوه ساخت رشته بایت برای امضای کلید امضای میانی

برای اعتبارسنجی امضای کلید امضای میانی در توکن روش پرداخت نمونه، signedStringForIntermediateSigningKeySignature را با فرمول زیر بسازید:

signedStringForIntermediateSigningKeySignature =
length_of_sender_id || sender_id || length_of_protocol_version || protocol_version || length_of_signed_key || signed_key

علامت "||" به معنی الحاق است. هر جزء sender_id ، protocolVersion ، signedKey - باید با UTF-8 کدگذاری شده باشد. signedKey باید رشته‌ای از intermediateSigningKey.signedKey باشد. طول بایت هر جزء در قالب little-endian، ۴ بایت است.

مثال

این مثال از توکن روش پرداخت نمونه زیر استفاده می‌کند:

{
  "protocolVersion":"ECv2",
  "signature":"MEQCIH6Q4OwQ0jAceFEkGF0JID6sJNXxOEi4r+mA7biRxqBQAiAondqoUpU/bdsrAOpZIsrHQS9nwiiNwOrr24RyPeHA0Q\u003d\u003d",
  "intermediateSigningKey":{
    "signedKey": "{\"keyExpiration\":\"1542323393147\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\\u003d\\u003d\"}",
    "signatures": ["MEYCIQCO2EIi48s8VTH+ilMEpoXLFfkxAwHjfPSCVED/QDSHmQIhALLJmrUlNAY8hDQRV/y1iKZGsWpeNmIP+z+tCQHQxP0v"]
  },
  "signedMessage":"{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\\u003d\",\"ephemeralPublicKey\":\"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\\u003d\",\"encryptedMessage\":\"mKOoXwi8OavZ\"}"
}

sender_id همیشه Google و protocol_version ECv2 است.

اگر sender_id Google باشد، signedString مطابق مثال زیر نمایش داده می‌شود:

signedStringForIntermediateSigningKeySignature =
\x06\x00\x00\x00 || Google || | \x04\x00\x00\x00 || ECv2 || \xb5\x00\x00\x00 || {"keyExpiration":"1542323393147","keyValue":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\u003d\u003d"}

نحوه تأیید امضا در signedStringForIntermediateSigningKeySignature

الگوریتم استاندارد تأیید ECDSA زمانی استفاده می‌شود که رشته امضا شده برای امضای کلید امضای میانی مونتاژ شده باشد. برای پروتکل ECv2، باید روی تمام امضاها در intermediateSigningKey.signatures تکرار کنید و سعی کنید هر یک را با کلیدهای امضای منقضی نشده گوگل در keys.json اعتبارسنجی کنید. اگر حداقل یک اعتبارسنجی امضا کار کرد، تأیید را کامل در نظر بگیرید. بعداً از intermediateSigningKey.signedKey.keyValue برای تأیید signedStringForMessageSignature استفاده کنید. گوگل اکیداً توصیه می‌کند که به جای کد تأیید خودتان، از یک کتابخانه رمزنگاری موجود استفاده کنید.

نحوه ساخت رشته بایت برای امضای پیام

برای اعتبارسنجی امضا در توکن روش پرداخت نمونه، signedStringForMessageSignature را با فرمول زیر بسازید:

signedStringForMessageSignature =
length_of_sender_id || sender_id || length_of_recipient_id || recipient_id || length_of_protocolVersion || protocolVersion || length_of_signedMessage || signedMessage

علامت "||" به معنی الحاق است. هر جزء sender_id ، recipient_id ، protocolVersion ، signedMessage - باید با UTF-8 کدگذاری شود. طول بایت هر جزء در قالب little-endian، 4 بایت است. هنگام ساخت رشته بایت، signedMessage تجزیه یا تغییر ندهید. برای مثال، \u003d را با کاراکتر = جایگزین نکنید.

مثال

مثال زیر یک نمونه توکن روش پرداخت است:

{
  "protocolVersion":"ECv2",
  "signature":"MEQCIH6Q4OwQ0jAceFEkGF0JID6sJNXxOEi4r+mA7biRxqBQAiAondqoUpU/bdsrAOpZIsrHQS9nwiiNwOrr24RyPeHA0Q\u003d\u003d",
  "intermediateSigningKey":{
    "signedKey": "{\"keyExpiration\":\"1542323393147\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\\u003d\\u003d\"}",
    "signatures": ["MEYCIQCO2EIi48s8VTH+ilMEpoXLFfkxAwHjfPSCVED/QDSHmQIhALLJmrUlNAY8hDQRV/y1iKZGsWpeNmIP+z+tCQHQxP0v"]
  },
  "signedMessage":"{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\\u003d\",\"ephemeralPublicKey\":\"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\\u003d\",\"encryptedMessage\":\"mKOoXwi8OavZ\"}"
}

sender_id همیشه Google و recipient_id merchant: merchantId است. شناسه merchantId با مقداری که در کنسول گوگل پی و کیف پول (Google Pay & Wallet Console) برای تاجرانی که به محیط عملیاتی (production access) دسترسی دارند، یافت می‌شود، مطابقت دارد.

اگر sender_id Google و recipient_id برابر merchant:12345 باشد، signedString به شکلی که در مثال زیر آمده است، نمایش داده می‌شود:

signedStringForMessageSignature =
\x06\x00\x00\x00 || Google || \x0e\x00\x00\x00 || merchant:12345 || | \x04\x00\x00\x00 || ECv2 || \xd2\x00\x00\x00 || {"tag":"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\u003d","ephemeralPublicKey":"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\u003d","encryptedMessage":"mKOoXwi8OavZ"}

نحوه تأیید امضا در signedStringForMessageSignature

الگوریتم استاندارد تأیید ECDSA هنگام مونتاژ رشته امضا شده استفاده می‌شود. intermediateSigningKey.signedKey.keyValue که در مرحله قبل تأیید شد، برای تأیید signedMessage استفاده می‌شود. گوگل اکیداً توصیه می‌کند که به جای کد تأیید خودتان، از یک کتابخانه رمزنگاری موجود استفاده کنید.

مشخصات طرح رمزگذاری

گوگل از طرح رمزگذاری یکپارچه منحنی بیضوی ( ECIES ) برای ایمن‌سازی توکن روش پرداختی که در پاسخ API گوگل پی برگردانده می‌شود، استفاده می‌کند. این طرح رمزگذاری از پارامترهای زیر استفاده می‌کند:

پارامتر تعریف
روش کپسوله‌سازی کلید

ECIES-KEM، همانطور که در استاندارد ISO 18033-2 تعریف شده است.

  • منحنی بیضوی: NIST P-256 (همچنین در OpenSSL با نام prime256v1 شناخته می‌شود).
  • CheckMode ، OldCofactorMode ، SingleHashMode و CofactorMode برابر با ۰ هستند.
  • فرمت نقطه‌ای فشرده نشده است.
تابع مشتق کلید

مبتنی بر HMAC با SHA-256 ( HKDFwithSHA256 ).

  • نمک نباید داده شود.
  • اطلاعات باید برای نسخه پروتکل ECv2 به صورت ASCII توسط گوگل کدگذاری شوند.
  • ۲۵۶ بیت باید برای کلید AES256 و ۲۵۶ بیت دیگر باید برای کلید HMAC_SHA256 استخراج شود.
الگوریتم رمزگذاری متقارن

DEM2، همانطور که در ISO 18033-2 تعریف شده است

الگوریتم رمزگذاری: AES-256-CTR با IV صفر و بدون لایه گذاری.

الگوریتم MAC HMAC_SHA256 با یک کلید ۲۵۶ بیتی که از تابع استخراج کلید مشتق شده است.

قالب کلید عمومی رمزگذاری

کلید عمومی رمزگذاری و کلید ephemeralPublicKey که در فایل‌های گوگل بازگردانده می‌شوند، با نمایش base64 کلید در قالب نقطه‌ای فشرده نشده قالب‌بندی شده‌اند. این شامل دو عنصر زیر است:

  • یک عدد جادویی که فرمت را مشخص می‌کند (0x04).
  • دو عدد صحیح بزرگ ۳۲ بایتی که مختصات X و Y را در منحنی بیضوی نشان می‌دهند.

این قالب با جزئیات بیشتر در «رمزنگاری کلید عمومی برای صنعت خدمات مالی: الگوریتم امضای دیجیتال منحنی بیضوی (ECDSA)،» ANSI X9.62، ۱۹۹۸، شرح داده شده است.

استفاده از OpenSSL برای تولید کلید عمومی

مرحله ۱: ایجاد کلید خصوصی

مثال زیر یک کلید خصوصی Elliptic Curve مناسب برای استفاده با NIST P-256 تولید می‌کند و آن را در key.pem می‌نویسد:

openssl ecparam -name prime256v1 -genkey -noout -out key.pem

اختیاری: مشاهده کلیدهای خصوصی و عمومی

برای مشاهده کلید خصوصی و عمومی از دستور زیر استفاده کنید:

openssl ec -in key.pem -pubout -text -noout

دستور خروجی مشابه زیر تولید می‌کند:

read EC key
Private-Key: (256 bit)
priv:
    08:f4:ae:16:be:22:48:86:90:a6:b8:e3:72:11:cf:
    c8:3b:b6:35:71:5e:d2:f0:c1:a1:3a:4f:91:86:8a:
    f5:d7
pub:
    04:e7:68:5c:ff:bd:02:ae:3b:dd:29:c6:c2:0d:c9:
    53:56:a2:36:9b:1d:f6:f1:f6:a2:09:ea:e0:fb:43:
    b6:52:c6:6b:72:a3:f1:33:df:fa:36:90:34:fc:83:
    4a:48:77:25:48:62:4b:42:b2:ae:b9:56:84:08:0d:
    64:a1:d8:17:66
ASN1 OID: prime256v1

مرحله ۲: یک کلید عمومی کدگذاری شده با base64 ایجاد کنید

کلید خصوصی و عمومی که در مثال مرحله اختیاری قبلی تولید شد، به صورت هگزادسیمال رمزگذاری شده است. برای دریافت کلید عمومی رمزگذاری شده با مبنای ۶۴ در قالب نقطه فشرده نشده، از دستور زیر استفاده کنید:

openssl ec -in key.pem -pubout -text -noout 2> /dev/null | grep "pub:" -A5 | sed 1d | xxd -r -p | base64 | paste -sd "\0" - | tr -d '\n\r ' > publicKey.txt

این دستور یک فایل publicKey.txt تولید می‌کند که محتوای آن، نسخه base64 کلید در قالب نقطه فشرده نشده، شبیه به محتوای زیر است:

BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=

محتوای فایل نباید دارای فضای خالی اضافی یا علامت بازگشت به ابتدای سطر باشد. برای تأیید این موضوع، دستور زیر را در لینوکس یا مک او اس اجرا کنید:

od -bc publicKey.txt

مرحله ۳: یک کلید خصوصی رمزگذاری شده با base64 و با فرمت PKCS #8 ایجاد کنید

کتابخانه Tink انتظار دارد که کلید خصوصی شما به صورت base64 و با فرمت PKCS #8 کدگذاری شده باشد. از دستور زیر برای تولید کلید خصوصی با این فرمت از کلید خصوصی تولید شده در مرحله اول استفاده کنید:

openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -nocrypt | base64 | paste -sd "\0" -

دستور خروجی مشابه زیر تولید می‌کند:

MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWV4oK8c/MZkCLk4qSCNjW0Zm6H0CBCtSYxkXkC9FBHehRANCAAQPldOnhO2/oXjdJD1dwlFPiNs6fcdoRgFu3/Z0iKj24SjTGyLRGAtYWLGXBZcDdPj3T2bJRHRVhE8Bc2AjkT7n

نحوه رمزگشایی توکن روش پرداخت

برای رمزگشایی توکن، مراحل زیر را دنبال کنید:

  1. با استفاده از کلید خصوصی خود و ephemeralPublicKey داده شده، یک کلید مشترک ۵۱۲ بیتی که از ECIES-KEM استفاده می‌کند، ایجاد کنید. از پارامترهای زیر استفاده کنید:
    • منحنی بیضوی: NIST P-256، که در OpenSSL با نام prime256v1 نیز شناخته می‌شود.
    • CheckMode ، OldCofactorMode ، SingleHashMode و CofactorMode 0 هستند.
    • تابع رمزگذاری: فرمت نقطه‌ای فشرده نشده.
    • تابع مشتق کلید: HKDF با SHA256، همانطور که در RFC 5869 شرح داده شده است، با پارامتر زیر:
      • نمک (Salt) نباید ارائه شود. طبق RFC، این مقدار باید معادل نمک ۳۲ بایت صفر باشد.
  2. کلید تولید شده را به دو کلید با طول ۲۵۶ بیت تقسیم کنید: symmetricEncryptionKey و macKey .
  3. تأیید کنید که فیلد tag یک MAC معتبر برای encryptedMessage است.

    برای تولید MAC مورد انتظار، از HMAC ( RFC 5869 ) به همراه تابع هش SHA256 و macKey به دست آمده در مرحله 2 استفاده کنید.

  4. رمزگشایی encryptedMessage با استفاده از حالت AES-256-CTR و با موارد زیر:

    • یک چهارم صفر.
    • روکش‌دار نیست.
    • کلید symmetricEncryptionKey که در مرحله ۲ به دست آمد.

مدیریت کلید

کلیدهای رمزگذاری فروشنده

فروشندگان طبق مشخصات ذکر شده در مشخصات طرح رمزگذاری، یک کلید عمومی تولید می‌کنند.

کلیدهای امضای ریشه گوگل

گوگل مجموعه‌ای از کلیدهای عمومی امضای ریشه معتبر فعلی را که از یک URL عمومی قابل دریافت هستند، منتشر می‌کند. این کلیدها تا زمانی که هدرهای حافظه پنهان HTTP که توسط URL برگردانده می‌شوند، نشان دهند، معتبر هستند. آنها تا زمان انقضا، که توسط فیلد keyExpiration تعیین می‌شود، در حافظه پنهان ذخیره می‌شوند. توصیه می‌کنیم وقتی یک واکشی منقضی می‌شود، کلیدها را دوباره از URL عمومی دریافت کنید تا لیست فعلی کلیدهای معتبر را دریافت کنید.

استثنا برای پروتکل ECv2: اگر نمی‌توانید کلیدها را در زمان اجرا از گوگل دریافت کنید، keys.json را از URL تولید ما دریافت کنید، آن را در سیستم خود ذخیره کنید و به صورت دوره‌ای به صورت دستی به‌روزرسانی کنید. در شرایط عادی، گوگل پنج سال قبل از انقضای کلیدی که طولانی‌ترین تاریخ انقضا را دارد، یک کلید امضای ریشه جدید برای ECv2 صادر می‌کند. در صورت به خطر افتادن کلید، گوگل از طریق اطلاعات تماس ارائه شده در پورتال سلف سرویس به همه فروشندگان اطلاع می‌دهد تا درخواست بارگیری سریع‌تر keys.json را داشته باشند. برای اطمینان از اینکه چرخش منظم را از دست نمی‌دهید، توصیه می‌کنیم فروشندگانی که تصمیم می‌گیرند کلیدهای گوگل را در محتویات keys.json ذخیره کنند، سالانه به عنوان بخشی از چرخش کلید سالانه خود، به‌روزرسانی کنند.

کلیدهای ارائه شده از طریق URL عمومی در قالب زیر نگاشت می‌شوند:

{
  "keys": [
    {
      "keyValue": "encoded public key",
      "protocolVersion": "ECv2"
      "keyExpiration":"2000000000000"
    },
    {
      "keyValue": "encoded public key",
      "protocolVersion": "ECv2"
      "keyExpiration":"3000000000000"
    }
  ]
}

keyValue یک نسخه base64، نه پیچیده شده یا padded، از کلید کدگذاری شده در نوع ASN.1 SubjectPublicKeyInfo تعریف شده در استاندارد X.509 است. در جاوا، کدگذاری ASN.1 ارجاع شده توسط کلاس X509EncodedKeySpec نمایش داده می‌شود. می‌توان آن را با ECPublicKey.getEncoded() بدست آورد.

آدرس‌های اینترنتی (URL) برای هر دو محیط آزمایشی و عملیاتی توسط لینک‌های زیر ارائه می‌شوند:

چرخش کلید

اگر یک توکن روش پرداخت را مستقیماً روی سرورهای خود با ادغام مستقیم رمزگشایی می‌کنید، باید کلیدها را سالانه تغییر دهید.

برای چرخاندن کلیدهای رمزگذاری، مراحل زیر را انجام دهید:

  1. از OpenSSL برای تولید یک جفت کلید جدید استفاده کنید .
  2. کنسول Google Pay & Wallet را در حالی که با حساب Google خود وارد شده‌اید، باز کنید. قبلاً برای مدیریت برنامه شما با Google Play استفاده می‌شد.
  3. در برگه Google Pay API ، در زیر پنل ادغام مستقیم ، روی مدیریت در کنار کلید عمومی فعلی خود کلیک کنید. روی افزودن یک کلید دیگر کلیک کنید.
  4. فیلد ورودی متن کلید رمزگذاری عمومی (Public encryption key) را انتخاب کنید و کلید عمومی جدید تولید شده خود را که به صورت base64-encoded و با فرمت نقطه‌ای غیرفشرده است، اضافه کنید.
  5. روی ذخیره کلیدهای رمزگذاری کلیک کنید.
  6. برای اطمینان از چرخش بی‌نقص کلید، هنگام انتقال کلیدها، از رمزگشایی کلیدهای خصوصی جدید و قدیمی پشتیبانی کنید.

    اگر از کتابخانه Tink برای رمزگشایی توکن استفاده می‌کنید، برای پشتیبانی از چندین کلید خصوصی از کد جاوای زیر استفاده کنید:

    String decryptedMessage =
        new PaymentMethodTokenRecipient.Builder()
            .addRecipientPrivateKey(newPrivateKey)
            .addRecipientPrivateKey(oldPrivateKey);

    مطمئن شوید که کد رمزگشایی در محیط عملیاتی مستقر شده است و رمزگشایی‌های موفق را رصد می‌کنید.

  7. کلید عمومی مورد استفاده در کد خود را تغییر دهید.

    مقدار ویژگی publicKey را در ویژگی parameters PaymentMethodTokenizationSpecification جایگزین کنید:

    /**
     * @param publicKey public key retrieved from your server
     */
    private static JSONObject getTokenizationSpecification(String publicKey) {
      JSONObject tokenizationSpecification = new JSONObject();
      tokenizationSpecification.put("type", "DIRECT");
      tokenizationSpecification.put(
        "parameters",
        new JSONObject()
            .put("protocolVersion", "ECv2")
            .put("publicKey", publicKey));
      return tokenizationSpecification;
    }
  8. کد را از مرحله ۴ به مرحله تولید منتقل کنید. پس از استقرار کد، تراکنش‌های رمزگذاری و رمزگشایی از جفت کلیدهای جدید استفاده می‌کنند.
  9. تأیید کنید که دیگر از کلید عمومی قدیمی برای رمزگذاری هیچ تراکنشی استفاده نمی‌شود.

  10. کلید خصوصی قدیمی را حذف کنید.
  11. کنسول Google Pay & Wallet را باز کنید و با همان حساب گوگلی که قبلاً برای ثبت نام به عنوان توسعه‌دهنده در Google Pay استفاده کرده‌اید، وارد سیستم شوید.
  12. در برگه Google Pay API ، در زیر پنل ادغام مستقیم ، روی مدیریت در کنار کلید عمومی فعلی خود کلیک کنید. روی حذف در کنار کلید عمومی قدیمی خود کلیک کنید و روی ذخیره کلیدهای رمزگذاری کلیک کنید.

گوگل از کلید مشخص شده در ویژگی publicKey درون شیء parameters PaymentMethodTokenizationSpecification استفاده می‌کند، همانطور که در مثال زیر نشان داده شده است:

{
  "protocolVersion": "ECv2",
  "publicKey": "BOdoXP+9Aq473SnGwg3JU1..."
}

از کتابخانه Tink برای مدیریت پاسخ رمزگذاری شده استفاده کنید

برای انجام تأیید امضا و رمزگشایی پیام، از کتابخانه‌ی Tink paymentmethodtoken استفاده کنید. این کتابخانه فقط در جاوا موجود است. برای استفاده از آن، مراحل زیر را انجام دهید:

  1. در pom.xml خود، برنامه‌ی Tink paymentmethodtoken را به عنوان یک وابستگی اضافه کنید:

    <dependencies>
      <!-- other dependencies ... -->
      <dependency>
        <groupId>com.google.crypto.tink</groupId>
        <artifactId>apps-paymentmethodtoken</artifactId>
        <version>1.9.1</version>  <!-- or latest version -->
      </dependency>
    </dependencies>
  2. هنگام راه‌اندازی سرور، کلیدهای امضای گوگل را پیش‌واکشی کنید تا کلید در حافظه در دسترس باشد. این کار مانع از مشاهده هرگونه تأخیر شبکه توسط کاربر در حین فرآیند رمزگشایی و دریافت کلیدها می‌شود.

    GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
  3. پیام را با کد زیر رمزگشایی کنید، که فرض می‌کند paymentMethodToken در متغیر encryptedMessage ذخیره شده است، و بخش‌های پررنگ را مطابق با سناریوی خود جایگزین کنید.

    برای تست‌های غیرتولیدی، INSTANCE_PRODUCTION را با INSTANCE_TEST جایگزین کنید، و اگر ادغام شما غیرفعال است یا کلید رمزگذاری پیکربندی نشده است، [YOUR MERCHANT ID] را با .

    • فعال
    • ادغام مستقیم فعال است
    • دارای کلید رمزگذاری پیکربندی شده است

    [YOUR MERCHANT ID] را جایگزین نکنید.

    String decryptedMessage =
        new PaymentMethodTokenRecipient.Builder()
        .fetchSenderVerifyingKeysWith(
            GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION)
        .recipientId("merchant:[YOUR MERCHANT ID]")
        // This guide applies only to protocolVersion = ECv2
        .protocolVersion("ECv2")
        // Multiple private keys can be added to support graceful
        // key rotations.
        .addRecipientPrivateKey(PrivateKey1)
        .addRecipientPrivateKey(PrivateKey2)
        .build()
        .unseal(encryptedMessage);
  4. PrivateKey1 با مقدار کلید خصوصی مناسبی که با مقدار کلید عمومی ثبت شده در Google از بخش «آماده‌سازی کلیدهایتان و ثبت در Google» مرتبط است، جایگزین کنید. می‌توانید بعداً، زمانی که نیاز به چرخش کلیدها با Google باشد، چندین مقدار کلید خصوصی دیگر اضافه کنید. متغیرها می‌توانند یک رشته PKCS8 رمزگذاری شده با base64 یا یک شیء ECPrivateKey باشند. برای اطلاعات بیشتر در مورد نحوه تولید یک کلید خصوصی PKCS8 رمزگذاری شده با base64، به بخش «آماده‌سازی کلیدهایتان و ثبت در Google» مراجعه کنید.

  5. اگر نمی‌توانید هر بار که کلیدها را رمزگشایی می‌کنید، با سرور گوگل تماس بگیرید، با کد زیر رمزگشایی کنید و بخش‌های پررنگ را مطابق با سناریوی خود جایگزین کنید.

    String decryptedMessage =
        new PaymentMethodTokenRecipient.Builder()
        .addSenderVerifyingKey("ECv2 key fetched from test or production url")
        .recipientId("merchant:[YOUR MERCHANT ID]")
        // This guide applies only to protocolVersion = ECv2
        .protocolVersion("ECv2")
        // Multiple private keys can be added to support graceful
        // key rotations.
        .addRecipientPrivateKey(PrivateKey1)
        .addRecipientPrivateKey(PrivateKey2)
        .build()
        .unseal(encryptedMessage);

    کلید فعلی در محیط عملیاتی، تحت شرایط عادی، به جز لو رفتن کلید، تا تاریخ 04/14/2038 معتبر است. در صورت لو رفتن کلید، گوگل از طریق اطلاعات تماس ارائه شده در پورتال سلف سرویس، به همه فروشندگان اطلاع می‌دهد تا درخواست بارگذاری مجدد سریع‌تر keys.json را داشته باشند.

    این قطعه کد جزئیات امنیتی زیر را مدیریت می‌کند تا بتوانید روی میزان مصرف بار داده تمرکز کنید:

    • کلیدهای امضای گوگل واکشی و در حافظه پنهان شدند
    • تأیید امضا
    • رمزگشایی