Guida a Google Tink

1. Introduzione

Al giorno d'oggi, molti sviluppatori utilizzano tecniche crittografiche per proteggere i dati degli utenti.

Nella crittografia, piccoli errori di implementazione possono avere gravi conseguenze e capire come implementare correttamente la crittografia è un'attività complessa e dispendiosa in termini di tempo.

In questo tutorial, descriveremo Tink, una libreria crittografica multi-lingua e multipiattaforma che può aiutarci a implementare codice crittografico sicuro.

2. Dipendenze

Possiamo usare Maven o Gradle per importare Tink.

Per il nostro tutorial, aggiungeremo semplicemente la dipendenza Maven di Tink:

 com.google.crypto.tink tink 1.2.2 

Anche se avremmo potuto usare Gradle invece:

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

3. Inizializzazione

Prima di utilizzare una qualsiasi delle API Tink, è necessario inizializzarle.

Se dobbiamo usare tutte le implementazioni di tutte le primitive in Tink, possiamo usare il metodo TinkConfig.register () :

TinkConfig.register();

Mentre, ad esempio, se abbiamo solo bisogno della primitiva AEAD, possiamo usare il metodo AeadConfig.register () :

AeadConfig.register();

Viene fornita anche un'inizializzazione personalizzabile per ciascuna implementazione.

4. Tink Primitives

Gli oggetti principali utilizzati dalla libreria sono chiamati primitive che, a seconda del tipo, contengono diverse funzionalità crittografiche.

Una primitiva può avere più implementazioni:

Primitivo Implementazioni
AEAD AES-EAX, AES-GCM, AES-CTR-HMAC, busta KMS, CHACHA20-POLY1305
Streaming AEAD AES-GCM-HKDF-STREAMING, AES-CTR-HMAC-STREAMING
AEAD deterministico AEAD: AES-SIV
MAC HMAC-SHA2
Firma digitale ECDSA sulle curve NIST, ED25519
Crittografia ibrida ECIES con AEAD e HKDF, (NaCl CryptoBox)

Possiamo ottenere una primitiva chiamando il metodo getPrimitive () della classe factory corrispondente passandogli un KeysetHandle :

Aead aead = AeadFactory.getPrimitive(keysetHandle); 

4.1. KeysetHandle

Per fornire funzionalità crittografiche, ogni primitiva necessita di una struttura chiave che contenga tutto il materiale ei parametri chiave.

Tink fornisce un oggetto - KeysetHandle - che racchiude un keyset con alcuni parametri e metadati aggiuntivi.

Quindi, prima di creare un'istanza di una primitiva, dobbiamo creare un oggetto KeysetHandle :

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

E dopo aver generato una chiave, potremmo volerla persistere:

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

Quindi, possiamo successivamente caricarlo:

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

5. Crittografia

Tink offre diversi modi per applicare l'algoritmo AEAD. Diamo un'occhiata.

5.1. AEAD

AEAD fornisce la crittografia autenticata con dati associati, il che significa che possiamo crittografare il testo in chiaro e, facoltativamente, fornire i dati associati che dovrebbero essere autenticati ma non crittografati .

Si noti che questo algoritmo garantisce l'autenticità e l'integrità dei dati associati ma non la loro segretezza.

Per crittografare i dati con una delle implementazioni AEAD, come abbiamo visto in precedenza, dobbiamo inizializzare la libreria e creare un keysetHandle:

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

Una volta fatto ciò, possiamo ottenere la primitiva e crittografare i dati desiderati:

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

Successivamente, possiamo decrittografare il testo cifrato usando il metodo 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.

Come sempre, il codice di esempio è disponibile su GitHub.