I want to encrypt data

  • The AEAD primitive with the AES128_GCM key type is recommended for most data encryption needs due to its simplicity and security features.

  • AEAD ensures secrecy, authenticity, and randomization, using a single key for both encryption and decryption.

  • Associated data used in AEAD is authenticated but not encrypted, meaning it is verifiable but still visible.

  • While AES128_GCM is generally the fastest and recommended, other key types like AES128_CTR_HMAC_SHA256, AES128_EAX, AES128_GCM_SIV, and XChaCha20Poly1305 offer varying security and performance trade-offs for specific needs.

  • AEAD implementations provide CCA2 security, at least 80-bit authentication strength, and the ability to encrypt a large number of messages with high security guarantees, but no secrecy for associated data.

We recommend the AEAD primitive with the AES128_GCM key type for most data encryption use cases.

Authenticated Encryption with Associated Data (AEAD) is the simplest and most appropriate primitive for most use cases. AEAD provides secrecy and authenticity and ensures that messages always have different ciphertexts (encrypted outputs) even if the plaintexts (the inputs for the encryption) are the same. It is symmetric, using a single key for both encryption and decryption.

The following examples get you started using the AEAD primitive:

C++

 // A command-line utility for testing Tink AEAD. 
 #include <iostream> 
 #include <memory> 
 #include <string> 
 #include 
  
 "absl/flags/flag.h" 
 #include 
  
 "absl/flags/parse.h" 
 #include 
  
 "absl/log/absl_check.h" 
 #include 
  
 "absl/status/status.h" 
 #include 
  
 "absl/status/statusor.h" 
 #include 
  
 "absl/strings/string_view.h" 
 #include 
  
 "tink/aead.h" 
 #include 
  
 "tink/aead/config_v0.h" 
 #include 
  
 "util/util.h" 
 #include 
  
 "tink/keyset_handle.h" 
 ABSL_FLAG 
 ( 
 std 
 :: 
 string 
 , 
  
 keyset_filename 
 , 
  
 "" 
 , 
  
 "Keyset file in JSON format" 
 ); 
 ABSL_FLAG 
 ( 
 std 
 :: 
 string 
 , 
  
 mode 
 , 
  
 "" 
 , 
  
 "Mode of operation {encrypt|decrypt}" 
 ); 
 ABSL_FLAG 
 ( 
 std 
 :: 
 string 
 , 
  
 input_filename 
 , 
  
 "" 
 , 
  
 "Filename to operate on" 
 ); 
 ABSL_FLAG 
 ( 
 std 
 :: 
 string 
 , 
  
 output_filename 
 , 
  
 "" 
 , 
  
 "Output file name" 
 ); 
 ABSL_FLAG 
 ( 
 std 
 :: 
 string 
 , 
  
 associated_data 
 , 
  
 "" 
 , 
  
 "Associated data for AEAD (default: empty" 
 ); 
 namespace 
  
 { 
 using 
  
 :: 
 crypto 
 :: 
 tink 
 :: 
 Aead 
 ; 
 using 
  
 :: 
 crypto 
 :: 
 tink 
 :: 
 KeysetHandle 
 ; 
 constexpr 
  
 absl 
 :: 
 string_view 
  
 kEncrypt 
  
 = 
  
 "encrypt" 
 ; 
 constexpr 
  
 absl 
 :: 
 string_view 
  
 kDecrypt 
  
 = 
  
 "decrypt" 
 ; 
 void 
  
 ValidateParams 
 () 
  
 { 
  
 // ... 
 } 
 } 
  
 // namespace 
 namespace 
  
 tink_cc_examples 
  
 { 
 // AEAD example CLI implementation. 
 absl 
 :: 
 Status 
  
 AeadCli 
 ( 
 absl 
 :: 
 string_view 
  
 mode 
 , 
  
 const 
  
 std 
 :: 
 string 
&  
 keyset_filename 
 , 
  
 const 
  
 std 
 :: 
 string 
&  
 input_filename 
 , 
  
 const 
  
 std 
 :: 
 string 
&  
 output_filename 
 , 
  
 absl 
 :: 
 string_view 
  
 associated_data 
 ) 
  
 { 
  
 // Read the keyset from file. 
  
 absl 
 :: 
 StatusOr<std 
 :: 
 unique_ptr<KeysetHandle> 
>  
 keyset_handle 
  
 = 
  
 ReadJsonCleartextKeyset 
 ( 
 keyset_filename 
 ); 
  
 if 
  
 ( 
 ! 
 keyset_handle 
 . 
 ok 
 ()) 
  
 return 
  
 keyset_handle 
 . 
 status 
 (); 
  
 // Get the primitive. 
  
 absl 
 :: 
 StatusOr<std 
 :: 
 unique_ptr<Aead> 
>  
 aead 
  
 = 
  
 ( 
 * 
 keyset_handle 
 ) 
  
 - 
> GetPrimitive<crypto 
 :: 
 tink 
 :: 
 Aead 
> ( 
 crypto 
 :: 
 tink 
 :: 
 ConfigAeadV0 
 ()); 
  
 if 
  
 ( 
 ! 
 aead 
 . 
 ok 
 ()) 
  
 return 
  
 aead 
 . 
 status 
 (); 
  
 // Read the input. 
  
 absl 
 :: 
 StatusOr<std 
 :: 
 string 
>  
 input_file_content 
  
 = 
  
 ReadFile 
 ( 
 input_filename 
 ); 
  
 if 
  
 ( 
 ! 
 input_file_content 
 . 
 ok 
 ()) 
  
 return 
  
 input_file_content 
 . 
 status 
 (); 
  
 // Compute the output. 
  
 std 
 :: 
 string 
  
 output 
 ; 
  
 if 
  
 ( 
 mode 
  
 == 
  
 kEncrypt 
 ) 
  
 { 
  
 absl 
 :: 
 StatusOr<std 
 :: 
 string 
>  
 encrypt_result 
  
 = 
  
 ( 
 * 
 aead 
 ) 
 - 
> Encrypt 
 ( 
 * 
 input_file_content 
 , 
  
 associated_data 
 ); 
  
 if 
  
 ( 
 ! 
 encrypt_result 
 . 
 ok 
 ()) 
  
 return 
  
 encrypt_result 
 . 
 status 
 (); 
  
 output 
  
 = 
  
 encrypt_result 
 . 
 value 
 (); 
  
 } 
  
 else 
  
 { 
  
 // operation == kDecrypt. 
  
 absl 
 :: 
 StatusOr<std 
 :: 
 string 
>  
 decrypt_result 
  
 = 
  
 ( 
 * 
 aead 
 ) 
 - 
> Decrypt 
 ( 
 * 
 input_file_content 
 , 
  
 associated_data 
 ); 
  
 if 
  
 ( 
 ! 
 decrypt_result 
 . 
 ok 
 ()) 
  
 return 
  
 decrypt_result 
 . 
 status 
 (); 
  
 output 
  
 = 
  
 decrypt_result 
 . 
 value 
 (); 
  
 } 
  
 // Write the output to the output file. 
  
 return 
  
 WriteToFile 
 ( 
 output 
 , 
  
 output_filename 
 ); 
 } 
 } 
  
 // namespace tink_cc_examples 
 int 
  
 main 
 ( 
 int 
  
 argc 
 , 
  
 char 
 ** 
  
 argv 
 ) 
  
 { 
  
 absl 
 :: 
 ParseCommandLine 
 ( 
 argc 
 , 
  
 argv 
 ); 
  
 ValidateParams 
 (); 
  
 std 
 :: 
 string 
  
 mode 
  
 = 
  
 absl 
 :: 
 GetFlag 
 ( 
 FLAGS_mode 
 ); 
  
 std 
 :: 
 string 
  
 keyset_filename 
  
 = 
  
 absl 
 :: 
 GetFlag 
 ( 
 FLAGS_keyset_filename 
 ); 
  
 std 
 :: 
 string 
  
 input_filename 
  
 = 
  
 absl 
 :: 
 GetFlag 
 ( 
 FLAGS_input_filename 
 ); 
  
 std 
 :: 
 string 
  
 output_filename 
  
 = 
  
 absl 
 :: 
 GetFlag 
 ( 
 FLAGS_output_filename 
 ); 
  
 std 
 :: 
 string 
  
 associated_data 
  
 = 
  
 absl 
 :: 
 GetFlag 
 ( 
 FLAGS_associated_data 
 ); 
  
 std 
 :: 
 clog 
 << 
 "Using keyset from file " 
 << 
 keyset_filename 
 << 
 " to AEAD-" 
 << 
 mode 
 << 
 " file " 
 << 
 input_filename 
 << 
 " with associated data '" 
 << 
 associated_data 
 << 
 "'." 
 << 
 '\n' 
 ; 
  
 std 
 :: 
 clog 
 << 
 "The resulting output will be written to " 
 << 
 output_filename 
 << 
 '\n' 
 ; 
  
 ABSL_CHECK_OK 
 ( 
 tink_cc_examples 
 :: 
 AeadCli 
 ( 
 mode 
 , 
  
 keyset_filename 
 , 
  
 input_filename 
 , 
  
 output_filename 
 , 
  
 associated_data 
 )); 
  
 return 
  
 0 
 ; 
 } 
  

