تعرض Google Pay API طُرق الدفع في حمولة PaymentMethodToken موقّعة ومشفّرة. طرق الدفع التي يتم عرضها هي إما بطاقات تتضمّن رقم الحساب الأساسي (PAN) أو بطاقات تم تحويلها إلى رموز مميّزة تتضمّن رقم الحساب الأساسي (PAN) للجهاز ورموز تشفير.
تحتوي الحمولة على حقل يُسمى protocolVersion يوضّح لمستلم الحمولة العناصر الأساسية للتشفير المستخدَمة والتنسيق المتوقّع.
يقدّم هذا الدليل معلومات حول كيفية إنشاء مفتاح عام لطلب رمز مميّز لطريقة دفع مشفّر وموقّع من Google، كما يوضّح الخطوات التي يجب اتّخاذها لتأكيد صحة الرمز وفك تشفيره.
لا ينطبق هذا الدليل إلا على protocolVersion = ECv2.
بما أنّك تتلقّى معلومات بطاقة الدفع مباشرةً، عليك التأكّد من أنّ تطبيقك متوافق مع معيار أمان بيانات قطاع بطاقات الدفع (PCI DSS) ومن أنّ خوادمك تتضمّن البنية الأساسية المطلوبة للتعامل بأمان مع بيانات اعتماد الدفع الخاصة بالمستخدم قبل المتابعة.
توضّح الخطوات التالية ما يجب أن يفعله القائم بالدمج لاستخدام حمولة Google Pay API
ECv2 PaymentMethodToken:
- استرجِع مفاتيح التوقيع الجذرية من Google.
- تأكَّد من أنّ توقيع مفتاح التوقيع الوسيط صالح من خلال أي من مفاتيح التوقيع الجذرية غير المنتهية الصلاحية.
- تأكَّد من عدم انتهاء صلاحية مفتاح التوقيع الوسيط للحمولة.
- تأكَّد من أنّ توقيع الحمولة صالح باستخدام مفتاح التوقيع الوسيط.
- فك تشفير محتوى الحمولة بعد التحقّق من التوقيع
- تأكَّد من عدم انتهاء صلاحية الرسالة. يتطلّب ذلك التحقّق من أنّ الوقت الحالي أقل من قيمة الحقل
messageExpirationفي المحتوى الذي تم فك تشفيره. - استخدام طريقة الدفع في المحتوى الذي تم فك تشفيره وتحصيل الرسوم منها
ينفّذ الرمز النموذجي في مكتبة Tink الخطوات من 1 إلى 6.
بنية رمز طريقة الدفع
الرسالة التي تعرضها Google في استجابة PaymentData هي عنصر JSON مسلسَل ومُرمَّز بتنسيق UTF-8، ويتضمّن المفاتيح المحدّدة في الجدول التالي:
| الاسم | النوع | الوصف |
|---|---|---|
protocolVersion |
سلسلة | تحدّد هذه السمة نظام التشفير أو التوقيع الذي تم إنشاء الرسالة بموجبه. ويسمح هذا الإجراء بتطوير البروتوكول بمرور الوقت، إذا لزم الأمر. |
signature |
سلسلة | تتحقّق هذه الميزة من أنّ الرسالة واردة من Google. وهي مشفّرة باستخدام Base64، ويتم إنشاؤها باستخدام 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 |
سلسلة | إصدار base64 من المفتاح المرمّز بنوع ASN.1 يتم تحديد SubjectPublicKeyInfo في معيار X.509. |
keyExpiration |
سلسلة | يشير إلى تاريخ ووقت انتهاء صلاحية المفتاح الوسيط بالملي ثانية منذ بداية حقبة يونكس حسب التوقيت العالمي المنسَّق. ويرفض المدمجون أي مفتاح انتهت صلاحيته. |
رسالة موقَّعة
signedMessage هو عنصر JSON متسلسل بترميز UTF-8 يحتوي على القيم التالية:
| الاسم | النوع | الوصف |
|---|---|---|
encryptedMessage |
سلسلة | رسالة مشفّرة بترميز base64 تتضمّن معلومات الدفع وبعض حقول الأمان الإضافية |
ephemeralPublicKey |
سلسلة | مفتاح عام مؤقت بترميز base64 مرتبط بالمفتاح الخاص لتشفير الرسالة بتنسيق النقطة غير المضغوطة. لمزيد من المعلومات، يُرجى الاطّلاع على تنسيق مفتاح التشفير العام. |
tag |
سلسلة | تمثّل هذه السمة رمز مصادقة الرسالة (MAC) المرمّز باستخدام Base64 الخاص بـ encryptedMessage. |
رسالة مشفَّرة
encryptedMessage الذي تم فك تشفيره هو عنصر JSON متسلسل بترميز UTF-8. يحتوي ملف JSON على مستويَين. يحتوي المستوى الخارجي على البيانات الوصفية والحقول المضمّنة لأغراض الأمان، بينما المستوى الداخلي هو عنصر JSON آخر يمثّل بيانات اعتماد الدفع الفعلية.
لمزيد من التفاصيل حول encryptedMessage، راجِع الجداول التالية وأمثلة عناصر JSON:
| الاسم | النوع | الوصف |
|---|---|---|
messageExpiration |
سلسلة | يشير إلى تاريخ ووقت انتهاء صلاحية الرسالة بالملي ثانية حسب التوقيت العالمي المنسَّق منذ بداية الحقبة. على الجهات التي تجري عمليات الدمج رفض أي رسالة انتهت صلاحيتها. |
messageId |
سلسلة | معرّف فريد يحدّد الرسالة في حال الحاجة إلى إبطالها أو تحديد موقعها في وقت لاحق |
paymentMethod |
سلسلة | تمثّل هذه السمة نوع بيانات اعتماد الدفع.
في الوقت الحالي، لا تتوفّر سوى اللغة CARD.
|
paymentMethodDetails |
عنصر | بيانات طريقة الدفع نفسها يتم تحديد تنسيق هذا العنصر من خلال
paymentMethod ويتم توضيحه في الجداول التالية. |
بطاقة
تتكوّن بيانات اعتماد طريقة الدفع CARD من الخصائص التالية:
| الاسم | النوع | الوصف |
|---|---|---|
pan |
سلسلة | رقم الحساب الشخصي الذي تم تحصيل الرسوم منه تحتوي هذه السلسلة على أرقام فقط. |
expirationMonth |
العدد | يشير هذا الحقل إلى شهر انتهاء صلاحية البطاقة، حيث يمثّل الرقم 1 شهر يناير، ويمثّل الرقم 2 شهر فبراير، وهكذا. |
expirationYear |
العدد | تمثّل هذه السمة سنة انتهاء صلاحية البطاقة المكوّنة من أربعة أرقام، مثل 2020. |
authMethod |
سلسلة | طريقة مصادقة معاملة البطاقة |
merchantTokenId |
سلسلة | معرّف الرمز المميّز للتاجر الخاص بمعاملة البطاقة لا يتم عرض هذا الحقل الاختياري إلا في حال استيفاء جميع الشروط التالية:
|
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، يُرجى الاطّلاع على الملحق A من أدوات IETF. تتكوّن التوقيع من الأعداد الصحيحة r وs في خوارزمية ECDSA. لمزيد من المعلومات، يُرجى الاطّلاع على خوارزمية إنشاء التوقيع.
في ما يلي مثال على تنسيق بايت ASN.1 المحدّد، وهو التنسيق العادي الذي تنتجه عمليات تنفيذ ECDSA في Java Cryptography Extension (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.
يبلغ طول البايت لكل مكوّن 4 بايت بتنسيق 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 ومحاولة التحقّق من صحة كل توقيع باستخدام مفاتيح توقيع 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. يبلغ طول البايت لكل مكوّن 4 بايت بتنسيق little-endian. عند إنشاء سلسلة البايت، لا تحلّل 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 للتجّار الذين لديهم إذن بالوصول إلى الإصدار العلني.
إذا كانت قيمة 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
|
| دالة اشتقاق المفاتيح | استنادًا إلى HMAC مع SHA-256 (
|
| خوارزمية التشفير المتماثل |
DEM2، كما هو محدّد في ISO 18033-2 خوارزمية التشفير: AES-256-CTR بدون تعبئة وبقيمة IV صفرية |
| خوارزمية MAC | HMAC_SHA256 باستخدام مفتاح 256 بت مشتق من دالة اشتقاق المفاتيح. |
تنسيق المفتاح العام للتشفير
يتم تنسيق مفتاح التشفير العام وephemeralPublicKey المعروضَين في حمولات Google باستخدام تمثيل base64 للمفتاح بتنسيق النقطة غير المضغوطة. وهي تتألف من العنصرَين التاليَين:
- رقم سحري واحد يحدّد التنسيق (0x04).
- عددان صحيحان كبيران بحجم 32 بايت يمثّلان إحداثيات X وY في المنحنى البيضاوي.
يتم وصف هذا التنسيق بتفصيل أكبر في "التشفير بالمفتاح العام لمؤسسات الخدمات المالية: خوارزمية التوقيع الرقمي للمنحنى الإهليلجي (ECDSA)"، ANSI X9.62، 1998.
استخدام OpenSSL لإنشاء مفتاح عام
الخطوة 1: إنشاء مفتاح خاص
يُنشئ المثال التالي مفتاحًا خاصًا لمنحنى إهليلجي مناسبًا للاستخدام مع 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
الخطوة 2: إنشاء مفتاح عام مشفّر باستخدام ترميز 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 يشبه محتواه، وهو نسخة base64 من المفتاح بتنسيق النقطة غير المضغوطة، ما يلي:
BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=
يجب ألا يحتوي محتوى الملف على مسافات فارغة أو عمليات إرجاع إضافية. للتحقّق من ذلك، شغِّل الأمر التالي في نظام التشغيل Linux أو MacOS:
od -bc publicKey.txt
الخطوة 3: إنشاء مفتاح خاص بترميز 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المحدّد لإنشاء مفتاح مشترك بطول 512 بت يستخدم ECIES-KEM. استخدِم المَعلمات التالية: - المنحنى البيضاوي: NIST P-256، المعروف أيضًا في OpenSSL باسم prime256v1.
-
CheckModeوOldCofactorModeوSingleHashModeوCofactorModeهي0. - دالة الترميز: تنسيق النقطة غير المضغوطة
- دالة اشتقاق المفتاح: HKDFwithSHA256، كما هو موضّح في RFC 5869، مع المَعلمة التالية:
- يجب عدم توفير قيمة Salt. وفقًا لمعايير RFC، يجب أن يكون هذا مكافئًا لقيمة salt تتألف من 32 بايت مصفّرة.
- قسِّم المفتاح الذي تم إنشاؤه إلى مفتاحَين بطول 256 بت:
symmetricEncryptionKeyوmacKey. تأكَّد من أنّ الحقل
tagهو عنوان MAC صالح لـencryptedMessage.لإنشاء رمز مصادقة الرسائل المتوقّع، استخدِم HMAC (RFC 5869) مع دالة التجزئة SHA256 و
macKeyالذي تم الحصول عليه في الخطوة 2.فك تشفير
encryptedMessageباستخدام وضع AES-256-CTR، مع ما يلي:- قيمة IV تساوي صفرًا
- لا يتم إضافة مساحة فارغة.
symmetricEncryptionKeyالذي تم الحصول عليه في الخطوة 2
إدارة المفاتيح
مفاتيح التشفير الخاصة بالتاجر
ينشئ التجّار مفتاحًا عامًا وفقًا للمواصفات الموضّحة في مواصفات نظام التشفير.
مفاتيح توقيع الجذر من Google
تنشر Google مجموعة المفاتيح العامة الحالية الصالحة لتوقيع الشهادات الجذرية، ويمكن استردادها من عنوان URL عام. تكون المفاتيح صالحة طالما تشير إلى ذلك عناوين ذاكرة التخزين المؤقت HTTP التي يعرضها عنوان URL. ويتم تخزينها مؤقتًا إلى أن تنتهي صلاحيتها، ويتم تحديد ذلك من خلال الحقل keyExpiration. ننصحك بأنّه عند انتهاء صلاحية عملية الاسترجاع، عليك استرجاع المفاتيح من عنوان URL العام مرة أخرى للحصول على القائمة الحالية من المفاتيح الصالحة.
استثناء لبروتوكول ECv2: إذا تعذّر عليك استرداد المفاتيح من Google في وقت التشغيل، استردِد keys.json من عنوان URL الخاص بالإنتاج، واحفظه في نظامك، ثم أعِد تحميله يدويًا بشكل دوري. في الظروف العادية، تصدر Google مفتاح توقيع جذر جديدًا لـ ECv2 قبل خمس سنوات من انتهاء صلاحية المفتاح الذي يتضمّن أطول تاريخ انتهاء صلاحية. في حال تعرّض المفاتيح للاختراق، ترسل Google إشعارًا إلى جميع التجّار من خلال معلومات الاتصال المقدَّمة في بوابة الخدمة الذاتية من أجل طلب إعادة تحميل keys.json بشكل أسرع. لضمان عدم تفويت عملية التبديل المنتظم، ننصح التجّار الذين يختارون حفظ مفاتيح Google في محتوى keys.json بإعادة تحميلها سنويًا كجزء من عملية تبديل المفاتيح السنوية.
يتم ربط المفاتيح المقدَّمة من خلال عنوان URL العام بالتنسيق التالي:
{ "keys": [ { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"2000000000000" }, { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"3000000000000" } ] }
keyValue هو إصدار من المفتاح بترميز base64، غير ملفوف أو مضاف إليه أي بيانات، ومشفّر بنوع ASN.1
SubjectPublicKeyInfo المحدّد في معيار X.509. في Java، يتم تمثيل ترميز 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 Console أثناء تسجيل الدخول باستخدام حساب Google الذي استخدمته سابقًا للاشتراك كمطوِّر في Google Pay.
- في علامة التبويب Google Pay API، ضمن لوحة الدمج المباشر، انقر على إدارة بجانب مفتاحك العام الحالي. انقر على إضافة مفتاح آخر.
- اختَر حقل إدخال النص مفتاح التشفير العام وأضِف مفتاحك العام الذي تم إنشاؤه حديثًا بترميز base64 بتنسيق النقطة غير المضغوطة.
- انقر على حفظ مفاتيح التشفير.
لضمان تدوير المفاتيح بسلاسة، يجب توفير إمكانية فك تشفير المفاتيح الخاصة الجديدة والقديمة أثناء نقل المفاتيح.
إذا كنت تستخدم مكتبة Tink لفك تشفير الرمز المميّز، استخدِم رمز Java التالي لتوفير مفاتيح خاصة متعددة:
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .addRecipientPrivateKey(newPrivateKey) .addRecipientPrivateKey(oldPrivateKey);
تأكَّد من نشر رمز فك التشفير في مرحلة الإنتاج ومن مراقبة عمليات فك التشفير الناجحة.
غيِّر المفتاح العام المستخدَم في الرمز.
استبدِل قيمة السمة
publicKeyفي السمةPaymentMethodTokenizationSpecificationparameters:const tokenizationSpecification = { "type": "DIRECT", "parameters": { "protocolVersion": "ECv2", "publicKey": "BOdoXP1aiNp.....kh3JUhiSZKHYF2Y=" } }
- انشر الرمز من الخطوة 4 إلى بيئة الإنتاج. بعد نشر الرمز، تستخدم معاملات التشفير وفك التشفير أزواج المفاتيح الجديدة.
تأكَّد من أنّه لم يعُد يتم استخدام المفتاح العام القديم لتشفير أي معاملات.
- أزِل المفتاح الخاص القديم.
- افتح Google Pay & Wallet Console بعد تسجيل الدخول باستخدام حساب Google الذي استخدمته سابقًا للاشتراك كمطوِّر في Google Pay.
- في علامة التبويب Google Pay API، ضمن لوحة الدمج المباشر، انقر على إدارة بجانب مفتاحك العام الحالي. انقر على حذف بجانب مفتاحك العام القديم، ثم انقر على حفظ مفاتيح التشفير.
يستخدم محرّك بحث Google المفتاح المحدّد في السمة publicKey ضمن العنصر PaymentMethodTokenizationSpecification parameters، كما هو موضّح في المثال التالي:
{
"protocolVersion": "ECv2",
"publicKey": "BOdoXP+9Aq473SnGwg3JU1..."
}استخدِم مكتبة Tink لإدارة الرد المشفّر.
لإجراء عملية التحقّق من صحة التوقيع وفك تشفير الرسالة، استخدِم مكتبة paymentmethodtoken في Tink. لا تتوفّر هذه المكتبة إلا في Java. لاستخدامها، أكمل الخطوات التالية:
في ملف
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>عند بدء تشغيل الخادم، يتم جلب مفاتيح التوقيع من Google مسبقًا لإتاحة المفتاح في الذاكرة. يمنع هذا الإجراء المستخدم من ملاحظة أي تأخير في الشبكة أثناء استرداد مفاتيح فك التشفير.
GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
يمكنك فك تشفير الرسالة باستخدام الرمز التالي، الذي يفترض أنّ
paymentMethodTokenمخزّن في المتغيّرencryptedMessage، واستبدال الأقسام المكتوبة بخط غامق بما يتوافق مع السيناريو الخاص بك.بالنسبة إلى الاختبارات غير الإنتاجية، استبدِل
INSTANCE_PRODUCTIONبـINSTANCE_TEST، وإذا كان الدمج غير نشط أو لم يتم ضبط مفتاح تشفير له، استبدِل [YOUR MERCHANT ID] بـ12345678901234567890.- نشطة
- تم تفعيل عملية الدمج المباشر
- تم ضبط مفتاح تشفير
لا تستبدِل [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.إذا لم تتمكّن من طلب خادم 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);
تكون المفتاح الحالي في بيئة التشغيل الفعلي صالحًا حتى 14/04/2038 في الظروف العادية، باستثناء حالات اختراق المفتاح. في حال تعرّض المفاتيح للاختراق، تُرسل Google إشعارًا إلى جميع التجّار من خلال معلومات الاتصال المقدَّمة في بوابة الخدمة الذاتية لطلب إعادة تحميل
keys.jsonبشكل أسرع.يتعامل مقتطف الرمز مع تفاصيل الأمان التالية حتى تتمكّن من التركيز على استخدام الحمولة:
- يتم استرداد مفاتيح التوقيع من Google وتخزينها مؤقتًا في الذاكرة
- التحقّق من التوقيع
- فك التشفير