It's important that Tink behaves "the same" in all programming languages. This concept is not straightforward, but most crucially:
To maintain consistency, Tink uses cross-language tests which can be found in the cross-language GitHub repository. These tests verify the consistency and interoperability of different languages.
However, defining consistency is not as straightforward as one would expect. Hence, this page provides our working definition. Basically, Tink provides two types of consistency:
- Evaluation consistency: For a given keyset1, if creation of the primitive succeeds in two languages, they behave the same.
- Creation consistency: Creation of a primitive succeeds in a language if the language supports all key types in a keyset, as documented in our list of supported key types.
Context
On a high level, Tink provides the following APIs:
Keyset manipulation: Tink provides APIs to add new keys to a keyset, remove keys from a keyset, and change the primary key in a keyset.
Keyset serialization: Tink provides APIs to serialize a keyset to a sequence of bytes, and conversely parse a keyset from a sequence of bytes.
Primitive creation: Tink provides an API to create an interface for a primitive from a keyset. For example, to create an
Aead
object from a keyset in Java, the user callskeysetHandle.getPrimitive(Aead.class, config)
.Primitive usage: The interface produced in the primitive creation step provides an API to perform cryptographic operations.
There are two important questions to ask about these APIs:
Creation: For a given serialized keyset, language, and primitive, is it possible to create the primitive from this keyset in the language?
Evaluation: If a primitive can be created in some language from a given keyset, how does the primitive object behave?
It is important to note that Tink does not provide consistency when parsing a keyset. For example, it is possible that Tink C++
- successfully parses keysets containing CHACHA20-POLY1305 keys, even though CHACHA20-POLY1305 AEAD operations are not implemented in Tink;
- successfully parses keysets with keys that have a length of 1-byte, which will fail in all cryptographic operations.
These behaviors may change in minor versions.
Evaluation consistency
Consistency of evaluation is more important than any consistency in the creation process: if an AEAD in Java cannot decrypt the encryption of the AEAD in C++, users have a serious problem.
In general, Tink aims to be consistent in the obvious way for primitives. For
example, if a C++ binary computes a signature
with public_key_sign->Sign(data)
, the corresponding Java verification
call publicKeyVerify.verify(signature, data)
is expected to succeed.
However, even here there are some caveats. For example,
the return type of aead.Encrypt
in Java is a byte[]
.
Per Java Language Specification (JLS) §10.7, the length of an array is of
type int
which per §JLS 4.2.1 can be a maximum of 2147483647. Hence,
encryption of an array with a length of 2147483647 fails in Java: encryption
has some overhead, meaning
the output would be too long. Nevertheless, in other languages encryption
is allowed to succeed for such inputs.
Hence, Tink provides evaluation consistency: For a given keyset, if creation of the primitive succeeds in two languages, they behave the same.
The exception is that some operations may fail in some exceptional circumstances.
Creation consistency
Creation of primitives does not always succeed for all keysets. For example, Tink does not allow users to create an AesSivKey if the key material has a length of 128 bits.
Nevertheless, Tink provides consistency as follows: if two languages both support a key type, the set of keys for which the primitive can be created coincides. Of course, if a language does not support a key type, then no primitive object can be created.
Creation consistency is less important than evaluation consistency, and there are more exceptions to this rule than for evaluation consistency. These limitations are documented on our list of supported key types. For example, for key type ECIES Tink offers a choice of which elliptic curve to use for key agreement, but Java does not support X25519. Hence, creation of a key using X25519 in Java fails.
-
In this document, we use the term
Keyset
to denote the object calledKeysetHandle
in most languages. ↩