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

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

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

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

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

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

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

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

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

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

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

نام نوع شرح
protocolVersion رشته طرح رمزگذاری یا امضا را که پیام تحت آن ایجاد شده است شناسایی می‌کند. این کار به پروتکل اجازه می‌دهد درصورت نیاز درطول زمان تکامل یابد.
signature رشته تأیید می‌کند که پیام از Google ارسال شده است. این امضا با کدبندی ۶۴پایه‌ای و با ECDSA توسط کلید امضای واسط ایجاد شده است.
intermediateSigningKey شیء شیء JSON که حاوی کلید امضای واسطه از Google است. این فایل حاوی signedKey با keyValue، keyExpiration، و signatures است. این گواهی برای ساده کردن فرایند درستی‌سنجی امضای کلید امضای واسط، سریالی شده است.
signedMessage رشته شیء JSON که به‌صورت رشته‌ای ایمن برای HTML سریال‌سازی شده است و حاوی 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 رشته تأیید می‌کند که کلید امضای واسط از Google آمده است. این کلید با کدبندی base64 و با ECDSA ایجاد شده است.

کلید امضاشده

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

نام نوع شرح
keyValue رشته نسخه ۶۴پایه‌ای کلید کدبندی‌شده در نوع ASN.1. SubjectPublicKeyInfo در استاندارد X.509 تعریف شده است.
keyExpiration رشته تاریخ و زمانی که کلید واسطه منقضی می‌شود برحسب میلی‌ثانیه UTC از تاریخ. یکپارچه‌سازها هر کلیدی را که منقضی شده باشد رد می‌کنند.

پیام امضاشده

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

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

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

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

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

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

کارت

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

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

شناسه ژتون فروشنده تراکنش کارت. این فیلد اختیاری فقط درصورتی برگردانده می‌شود که همه شرایط زیر برآورده شده باشد:

  • فروشنده شیء MIT *TransactionInfo را در درخواست مشخص می‌کند.
  • فروشنده tokenUpdateUrl را در درخواست لحاظ می‌کند.
  • کاربر ابزار نشان‌گذاری‌شده‌ای (مثلاً DPAN) را انتخاب می‌کند.

PAN_ONLY

تکه‌کد JSON زیر نمونه‌ای از encryptedMessage کامل برای CARD paymentMethod با 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 بااستفاده از رمزنگاری 3-D Secure اصالت‌سنجی شد، CRYPTOGRAM_3DS authMethod. این فیلدها شامل فیلدهای اضافی زیر است:

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

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

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

eciIndicator

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

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

مقدار eciIndicator شبکه کارت طرف مسئول authMethod
""(empty) Mastercard فروشنده/خریدار CRYPTOGRAM_3DS
02 Mastercard صادرکننده کارت CRYPTOGRAM_3DS
06 Mastercard فروشنده/خریدار CRYPTOGRAM_3DS
05 Visa صادرکننده کارت CRYPTOGRAM_3DS
07 Visa فروشنده/خریدار CRYPTOGRAM_3DS
""(empty) شبکه‌های دیگر فروشنده/خریدار CRYPTOGRAM_3DS

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

درستی‌سنجی امضا

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

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

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

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

امضا

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

در زیر نمونه‌ای از قالب بایت ASN.1 مشخص‌شده آورده شده است که قالب استاندارد تولیدشده توسط پیاده‌سازی‌های Java Cryptography Extension (JCE) ECDSA است.

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 باشد. طول بایت هر مؤلفه ۴ بایت در قالب لیتل اندین است.

مثال

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

