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.