Wir empfehlen für die meisten Anwendungsfälle der Datenverschlüsselung das AEAD-Primitive mit dem AES128_GCM.
Authenticated Encryption with Associated Data (AEAD) ist das einfachste und für die meisten Anwendungsfälle am besten geeignete Primitive. 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::ConfigAead2026()); 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://developers.google.com/tink/key-management-overview. 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
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 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 nicht möglich, den verschlüsselten Klartext , der dem Geheimtext zugrunde liegt, unbemerkt zu ändern.
- Symmetrisch: Die Nachricht wird verschlüsselt und der Geheimtext wird mit demselben Schlüssel entschlüsselt.
- Randomisierung: Die Verschlüsselung wird zufällig durchgeführt. Zwei Nachrichten mit demselben Klartext liefern unterschiedliche Geheimtexte. Angreifer können nicht wissen, welcher Geheimtext einem bestimmten Klartext entspricht. Wenn Sie das vermeiden möchten, verwenden Sie stattdessen deterministisches AEAD.
Verknüpfte Daten
Mit AEAD kann ein 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 Fall kann user-id als verknüpfte Daten verwendet werden, wenn encrypted-medical-history verschlüsselt wird. So wird verhindert, dass ein Angreifer die Krankengeschichte von einem Nutzer zu einem anderen verschiebt.
Verknüpfte Daten sind optional. Wenn sie angegeben sind, ist die Entschlüsselung nur erfolgreich, wenn dieselben verknüpften Daten an beide 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:
- QPS: Wie viele Nachrichten werden mit demselben Schlüssel verschlüsselt?
- 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 (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 (232) und die Nachrichtengröße
(~64 GB pro Nachricht). Wenn diese Beschränkungen ü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)
[RFC8452] ist resistent gegen versehentlichen
Nonce-Missbrauch und fast so leistungsstark wie AES-GCM. Die Beschränkungen für die Anzahl der Nachrichten und die Nachrichtengröße für AES-GCM-SIV mit zufälligen IVs sind viel höher als die Beschränkungen von AES-GCM. Wenn diese Beschränkungen überschritten werden, schlägt AES-GCM-SIV
weniger katastrophal fehl: Es wird nur offengelegt, dass
zwei Nachrichten gleich sind.
AES-GCM-SIV ist sicherer, wird aber in der Praxis weniger häufig verwendet.
- Beschränkungen für zufällige Nonces:
- 232 Nachrichten, wobei jeder Klartext maximal 8 GiB groß ist
- 248 Nachrichten, wobei jeder Klartext maximal 32 MiB groß ist
- 264 Nachrichten, wobei jeder Klartext maximal 128 KiB groß ist
- Wenn Sie es in Java verwenden möchten, installieren Sie Conscrypt.
- Keine Schlüsselbindung für ADGKLS.
- Beschränkungen für zufällige Nonces:
- 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), wird auch Schlüsselmaterial offengelegt. Es ist nicht hardwarebeschleunigt und kann daher langsamer als AES-Modi sein, wenn Hardwarebeschleunigung verfügbar ist.
- 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.