Go

 import 
  
 ( 
  
 "bytes" 
  
 "fmt" 
  
 "log" 
  
 "github.com/tink-crypto/tink-go/v2/aead" 
  
 "github.com/tink-crypto/tink-go/v2/insecurecleartextkeyset" 
  
 "github.com/tink-crypto/tink-go/v2/keyset" 
 ) 
 func 
  
 Example 
 () 
  
 { 
  
 // A keyset created with "tinkey create-keyset --key-template=AES256_GCM". Note 
  
 // that this keyset has the secret key information in cleartext. 
  
 jsonKeyset 
  
 := 
  
 `{ 
 "key": [{ 
 "keyData": { 
 "keyMaterialType": 
 "SYMMETRIC", 
 "typeUrl": 
 "type.googleapis.com/google.crypto.tink.AesGcmKey", 
 "value": 
 "GiBWyUfGgYk3RTRhj/LIUzSudIWlyjCftCOypTr0jCNSLg==" 
 }, 
 "keyId": 294406504, 
 "outputPrefixType": "TINK", 
 "status": "ENABLED" 
 }], 
 "primaryKeyId": 294406504 
 }` 
  
 // Create a keyset handle from the cleartext keyset in the previous 
  
 // step. The keyset handle provides abstract access to the underlying keyset to 
  
 // limit the exposure of accessing the raw key material. WARNING: In practice, 
  
 // it is unlikely you will want to use a insecurecleartextkeyset, as it implies 
  
 // that your key material is passed in cleartext, which is a security risk. 
  
 // Consider encrypting it with a remote key in Cloud KMS, AWS KMS or HashiCorp Vault. 
  
 // See https://github.com/google/tink/blob/master/docs/GOLANG-HOWTO.md#storing-and-loading-existing-keysets. 
  
 keysetHandle 
 , 
  
 err 
  
 := 
  
 insecurecleartextkeyset 
 . 
 Read 
 ( 
  
 keyset 
 . 
 NewJSONReader 
 ( 
 bytes 
 . 
 NewBufferString 
 ( 
 jsonKeyset 
 ))) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 log 
 . 
 Fatal 
 ( 
 err 
 ) 
  
 } 
  
 // Retrieve the AEAD primitive we want to use from the keyset handle. 
  
 primitive 
 , 
  
 err 
  
 := 
  
 aead 
 . 
 New 
 ( 
 keysetHandle 
 ) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 log 
 . 
 Fatal 
 ( 
 err 
 ) 
  
 } 
  
 // Use the primitive to encrypt a message. In this case the primary key of the 
  
 // keyset will be used (which is also the only key in this example). 
  
 plaintext 
  
 := 
  
 [] 
 byte 
 ( 
 "message" 
 ) 
  
 associatedData 
  
 := 
  
 [] 
 byte 
 ( 
 "associated data" 
 ) 
  
 ciphertext 
 , 
  
 err 
  
 := 
  
 primitive 
 . 
 Encrypt 
 ( 
 plaintext 
 , 
  
 associatedData 
 ) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 log 
 . 
 Fatal 
 ( 
 err 
 ) 
  
 } 
  
 // Use the primitive to decrypt the message. Decrypt finds the correct key in 
  
 // the keyset and decrypts the ciphertext. If no key is found or decryption 
  
 // fails, it returns an error. 
  
 decrypted 
 , 
  
 err 
  
 := 
  
 primitive 
 . 
 Decrypt 
 ( 
 ciphertext 
 , 
  
 associatedData 
 ) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 log 
 . 
 Fatal 
 ( 
 err 
 ) 
  
 } 
  
 fmt 
 . 
 Println 
 ( 
 string 
 ( 
 decrypted 
 )) 
  
 // Output: message 
 } 
  

