xref: /aosp_15_r20/external/tink/docs/OBJC-HOWTO.md (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1# Tink for Obj-C HOW-TO
2
3This document contains instructions and Obj-C code snippets for common tasks in
4[Tink](https://github.com/google/tink).
5
6## Setup instructions
7
8Tink is released as a [Cocoapod](https://cocoapods.org/). It can be installed by
9using the pod command as described below, which is the recommended way to use
10Tink.
11
12We also provide step-by-step instructions on building and using Tink from
13source.
14
15#### Supported platforms
16
17 * iOS 9.0 or newer
18 * Xcode 9.2 or newer
19
20### Installing via Cocoapods
21
221. Change into the directory that contains your Xcode project.
23
24   ```sh
25   cd /path/to/your/Xcode project/
26   ```
27
282. Initialize Cocoapods.
29
30   ```sh
31   pod init
32   ```
33
34   This command creates a file called Podfile.
35
363. Edit the Podfile.
37
38   For the current stable release, add the following line:
39
40   ```
41   pod 'Tink'
42   ```
43
44   For a particular version, use a line like the following instead:
45
46   ```
47   pod 'Tink', '1.2.0-rc2'
48   ```
49
50   Note: Replace 1.2.0-rc2 with the pre-release version you want to install.
51
524. Install the pod.
53
54  ```sh
55  $ pod install
56  ```
57
585. Open the newly generated .xcworkspace and start using Tink.
59
60   You can import the umbrella header:
61
62   ```objc
63   #import "Tink/Tink.h"
64   ```
65
66   Or individual headers:
67
68   ```objc
69   #import "Tink/TINKAeadConfig.h"
70   #import "Tink/TINKAeadKeyTemplate.h"
71   #import "Tink/TINKAead.h"
72   ```
73
74### Installing from source
75
76#### Prerequisites
77
78To install Tink from the source code, the following prerequisites must be
79installed:
80
81*   [git](https://git-scm.com/) - to download the source of Tink
82*   [Bazel](https://www.bazel.build) v0.15.0 or newer - to build Tink
83
84#### Step-by-step instructions
85
861.  Clone Tink from GitHub.
87
88    ```sh
89    git clone https://github.com/google/tink/
90    ```
91
922.  Build the library and generate a static iOS framework.
93
94    ```sh
95    cd tink
96    export XCODE_VERSION=9.2
97    export IOS_SDK=11.2
98    bazel build -c opt --ios_multi_cpus=i386,x86_64,armv7,arm64 --xcode_version="${XCODE_VERSION}" --ios_sdk_version="${IOS_SDK}" //objc:Tink_framework
99    ```
100
101    Adjust the following options according to your build environment:
102
103    *   Set `XCODE_VERSION` to the Xcode version you are using to build your
104        application.
105
106    *   Set `IOS_SDK` to the version of the iOS SDK you are using in your
107        application.
108
109    *   The option `ios_multi_cpus` is used to generate a fat library that
110        includes multiple architectures. Before submitting your application to
111        the App Store you should generate a framework that includes only the ARM
112        architectures and link it to your binary.
113
1143.  Unzip Tink\_framework.zip into your Xcode project folder.
115
116    ```sh
117    unzip bazel-bin/objc/Tink_framework.zip -d /path/to/your/project/folder/
118    ```
119
1204.  Add the static framework to your Xcode project options:
121
122    *   Open your Xcode project
123
124    *   Navigate to your project's folder and drag Tink.framework into your
125        Xcode's left pane.
126
127    *   In the following dialog select `Copy items if needed` and the target of
128        your application that will use Tink. Click `Finish`.
129
130    *   Select your project on the left pane and click on "Build Settings"
131
132    *   Find `Other Linker Flags` and add `-lc++`
133
1345.  Start using Tink in your code.
135
136   You can import the umbrella header:
137
138   ```objc
139   #import "Tink/Tink.h"
140   ```
141
142   Or individual headers:
143
144   ```objc
145   #import "Tink/TINKAeadConfig.h"
146   #import "Tink/TINKAeadKeyTemplate.h"
147   #import "Tink/TINKAead.h"
148   ```
149
150## Initializing Tink
151
152Tink provides customizable initialization, which allows for choosing specific
153implementations (identified by _key types_) of desired primitives. This
154initialization happens via _registration_ of the implementations.
155
156For example, if you want to use all implementations of all primitives in the
157current version of Tink, the initialization would look as follows:
158
159```objc
160   #import "Tink/TINKAllConfig.h"
161   #import "Tink/TINKConfig.h"
162
163   NSError *error = nil;
164   TINKAllConfig *config = [[TINKAllConfig alloc] initWithError:&error];
165   if (!config || error) {
166     // handle error.
167   }
168
169   if (![TINKConfig registerConfig:config error:&error]) {
170     // handle error.
171   }
172```
173
174To use only implementations of the AEAD primitive:
175
176```objc
177    #import "Tink/TINKAeadConfig.h"
178    #import "Tink/TINKConfig.h"
179
180    NSError *error = nil;
181    TINKAeadConfig *aeadConfig = [[TINKAeadConfig alloc] initWithError:&error];
182    if (!aeadConfig || error) {
183      // handle error.
184    }
185
186    if (![TINKConfig registerConfig:aeadConfig error:&error]) {
187      // handle error.
188    }
189```
190
191## Generating new keys and keysets
192
193To avoid accidental leakage of sensitive key material, you should avoid mixing
194keyset generation and usage in code. To support the separation between these
195activities the Tink package provides a command-line tool called
196[Tinkey](TINKEY.md), which can be used for common key management tasks.
197
198Still, if there is a need to generate a KeysetHandle with fresh key material
199directly in Obj-C code, one can use
200[`TINKKeysetHandle`](https://github.com/google/tink/blob/master/objc/TINKKeysetHandle.h)
201with one of the available KeyTemplates (AeadKeyTemplate, HybridKeyTemplate, etc.):
202
203```objc
204    #import "Tink/TINKAeadKeyTemplate.h"
205    #import "Tink/TINKKeysetHandle.h"
206
207    NSError *error = nil;
208    TINKAeadKeyTemplate *tpl = [[TINKAeadKeyTemplate alloc] initWithKeyTemplate:TINKAes128Gcm error:&error];
209    if (!tpl || error) {
210      // handle error.
211    }
212
213    TINKKeysetHandle *handle = [[TINKKeysetHandle alloc] initWithKeyTemplate:tpl error:&error];
214    if (!handle || error) {
215      // handle error.
216    }
217```
218
219## Storing keysets
220
221After generating key material, you might want to persist it to a storage system.
222Tink supports storing keysets to the iOS keychain where they remain encrypted:
223
224```objc
225    #import "Tink/TINKKeysetHandle.h"
226
227    NSError *error = nil;
228    TINKKeysetHandle *handle = [[TINKKeysetHandle alloc] initWithKeyTemplate:tpl error:&error];
229    if (!handle || error) {
230      // handle error.
231    }
232
233    NSString *keysetName = @"com.yourcompany.yourapp.uniqueKeysetName";
234    if (![handle writeToKeychainWithName:keysetName overwrite:NO error:&error]) {
235      // handle error.
236    }
237```
238
239The keysets are stored in the keychain with the following options set:
240
241*   kSecAttrAccessible = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
242*   kSecAttrSynchronizable = False
243
244These settings prevent the keysets from leaving the device and keep them
245encrypted until the device is unlocked once.
246
247## Loading existing keysets
248
249To load keysets from the iOS keychain:
250
251```objc
252    #import "Tink/TINKKeysetHandle.h"
253
254    NSError *error = nil;
255    NSString *keysetName = @"com.yourcompany.yourapp.uniqueKeysetName";
256    TINKKeysetHandle *handle = [[TINKKeysetHandle alloc] initFromKeychainWithName:keysetName error:&error];
257    if (!handle || error) {
258      // handle error.
259    }
260```
261
262To load cleartext keysets, use
263[`TINKKeysetHandle+Cleartext`](https://github.com/google/tink/blob/master/objc/TINKKeysetHandle+Cleartext.h)
264and an appropriate
265[`KeysetReader`](https://github.com/google/tink/blob/master/objc/TINKKeysetReader.h),
266depending on the wire format of the stored keyset, for example a
267[`TINKBinaryKeysetReader`](https://github.com/google/tink/blob/master/objc/TINKBinaryKeysetReader.h).
268
269Note: We don't recommend storing keysets in cleartext in the filesystem.
270Instead, use the iOS keychain as demonstrated above.
271
272```objc
273    #import "Tink/TINKBinaryKeysetReader.h"
274    #import "Tink/TINKKeysetHandle+Cleartext.h"
275
276    NSError *error = nil;
277    NSData *binaryKeyset = ...;
278    TINKBinaryKeysetReader *reader = [[TINKBinaryKeysetReader alloc] initWithSerializedKeyset:binaryKeyset
279                                                                                        error:&error];
280    if (!reader || error) {
281      // handle error.
282    }
283
284    TINKKeysetHandle *handle = [[TINKKeysetHandle alloc] initCleartextKeysetHandleWithKeysetReader:reader
285                                                                                             error:&error];
286    if (!handle || error) {
287      // handle error.
288    }
289```
290
291## Obtaining and using primitives
292
293[_Primitives_](PRIMITIVES.md) represent cryptographic operations offered by
294Tink, hence they form the core of Tink API. A primitive is just an interface
295that specifies what operations are offered by the primitive. A primitive can
296have multiple implementations, and you choose a desired implementation by using
297a key of corresponding type (see the [this
298section](KEY-MANAGEMENT.md#key-keyset-and-keysethandle) for details).  A list of
299primitives and their implementations currently supported by Tink in Objective-C
300can be found [here](PRIMITIVES.md#objective-c).
301
302You access implementations of a primitive via a factory that corresponds to the
303primitive which offers corresponding `primitiveWithKeysetHandle:error:` methods.
304
305*  AEAD via `TINKAeadFactory`
306*  MAC via `TINKMacFactory`
307*  etc.
308
309### Symmetric key encryption
310
311You can use an [AEAD (Authenticated Encryption with Associated
312Data)](PRIMITIVES.md#authenticated-encryption-with-associated-data) primitive to
313encrypt or decrypt data:
314
315```objc
316    #import "Tink/TINKAead.h"
317    #import "Tink/TINKKeysetHandle.h"
318    #import "Tink/TINKAeadFactory.h"
319
320    // 1. Get a handle to the key material.
321    TINKKeysetHandle *keysetHandle = ...;
322
323    // 2. Get the primitive.
324    NSError *error = nil;
325    id<TINKAead> aead = [TINKAeadFactory primitiveWithKeysetHandle:keysetHandle error:&error];
326    if (!aead || error) {
327      // handle error.
328    }
329
330    // 3. Use the primitive.
331    NSData *ciphertext = [aead encrypt:plaintext withAdditionalData:aad error:&error];
332    if (!ciphertext || error) {
333      // handle error.
334    }
335```
336
337### Hybrid encryption
338
339To decrypt using [a combination of public key encryption and symmetric key
340encryption](PRIMITIVES.md#hybrid-encryption):
341
342```objc
343    #import "Tink/TINKHybridDecrypt.h"
344    #import "Tink/TINKKeysetHandle.h"
345    #import "Tink/TINKHybridDecryptFactory.h"
346
347    // 1. Get a handle to the key material.
348    TINKKeysetHandle *keysetHandle = ...;
349
350    // 2. Get the primitive.
351    NSError *error = nil;
352    id<TINKHybridDecrypt> hybridDecrypt = [TINKHybridDecryptFactory primitiveWithKeysetHandle:keysetHandle
353                                                                                        error:&error];
354    if (!hybridDecrypt || error) {
355      // handle error.
356    }
357
358    // 3. Use the primitive.
359    NSData *plaintext = [hybridDecrypt decrypt:ciphertext withContextInfo:contextInfo error:&error];
360    if (!plaintext || error) {
361      // handle error.
362    }
363```
364