Leitfaden zu Google Tink

1. Einleitung

Heutzutage verwenden viele Entwickler kryptografische Techniken, um Benutzerdaten zu schützen.

In der Kryptografie können kleine Implementierungsfehler schwerwiegende Folgen haben, und das Verständnis der korrekten Implementierung der Kryptografie ist eine komplexe und zeitaufwändige Aufgabe.

In diesem Tutorial beschreiben wir Tink - eine mehrsprachige, plattformübergreifende kryptografische Bibliothek, die uns bei der Implementierung von sicherem kryptografischem Code helfen kann.

2. Abhängigkeiten

Wir können Maven oder Gradle verwenden, um Tink zu importieren.

Für unser Tutorial fügen wir einfach Tinks Maven-Abhängigkeit hinzu:

 com.google.crypto.tink tink 1.2.2 

Obwohl wir stattdessen Gradle hätten verwenden können:

dependencies { compile 'com.google.crypto.tink:tink:latest' }

3. Initialisierung

Bevor wir eine der Tink-APIs verwenden, müssen wir sie initialisieren.

Wenn wir alle Implementierungen aller Grundelemente in Tink verwenden müssen, können wir die Methode TinkConfig.register () verwenden:

TinkConfig.register();

Wenn wir beispielsweise nur das Grundelement AEAD benötigen, können wir die Methode AeadConfig.register () verwenden:

AeadConfig.register();

Auch für jede Implementierung wird eine anpassbare Initialisierung bereitgestellt.

4. Tink Primitive

Die Hauptobjekte, die die Bibliothek verwendet, werden als Grundelemente bezeichnet, die je nach Typ unterschiedliche kryptografische Funktionen enthalten.

Ein Grundelement kann mehrere Implementierungen haben:

Primitive Implementierungen
AEAD AES-EAX, AES-GCM, AES-CTR-HMAC, KMS-Umschlag, CHACHA20-POLY1305
Streaming AEAD AES-GCM-HKDF-STREAMING, AES-CTR-HMAC-STREAMING
Deterministischer AEAD AEAD: AES-SIV
MAC HMAC-SHA2
Digitale Unterschrift ECDSA über NIST-Kurven, ED25519
Hybridverschlüsselung ECIES mit AEAD und HKDF (NaCl CryptoBox)

Wir können ein Grundelement erhalten, indem wir die Methode getPrimitive () der entsprechenden Factory-Klasse aufrufen und ihr ein KeysetHandle übergeben :

Aead aead = AeadFactory.getPrimitive(keysetHandle); 

4.1. KeysetHandle

Um kryptografische Funktionen bereitzustellen, benötigt jedes Grundelement eine Schlüsselstruktur , die alle Schlüsselmaterialien und -parameter enthält.

Tink stellt ein Objekt bereit - KeysetHandle - das ein Keyset mit einigen zusätzlichen Parametern und Metadaten umschließt.

Bevor wir also ein Grundelement instanziieren, müssen wir ein KeysetHandle- Objekt erstellen :

KeysetHandle keysetHandle = KeysetHandle.generateNew(AeadKeyTemplates.AES256_GCM);

Und nachdem wir einen Schlüssel generiert haben, möchten wir ihn vielleicht beibehalten:

String keysetFilename = "keyset.json"; CleartextKeysetHandle.write(keysetHandle, JsonKeysetWriter.withFile(new File(keysetFilename)));

Dann können wir es anschließend laden:

String keysetFilename = "keyset.json"; KeysetHandle keysetHandle = CleartextKeysetHandle.read(JsonKeysetReader.withFile(new File(keysetFilename)));

5. Verschlüsselung

Tink bietet mehrere Möglichkeiten zur Anwendung des AEAD-Algorithmus. Lass uns einen Blick darauf werfen.

5.1. AEAD

AEAD bietet authentifizierte Verschlüsselung mit zugehörigen Daten. Dies bedeutet, dass wir Klartext verschlüsseln und optional zugehörige Daten bereitstellen können, die authentifiziert, aber nicht verschlüsselt werden sollen .

Beachten Sie, dass dieser Algorithmus die Authentizität und Integrität der zugehörigen Daten gewährleistet, nicht jedoch deren Geheimhaltung.

Um Daten mit einer der AEAD-Implementierungen zu verschlüsseln, müssen wir, wie wir zuvor gesehen haben, die Bibliothek initialisieren und ein keysetHandle erstellen :

AeadConfig.register(); KeysetHandle keysetHandle = KeysetHandle.generateNew( AeadKeyTemplates.AES256_GCM);

Sobald wir das getan haben, können wir das Grundelement erhalten und die gewünschten Daten verschlüsseln:

String plaintext = "baeldung"; String associatedData = "Tink"; Aead aead = AeadFactory.getPrimitive(keysetHandle); byte[] ciphertext = aead.encrypt(plaintext.getBytes(), associatedData.getBytes());