Java

 package 
  
 aead 
 ; 
 import static 
  
 java.nio.charset.StandardCharsets.UTF_8 
 ; 
 import 
  
 com.google.crypto.tink.Aead 
 ; 
 import 
  
 com.google.crypto.tink.InsecureSecretKeyAccess 
 ; 
 import 
  
 com.google.crypto.tink.KeysetHandle 
 ; 
 import 
  
 com.google.crypto.tink.RegistryConfiguration 
 ; 
 import 
  
 com.google.crypto.tink.TinkJsonProtoKeysetFormat 
 ; 
 import 
  
 com.google.crypto.tink.aead.AeadConfig 
 ; 
 import 
  
 java.nio.file.Files 
 ; 
 import 
  
 java.nio.file.Path 
 ; 
 import 
  
 java.nio.file.Paths 
 ; 
 /** 
 * A command-line utility for encrypting small files with AEAD. 
 * 
 * <p>It loads cleartext keys from disk - this is not recommended! 
 * 
 * <p>It requires the following arguments: 
 * 
 * <ul> 
 *   <li>mode: Can be "encrypt" or "decrypt" to encrypt/decrypt the input to the output. 
 *   <li>key-file: Read the key material from this file. 
 *   <li>input-file: Read the input from this file. 
 *   <li>output-file: Write the result to this file. 
 *   <li>[optional] associated-data: Associated data used for the encryption or decryption. 
 */ 
 public 
  
 final 
  
 class 
 AeadExample 
  
 { 
  
 private 
  
 static 
  
 final 
  
 String 
  
 MODE_ENCRYPT 
  
 = 
  
 "encrypt" 
 ; 
  
 private 
  
 static 
  
 final 
  
 String 
  
 MODE_DECRYPT 
  
 = 
  
 "decrypt" 
 ; 
  
 public 
  
 static 
  
 void 
  
 main 
 ( 
 String 
 [] 
  
 args 
 ) 
  
 throws 
  
 Exception 
  
 { 
  
 if 
  
 ( 
 args 
 . 
 length 
  
 != 
  
 4 
 && 
 args 
 . 
 length 
  
 != 
  
 5 
 ) 
  
 { 
  
 System 
 . 
 err 
 . 
 printf 
 ( 
 "Expected 4 or 5 parameters, got %d\n" 
 , 
  
 args 
 . 
 length 
 ); 
  
 System 
 . 
 err 
 . 
 println 
 ( 
  
 "Usage: java AeadExample encrypt/decrypt key-file input-file output-file" 
  
 + 
  
 " [associated-data]" 
 ); 
  
 System 
 . 
 exit 
 ( 
 1 
 ); 
  
 } 
  
 String 
  
 mode 
  
 = 
  
 args 
 [ 
 0 
 ] 
 ; 
  
 Path 
  
 keyFile 
  
 = 
  
 Paths 
 . 
 get 
 ( 
 args 
 [ 
 1 
 ] 
 ); 
  
 Path 
  
 inputFile 
  
 = 
  
 Paths 
 . 
 get 
 ( 
 args 
 [ 
 2 
 ] 
 ); 
  
 Path 
  
 outputFile 
  
 = 
  
 Paths 
 . 
 get 
 ( 
 args 
 [ 
 3 
 ] 
 ); 
  
 byte 
 [] 
  
 associatedData 
  
 = 
  
 new 
  
 byte 
 [ 
 0 
 ] 
 ; 
  
 if 
  
 ( 
 args 
 . 
 length 
  
 == 
  
 5 
 ) 
  
 { 
  
 associatedData 
  
 = 
  
 args 
 [ 
 4 
 ] 
 . 
 getBytes 
 ( 
 UTF_8 
 ); 
  
 } 
  
 // Register all AEAD key types with the Tink runtime. 
  
 AeadConfig 
 . 
 register 
 (); 
  
 // Read the keyset into a KeysetHandle. 
  
 KeysetHandle 
  
 handle 
  
 = 
  
 TinkJsonProtoKeysetFormat 
 . 
 parseKeyset 
 ( 
  
 new 
  
 String 
 ( 
 Files 
 . 
 readAllBytes 
 ( 
 keyFile 
 ), 
  
 UTF_8 
 ), 
  
 InsecureSecretKeyAccess 
 . 
 get 
 ()); 
  
 // Get the primitive. 
  
 Aead 
  
 aead 
  
 = 
  
 handle 
 . 
 getPrimitive 
 ( 
 RegistryConfiguration 
 . 
 get 
 (), 
  
 Aead 
 . 
 class 
 ); 
  
 // Use the primitive to encrypt/decrypt files. 
  
 if 
  
 ( 
 MODE_ENCRYPT 
 . 
 equals 
 ( 
 mode 
 )) 
  
 { 
  
 byte 
 [] 
  
 plaintext 
  
 = 
  
 Files 
 . 
 readAllBytes 
 ( 
 inputFile 
 ); 
  
 byte 
 [] 
  
 ciphertext 
  
 = 
  
 aead 
 . 
 encrypt 
 ( 
 plaintext 
 , 
  
 associatedData 
 ); 
  
 Files 
 . 
 write 
 ( 
 outputFile 
 , 
  
 ciphertext 
 ); 
  
 } 
  
 else 
  
 if 
  
 ( 
 MODE_DECRYPT 
 . 
 equals 
 ( 
 mode 
 )) 
  
 { 
  
 byte 
 [] 
  
 ciphertext 
  
 = 
  
 Files 
 . 
 readAllBytes 
 ( 
 inputFile 
 ); 
  
 byte 
 [] 
  
 plaintext 
  
 = 
  
 aead 
 . 
 decrypt 
 ( 
 ciphertext 
 , 
  
 associatedData 
 ); 
  
 Files 
 . 
 write 
 ( 
 outputFile 
 , 
  
 plaintext 
 ); 
  
 } 
  
 else 
  
 { 
  
 System 
 . 
 err 
 . 
 println 
 ( 
 "The first argument must be either encrypt or decrypt, got: " 
  
 + 
  
 mode 
 ); 
  
 System 
 . 
 exit 
 ( 
 1 
 ); 
  
 } 
  
 } 
  
 private 
  
 AeadExample 
 () 
  
 {} 
 } 
  

