Tạo và lưu trữ tập hợp khoá ở dạng văn bản thuần tuý

Các ví dụ sau đây minh hoạ cách tạo một tập hợp khoá bằng một khoá và lưu trữ mã đó dưới dạng văn bản thuần tuý trên ổ đĩa.

Tinkey

tinkey create-keyset \
  --key-template AES128_GCM \
  --out-format json \
  --out aead_keyset.json

Java

package cleartextkeyset;

import com.google.crypto.tink.Aead;
import com.google.crypto.tink.CleartextKeysetHandle;
import com.google.crypto.tink.JsonKeysetReader;
import com.google.crypto.tink.JsonKeysetWriter;
import com.google.crypto.tink.KeyTemplates;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.aead.AeadConfig;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;

/**
 * A command-line utility for generating, storing and using cleartext AES128_GCM keysets.
 *
 * <h1>WARNING: It loads cleartext keys from disk - this is not recommended!
 *
 * <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);
    }
    File keyFile = new File(args[1]);

    // Initialise Tink: register all AEAD key types with the Tink runtime
    AeadConfig.register();

    if (MODE_GENERATE.equals(mode)) {
      KeysetHandle handle = KeysetHandle.generateNew(KeyTemplates.get("AES128_GCM"));

      try (FileOutputStream outputStream = new FileOutputStream(keyFile)) {
        CleartextKeysetHandle.write(handle, JsonKeysetWriter.withOutputStream(outputStream));
      }
      System.exit(0);
    }

    // Use the primitive to encrypt/decrypt files

    // Read the cleartext keyset
    KeysetHandle handle = null;
    try (FileInputStream inputStream = new FileInputStream(keyFile)) {
      handle = CleartextKeysetHandle.read(JsonKeysetReader.withInputStream(inputStream));
    } catch (GeneralSecurityException | IOException ex) {
      System.err.println("Error reading key: " + ex);
      System.exit(1);
    }

    // Get the primitive
    Aead aead = null;
    try {
      aead = handle.getPrimitive(Aead.class);
    } catch (GeneralSecurityException ex) {
      System.err.println("Error creating primitive: %s " + ex);
      System.exit(1);
    }

    byte[] input = Files.readAllBytes(Paths.get(args[2]));
    File outputFile = new File(args[3]);

    if (MODE_ENCRYPT.equals(mode)) {
      byte[] ciphertext = aead.encrypt(input, EMPTY_ASSOCIATED_DATA);
      try (FileOutputStream stream = new FileOutputStream(outputFile)) {
        stream.write(ciphertext);
      }
    } else if (MODE_DECRYPT.equals(mode)) {
      byte[] plaintext = aead.decrypt(input, EMPTY_ASSOCIATED_DATA);
      try (FileOutputStream stream = new FileOutputStream(outputFile)) {
        stream.write(plaintext);
      }
    }

    System.exit(0);
  }

  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 cleartext_keyset_handle


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:
        cleartext_keyset_handle.write(
            tink.JsonKeysetWriter(keyset_file), keyset_handle)
      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:
      text = keyset_file.read()
      keyset_handle = cleartext_keyset_handle.read(tink.JsonKeysetReader(text))
    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)