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