Obj-C

HOW-TO

Python

 import 
  
 tink 
 from 
  
 tink 
  
 import 
 aead 
 from 
  
 tink 
  
 import 
 secret_key_access 
 def 
  
 example 
 (): 
  
 """Encrypt and decrypt using AEAD.""" 
 # Register the AEAD key managers. This is needed to create an Aead primitive 
 # later. 
 aead 
 . 
 register 
 () 
 # A keyset created with "tinkey create-keyset --key-template=AES256_GCM". Note 
 # that this keyset has the secret key information in cleartext. 
 keyset 
 = 
 r 
 """{ 
 "key": [{ 
 "keyData": { 
 "keyMaterialType": 
 "SYMMETRIC", 
 "typeUrl": 
 "type.googleapis.com/google.crypto.tink.AesGcmKey", 
 "value": 
 "GiBWyUfGgYk3RTRhj/LIUzSudIWlyjCftCOypTr0jCNSLg==" 
 }, 
 "keyId": 294406504, 
 "outputPrefixType": "TINK", 
 "status": "ENABLED" 
 }], 
 "primaryKeyId": 294406504 
 }""" 
 # Create a keyset handle from the cleartext keyset in the previous 
 # step. The keyset handle provides abstract access to the underlying keyset to 
 # limit access of the raw key material. WARNING: In practice, it is unlikely 
 # you will want to use a cleartext_keyset_handle, as it implies that your key 
 # material is passed in cleartext, which is a security risk. 
 keyset_handle 
 = 
 tink 
 . 
 json_proto_keyset_format 
 . 
 parse 
 ( 
 keyset 
 , 
 secret_key_access 
 . 
 TOKEN 
 ) 
 # Retrieve the Aead primitive we want to use from the keyset handle. 
 primitive 
 = 
 keyset_handle 
 . 
 primitive 
 ( 
 aead 
 . 
 Aead 
 ) 
 # Use the primitive to encrypt a message. In this case the primary key of the 
 # keyset will be used (which is also the only key in this example). 
 ciphertext 
 = 
 primitive 
 . 
 encrypt 
 ( 
 b 
 'msg' 
 , 
 b 
 'associated_data' 
 ) 
 # Use the primitive to decrypt the message. Decrypt finds the correct key in 
 # the keyset and decrypts the ciphertext. If no key is found or decryption 
 # fails, it raises an error. 
 output 
 = 
 primitive 
 . 
 decrypt 
 ( 
 ciphertext 
 , 
 b 
 'associated_data' 
 ) 
  

