Créer et stocker une collection de clés en texte brut

Les exemples suivants montrent comment créer un ensemble de clés avec une seule clé et le stocker en texte brut sur disque.

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)