تنظيم صفحاتك في مجموعات
يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.
يستخدم Tink مجموعات المفاتيح لتفعيل ميزة تغيير مفاتيح التشفير. من الناحية الرسمية، مجموعة المفاتيح هي
قائمة1 غير فارغة من المفاتيح التي يتم فيها تحديد مفتاح أساسي (المفتاح
الذي يتم استخدامه مثلاً لتوقيع النصوص الواضحة الجديدة وتشفيرها). بالإضافة إلى ذلك، تحصل المفاتيح
في مجموعة مفاتيح على معرّف فريد2 وحالة مفتاح تسمح
بإيقاف المفاتيح بدون إزالتها من مجموعة مفاتيح.
مجموعات المفاتيح هي الطريقة الرئيسية التي يمكن للمستخدمين من خلالها الوصول إلى المفاتيح (من خلال الفئة
KeysetHandle). ويضمن ذلك أن يكون لكل مستخدم رمز لمعالجة مفاتيح متعددة
في آنٍ واحد. بالنسبة إلى معظم مستخدمي التشفير، فإنّ التعامل مع مفاتيح متعددة هو
ضرورة: يجب أن يكون من الممكن تغيير المفاتيح (يمكن تسريب المفاتيح القديمة،
على سبيل المثال)، ولا يكاد يكون هناك عملية "تبديل إلى المفتاح التالي"
يمكن تطبيقها على الأجهزة التي يتم تشغيل الرمز عليها وجميع النصوص المشفَّرة،
على مستوى العالم وفي لحظة. وبالتالي، يحتاج المستخدم إلى كتابة رمز برمجي يعمل عند تغيير المفتاح من مفتاح إلى آخر.
مثال: AEAD
فكِّر في مجموعة مفاتيح AEAD التي تحتوي على مفاتيح متعددة لعنصر AEAD
الأولي. كما سبق أن أوضحنا، يحدِّد كل مفتاح بشكل فريد وظيفتَين:
\(\mathrm{Enc}\) و \(\mathrm{Dec}\). تحدِّد مجموعة المفاتيح الآن أيضًا دالتَين جديدتَين: \(\mathrm{Enc}\) و \(\mathrm{Dec}\) - \(\mathrm{Enc}\) ، وهما تساويان ببساطة الدالة \(\mathrm{Enc}\) للمفتاح الأساسي لمجموعة المفاتيح، بينما تحاول الدالة \(\mathrm{Dec}\) فك التشفير باستخدام كل المفاتيح، مع مراجعتها بترتيب معيّن (اطّلِع على القسم أدناه لمعرفة كيفية تحسين Tink لأداء
هذه العملية).
تجدر الإشارة إلى أنّ مجموعات المفاتيح هي مفاتيح كاملة:
فهي وصف كامل للدوالّ \(\mathrm{Enc}\) و
\(\mathrm{Dec}\) المستخدَمة. وهذا يعني أنّه يمكن للمستخدمين كتابة فئة تأخذ KeysetHandle كمدخل، ما يشير إلى أنّ الفئة تحتاج إلى وصف كامل
للكائنات \(\mathrm{Enc}\) و \(\mathrm{Dec}\) لكي تعمل
بشكلٍ سليم. يتيح ذلك للمستخدم كتابة واجهات برمجة تطبيقات تُعلمه بأنّه لاستخدام
هذه الفئة، عليك تقديم وصف لآلية تشفير أساسية.
تغيير مفاتيح التشفير
لنفترض أنّ أحد مستخدمي Tink يكتب برنامجًا يحصل أولاً على مجموعة مفاتيح من
إدارة الخدمات الرئيسية (KMS)، ثم ينشئ عنصر AEAD من مجموعة المفاتيح هذه، ويستخدم أخيرًا
هذا العنصر لتشفير النصوص المشفّرة وفك تشفيرها.
يتم إعداد هذا المستخدم تلقائيًا لتغيير المفاتيح، وتغيير
الخوارزميات في حال لم يعد اختياره الحالي يستوفي المعيار.
يجب الانتباه إلى بعض الأمور عند تنفيذ عملية تدوير المفاتيح هذه:
أولاً، يجب أن تضيف خدمة إدارة مفاتيح التشفير مفتاحًا جديدًا إلى مجموعة المفاتيح (ولكن ليس كملف أساسي بعد). بعد ذلك، يجب طرح مجموعة المفاتيح الجديدة في
جميع الملفات الثنائية، بحيث يحتوي كل ملف ثنائي يستخدم مجموعة المفاتيح هذه على أحدث مفتاح في
مجموعة المفاتيح. بعد ذلك فقط، يجب جعل المفتاح الجديد أساسيًا، وتوزيع مجموعة المفاتيح الناتجة مرة أخرى على جميع الملفات الثنائية التي تستخدم مجموعة المفاتيح.
معرّفات المفاتيح في النصوص المشفّرة
نذكّرك مرة أخرى بمثال مجموعة مفاتيح التشفير من النوع AEAD. في حال إجراء ذلك بشكل عفوي،
يتطلب فك تشفير نص مشفَّر من Tink محاولة فك التشفير باستخدام جميع المفاتيح في
مجموعة المفاتيح، لأنّه لا توجد طريقة لمعرفة المفتاح الذي تم استخدامه لتشفير
مجموعة المفاتيح. وقد يؤدي ذلك إلى زيادة كبيرة في تكلفة الأداء.
لهذا السبب، تسمح Tink بإضافة سلسلة من 5 بايت قبل النصوص المشفّرة، تكون مستمَدة
من المعرّف. وفقًا لفلسفة "المفاتيح الكاملة" أعلاه، هذه البادئة
جزء من المفتاح،
وجميع النصوص المشفّرة التي تم الحصول عليها باستخدام هذا المفتاح يجب أن تحتوي على هذه البادئة. عندما ينشئ
المستخدمون مفاتيح، يمكنهم اختيار ما إذا كان المفتاح سيستخدم بادئة مماثلة، أو
إذا كان يجب استخدام تنسيق نص مشفَّر بدونها.
عندما يكون المفتاح في مجموعة مفاتيح، تحسب Tink هذه العلامة من المعرّف الذي يحتوي عليه المفتاح في
مجموعة المفاتيح. تشير حقيقة أنّ المعرّفات فريدة2 ضمن مجموعة مفاتيح إلى
أنّ العلامات فريدة. وبالتالي، في حال استخدام المفاتيح المُصنَّفة فقط، لن ينخفض
الأداء مقارنةً بفك التشفير باستخدام مفتاح واحد: ما على Tink سوى تجربة أحد
المفاتيح عند فك التشفير.
ومع ذلك، بما أنّ العلامة هي جزء من المفتاح، يعني ذلك أيضًا أنّه لا يمكن أن يكون المفتاح
في مجموعة مفاتيح إلّا إذا كان لديه معرّف واحد محدّد. وينتج عن ذلك بعض التأثيرات عند
وصف تنفيذ العناصر الرئيسية بلغات مختلفة.
لا تزال بعض أجزاء Tink تتعامل مع مجموعات المفاتيح كمجموعة. ومع ذلك، ينبغي
تغيير ذلك.
والسبب هو أنّ الترتيب مهم بشكل عام: على سبيل المثال، نأخذ بعين الاعتبار دورة حياة تدوير المفتاح المعتادة باستخدام Aead. أولاً، تتم إضافة مفتاح جديد إلى مجموعة مفاتيح. لم يتم ضبط هذا المفتاح على أنّه أساسي بعد، ولكنه نشط. يتم طرح مجموعة المفاتيح الجديدة هذه لجميع الملفات الثنائية. بعد أن تعرف جميع الملفات الثنائية
على المفتاح الجديد، يصبح المفتاح أساسيًا (في هذه المرحلة فقط، يكون استخدام هذا المفتاح
آمنًا). في هذه الخطوة الثانية، يجب أن يعرف تبديل المفاتيح المفتاح الأخير الذي تمت إضافته. ↩
للتوافق مع مكتبة داخلية في Google، يسمح Tink
باستخدام مجموعات مفاتيح يتم فيها تكرار المعرّفات. ستتم إزالة هذه الميزة في المستقبل. ↩
تاريخ التعديل الأخير: 2025-07-25 (حسب التوقيت العالمي المتفَّق عليه)
[null,null,["تاريخ التعديل الأخير: 2025-07-25 (حسب التوقيت العالمي المتفَّق عليه)"],[[["\u003cp\u003eIn Tink, a Keyset is a list of keys, with one primary key and unique IDs for key rotation and management.\u003c/p\u003e\n"],["\u003cp\u003eKeysets are crucial for enabling key rotation without requiring users to implement it themselves.\u003c/p\u003e\n"],["\u003cp\u003eTink optimizes decryption by using key identifiers in ciphertexts to avoid trying all keys in a keyset.\u003c/p\u003e\n"],["\u003cp\u003eWhile Keysets offer significant advantages, users should consider careful key rotation procedures.\u003c/p\u003e\n"],["\u003cp\u003eTink primarily uses Keysets for key access, ensuring user code can handle multiple keys, which is often necessary for robust cryptography.\u003c/p\u003e\n"]]],["Tink uses **Keysets**, a list of keys with one designated as primary, to enable key rotation. Keyset keys have unique IDs and a status, allowing for disabling without removal. Encryption uses the primary key, while decryption iterates through all keys. Ciphertexts can be prefixed with a unique 5-byte tag derived from the key's ID to optimize decryption. Key rotation involves adding a new key, distributing the updated keyset, then setting the new key as primary, ensuring all binaries are updated.\n"],null,["# Keysets\n\n| In Tink, a **Keyset** is a list of keys, with one designated primary key.\n\nTink uses Keysets to enable key rotation. Formally, a keyset is a non-empty\nlist^[1](#fn1)^ of keys in which one key is designated primary (the key\nwhich is used for example to sign and encrypt new plaintexts). In addition, keys\nin a keyset get a unique ID^[2](#fn2)^ and a key status which allows\nto disable keys without removing them from a keyset.\n\nKeysets are the main way in which users can access keys (via the class\n`KeysetHandle`). This ensures that every user has code to handle multiple keys\nat once. For most users of cryptography, handling multiple keys is\n*a necessity*: it needs to be possible to change keys (old keys can be leaked,\nfor example), and there is almost never an atomic \"switch to the next key\"\nwhich can be applied to the machines the code runs and all ciphertexts,\nglobally, and in an instant. Hence, the user needs to write code which\nworks when one changes from one key to the next one.\n| **Note:** The full support of Keysets is one big advantage Tink has over other libraries: they facilitate key rotation, which otherwise every user would have to implement by themselves.\n\nExample: AEAD\n-------------\n\nConsider an AEAD keyset, which contains multiple keys for the AEAD\nprimitive. As explained before, each key uniquely specifies two functions:\n\\\\(\\\\mathrm{Enc}\\\\) and \\\\(\\\\mathrm{Dec}\\\\). The keyset now also specifies two new\nfunctions: \\\\(\\\\mathrm{Enc}\\\\) and \\\\(\\\\mathrm{Dec}\\\\) - \\\\(\\\\mathrm{Enc}\\\\) simply\nequals the function \\\\(\\\\mathrm{Enc}\\\\) of the primary key of the keyset, while\nthe function \\\\(\\\\mathrm{Dec}\\\\) tries to decrypt with all keys, going through\nthem in some order (see [below](#keyids) for how Tink improves the performance\nof this).\n\nIt is interesting to note that Keysets are *full keys* :\nthey are a complete description of the functions \\\\(\\\\mathrm{Enc}\\\\) and\n\\\\(\\\\mathrm{Dec}\\\\) used. This means that users can write a class which takes as\ninput a `KeysetHandle`, expressing the idea that the class needs a *complete\ndescription of objects \\\\(\\\\mathrm{Enc}\\\\) and \\\\(\\\\mathrm{Dec}\\\\) to function\nproperly*. This enables user to write APIs which communicate that: to use\nthis class you need to provide me the description of a cryptographic primitive.\n\nKey rotation\n------------\n\nConsider a Tink user, writing a program which first obtains a keyset from\na KMS, then creates an AEAD object from this keyset, and finally uses this\nobject to encrypt and decrypt ciphertexts.\n\nSuch a user is automatically prepared for key rotation; and switching\nalgorithms in case their current choice does not meet the standard anymore.\n\nOne has to be somewhat careful though when implementing such key rotation:\nFirst, the KMS should add a new key to the keyset (but not yet set it as a\nprimary). Then, the new keyset needs to be rolled out to\nall binaries, so that every binary using this keyset has the newest key in\nthe keyset. Only then should the new key be made primary, and the resulting\nkeyset is again distributed to all binaries using the keyset.\n\nKey identifiers in ciphertexts\n------------------------------\n\nConsider again the example of an AEAD keyset. If done naively,\ndecrypting a ciphertext requires Tink to try to decrypt with all the keys in\nthe Keyset, as there is no way of knowing which key was used to encrypt the\nkeyset. This can cause a large performance overhead.\n\nBecause of this, Tink allows to prefix ciphertexts with a 5-byte string derived\nfrom the ID. Following the philosophy of 'Full Keys' above, this prefix\nis *part of the key*,\nand all ciphertexts ever derived with this key should have this prefix. When\nusers create keys, they can choose whether the key should use such a prefix, or\nif a ciphertext format without it should be used.\n| **Note:** Some primitives don't allow such tagging; for example in a [PRF](https://en.wikipedia.org/wiki/Pseudorandom_function_family) there is no obvious way how to embed such a prefix. For these keys, Tink does not offer such a facility.\n\nWhen a key is in a keyset, Tink computes this tag from the ID the key has in the\nkeyset. The fact that IDs are unique[^2^](#fn2) within a keyset implies\nthat the tags are unique. Hence, if only tagged keys are used, there is no\nperformance\nloss compared to decrypting with a single key: Tink only needs to try one of\nthe keys when decrypting.\n\nHowever, since the tag is part of the key, this also implies that the key can\nonly be in a keyset if it has one specific ID. This has some implications when\ndescribing the implementation of [key objects](/tink/design/key_objects) in\ndifferent languages. \n\n*** ** * ** ***\n\n1. Some parts of Tink still treat Keysets as a set. However, this\n should be changed.\n\n The reason is that the order is in general\n important: for example, consider the typical lifecycle of a key rotation with\n Aead. First, a new key is added to a keyset. This key is not made primary yet,\n but active. This new keyset is rolled out to all binaries. Once all binaries\n know the new key, the key is made primary (only at this point using this key\n is safe). In this second step, key rotation needs to know the last key added. [↩](#fnref1)\n\n2. For compatibility with a Google internal library, Tink\n allows to have keysets in which IDs are repeated. This support will be\n removed in the future. [↩](#fnref2)"]]