AEAD

The Authenticated Encryption with Associated Data (AEAD) primitive is the most common primitive for data encryption and is suitable for most needs.

AEAD has the following properties:

  • Secrecy: Nothing about the plaintext is known, except its length.
  • Authenticity: It is impossible to change the encrypted plaintext underlying the ciphertext without being detected.
  • Symmetric: Encrypting the plaintext and decrypting the ciphertext is done with the same key.
  • Randomization: Encryption is randomized. Two messages with the same plaintext yield different ciphertexts. Attackers cannot know which ciphertext corresponds to a given plaintext. If you want to avoid this, use Deterministic AEAD instead.

Associated data

AEAD can be used to tie ciphertext to specific associated data . Suppose you have a database with the fields user-id and encrypted-medical-history . In this scenario, user-id can be used as associated data when encrypting encrypted-medical-history . This prevents an attacker from moving medical history from one user to another.

Associated data is optional. If specified, decryption only succeeds if the same associated data is passed to both encrypt and decrypt calls.

Choose a key type

While we recommend AES128_GCMfor most uses, there are various key types for different needs (for 256-bit security, replace AES128 with AES256 below). Generally:

  • AES128_CTR_HMAC_SHA256 with a 16-byte Initialization Vector (IV) is the most conservative mode with good bounds.
  • AES128_EAX is slightly less conservative and slightly faster than AES128_CTR_HMAC_SHA256.
  • AES128_GCM is usually the fastest mode, with the strictest limits on the number of messages and message size. When these limits on plaintext and associated data lengths (below) are exceeded, AES128_GCM fails and leaks key material.
  • AES128_GCM_SIV is nearly as fast as AES128_GCM. It has the same limits as AES128_GCM on the number of messages and message size, but when these limits are exceeded, it fails in a less catastrophic way: it may only leak the fact that two messages are equal. This makes it safer to use than AES128_GCM, but it is less widely used in practice. To use this in Java, you have to install Conscrypt .
  • XChaCha20Poly1305 has a much greater limit on the number of messages and message size than AES128_GCM, but when it does fail (very unlikely) it also leaks key material. It isn't hardware accelerated, so it can be slower than AES modes in situations where hardware acceleration is available.

Security guarantees

AEAD implementations offer:

  • CCA2 security.
  • At least 80-bit authentication strength.
  • The ability to encrypt at least 2 32 messages with a total of 2 50 bytes. No attack with up to 2 32 chosen plaintexts or chosen ciphertexts has success probability larger than 2 -32 .
Design a Mobile Site
View Site in Mobile | Classic
Share by: