Page Summary
-
This page demonstrates how to create and use cleartext keysets for encryption and decryption with Tink, but strongly advises against storing keysets in plaintext due to security risks.
-
Instead of storing keysets in plaintext, it recommends encrypting them for secure storage, providing a link to instructions on how to generate encrypted keysets.
-
Examples of cleartext keyset creation and usage are given in Tinkey, Java, Go, and Python for illustrative purposes despite the security concerns.
The following examples show how to create a keyset with a single key and store it in plaintext on disk.
Tinkey
tinkey create-keyset \
--key-template AES128_GCM \
--out-format json \
--out aead_keyset.json
Java
package cleartextkeyset ; 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 com.google.crypto.tink.aead.PredefinedAeadParameters ; import java.nio.file.Files ; import java.nio.file.Path ; import java.nio.file.Paths ; /** * A command-line utility for generating, storing and using AES128_GCM keysets. * * <h1>WARNING: Loading a Keyset from disk is often a security problem -- hence this needs {@code * InsecureSecretKeyAccess.get()}. * * <p>It requires the following arguments: * * <ul> * <li>mode: Can be "generate", "encrypt" or "decrypt". If mode is "generate" it will generate, * encrypt a keyset, store it in key-file. If mode is "encrypt" or "decrypt" it will read and * decrypt an keyset from key-file, and use it to encrypt or decrypt input-file. * <li>key-file: Read the encrypted key material from this file. * <li>input-file: If mode is "encrypt" or "decrypt", read the input from this file. * <li>output-file: If mode is "encrypt" or "decrypt", write the result to this file. */ public final class CleartextKeysetExample { private static final String MODE_ENCRYPT = "encrypt" ; private static final String MODE_DECRYPT = "decrypt" ; private static final String MODE_GENERATE = "generate" ; private static final byte [] EMPTY_ASSOCIATED_DATA = new byte [ 0 ] ; public static void main ( String [] args ) throws Exception { if ( args . length != 2 && args . length != 4 ) { System . err . printf ( "Expected 2 or 4 parameters, got %d\n" , args . length ); System . err . println ( "Usage: java CleartextKeysetExample generate/encrypt/decrypt key-file input-file" + " output-file" ); System . exit ( 1 ); } String mode = args [ 0 ] ; if ( ! MODE_ENCRYPT . equals ( mode ) && ! MODE_DECRYPT . equals ( mode ) && ! MODE_GENERATE . equals ( mode )) { System . err . print ( "The first argument should be either encrypt, decrypt or generate" ); System . exit ( 1 ); } Path keyFile = Paths . get ( args [ 1 ] ); // Initialise Tink: register all AEAD key types with the Tink runtime AeadConfig . register (); if ( MODE_GENERATE . equals ( mode )) { KeysetHandle handle = KeysetHandle . generateNew ( PredefinedAeadParameters . AES128_GCM ); String serializedKeyset = TinkJsonProtoKeysetFormat . serializeKeyset ( handle , InsecureSecretKeyAccess . get ()); Files . write ( keyFile , serializedKeyset . getBytes ( UTF_8 )); return ; } // Use the primitive to encrypt/decrypt files // Read the keyset from disk String serializedKeyset = new String ( Files . readAllBytes ( keyFile ), UTF_8 ); KeysetHandle handle = TinkJsonProtoKeysetFormat . parseKeyset ( serializedKeyset , InsecureSecretKeyAccess . get ()); // Get the primitive Aead aead = handle . getPrimitive ( RegistryConfiguration . get (), Aead . class ); byte [] input = Files . readAllBytes ( Paths . get ( args [ 2 ] )); Path outputFile = Paths . get ( args [ 3 ] ); if ( MODE_ENCRYPT . equals ( mode )) { byte [] ciphertext = aead . encrypt ( input , EMPTY_ASSOCIATED_DATA ); Files . write ( outputFile , ciphertext ); } else if ( MODE_DECRYPT . equals ( mode )) { byte [] plaintext = aead . decrypt ( input , EMPTY_ASSOCIATED_DATA ); Files . write ( outputFile , plaintext ); } } private CleartextKeysetExample () {} }
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_cleartextKeysetInBinary () { // Generate a new keyset handle for the primitive we want to use. handle , err := keyset . NewHandle ( aead . AES256GCMKeyTemplate ()) if err != nil { log . Fatal ( err ) } // Serialize the keyset. buff := & bytes . Buffer {} err = insecurecleartextkeyset . Write ( handle , keyset . NewBinaryWriter ( buff )) if err != nil { log . Fatal ( err ) } serializedKeyset := buff . Bytes () // serializedKeyset can now be stored at a secure location. // WARNING: Storing the keyset in cleartext to disk is not recommended! // Parse the keyset. parsedHandle , err := insecurecleartextkeyset . Read ( keyset . NewBinaryReader ( bytes . NewBuffer ( serializedKeyset ))) if err != nil { log . Fatal ( err ) } // Get the primitive. primitive , err := aead . New ( parsedHandle ) if err != nil { log . Fatal ( err ) } // Use the primitive. plaintext := [] byte ( "message" ) associatedData := [] byte ( "example encryption" ) ciphertext , err := primitive . Encrypt ( plaintext , associatedData ) if err != nil { log . Fatal ( err ) } decrypted , err := primitive . Decrypt ( ciphertext , associatedData ) if err != nil { log . Fatal ( err ) } fmt . Println ( string ( decrypted )) // Output: message }
Python
"""A command-line utility for generating, storing and using cleartext AES128_GCM keysets. It loads cleartext keys from disk - this is not recommended! """ from absl import app from absl import flags from absl import logging import tink from tink import aead from tink import secret_key_access FLAGS = flags . FLAGS flags . DEFINE_enum ( ' mode ' , None , [ ' generate ' , ' encrypt ' , ' decrypt ' ], ' The operation to perform . ' ) flags . DEFINE_string ( ' keyset_path ' , None , ' Path to the keyset used for encryption . ' ) flags . DEFINE_string ( ' input_path ' , None , ' Path to the input file . ' ) flags . DEFINE_string ( ' output_path ' , None , ' Path to the output file . ' ) def main ( argv ): del argv # Unused . # Initialise Tink aead . register () if FLAGS . mode == ' generate ' : # Generate a new keyset try : key_template = aead . aead_key_templates . AES128_GCM keyset_handle = tink . new_keyset_handle ( key_template ) except tink . TinkError as e : logging . exception ( ' Error creating primitive : % s ' , e ) return 1 with open ( FLAGS . keyset_path , ' wt ' ) as keyset_file : try : serialized_keyset = tink . json_proto_keyset_format . serialize ( keyset_handle , secret_key_access . TOKEN ) keyset_file . write ( serialized_keyset ) except tink . TinkError as e : logging . exception ( ' Error writing key : % s ' , e ) return 1 return 0 # Use the input keyset to encrypt / decrypt data # Read the keyset into a keyset_handle with open ( FLAGS . keyset_path , ' rt ' ) as keyset_file : try : serialized_keyset = keyset_file . read () keyset_handle = tink . json_proto_keyset_format . parse ( serialized_keyset , secret_key_access . TOKEN ) except tink . TinkError as e : logging . exception ( ' Error reading key : % s ' , e ) return 1 # Get the primitive try : cipher = keyset_handle . primitive ( aead . Aead ) except tink . TinkError as e : logging . error ( ' Error creating primitive : % s ' , e ) return 1 with open ( FLAGS . input_path , ' rb ' ) as input_file : input_data = input_file . read () if FLAGS . mode == ' decrypt ' : output_data = cipher . decrypt ( input_data , b ' envelope_example ' ) elif FLAGS . mode == ' encrypt ' : output_data = cipher . encrypt ( input_data , b ' envelope_example ' ) else : logging . error ( ' Error mode not supported . Please choose "encrypt" or "decrypt" . ' ) return 1 with open ( FLAGS . output_path , ' wb ' ) as output_file : output_file . write ( output_data ) if __name__ == ' __main__ ' : flags . mark_flags_as_required ([ ' mode ' , ' keyset_path ' ]) app . run ( main )


