| # Tink for C++ HOW-TO |
| |
| This document contains instructions and C++ code snippets for common tasks in |
| [Tink](https://github.com/google/tink). |
| |
| ## Setup instructions |
| |
| Tink can be built using [Bazel](https://www.bazel.build) or |
| [CMake](http://cmake.org). Using any other build system is currently not |
| supported. This implies that you need to build your binary from scratch. |
| |
| ### Bazel |
| |
| Using Tink in projects built with Bazel is straighforward and is the recommended |
| approach. For an example, see [this project which specifies Tink as a dependency |
| in a Bazel WORKSPACE file](https://github.com/thaidn/tink-examples). |
| |
| ### CMake |
| |
| Using Tink with CMake is suported, see [CMAKE-HOWTO](CMAKE-HOWTO.md) for for a |
| detailed description. |
| |
| ## Initializing Tink |
| |
| Tink provides customizable initialization, which allows for choosing specific |
| implementations (identified by _key types_) of desired primitives. This |
| initialization happens via _registration_ of the implementations. |
| |
| For example, if you want to use all standard implementations of all primitives |
| in the current release of Tink, the initialization would be: |
| |
| ```cpp |
| #include "tink/config/tink_config.h" |
| |
| // ... |
| auto status = TinkConfig::Register(); |
| if (!status.ok()) /* ... handle failure */; |
| // ... |
| ``` |
| |
| To use standard implementations of only one primitive, say AEAD: |
| |
| ```cpp |
| #include "tink/aead/aead_config.h" |
| |
| // ... |
| auto status = AeadConfig::Register(); |
| if (!status.ok()) /* ... handle failure */; |
| // ... |
| ``` |
| |
| The registration of custom key managers can proceed directly via |
| `Registry` class: |
| |
| ```cpp |
| #include "tink/registry.h" |
| #include "custom_project/custom_aead_key_manager.h" |
| |
| // ... |
| auto status = Registry::RegisterKeyManager(new CustomAeadKeyManager()); |
| if (!status.ok()) /* ... handle failure */; |
| ``` |
| |
| ## Generating new keys and keysets |
| |
| Each `KeyManager` implementation provides a `NewKey(template)` method that |
| generates new keys of the corresponding key type. However, to avoid accidental |
| leakage of sensitive key material, you should avoid mixing key(set) generation |
| with key(set) usage in code. To support the separation between these activities, |
| Tink provides a command-line tool called [Tinkey](TINKEY.md), which can be used |
| for common key management tasks. |
| |
| Still, if there is a need to generate a KeysetHandle with fresh key material |
| directly in C++ code, you can use |
| [`KeysetHandle`](https://github.com/google/tink/blob/master/cc/keyset_handle.h): |
| |
| ```cpp |
| auto new_keyset_handle_result = KeysetHandle::GenerateNew(key_template); |
| if (!new_keyset_handle_result.ok()) return new_keyset_handle_result.status(); |
| auto keyset_handle = std::move(new_keyset_handle_result.ValueOrDie()); |
| // use the keyset... |
| ``` |
| |
| Recommended key templates can be obtained from util classes corresponding to |
| Tink primitives, e.g. |
| [MacKeyTemplates](https://github.com/google/tink/blob/master/cc/mac/mac_key_templates.h), |
| [AeadKeyTemplates](https://github.com/google/tink/blob/master/cc/aead/aead_key_templates.h), |
| and |
| [HybridKeyTemplates](https://github.com/google/tink/blob/master/cc/hybrid/hybrid_key_templates.h). |
| |
| ## Loading existing keysets |
| |
| To load encrypted keysets, use |
| [`KeysetHandle`](https://github.com/google/tink/blob/master/cc/keyset_handle.h) |
| and an appropriate |
| [`KeysetReader`](https://github.com/google/tink/blob/master/cc/keyset_reader.h) |
| depending on the wire format of the stored keyset, for example a |
| [`BinaryKeysetReader`](https://github.com/google/tink/blob/master/cc/binary_keyset_reader.h) |
| or a |
| [`JsonKeysetReader`](https://github.com/google/tink/blob/master/cc/json_keyset_reader.h): |
| |
| ```cpp |
| #include "tink/aead.h" |
| #include "tink/json_keyset_reader.h" |
| #include "tink/cleartext_keyset_handle.h" |
| #include "tink/integration/aws_kms_client.h" |
| |
| // ... |
| std::string json_encrypted_keyset = ...; |
| auto reader_result = JsonKeysetReader::New(json_encrypted_keyset); |
| if (!reader_result.ok()) return reader_result.status(); |
| auto reader = std::move(reader_result.ValueOrDie()); |
| std::string master_key_uri = |
| "aws-kms://arn:aws:kms:us-east-1:007084425826:key/84a65985-f868-4bfc-83c2-366618acf147"; |
| auto aead = std::move(AwsKmsClient::NewAead(master_key_uri).ValueOrDie()); |
| auto handle_result = KeysetHandle::Read(std::move(reader), *aead); |
| if (!handle_result.ok()) return handle_result.status(); |
| auto keyset_handle = std::move(handle_result.ValueOrDie()); |
| ``` |
| |
| To load cleartext keysets, use |
| [`CleartextKeysetHandle`](https://github.com/google/tink/blob/master/cc/cleartext_keyset_handle.h) |
| and an appropriate |
| [`KeysetReader`](https://github.com/google/tink/blob/master/cc/keyset_reader.h), |
| |
| ```cpp |
| #include "tink/binary_keyset_reader.h" |
| #include "tink/cleartext_keyset_handle.h" |
| |
| // ... |
| std::string binary_keyset = ...; |
| auto reader_result = BinaryKeysetReader::New(binary_keyset); |
| if (!reader_result.ok()) return reader_result.status(); |
| auto reader = std::move(reader_result.ValueOrDie()); |
| auto handle_result = CleartextKeysetHandle::Read(std::move(reader)); |
| if (!handle_result.ok()) return handle_result.status(); |
| auto keyset_handle = std::move(handle_result.ValueOrDie()); |
| ``` |
| |
| ## Obtaining and using primitives |
| |
| [_Primitives_](PRIMITIVES.md) represent cryptographic operations offered by |
| Tink, hence they form the core of the Tink API. A primitive is an interface that |
| specifies what operations are offered by the primitive. A primitive can have |
| multiple implementations, and you choose a desired implementation by using a key |
| of a corresponding type (see [this |
| document](KEY-MANAGEMENT.md#key-keyset-and-keysethandle) for further details). |
| |
| A list of primitives and the implementations currently supported by Tink in C++ |
| can be found [here](PRIMITIVES.md#c). |
| |
| You obtain a primitive by calling the method `GetPrimitive<>` of a |
| `KeysetHandle`. |
| |
| ### Symmetric key encryption |
| |
| You can use an [AEAD (Authenticated Encryption with Associated |
| Data)](PRIMITIVES.md#authenticated-encryption-with-associated-data) primitive to |
| encrypt or decrypt data: |
| |
| ```cpp |
| #include "tink/aead.h" |
| #include "tink/keyset_handle.h" |
| |
| |
| // 1. Get a handle to the key material. |
| KeysetHandle keyset_handle = ...; |
| |
| // 2. Get the primitive. |
| auto aead_result= keyset_handle.GetPrimitive<Aead>(); |
| if (!aead_result.ok()) return aead_result.status(); |
| auto aead = std::move(aead_result.ValueOrDie()); |
| |
| // 3. Use the primitive. |
| auto ciphertext_result = aead.Encrypt(plaintext, aad); |
| if (!ciphertext_result.ok()) return ciphertext_result.status(); |
| auto ciphertext = std::move(ciphertext_result.ValueOrDie()); |
| ``` |
| |
| ### Hybrid encryption |
| |
| You can encrypt and decrypt using [a combination of public key encryption and |
| symmetric key encryption](PRIMITIVES.md#hybrid-encryption): |
| |
| ```cpp |
| #include "tink/hybrid_decrypt.h" |
| #include "tink/keyset_handle.h" |
| |
| |
| // 1. Get a handle to the key material. |
| KeysetHandle keyset_handle = ...; |
| |
| // 2. Get the primitive. |
| auto hybrid_decrypt_result = keyset_handle.GetPrimitive<HybridDecrypt>(); |
| if (!hybrid_decrypt_result.ok()) return hybrid_decrypt_result.status(); |
| auto hybrid_decrypt = std::move(hybrid_decrypt_result.ValueOrDie()); |
| |
| // 3. Use the primitive. |
| auto plaintext_result = hybrid_decrypt.Decrypt(ciphertext, context_info); |
| if (!plaintext_result.ok()) return plaintext_result.status(); |
| auto plaintext = std::move(plaintext_result.ValueOrDie()); |
| ``` |