xref: /aosp_15_r20/external/tink/docs/CPP-HOWTO.md (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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