تشفير بيانات الدفع للتجّار

تعرض 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 الخطوات من 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 سلسلة تاريخ ووقت انتهاء صلاحية المفتاح الوسيط بالملي ثانية حسب التوقيت العالمي المنسق (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 العدد شهر انتهاء صلاحية البطاقة، حيث يمثّل الرقم 1 شهر يناير، ويمثّل الرقم 2 شهر فبراير، وهكذا.
expirationYear العدد سنة انتهاء صلاحية البطاقة المكوّنة من أربعة أرقام، مثل 2020
authMethod سلسلة طريقة المصادقة على معاملة البطاقة
merchantTokenId سلسلة

معرّف الرمز المميّز للتاجر في معاملة البطاقة لا يتم عرض هذا الحقل الاختياري إلا في حال استيفاء جميع الشروط التالية:

  • يحدّد التاجر عنصر *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 المحدّد، وهو التنسيق العادي الذي تنتجه عمليات تنفيذ 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

  • المنحنى الإهليلجي: NIST P-256 (المعروف أيضًا في OpenSSL باسم prime256v1).
  • ‫CheckMode وOldCofactorMode وSingleHashMode وCofactorMode تساوي 0.
  • تنسيق النقطة غير مضغوط.
دالة اشتقاق المفاتيح

رمز مصادقة الرسالة المستند إلى التجزئة (HMAC) مع خوارزمية SHA-256 ‏(HKDFwithSHA256)

  • يجب عدم تقديم قيمة عشوائية.
  • يجب أن تكون المعلومات "Google"، ومشفّرة بترميز ASCII لإصدار البروتوكول ECv2.
  • يجب اشتقاق 256 بت لمفتاح AES256 و256 بت أخرى لمفتاح HMAC_SHA256.
خوارزمية التشفير المتماثل

‫DEM2، كما هو محدّد في ISO 18033-2

خوارزمية التشفير: AES-256-CTR مع متجه إعداد صفري وبدون حشو

خوارزمية 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

كيفية فك تشفير الرمز المميّز لطريقة الدفع

اتّبِع الخطوات التالية لفك تشفير الرمز المميّز:

  1. استخدِم مفتاحك الخاص وephemeralPublicKey المحدّد لاستخراج مفتاح مشترك بطول 512 بت يستخدم ECIES-KEM. استخدِم المَعلمات التالية:
    • المنحنى الإهليلجي: NIST P-256، والمعروف أيضًا في OpenSSL باسم prime256v1.
    • ‫CheckMode وOldCofactorMode وSingleHashMode وCofactorMode هي 0.
    • دالة الترميز: تنسيق نقطة غير مضغوط
    • دالة اشتقاق المفتاح: HKDFwithSHA256، كما هو موضّح في RFC 5869، مع المَعلمة التالية:
      • يجب عدم تقديم قيمة عشوائية. وفقًا لمعيار RFC، يجب أن يكون هذا مكافئًا لـ 32 بايت من الأصفار.
  2. قسِّم المفتاح الذي تم إنشاؤه إلى مفتاحَين بطول 256 بت: symmetricEncryptionKey وmacKey.
  3. يُرجى التحقّق من أنّ الحقل "tag" هو عنوان MAC صالح لـ "encryptedMessage".

    لإنشاء رمز MAC المتوقّع، استخدِم HMAC (RFC 5869) مع دالة التجزئة SHA256 وmacKey الذي تم الحصول عليه في الخطوة 2.

  4. يمكنك فك تشفير encryptedMessage باستخدام وضع AES-256-CTR، ومع ما يلي:

    • قيمة IV صفرية
    • بدون حشو
    • ‫symmetricEncryptionKey التي تم اشتقاقها في الخطوة 2

إدارة المفاتيح

مفاتيح التشفير الخاصة بالتجّار

ينشئ التجّار مفتاحًا عامًا وفقًا للمواصفات الموضّحة في مواصفات نظام التشفير.

مفاتيح توقيع الجذر من Google

تنشر Google مجموعة من المفاتيح العامة الصالحة حاليًا لتوقيع الجذر والتي يمكن جلبها من عنوان URL متاح للجميع. تكون المفاتيح صالحة طالما أنّ عناوين ذاكرة التخزين المؤقت لبروتوكول HTTP التي يعرضها عنوان URL تشير إلى ذلك. ويتم تخزينها مؤقتًا إلى أن تنتهي صلاحيتها، ويتم تحديد ذلك من خلال حقل keyExpiration. ننصحك بإعادة جلب المفاتيح من عنوان URL العلني عند انتهاء صلاحية عملية الجلب، وذلك للحصول على القائمة الحالية للمفاتيح الصالحة.

استثناء لبروتوكول ECv2: إذا لم تتمكّن من جلب المفاتيح من Google في وقت التشغيل، يمكنك جلب keys.json من عنوان URL الخاص بالإنتاج وحفظه في نظامك وإعادة تحميله يدويًا بشكل دوري. في الظروف العادية، تُصدر Google مفتاح توقيع جذر جديدًا للإصدار الثاني من EC قبل خمس سنوات من انتهاء صلاحية المفتاح الذي له أطول تاريخ انتهاء صلاحية. في حال اختراق المفاتيح، تُرسل 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 لكل من بيئات الاختبار والتشغيل الفعلي من خلال الروابط التالية:

تدوير المفاتيح

إذا فككت تشفير رمز مميّز لطريقة الدفع مباشرةً على خوادمك من خلال الدمج المباشر، عليك تبديل المفاتيح سنويًا.

أكمِل الخطوات التالية لتبديل مفاتيح التشفير:

  1. استخدِم OpenSSL لإنشاء مفتاحَي تشفير جديدَين.
  2. افتح Google Pay & Wallet Console أثناء تسجيل الدخول باستخدام حساب Google الذي استخدمته سابقًا للاشتراك كمطوّر في Google Pay.
  3. في علامة التبويب Google Pay API، ضمن لوحة الدمج المباشر، انقر على إدارة بجانب مفتاحك العام الحالي. انقر على إضافة مفتاح آخر.
  4. اختَر حقل إدخال النص مفتاح التشفير العام وأضِف المفتاح العام الذي تم إنشاؤه حديثًا والمشفَّر باستخدام Base64 بتنسيق نقطي غير مضغوط.
  5. انقر على حفظ مفاتيح التشفير.
  6. لضمان تدوير المفاتيح بسلاسة، يجب إتاحة فك تشفير المفاتيح الخاصة الجديدة والقديمة أثناء نقل المفاتيح.

    إذا كنت تستخدم مكتبة Tink لفك تشفير الرمز المميّز، استخدِم رمز Java التالي لإتاحة استخدام مفاتيح خاصة متعددة:

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

    تأكَّد من نشر رمز فك التشفير في مرحلة الإنتاج ومن مراقبة عمليات فك التشفير الناجحة.

  7. غيِّر المفتاح العام المستخدَم في الرمز.

    استبدِل قيمة السمة publicKey في السمة PaymentMethodTokenizationSpecification parameters:

    const tokenizationSpecification = {
      "type": "DIRECT",
      "parameters": {
        "protocolVersion": "ECv2",
        "publicKey": "BOdoXP1aiNp.....kh3JUhiSZKHYF2Y="
      }
    }
  8. انشر الرمز من الخطوة 4 في بيئة الإنتاج. بعد نشر الرمز، تستخدم معاملات التشفير وفك التشفير مفتاحَي التشفير الجديدَين.
  9. تأكَّد من أنّ المفتاح العام القديم لم يعُد يُستخدَم لتشفير أي معاملات.

  10. أزِل المفتاح الخاص القديم.
  11. افتح Google Pay & Wallet Console بعد تسجيل الدخول باستخدام حساب 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] بـ 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);
  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);

    المفتاح الحالي في بيئة التشغيل الفعلي صالح حتى 14 أبريل 2038 في الظروف العادية، باستثناء حالات اختراق المفاتيح. في حال اختراق المفاتيح، تُرسل Google إشعارًا إلى جميع التجّار من خلال معلومات الاتصال المقدَّمة في بوابة الخدمة الذاتية لطلب إعادة تحميل keys.json بشكل أسرع.

    يتعامل مقتطف الرمز مع تفاصيل الأمان التالية حتى تتمكّن من التركيز على استهلاك الحمولة:

    • تم جلب مفاتيح توقيع Google وتخزينها مؤقتًا في الذاكرة
    • التحقّق من التوقيع
    • فك التشفير