> but also key serialization. libsodium kind of strands you when it comes to the question how to actually store keys.
Hmm. Is there really interesting work needed here? The keys are (should be treated as) an opaque blob and it'll probably generally be a mistake to do anything with them except load them back into (maybe a different language implementation of) Tink / libsodium.
If you're a cryptanalyst it can make sense to get a structure rather than a blob but I don't see a value in this for the intended users of Tink, and if it's just a blob -- who doesn't know how to serialize and de-serialize some bytes in their preferred language?
From a user's point of view, keys are still binary blob. Internally Tink serializes keys using protobuf, but in principle it supports arbitrary key formats via the KeysetReader/KeysetWriter interfaces. Admittedly, this aspect of our design is somewhat clumsy. We're working on a new design.
The key differences (pun intended) between Tink and other libraries are:
1/ Tink works with keysets instead of individual keys. This enables key rotation and crypto agility. This is very important at Google because there are systems that generate too much data to encrypt with a single key. We want to be able to rotate keys and still be able to decrypt old ciphertext.
Also most crypto schemes we're using today would be broken eventually. We want to make sure we can add new schemes and retire old ones over time without users having to change their code. For example, a lot of libraries have functions containing algorithm names, e.g., aes_gcm_encrypt. When GCM is no longer adequate, users of these libraries would have a hard time upgrading to alternatives.
Tink interfaces don't contain the algorithm name. We name our APIs after generic crypto primitives rather than famous cryptographers or algorithms. For example, we provide a generic AEAD interface for symmetric key encryption. With proper key management, users don't have to know anything about any particular algorithms and can easily rotate to new ones without changing a single line of code (rather than upgrading Tink).
2/ A key in Tink contains not only the raw key material, but also all necessary parameters. It is equivalent to the result of a handshake. Before any data encryption can take place, both sides have to reach an agreement not only on a raw key, but also how to use that key to encrypt data. Since a key in Tink contains all parameters, Tink does not require in-band ciphersuite negotiation. That is no ciphertext in Tink contains any other metadata aside from a key ID.
This design sounds so simple but I've seen people get this wrong all the time. For example, the root cause of many embarrassing vulnerabilities in JWT [1] is in-band ciphersuite negotiation. That is, a JWT contains an alg field that dictates how the receiver should process it. This alg field should rather be included as part of the key.
JWT is not the only standard making this mistake. Many crypto libraries only ask users for the raw key material. This means the parameters are either implicitly assumed or under specified. Aside from the aforementioned vulnerabilities, this can also lead to key confusion, cross-protocol key reuse and make it hard to rotate keys or change algorithms.
To the best of my knowledge, Tink is the only high-level library that gets this right.
Hmm. Is there really interesting work needed here? The keys are (should be treated as) an opaque blob and it'll probably generally be a mistake to do anything with them except load them back into (maybe a different language implementation of) Tink / libsodium.
If you're a cryptanalyst it can make sense to get a structure rather than a blob but I don't see a value in this for the intended users of Tink, and if it's just a blob -- who doesn't know how to serialize and de-serialize some bytes in their preferred language?