1# Tink for C++ HOW-TO 2 3This document contains instructions and C++ code snippets for common tasks in 4[Tink](https://github.com/google/tink). 5 6## Setup instructions 7 8Tink can be built using [Bazel](https://www.bazel.build) or 9[CMake](http://cmake.org). Using any other build system is currently not 10supported. This implies that you need to build your binary from scratch. 11 12### Bazel 13 14Using Tink in projects built with Bazel is straightforward and is the 15recommended approach. For reference, see 16[the C++ examples](https://github.com/google/tink/tree/master/cc/examples). 17 18### CMake 19 20Using Tink with CMake is supported, see [CMAKE-HOWTO](CMAKE-HOWTO.md) for a 21detailed description. 22 23## Initializing Tink 24 25Tink provides customizable initialization, which allows for choosing specific 26implementations (identified by _key types_) of desired primitives. This 27initialization happens via _registration_ of the implementations. 28 29For example, if you want to use all standard implementations of all primitives 30in the current release of Tink, the initialization would be: 31 32```cpp 33 #include "tink/config/tink_config.h" 34 35 // ... 36 auto status = TinkConfig::Register(); 37 if (!status.ok()) /* ... handle failure */; 38 // ... 39``` 40 41To use standard implementations of only one primitive, say AEAD: 42 43```cpp 44 #include "tink/aead/aead_config.h" 45 46 // ... 47 auto status = AeadConfig::Register(); 48 if (!status.ok()) /* ... handle failure */; 49 // ... 50``` 51 52The registration of custom key managers can proceed directly via 53`Registry` class: 54 55```cpp 56 #include "tink/registry.h" 57 #include "custom_project/custom_aead_key_manager.h" 58 59 // ... 60 auto status = 61 Registry::RegisterKeyManager(absl::make_unique<CustomAeadKeyManager>()); 62 if (!status.ok()) /* ... handle failure */; 63``` 64 65## Generating new keys and keysets 66 67Each `KeyManager` implementation provides a `NewKey(template)` method that 68generates new keys of the corresponding key type. However, to avoid accidental 69leakage of sensitive key material, you should avoid mixing key(set) generation 70with key(set) usage in code. To support the separation between these activities, 71Tink provides a command-line tool called [Tinkey](TINKEY.md), which can be used 72for common key management tasks. 73 74Still, if there is a need to generate a KeysetHandle with fresh key material 75directly in C++ code, you can use 76[`KeysetHandle`](https://github.com/google/tink/blob/master/cc/keyset_handle.h): 77 78```cpp 79 auto new_keyset_handle_result = KeysetHandle::GenerateNew(key_template); 80 if (!new_keyset_handle_result.ok()) return new_keyset_handle_result.status(); 81 auto keyset_handle = std::move(new_keyset_handle_result.ValueOrDie()); 82 // use the keyset... 83``` 84 85Recommended key templates can be obtained from util classes corresponding to 86Tink primitives, e.g. 87[MacKeyTemplates](https://github.com/google/tink/blob/master/cc/mac/mac_key_templates.h), 88[AeadKeyTemplates](https://github.com/google/tink/blob/master/cc/aead/aead_key_templates.h), 89and 90[HybridKeyTemplates](https://github.com/google/tink/blob/master/cc/hybrid/hybrid_key_templates.h). 91 92## Loading existing keysets 93 94To load encrypted keysets, use 95[`KeysetHandle`](https://github.com/google/tink/blob/master/cc/keyset_handle.h) 96and an appropriate 97[`KeysetReader`](https://github.com/google/tink/blob/master/cc/keyset_reader.h) 98depending on the wire format of the stored keyset, for example a 99[`BinaryKeysetReader`](https://github.com/google/tink/blob/master/cc/binary_keyset_reader.h) 100or a 101[`JsonKeysetReader`](https://github.com/google/tink/blob/master/cc/json_keyset_reader.h): 102 103```cpp 104 #include "tink/aead.h" 105 #include "tink/json_keyset_reader.h" 106 #include "tink/cleartext_keyset_handle.h" 107 #include "tink/integration/aws_kms_client.h" 108 109 // ... 110 std::string json_encrypted_keyset = ...; 111 auto reader_result = JsonKeysetReader::New(json_encrypted_keyset); 112 if (!reader_result.ok()) return reader_result.status(); 113 auto reader = std::move(reader_result.ValueOrDie()); 114 std::string master_key_uri = 115 "aws-kms://arn:aws:kms:us-east-1:007084425826:key/84a65985-f868-4bfc-83c2-366618acf147"; 116 auto aead = std::move(AwsKmsClient::NewAead(master_key_uri).ValueOrDie()); 117 auto handle_result = KeysetHandle::Read(std::move(reader), *aead); 118 if (!handle_result.ok()) return handle_result.status(); 119 auto keyset_handle = std::move(handle_result.ValueOrDie()); 120``` 121 122To load cleartext keysets, use 123[`CleartextKeysetHandle`](https://github.com/google/tink/blob/master/cc/cleartext_keyset_handle.h) 124and an appropriate 125[`KeysetReader`](https://github.com/google/tink/blob/master/cc/keyset_reader.h), 126 127```cpp 128 #include "tink/binary_keyset_reader.h" 129 #include "tink/cleartext_keyset_handle.h" 130 131 // ... 132 std::string binary_keyset = ...; 133 auto reader_result = BinaryKeysetReader::New(binary_keyset); 134 if (!reader_result.ok()) return reader_result.status(); 135 auto reader = std::move(reader_result.ValueOrDie()); 136 auto handle_result = CleartextKeysetHandle::Read(std::move(reader)); 137 if (!handle_result.ok()) return handle_result.status(); 138 auto keyset_handle = std::move(handle_result.ValueOrDie()); 139``` 140 141## Obtaining and using primitives 142 143[_Primitives_](PRIMITIVES.md) represent cryptographic operations offered by 144Tink, hence they form the core of the Tink API. A primitive is an interface that 145specifies what operations are offered by the primitive. A primitive can have 146multiple implementations, and you choose a desired implementation by using a key 147of a corresponding type (see [this 148document](KEY-MANAGEMENT.md#key-keyset-and-keysethandle) for further details). 149 150A list of primitives and the implementations currently supported by Tink in C++ 151can be found [here](PRIMITIVES.md#c). 152 153You obtain a primitive by calling the method `GetPrimitive<>` of a 154`KeysetHandle`. 155 156### Symmetric key encryption 157 158You can use an [AEAD (Authenticated Encryption with Associated 159Data)](PRIMITIVES.md#authenticated-encryption-with-associated-data) primitive to 160encrypt or decrypt data: 161 162```cpp 163 #include "tink/aead.h" 164 #include "tink/keyset_handle.h" 165 166 167 // 1. Get a handle to the key material. 168 KeysetHandle keyset_handle = ...; 169 170 // 2. Get the primitive. 171 auto aead_result= keyset_handle.GetPrimitive<Aead>(); 172 if (!aead_result.ok()) return aead_result.status(); 173 auto aead = std::move(aead_result.ValueOrDie()); 174 175 // 3. Use the primitive. 176 auto ciphertext_result = aead.Encrypt(plaintext, aad); 177 if (!ciphertext_result.ok()) return ciphertext_result.status(); 178 auto ciphertext = std::move(ciphertext_result.ValueOrDie()); 179``` 180 181### Hybrid encryption 182 183You can encrypt and decrypt using [a combination of public key encryption and 184symmetric key encryption](PRIMITIVES.md#hybrid-encryption): 185 186```cpp 187 #include "tink/hybrid_decrypt.h" 188 #include "tink/keyset_handle.h" 189 190 191 // 1. Get a handle to the key material. 192 KeysetHandle keyset_handle = ...; 193 194 // 2. Get the primitive. 195 auto hybrid_decrypt_result = keyset_handle.GetPrimitive<HybridDecrypt>(); 196 if (!hybrid_decrypt_result.ok()) return hybrid_decrypt_result.status(); 197 auto hybrid_decrypt = std::move(hybrid_decrypt_result.ValueOrDie()); 198 199 // 3. Use the primitive. 200 auto plaintext_result = hybrid_decrypt.Decrypt(ciphertext, context_info); 201 if (!plaintext_result.ok()) return plaintext_result.status(); 202 auto plaintext = std::move(plaintext_result.ValueOrDie()); 203``` 204 205### Envelope encryption 206 207Via the AEAD interface, Tink supports 208[envelope encryption](KEY-MANAGEMENT.md#envelope-encryption). 209 210For example, you can perform envelope encryption with a Google Cloud KMS key at 211`gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar` 212using the credentials in `credentials.json` as follows: 213 214```cpp 215 #include "tink/aead.h" 216 #include "tink/aead_key_templates.h" 217 #include "tink/keyset_handle.h" 218 #include "tink/integration/gcpkms/gcp_kms_client.h" 219 220 using crypto::tink::Aead; 221 using crypto::tink::integration::gcpkms::GcpKmsClient; 222 223 std::string kek_uri = "gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar"; 224 std::string credentials = "credentials.json"; 225 const KeyTemplate& dek_template = AeadKeyTemplates::Aes128Gcm(); 226 227 // Register GcpKmsClient. 228 auto client_result = GcpKmsClient::RegisterNewClient(kek_uri, credentials); 229 if (!client_result.ok()) { 230 std::clog << "GCP KMS client registration failed: " 231 << client_result.status().error_message() 232 << "\n"; 233 exit(1); 234 } 235 236 237 // 1. Get a handle to the key material. 238 const KeyTemplate& envelope_kt = AeadKeyTemplates::KmsEnvelopeAead(kek_uri, dek_template); 239 auto new_keyset_handle_result = KeysetHandle::GenerateNew(envelope_kt); 240 if (!new_keyset_handle_result.ok()) return new_keyset_handle_result.status(); 241 // The nice thing about envelope encryption is that you don't have to store 242 // this keyset handle because it only contains a reference to the remote KEK. 243 auto keyset_handle = std::move(new_keyset_handle_result.ValueOrDie()); 244 245 // 2. Get the primitive. 246 auto aead_result= keyset_handle.GetPrimitive<Aead>(); 247 if (!aead_result.ok()) return aead_result.status(); 248 auto aead = std::move(aead_result.ValueOrDie()); 249 250 // 3. Use the primitive. 251 auto ciphertext_result = aead->Encrypt(plaintext, aad); 252 if (!ciphertext_result.ok()) return ciphertext_result.status(); 253 auto ciphertext = std::move(ciphertext_result.ValueOrDie()); 254``` 255