Als nächstes können wir den Chiffretext mit der Methode decrypt () entschlüsseln :

String decrypted = new String(aead.decrypt(ciphertext, associatedData.getBytes()));

5.2. Streaming AEAD

Similarly, when the data to be encrypted is too large to be processed in a single step, we can use the streaming AEAD primitive:

AeadConfig.register(); KeysetHandle keysetHandle = KeysetHandle.generateNew( StreamingAeadKeyTemplates.AES128_CTR_HMAC_SHA256_4KB); StreamingAead streamingAead = StreamingAeadFactory.getPrimitive(keysetHandle); FileChannel cipherTextDestination = new FileOutputStream("cipherTextFile").getChannel(); WritableByteChannel encryptingChannel = streamingAead.newEncryptingChannel(cipherTextDestination, associatedData.getBytes()); ByteBuffer buffer = ByteBuffer.allocate(CHUNK_SIZE); InputStream in = new FileInputStream("plainTextFile"); while (in.available() > 0) { in.read(buffer.array()); encryptingChannel.write(buffer); } encryptingChannel.close(); in.close();

Basically, we needed WriteableByteChannel to achieve this.

So, to decrypt the cipherTextFile, we'd want to use a ReadableByteChannel:

FileChannel cipherTextSource = new FileInputStream("cipherTextFile").getChannel(); ReadableByteChannel decryptingChannel = streamingAead.newDecryptingChannel(cipherTextSource, associatedData.getBytes()); OutputStream out = new FileOutputStream("plainTextFile"); int cnt = 1; do { buffer.clear(); cnt = decryptingChannel.read(buffer); out.write(buffer.array()); } while (cnt>0); decryptingChannel.close(); out.close();

6. Hybrid Encryption

In addition to symmetric encryption, Tink implements a couple of primitives for hybrid encryption.

With Hybrid Encryption we can get the efficiency of symmetric keys and the convenience of asymmetric keys.

Simply put, we'll use a symmetric key to encrypt the plaintext and a public key to encrypt the symmetric key only.

Notice that it provides secrecy only, not identity authenticity of the sender.

So, let's see how to use HybridEncrypt and HybridDecrypt:

TinkConfig.register(); KeysetHandle privateKeysetHandle = KeysetHandle.generateNew( HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256); KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle(); String plaintext = "baeldung"; String contextInfo = "Tink"; HybridEncrypt hybridEncrypt = HybridEncryptFactory.getPrimitive(publicKeysetHandle); HybridDecrypt hybridDecrypt = HybridDecryptFactory.getPrimitive(privateKeysetHandle); byte[] ciphertext = hybridEncrypt.encrypt(plaintext.getBytes(), contextInfo.getBytes()); byte[] plaintextDecrypted = hybridDecrypt.decrypt(ciphertext, contextInfo.getBytes());

The contextInfo is implicit public data from the context that can be null or empty or used as “associated data” input for the AEAD encryption or as “CtxInfo” input for HKDF.

The ciphertext allows for checking the integrity of contextInfo but not its secrecy or authenticity.

7. Message Authentication Code

Tink also supports Message Authentication Codes or MACs.

A MAC is a block of a few bytes that we can use to authenticate a message.

Let's see how we can create a MAC and then verify its authenticity:

TinkConfig.register(); KeysetHandle keysetHandle = KeysetHandle.generateNew( MacKeyTemplates.HMAC_SHA256_128BITTAG); String data = "baeldung"; Mac mac = MacFactory.getPrimitive(keysetHandle); byte[] tag = mac.computeMac(data.getBytes()); mac.verifyMac(tag, data.getBytes());

In the event that the data isn't authentic, the method verifyMac() throws a GeneralSecurityException.

8. Digital Signature

As well as encryption APIs, Tink supports digital signatures.

To implement digital signature, the library uses the PublicKeySign primitive for the signing of data, and PublickeyVerify for verification:

TinkConfig.register(); KeysetHandle privateKeysetHandle = KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P256); KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle(); String data = "baeldung"; PublicKeySign signer = PublicKeySignFactory.getPrimitive(privateKeysetHandle); PublicKeyVerify verifier = PublicKeyVerifyFactory.getPrimitive(publicKeysetHandle); byte[] signature = signer.sign(data.getBytes()); verifier.verify(signature, data.getBytes());

Similar to the previous encryption method, when the signature is invalid, we'll get a GeneralSecurityException.

9. Conclusion

In this article, we introduced the Google Tink library using its Java implementation.

We've seen how to use to encrypt and decrypt data and how to protect its integrity and authenticity. Moreover, we've seen how to sign data using digital signature APIs.

Wie immer ist der Beispielcode über GitHub verfügbar.