Ich möchte Daten verschlüsseln

Wir empfehlen für die meisten Anwendungsfälle der Datenverschlüsselung das AEAD-Primitive mit dem AES128_GCM.

Die authentifizierte Verschlüsselung mit verknüpften Daten (Authenticated Encryption with Associated Data, AEAD) ist das einfachste und am besten geeignete Primitive für die meisten Anwendungsfälle. AEAD bietet Vertraulichkeit und Authentizität und sorgt dafür, dass Nachrichten immer unterschiedliche Geheimtexte (verschlüsselte Ausgaben) haben, auch wenn die Klartexte (die Eingaben für die Verschlüsselung) gleich sind. Es ist symmetrisch und verwendet einen einzigen Schlüssel für die Ver- und Entschlüsselung.

Die folgenden Beispiele helfen Ihnen beim Einstieg in die Verwendung des AEAD-Primitivs:

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

ANLEITUNG

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

Das Primitive für die authentifizierte Verschlüsselung mit verknüpften Daten (Authenticated Encryption with Associated Data, AEAD) ist das am häufigsten verwendete Primitive für die Datenverschlüsselung und eignet sich für die meisten Anforderungen.

AEAD hat die folgenden Eigenschaften:

  • Secrecy: Es ist nichts über den Klartext bekannt, außer seiner Länge.
  • Authentizität: Es ist unmöglich, den verschlüsselten Klartext , der dem Geheimtext zugrunde liegt, unbemerkt zu ändern.
  • Symmetrisch: Die Verschlüsselung des Klartexts und die Entschlüsselung des Geheimtexts erfolgen mit demselben Schlüssel.
  • Zufälligkeit: Die Verschlüsselung wird zufällig durchgeführt. Zwei Nachrichten mit demselben Klartext liefern unterschiedliche Geheimtexte. Angreifer können nicht erkennen, welcher Geheimtext einem bestimmten Klartext entspricht. Wenn Sie das vermeiden möchten, verwenden Sie stattdessen deterministisches AEAD.

Verknüpfte Daten

Mit AEAD kann der Geheimtext mit bestimmten verknüpften Daten verknüpft werden. Angenommen, Sie haben eine Datenbank mit den Feldern user-id und encrypted-medical-history. In diesem Szenario kann user-id als verknüpfte Daten verwendet werden, wenn encrypted-medical-history verschlüsselt wird. Dadurch wird verhindert, dass ein Angreifer einen medizinischen Verlauf von einem Nutzer zu einem anderen verschieben kann.

Verknüpfte Daten sind optional. Wenn sie angegeben sind, ist die Entschlüsselung nur erfolgreich, wenn dieselben verknüpften Daten an die Ver- und Entschlüsselungsaufrufe übergeben werden.

Schlüsseltyp auswählen

Wir empfehlen zwar AES128_GCM für die meisten Anwendungsfälle, aber es gibt verschiedene Schlüsseltypen für unterschiedliche Anforderungen. AES128 bietet 128-Bit-Sicherheit und AES256 bietet 256-Bit-Sicherheit.

Die beiden wichtigsten Sicherheitsbeschränkungen bei der Auswahl eines Modus sind:

  1. Abfragen pro Sekunde (Queries per Second, QPS): Wie viele Nachrichten werden mit demselben Schlüssel verschlüsselt?
  2. Nachrichtengröße: Wie groß sind die Nachrichten?

Unterstützte Schlüsseltypen:

  • AES-CTR-HMAC (AES128_CTR_HMAC_SHA256, AES256_CTR_HMAC_SHA256) mit einem 16-Byte-Initialisierungsvektor (Initialization Vector, IV) ist der konservativste Modus mit guten Grenzen.
    • Schlüsselbindung.
  • AES-EAX (AES128_EAX, AES256_EAX) ist etwas weniger konservativ und etwas schneller als AES128_CTR_HMAC_SHA256.
    • Keine Schlüsselbindung für MLGR.
  • AES-GCM (AES128_GCM, AES256_GCM) ist in der Regel der schnellste Modus mit den strengsten Beschränkungen für die Anzahl der Nachrichten und die Nachrichtengröße. Wenn diese Beschränkungen für die Länge von Klartext und verknüpften Daten (siehe unten) überschritten werden, schlägt AES-GCM katastrophal fehl, indem Klartext und der Authentifizierungsteil des internen AES-GCM-Schlüssels offengelegt werden.
    • AES-GCM ist weder robust [ABN] noch schlüsselbindend [GLR]. Es ist möglich, einen Geheimtext zu generieren, der mit zwei verschiedenen Schlüsseln entschlüsselt werden kann. Dies kann zu praktischen Angriffen führen [DGRW]. Überprüfen Sie Ihr Bedrohungsmodell sorgfältig, wenn der Schlüssel vom Angreifer ausgewählt wird.
  • AES-GCM-SIV (AES128_GCM_SIV, AES256_GCM_SIV) ist fast so schnell wie AES-GCM. Es hat dieselben Beschränkungen wie AES-GCM für die Anzahl der Nachrichten und die Nachrichtengröße. Wenn diese Beschränkungen jedoch überschritten werden, schlägt es weniger katastrophal fehl: Es kann nur die Tatsache offengelegt werden, dass zwei Nachrichten gleich sind. Dadurch ist es sicherer als AES-GCM, wird aber in der Praxis weniger häufig verwendet. Wenn Sie es in Java verwenden möchten, müssen Sie Conscrypt installieren.
    • Keine Schlüsselbindung für ADGKLS.
  • XChaCha20-Poly1305 (XCHACHA20_POLY1305) hat eine viel höhere Beschränkung für die Anzahl der Nachrichten und die Nachrichtengröße als AES-GCM. Wenn es jedoch fehlschlägt (sehr unwahrscheinlich), werden auch Schlüsselmaterialien offengelegt. Es ist nicht hardwarebeschleunigt und kann daher in Situationen, in denen eine Hardwarebeschleunigung verfügbar ist, langsamer als AES-Modi sein.
    • Keine Schlüsselbindung für LGR.

Weitere Informationen zum Wire-Format des AEAD-Geheimtexts

Sicherheitsgarantien

AEAD-Implementierungen bieten Folgendes:

  • CCA2-Sicherheit
  • Mindestens 80-Bit-Authentifizierungsstärke
  • Die Möglichkeit, mindestens 232 Nachrichten mit insgesamt 250 Byte zu verschlüsseln Kein Angriff mit bis zu 232 ausgewählten Klartexten oder ausgewählten Geheimtexten hat eine Erfolgswahrscheinlichkeit von mehr als 2-32.