Guide de Google Tink

1. Introduction

De nos jours, de nombreux développeurs utilisent des techniques cryptographiques pour protéger les données des utilisateurs.

En cryptographie, de petites erreurs de mise en œuvre peuvent avoir de graves conséquences, et comprendre comment implémenter correctement la cryptographie est une tâche complexe et longue.

Dans ce tutoriel, nous allons décrire Tink - une bibliothèque cryptographique multi-langues et multiplateforme qui peut nous aider à implémenter un code cryptographique sécurisé.

2. Dépendances

Nous pouvons utiliser Maven ou Gradle pour importer Tink.

Pour notre tutoriel, nous allons simplement ajouter la dépendance Maven de Tink:

 com.google.crypto.tink tink 1.2.2 

Bien que nous aurions pu utiliser Gradle à la place:

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

3. Initialisation

Avant d'utiliser l'une des API Tink, nous devons les initialiser.

Si nous devons utiliser toutes les implémentations de toutes les primitives dans Tink, nous pouvons utiliser la méthode TinkConfig.register () :

TinkConfig.register();

Alors que, par exemple, si nous n'avons besoin que de la primitive AEAD, nous pouvons utiliser la méthode AeadConfig.register () :

AeadConfig.register();

Une initialisation personnalisable est également fournie pour chaque implémentation.

4. Tink Primitives

Les principaux objets utilisés par la bibliothèque sont appelés primitives qui, selon le type, contiennent différentes fonctionnalités cryptographiques.

Une primitive peut avoir plusieurs implémentations:

Primitif Implémentations
AEAD AES-EAX, AES-GCM, AES-CTR-HMAC, Enveloppe KMS, CHACHA20-POLY1305
Streaming AEAD AES-GCM-HKDF-STREAMING, AES-CTR-HMAC-STREAMING
AEAD déterministe AEAD: AES-SIV
MAC HMAC-SHA2
Signature numérique ECDSA sur courbes NIST, ED25519
Cryptage hybride ECIES avec AEAD et HKDF, (NaCl CryptoBox)

On peut obtenir une primitive en appelant la méthode getPrimitive () de la classe factory correspondante en lui passant un KeysetHandle :

Aead aead = AeadFactory.getPrimitive(keysetHandle); 

4.1. KeysetHandle

Afin de fournir une fonctionnalité cryptographique, chaque primitive a besoin d'une structure de clé contenant tous les éléments et paramètres clés.

Tink fournit un objet - KeysetHandle - qui enveloppe un jeu de clés avec quelques paramètres et métadonnées supplémentaires.

Donc, avant d'instancier une primitive, nous devons créer un objet KeysetHandle :

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

Et après avoir généré une clé, nous pourrions vouloir la conserver:

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

Ensuite, nous pouvons le charger par la suite:

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

5. Chiffrement

Tink propose plusieurs façons d'appliquer l'algorithme AEAD. Nous allons jeter un coup d'oeil.

5.1. AEAD

AEAD fournit un cryptage authentifié avec des données associées, ce qui signifie que nous pouvons crypter du texte en clair et, éventuellement, fournir des données associées qui doivent être authentifiées mais non cryptées .

Notez que cet algorithme garantit l'authenticité et l'intégrité des données associées mais pas leur secret.

Pour crypter les données avec l'une des implémentations AEAD, comme nous l'avons vu précédemment, nous devons initialiser la bibliothèque et créer un keysetHandle:

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

Une fois que nous avons fait cela, nous pouvons obtenir la primitive et crypter les données souhaitées:

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

Ensuite, nous pouvons déchiffrer le texte chiffré en utilisant la méthode decrypt () :

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.

Comme toujours, l'exemple de code est disponible à l'adresse over sur GitHub.