Guia do Google Tink

Guia do Google Tink

1. Introdução

Atualmente, muitos desenvolvedores usam técnicas criptográficas para proteger os dados do usuário.

Na criptografia, pequenos erros de implementação podem ter sérias conseqüências, e entender como implementar a criptografia corretamente é uma tarefa complexa e demorada.

Neste tutorial, vamos descreverTink - uma biblioteca criptográfica multi-linguagem e multiplataforma que pode nos ajudar a implementar um código criptográfico seguro.

2. Dependências

Podemos usar o Maven ou o Gradle para importar o Tink.

Para nosso tutorial, vamos apenas adicionarTink’s Maven dependency:


    com.google.crypto.tink
    tink
    1.2.2

Embora pudéssemos ter usado Gradle:

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

3. Inicialização

Antes de usar qualquer uma das APIs do Tink, precisamos inicializá-los.

Se precisarmos usar todas as implementações de todas as primitivas no Tink, podemos usar o métodoTinkConfig.register():

TinkConfig.register();

Enquanto, por exemplo, se precisarmos apenas da primitiva AEAD, podemos usar o métodoAeadConfig.register():

AeadConfig.register();

Também é fornecida uma inicialização personalizável para cada implementação.

4. Tink Primitives

Os principais objetos que a biblioteca usa são chamados de primitivos que, dependendo do tipo, contêm diferentes funcionalidades criptográficas.

Uma primitiva pode ter várias implementações:

Primitivo Implementações

AEAD

AES-EAX, AES-GCM, AES-CTR-HMAC, Envelope KMS, CHACHA20-POLY1305

Streaming AEAD

AES-GCM-HKDF-STREAMING, AES-CTR-HMAC-STREAMING

AEAD determinista

AEAD: AES-SIV

MAC

HMAC-SHA2

Assinatura digital

ECDSA sobre curvas NIST, ED25519

Criptografia híbrida

ECIES com AEAD e HKDF, (NaCl CryptoBox)

Podemos obter uma primitiva chamando o métodogetPrimitive() da classe de fábrica correspondente, passando aKeysetHandle:

Aead aead = AeadFactory.getPrimitive(keysetHandle);

4.1. KeysetHandle

Na ordemto provide cryptographic functionality, each primitive needs a key structure que contém todos os principais materiais e parâmetros.

O Tink fornece um objeto -KeysetHandle – que envolve um conjunto de chaves com alguns parâmetros e metadados adicionais.

Portanto, antes de instanciar um primitivo, precisamos criar um sobjetoKeysetHandle :

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

E depois de gerar uma chave, podemos persistir:

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

Em seguida, podemos carregá-lo posteriormente:

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

5. Criptografia

O Tink fornece várias maneiras de aplicar o algoritmo AEAD. Vamos dar uma olhada.

5.1. AEAD

AEAD fornece criptografia autenticada com dados associados, o que significa quewe can encrypt plaintext and, optionally, provide associated data that should be authenticated but not encrypted.

Observe que esse algoritmo garante a autenticidade e integridade dos dados associados, mas não seu sigilo.

Para criptografar dados com uma das implementações AEAD, como vimos anteriormente, precisamos inicializar a biblioteca e criar umkeysetHandle:

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

Depois de fazer isso, podemos obter o primitivo e criptografar os dados desejados:

String plaintext = "example";
String associatedData = "Tink";

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

Em seguida, podemos descriptografarciphertext usando o métododecrypt():

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

5.2. Streaming AEAD

Da mesma forma,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();

Basicamente, precisamos deWriteableByteChannel para conseguir isso.

Então, para descriptografar ocipherTextFile,, gostaríamos de usar umReadableByteChannel:

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. Criptografia híbrida

Além da criptografia simétrica, o Tink implementa algumas primitivas para criptografia híbrida.

Com a criptografia híbrida, podemos obter a eficiência das chaves simétricas e a conveniência das chaves assimétricas.

Simplificando, usaremos uma chave simétrica para criptografar o texto simplesand a public key to encrypt the symmetric key only.

Observe que ele fornece apenas sigilo, não autenticidade de identidade do remetente.

Então, vamos ver como usarHybridEncrypteHybridDecrypt:

TinkConfig.register();

KeysetHandle privateKeysetHandle = KeysetHandle.generateNew(
  HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256);
KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle();

String plaintext = "example";
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());

OcontextInfo são dados públicos implícitos do contexto que podem sernull ou vazios ou usados ​​como entrada de “dados associados” para a criptografia AEAD ou como entrada “CtxInfo” para HKDF.

Ociphertext permite verificar a integridade decontextInfo, mas não seu sigilo ou autenticidade.

7. Código de autenticação de mensagem

O Tink também oferece suporte a códigos de autenticação de mensagens ou MACs.

Um MAC é um bloco de poucos bytes que podemos usar para autenticar uma mensagem.

Vamos ver como podemos criar um MAC e, em seguida, verificar sua autenticidade:

TinkConfig.register();

KeysetHandle keysetHandle = KeysetHandle.generateNew(
  MacKeyTemplates.HMAC_SHA256_128BITTAG);

String data = "example";

Mac mac = MacFactory.getPrimitive(keysetHandle);

byte[] tag = mac.computeMac(data.getBytes());
mac.verifyMac(tag, data.getBytes());

No caso de os dados não serem autênticos, o métodoverifyMac() lança umGeneralSecurityException.

8. Assinatura digital

Além de APIs de criptografia, o Tink suporta assinaturas digitais.

Para implementar a assinatura digital, a biblioteca usa a primitivaPublicKeySign para a assinatura dos dados ePublickeyVerify para verificação:

TinkConfig.register();

KeysetHandle privateKeysetHandle = KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P256);
KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle();

String data = "example";

PublicKeySign signer = PublicKeySignFactory.getPrimitive(privateKeysetHandle);
PublicKeyVerify verifier = PublicKeyVerifyFactory.getPrimitive(publicKeysetHandle);

byte[] signature = signer.sign(data.getBytes());
verifier.verify(signature, data.getBytes());

Semelhante ao método de criptografia anterior, quando a assinatura é inválida, obteremos umGeneralSecurityException.

9. Conclusão

Neste artigo, apresentamos a biblioteca do Google Tink usando sua implementação Java.

Vimos como usar para criptografar e descriptografar dados e como proteger sua integridade e autenticidade. Além disso, vimos como assinar dados usando APIs de assinatura digital.

Como sempre, o código de amostra está disponívelover on GitHub.