{
  "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 تکرار کنید و هرکدام را با کلیدهای امضای منقضی‌نشده Google در keys.json اعتبارسنجی کنید. اگر حداقل یک اعتبارسنجی امضا کار کند، درستی‌سنجی را کامل درنظر بگیرید. بعداً از intermediateSigningKey.signedKey.keyValue برای درستی‌سنجی signedStringForMessageSignature استفاده کنید. Google اکیداً توصیه می‌کند به‌جای کد درستی‌سنجی خودتان، از کتابخانه رمزنگاری موجود استفاده کنید.

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

برای اعتبارسنجی امضا در نمونه کد روش پرداخت، 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 کدبندی شود. طول بایت هر مؤلفه ۴ بایت در قالب لیتل اندین است. وقتی رشته بایت را می‌سازید، 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 برای فروشندگان دارای دسترسی تولید مطابقت دارد.

اگر 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 استفاده می‌شود. Google اکیداً توصیه می‌کند به‌جای کد درستی‌سنجی خودتان، از کتابخانه رمزنگاری موجود استفاده کنید.

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

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

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

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

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

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

  • Salt نباید ارائه شود.
  • اطلاعات باید "Google" باشد، کدبندی‌شده در ASCII برای نسخه پروتکل ECv2.
  • باید ۲۵۶ بیت برای کلید AES256 و ۲۵۶ بیت دیگر برای کلید HMAC_SHA256 مشتق شود.
الگوریتم رمزگذاری متقارن

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

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

الگوریتم کد اصالت‌سنجی پیام HMAC_SHA256 با کلید ۲۵۶ بیتی که از تابع مشتق کلید مشتق شده است.

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

کلید عمومی رمزگذاری و ephemeralPublicKey که در پایه‌بارهای Google برگردانده شده‌اند با نمایش ۶۴پایه‌ای کلید در قالب نقطه غیرفشرده قالب‌بندی شده‌اند. این شناسه از دو عنصر زیر تشکیل شده است:

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

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

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

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

نمونه زیر کلید خصوصی «منحنی بیضوی» مناسب برای استفاده با 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

کلید خصوصی و عمومی که در مثال مرحله اختیاری قبلی تولید شده است، به‌صورت شانزده‌شانزدهی کدگذاری شده است. برای دریافت کلید عمومی کدبندی‌شده با 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 را تولید می‌کند که محتوای آن، نسخه ۶۴پایه‌ای کلید در قالب نقطه فشرده‌نشده، شبیه به موارد زیر است:

BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=

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

od -bc publicKey.txt

مرحله ۳: تولید کلید خصوصی کدبندی‌شده با base64 در قالب PKCS #8

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

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 هستند.
    • تابع کدبندی: قالب نقطه فشرده‌نشده.
    • تابع استخراج کلید: HKDFwithSHA256، همان‌طور که در RFC 5869 شرح داده شده است، با پارامتر زیر:
      • Salt نباید ارائه شود. طبق RFC، این باید معادل یک سالت ۳۲ بایت صفرشده باشد.
  2. کلید تولیدشده را به دو کلید ۲۵۶ بیتی تقسیم کنید: symmetricEncryptionKey و macKey.
  3. بررسی کنید که فیلد tag یک MAC معتبر برای encryptedMessage باشد.

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

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

    • بردار مقداردهی اولیه صفر.
    • بدون لایه محافظ.
    • symmetricEncryptionKey مشتق‌شده در مرحله ۲.

مدیریت کلید

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

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

کلیدهای امضای ریشه Google

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

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

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

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

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

نشانی‌های وب برای هر دو محیط آزمایشی و تولیدی در پیوندهای زیر ارائه شده است:

چرخش کلید

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

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

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

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

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

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

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

    مقدار مشخصه publicKey را در خصوصیت PaymentMethodTokenizationSpecification parameters جایگزین کنید:

    /**
     * @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. کنسول Pay و کیف پول Google را باز کنید و با همان «حساب Google» که قبلاً برای ثبت‌نام به‌عنوان توسعه‌دهنده در Google Pay استفاده کرده‌اید به سیستم وارد شوید.
  12. در برگه Google Pay API، در زیر قاب ادغام مستقیم، روی مدیریت در کنار کلید عمومی موجود کلیک کنید. روی حذف در کنار کلید عمومی قدیمی‌تان کلیک کنید و روی ذخیره کلیدهای رمزگذاری کلیک کنید.

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

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

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

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

  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. هنگام راه‌اندازی سرور، کلیدهای امضای Google را پیش‌واکشی کنید تا کلید در حافظه دردسترس قرار گیرد. این کار از مشاهده هرگونه تأخیر شبکه توسط کاربر درحین واکشی کلیدها توسط فرایند رمزگشایی جلوگیری می‌کند.

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

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

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

    [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. اگر نمی‌توانید هربار که کلیدها را رمزگشایی می‌کنید با سرور Google تماس بگیرید، با کد زیر رمزگشایی کنید و بخش‌های پررنگ را مطابق با سناریو خود جایگزین کنید.

    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);

    کلید فعلی در محیط تولید تا تاریخ ۲۰۳۸/۰۴/۱۴ تحت شرایط عادی معتبر است، مگر اینکه کلید لو برود. درصورت لو رفتن کلید، Google ازطریق اطلاعات تماس ارائه‌شده در درگاه خودخدمتی به همه فروشندگان اطلاع می‌دهد تا درخواست بار کردن مجدد سریع‌تر keys.json را بدهد.

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

    • کلیدهای امضای Google واکشی و در حافظه پنهان ذخیره شد
    • درستی‌سنجی امضا
    • رمزگشایی