[null,null,["อัปเดตล่าสุด 2025-07-25 UTC"],[[["\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)"]]