xref: /aosp_15_r20/external/tink/docs/JAVA-HOWTO.md (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1# Tink for Java HOW-TO
2
3This document contains instructions and Java code snippets for common tasks in
4[Tink](https://github.com/tink-crypto/tink-java).
5
6If you want to contribute code to the Java implementation, please read the [Java
7hacking guide](JAVA-HACKING.md).
8
9## Setup instructions
10
11See https://developers.google.com/tink/tink-setup#java for setup
12instructions.
13
14## API documentation
15
16*   Java:
17    *   [1.9.0](https://google.github.io/tink/javadoc/tink/1.9.0)
18    *   [HEAD-SNAPSHOT](https://google.github.io/tink/javadoc/tink/HEAD-SNAPSHOT)
19*   Android:
20    *   [1.9.0](https://google.github.io/tink/javadoc/tink-android/1.9.0)
21    *   [HEAD-SNAPSHOT](https://google.github.io/tink/javadoc/tink-android/HEAD-SNAPSHOT)
22
23## Important warnings
24
25**Do not use APIs which have fields or methods marked with the `@Alpha`
26annotation.** They can be modified in any way, or even removed, at any time.
27They are in the package, but not for official, production release, but only for
28testing.
29
30**Do not use APIs in `com.google.crypto.tink.subtle`.** While they're generally
31safe to use, they're not meant for public consumption and can be modified in any
32way, or even removed, at any time.
33
34## Initializing Tink
35
36Tink provides customizable initialization, which allows you to choose specific
37implementations (identified by _key types_) of desired primitives. This
38initialization happens via _registration_ of the implementations.
39
40For example, if you want to use all implementations of all primitives in Tink,
41the initialization would be:
42
43```java
44    import com.google.crypto.tink.config.TinkConfig;
45
46    TinkConfig.register();
47```
48
49To use only implementations of the AEAD primitive:
50
51```java
52    import com.google.crypto.tink.aead.AeadConfig;
53
54    AeadConfig.register();
55```
56
57For custom initialization the registration proceeds directly via the
58`Registry` class:
59
60```java
61    import com.google.crypto.tink.Registry;
62    import my.custom.package.aead.MyAeadKeyManager;
63
64    // Register a custom implementation of AEAD.
65    Registry.registerKeyManager(new MyAeadKeyManager());
66
67```
68
69## Generating new keys and keysets
70
71Each `KeyManager`-implementation provides `newKey(..)`-methods that generate new
72keys of the corresponding key type. However, to avoid accidental leakage of
73sensitive key material, you should avoid mixing key(set) generation with
74key(set) usage in code. To support the separation between these activities, Tink
75provides a command-line tool called [Tinkey](TINKEY.md), which can be used for
76common key management tasks.
77
78Still, if there is a need to generate a KeysetHandle with fresh key material
79directly in Java code, you can use
80[`KeysetHandle`](https://github.com/tink-crypto/tink-java/blob/main/src/main/java/com/google/crypto/tink/KeysetHandle.java).
81For example, you can generate a keyset containing a randomly generated
82AES128-GCM key as follows.
83
84```java
85    import com.google.crypto.tink.KeysetHandle;
86    import com.google.crypto.tink.aead.PredefinedAeadParameters;
87
88    KeysetHandle keysetHandle = KeysetHandle.generateNew(
89        PredefinedAeadParameters.AES128_GCM);
90```
91
92## Serializing keysets
93
94After generating key material, you might want to serialize it in order to
95persist it to a storage system, e.g., writing to a file.
96
97```java
98    import com.google.crypto.tink.InsecureSecretKeyAccess;
99    import com.google.crypto.tink.KeysetHandle;
100    import com.google.crypto.tink.TinkJsonProtoKeysetFormat;
101    import com.google.crypto.tink.aead.PredefinedAeadParameters;
102    import java.nio.Files;
103
104    // Generate the key material...
105    KeysetHandle keysetHandle = KeysetHandle.generateNew(
106        PredefinedAeadParameters.AES128_GCM);
107
108    // and serialize it to a string.
109    String keysetFilename = "my_keyset.json";
110    String serializedKeyset =
111        TinkJsonProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get());
112```
113
114Parsing can be done with `TinkJsonProtoKeysetFormat.parseKeyset`. If the keyset
115has no secret key material, the method `serializeKeysetWithoutSecret` can be
116used (which does not require `InsecureSecretKeyAccess`).
117
118Storing keysets unencrypted on disk is not recommended. Tink supports encrypting
119keysets with master keys stored in remote key management systems, see for
120example
121https://developers.google.com/tink/client-side-encryption#java.
122
123## Obtaining and using primitives
124
125[Primitives](PRIMITIVES.md) represent cryptographic operations offered by Tink,
126hence they form the core of the Tink API. A primitive is an interface which
127specifies what operations are offered by the primitive. A primitive can have
128multiple implementations, and you choose a desired implementation by using a key
129of a corresponding type (see [this
130document](KEY-MANAGEMENT.md#key-keyset-and-keysethandle) for further details).
131
132A list of primitives and the implementations currently supported by Tink in Java
133can be found [here](PRIMITIVES.md#java).
134
135You obtain a primitive by calling the method `getPrimitive(classObject)` of a
136`KeysetHandle`, where the `classObject` is the class object corresponding to the
137primitive (for example `Aead.class` for AEAD).
138
139### Symmetric Key Encryption
140
141You can obtain and use an
142[AEAD](PRIMITIVES.md#authenticated-encryption-with-associated-data)
143(Authenticated Encryption with Associated Data) primitive to encrypt or decrypt
144data:
145
146```java
147    import com.google.crypto.tink.Aead;
148    import com.google.crypto.tink.aead.PredefinedAeadParameters;
149
150    // 1. Generate the key material.
151    KeysetHandle keysetHandle = KeysetHandle.generateNew(
152        PredefinedAeadParameters.AES128_GCM);
153
154    // 2. Get the primitive.
155    Aead aead = keysetHandle.getPrimitive(Aead.class);
156
157    // 3. Use the primitive to encrypt a plaintext,
158    byte[] ciphertext = aead.encrypt(plaintext, aad);
159
160    // ... or to decrypt a ciphertext.
161    byte[] decrypted = aead.decrypt(ciphertext, aad);
162```
163
164### Deterministic symmetric key encryption
165
166You can obtain and use a
167[DeterministicAEAD](PRIMITIVES.md#deterministic-authenticated-encryption-with-associated-data)
168(Deterministic Authenticated Encryption with Associated Data primitive to
169encrypt or decrypt data:
170
171```java
172    import com.google.crypto.tink.daead.PredefinedDeterministicAeadParameters;
173    import com.google.crypto.tink.KeysetHandle;
174
175    // 1. Generate the key material.
176    KeysetHandle keysetHandle = KeysetHandle.generateNew(
177        PredefinedDeterministicAeadParameters.AES256_SIV);
178
179    // 2. Get the primitive.
180    DeterministicAead daead =
181       keysetHandle.getPrimitive(DeterministicAead.class);
182
183    // 3. Use the primitive to deterministically encrypt a plaintext,
184    byte[] ciphertext = daead.encryptDeterministically(plaintext, aad);
185
186    // ... or to deterministically decrypt a ciphertext.
187    byte[] decrypted = daead.decryptDeterministically(ciphertext, aad);
188```
189
190### Symmetric key encryption of streaming data
191
192See
193https://developers.google.com/tink/encrypt-large-files-or-data-streams#java
194
195### Message Authentication Code
196
197See
198https://developers.google.com/tink/protect-data-from-tampering#java
199
200### Digital signatures
201
202See https://developers.google.com/tink/digitally-sign-data
203
204### Hybrid encryption
205
206See https://developers.google.com/tink/exchange-data#java
207
208### Envelope encryption
209
210Via the AEAD interface, Tink supports
211[envelope encryption](KEY-MANAGEMENT.md#envelope-encryption).
212
213For example, you can perform envelope encryption with a Google Cloud KMS key at
214`gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar`
215using the credentials in `credentials.json` as follows:
216
217```java
218    import com.google.crypto.tink.Aead;
219    import com.google.crypto.tink.KeyTemplates;
220    import com.google.crypto.tink.KeysetHandle;
221    import com.google.crypto.tink.KmsClients;
222    import com.google.crypto.tink.aead.KmsEnvelopeAeadKeyManager;
223    import com.google.crypto.tink.integration.gcpkms.GcpKmsClient;
224
225    // 1. Generate the key material.
226    String kmsKeyUri =
227        "gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar";
228    KeysetHandle handle =
229        KeysetHandle.generateNew(
230            KmsEnvelopeAeadKeyManager.createKeyTemplate(
231                kmsKeyUri, KeyTemplates.get("AES128_GCM")));
232
233    // 2. Register the KMS client.
234    KmsClients.add(new GcpKmsClient()
235        .withCredentials("credentials.json"));
236
237    // 3. Get the primitive.
238    Aead aead = handle.getPrimitive(Aead.class);
239
240    // 4. Use the primitive.
241    byte[] ciphertext = aead.encrypt(plaintext, aad);
242```
243
244## Key rotation
245
246Support for key rotation in Tink is provided via the
247[`KeysetHandle.Builder`](https://github.com/tink-crypto/tink-java/blob/main/src/main/java/com/google/crypto/tink/KeysetHandle.java)
248class.
249
250You have to provide a `KeysetHandle`-object that contains the keyset that should
251be rotated, and a specification of the new key via a
252[`Parameters`](https://github.com/tink-crypto/tink-java/blob/main/src/main/java/com/google/crypto/tink/Parameters.java)
253object.
254
255```java
256    import com.google.crypto.tink.KeysetHandle;
257    import com.google.crypto.tink.KeysetManager;
258
259    KeysetHandle keysetHandle = ...;   // existing keyset
260    KeysetHandle.Builder builder = KeysetHandle.newBuilder(keysetHandle);
261    builder.addEntry(KeysetHandle.generateEntryFromParameters(
262      ChaCha20Poly1305Parameters.create()).withRandomId());
263    KeysetHandle keysetHandleWithAdditionalEntry = builder.build();
264```
265
266After a successful rotation, the resulting keyset contains a new key generated
267according to the specification in the parameters object. For the rotation to
268succeed the `Registry` must contain a key manager for the key type specified in
269`keyTemplate`.
270
271Alternatively, you can use [Tinkey](TINKEY.md) to rotate or manage a keyset.
272
273## Custom implementation of a primitive
274
275**NOTE**: The usage of **custom key managers should be enjoyed responsibly**. We
276(i.e. Tink developers) have no way of checking or enforcing that a custom
277implementation satisfies security properties of the corresponding primitive
278interface, so it is up to the implementer and the user of the custom
279implementation ensure the required properties are met.
280
281The main cryptographic operations offered by Tink are accessible via so-called
282_primitives_, which are interfaces that represent corresponding cryptographic
283functionalities. While Tink comes with several standard implementations of
284common primitives, it also allows for adding custom implementations of
285primitives. Such implementations allow for seamless integration of Tink with
286custom third-party cryptographic schemes or hardware modules, and in combination
287with [key rotation](#key-rotation) features, enables the painless migration
288between cryptographic schemes.
289
290To create a custom implementation of a primitive proceed as follows:
291
2921.  Determine for which _primitive_ a custom implementation is needed.
2932.  Define protocol buffers that hold key material and parameters for the custom
294    cryptographic scheme; the name of the key protocol buffer (a.k.a. type URL)
295    determines the _key type_ for the custom implementation.
2963.  Implement a
297    [`KeyManager`](https://github.com/google/tink/blob/master/java_src/src/main/java/com/google/crypto/tink/KeyManager.java)
298    interface for the _primitive_ from step #1 and the _key type_ from step #2.
299
300To use a custom implementation of a primitive in an application, register with
301the
302[`Registry`](https://github.com/google/tink/blob/master/java_src/src/main/java/com/google/crypto/tink/Registry.java)
303the custom `KeyManager` implementation (from step #3 above) for the custom key
304type (from step #2 above):
305
306```java
307    Registry.registerKeyManager(keyManager);
308```
309
310Afterwards the implementation will be accessed automatically by the
311`keysetHandle.getPrimitive` corresponding to the primitive (when keys of the
312specific key type are in use). It can also be retrieved directly via
313`Registry.getKeyManager(keyType)`.
314
315When defining the protocol buffers for the key material and parameters (step #2
316above), you should provide definitions of three messages:
317
318 * `...Params`: parameters of an instantiation of the primitive,
319   needed when a key is being used.
320 * `...Key`: the actual key proto, contains the key material and the
321   corresponding `...Params` proto.
322 * `...KeyFormat`: parameters needed to generate a new key.
323
324Here are a few conventions/recommendations when defining these messages (see
325[tink.proto](https://github.com/google/tink/blob/master/proto/tink.proto) and
326definitions of [existing key
327types](https://github.com/google/tink/blob/master/proto/) for details):
328
329 * `...Key` should contain a version field (a monotonic counter, `uint32 version;`),
330   which identifies the version of implementation that can work with this key.
331 * `...Params` should be a field of `...Key`, as by definition `...Params`
332   contains parameters needed when the key is being used.
333 * `...Params` should be also a field of `...KeyFormat`, so that given `...KeyFormat`
334   one has all information it needs to generate a new `...Key` message.
335
336Alternatively, depending on the use case requirements, you can skip step #2
337entirely and re-use an existing protocol buffer messages for the key material.
338In such a case, you should not configure the Registry via the `Config`-class, but
339rather register the needed `KeyManager`-instances manually.
340
341For a concrete example, let's assume that we'd like a custom implementation of
342the
343[`Aead`](https://github.com/google/tink/blob/master/java_src/src/main/java/com/google/crypto/tink/Aead.java)
344primitive (step #1). We define then three protocol buffer messages (step #2):
345
346 * `MyCustomAeadParams`: holds parameters needed for the use of the key material.
347 * `MyCustomAeadKey`: holds the actual key material and parameters needed for its use.
348 * `MyCustomAeadKeyFormat`: holds parameters needed for generation of a new `MyCustomAeadKey`-key.
349
350```proto
351    syntax = "proto3";
352    package mycompany.mypackage;
353
354    message MyCustomAeadParams {
355      uint32 iv_size = 1;     // size of initialization vector in bytes
356    }
357
358    message MyCustomAeadKeyFormat {
359      MyCustomAeadParams params = 1;
360      uint32 key_size = 2;    // key size in bytes
361    }
362
363    // key_type: type.googleapis.com/mycompany.mypackage.MyCustomAeadKey
364    message MyCustomAeadKey {
365        uint32 version = 1;
366        MyCustomAeadParams params = 2;
367        bytes key_value = 3;  // the actual key material
368    }
369```
370
371The corresponding _key type_ in Java is defined as
372
373```java
374    String keyType = "type.googleapis.com/mycompany.mypackage.MyCustomAeadKey";`
375```
376
377and the corresponding _key manager_ implements (step #3) the interface
378[`KeyManager<Aead>`](https://github.com/google/tink/blob/master/java_src/src/main/java/com/google/crypto/tink/KeyManager.java)
379
380```java
381    class MyCustomAeadKeyManager implements KeyManager<Aead> {
382      // ...
383    }
384```
385
386After registering `MyCustomAeadKeyManager` with the Registry, it will be used
387when you call `keysetHandle.getPrimitive(Aead.class)`.
388