API گوگل پی، روشهای پرداخت را در یک payload امضا شده و رمزگذاری شده PaymentMethodToken برمیگرداند. روشهای پرداخت برگردانده شده یا کارتهایی هستند که شامل PAN میشوند، یا کارتهای توکنیزه شدهای هستند که شامل PAN دستگاه و رمزنگاریها میشوند.
این payload حاوی فیلدی به نام protocolVersion است که به گیرندهی payload میگوید کدام اصول رمزنگاری در حال استفاده هستند و فرمت مورد انتظار چیست.
این راهنما اطلاعاتی در مورد نحوه تولید کلید عمومی برای درخواست توکن روش پرداخت رمزگذاری شده و امضا شده توسط گوگل ارائه میدهد و مراحل لازم برای تأیید و رمزگشایی توکن را به تفصیل شرح میدهد.
این راهنما فقط برای protocolVersion = ECv2 اعمال میشود.
از آنجا که اطلاعات کارت پرداخت را مستقیماً دریافت میکنید، قبل از ادامه، مطمئن شوید که برنامه شما با PCI DSS سازگار است و سرورهای شما زیرساخت لازم برای مدیریت ایمن اعتبارنامههای پرداخت کاربر را دارند.
مراحل زیر مشخص میکند که یک یکپارچهساز برای استفاده از بار دادهی Google Pay API ECv2 PaymentMethodToken چه کاری باید انجام دهد:
- کلیدهای امضای روت گوگل را دریافت کنید.
- تأیید کنید که امضای کلید امضای میانی توسط هر یک از کلیدهای امضای ریشه که منقضی نشدهاند، معتبر است.
- تأیید کنید که کلید امضای میانیِ پیلود منقضی نشده باشد.
- تأیید کنید که امضای محموله توسط کلید امضای میانی معتبر است.
- پس از تأیید امضا، محتویات payload را رمزگشایی کنید.
- تأیید کنید که پیام منقضی نشده باشد. برای این کار لازم است بررسی کنید که زمان فعلی کمتر از فیلد
messageExpirationدر محتوای رمزگشایی شده باشد. - از روش پرداخت موجود در محتوای رمزگشایی شده استفاده کنید و آن را شارژ کنید.
کد نمونه موجود در کتابخانه 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 تعریف شده است.
|
| تابع مشتق کلید | مبتنی بر HMAC با SHA-256 (
|
| الگوریتم رمزگذاری متقارن | 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
نحوه رمزگشایی توکن روش پرداخت
برای رمزگشایی توکن، مراحل زیر را دنبال کنید:
- با استفاده از کلید خصوصی خود و
ephemeralPublicKeyداده شده، یک کلید مشترک ۵۱۲ بیتی که از ECIES-KEM استفاده میکند، ایجاد کنید. از پارامترهای زیر استفاده کنید: - منحنی بیضوی: NIST P-256، که در OpenSSL با نام prime256v1 نیز شناخته میشود.
-
CheckMode،OldCofactorMode،SingleHashModeوCofactorMode0هستند. - تابع رمزگذاری: فرمت نقطهای فشرده نشده.
- تابع مشتق کلید: HKDF با SHA256، همانطور که در RFC 5869 شرح داده شده است، با پارامتر زیر:
- نمک (Salt) نباید ارائه شود. طبق RFC، این مقدار باید معادل نمک ۳۲ بایت صفر باشد.
- کلید تولید شده را به دو کلید با طول ۲۵۶ بیت تقسیم کنید:
symmetricEncryptionKeyوmacKey. تأیید کنید که فیلد
tagیک MAC معتبر برایencryptedMessageاست.برای تولید MAC مورد انتظار، از HMAC ( RFC 5869 ) به همراه تابع هش SHA256 و
macKeyبه دست آمده در مرحله 2 استفاده کنید.رمزگشایی
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) برای هر دو محیط آزمایشی و عملیاتی توسط لینکهای زیر ارائه میشوند:
- تست:
https://payments.developers.google.com/paymentmethodtoken/test/keys.json - تولید:
https://payments.developers.google.com/paymentmethodtoken/keys.json
چرخش کلید
اگر یک توکن روش پرداخت را مستقیماً روی سرورهای خود با ادغام مستقیم رمزگشایی میکنید، باید کلیدها را سالانه تغییر دهید.
برای چرخاندن کلیدهای رمزگذاری، مراحل زیر را انجام دهید:
- از OpenSSL برای تولید یک جفت کلید جدید استفاده کنید .
- کنسول Google Pay & Wallet را در حالی که با حساب Google خود وارد شدهاید، باز کنید. قبلاً برای مدیریت برنامه شما با Google Play استفاده میشد.
- در برگه Google Pay API ، در زیر پنل ادغام مستقیم ، روی مدیریت در کنار کلید عمومی فعلی خود کلیک کنید. روی افزودن یک کلید دیگر کلیک کنید.
- فیلد ورودی متن کلید رمزگذاری عمومی (Public encryption key) را انتخاب کنید و کلید عمومی جدید تولید شده خود را که به صورت base64-encoded و با فرمت نقطهای غیرفشرده است، اضافه کنید.
- روی ذخیره کلیدهای رمزگذاری کلیک کنید.
برای اطمینان از چرخش بینقص کلید، هنگام انتقال کلیدها، از رمزگشایی کلیدهای خصوصی جدید و قدیمی پشتیبانی کنید.
اگر از کتابخانه Tink برای رمزگشایی توکن استفاده میکنید، برای پشتیبانی از چندین کلید خصوصی از کد جاوای زیر استفاده کنید:
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .addRecipientPrivateKey(newPrivateKey) .addRecipientPrivateKey(oldPrivateKey);
مطمئن شوید که کد رمزگشایی در محیط عملیاتی مستقر شده است و رمزگشاییهای موفق را رصد میکنید.
کلید عمومی مورد استفاده در کد خود را تغییر دهید.
مقدار ویژگی
publicKeyرا در ویژگیparametersPaymentMethodTokenizationSpecificationجایگزین کنید:/** * @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; }
- کد را از مرحله ۴ به مرحله تولید منتقل کنید. پس از استقرار کد، تراکنشهای رمزگذاری و رمزگشایی از جفت کلیدهای جدید استفاده میکنند.
تأیید کنید که دیگر از کلید عمومی قدیمی برای رمزگذاری هیچ تراکنشی استفاده نمیشود.
- کلید خصوصی قدیمی را حذف کنید.
- کنسول Google Pay & Wallet را باز کنید و با همان حساب گوگلی که قبلاً برای ثبت نام به عنوان توسعهدهنده در Google Pay استفاده کردهاید، وارد سیستم شوید.
- در برگه Google Pay API ، در زیر پنل ادغام مستقیم ، روی مدیریت در کنار کلید عمومی فعلی خود کلیک کنید. روی حذف در کنار کلید عمومی قدیمی خود کلیک کنید و روی ذخیره کلیدهای رمزگذاری کلیک کنید.
گوگل از کلید مشخص شده در ویژگی publicKey درون شیء parameters PaymentMethodTokenizationSpecification استفاده میکند، همانطور که در مثال زیر نشان داده شده است:
{
"protocolVersion": "ECv2",
"publicKey": "BOdoXP+9Aq473SnGwg3JU1..."
}از کتابخانه Tink برای مدیریت پاسخ رمزگذاری شده استفاده کنید
برای انجام تأیید امضا و رمزگشایی پیام، از کتابخانهی Tink paymentmethodtoken استفاده کنید. این کتابخانه فقط در جاوا موجود است. برای استفاده از آن، مراحل زیر را انجام دهید:
در
pom.xmlخود، برنامهی Tinkpaymentmethodtokenرا به عنوان یک وابستگی اضافه کنید:<dependencies> <!-- other dependencies ... --> <dependency> <groupId>com.google.crypto.tink</groupId> <artifactId>apps-paymentmethodtoken</artifactId> <version>1.9.1</version> <!-- or latest version --> </dependency> </dependencies>هنگام راهاندازی سرور، کلیدهای امضای گوگل را پیشواکشی کنید تا کلید در حافظه در دسترس باشد. این کار مانع از مشاهده هرگونه تأخیر شبکه توسط کاربر در حین فرآیند رمزگشایی و دریافت کلیدها میشود.
GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
پیام را با کد زیر رمزگشایی کنید، که فرض میکند
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);
PrivateKey1با مقدار کلید خصوصی مناسبی که با مقدار کلید عمومی ثبت شده در Google از بخش «آمادهسازی کلیدهایتان و ثبت در Google» مرتبط است، جایگزین کنید. میتوانید بعداً، زمانی که نیاز به چرخش کلیدها با Google باشد، چندین مقدار کلید خصوصی دیگر اضافه کنید. متغیرها میتوانند یک رشته PKCS8 رمزگذاری شده با base64 یا یک شیءECPrivateKeyباشند. برای اطلاعات بیشتر در مورد نحوه تولید یک کلید خصوصی PKCS8 رمزگذاری شده با base64، به بخش «آمادهسازی کلیدهایتان و ثبت در 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);
کلید فعلی در محیط عملیاتی، تحت شرایط عادی، به جز لو رفتن کلید، تا تاریخ 04/14/2038 معتبر است. در صورت لو رفتن کلید، گوگل از طریق اطلاعات تماس ارائه شده در پورتال سلف سرویس، به همه فروشندگان اطلاع میدهد تا درخواست بارگذاری مجدد سریعتر
keys.jsonرا داشته باشند.این قطعه کد جزئیات امنیتی زیر را مدیریت میکند تا بتوانید روی میزان مصرف بار داده تمرکز کنید:
- کلیدهای امضای گوگل واکشی و در حافظه پنهان شدند
- تأیید امضا
- رمزگشایی