Secure Anything with Google Tink: Encrypt Everywhere in Just Three Lines

This article introduces Google Tink, an open‑source cryptographic library for Java, explains its design goals and primitive abstractions, and walks through concise code examples that generate keysets, perform AEAD encryption, stream large files, compute MACs, and create digital signatures, all with minimal boilerplate.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Secure Anything with Google Tink: Encrypt Everywhere in Just Three Lines

Introduction

Google Tink is an open‑source cryptographic library created by Google security engineers. It offers a user‑centric API, rigorous implementation, code review, and comprehensive testing to reduce common encryption bugs.

Tink Goals and Mechanisms

Cryptographic agility : Users can switch keys and algorithms easily.

Secure reviewability : Clear security‑guaranteed interfaces enable local code review.

Tink abstracts cryptographic primitives and introduces the concept of a keyset , a collection of keys bound to a specific primitive, allowing code to work with multiple keys without specifying algorithms directly.

Core Primitives

Typical primitives include Aead, PublicKeySign, and Mac. These are accessed via the KeysetHandle class.

1. Setting Up the Environment

Java 21 is used. Add the following Maven dependencies:

<dependency>
  <groupId>com.google.crypto.tink</groupId>
  <artifactId>tink</artifactId>
  <version>1.20.0</version>
</dependency>
<dependency>
  <groupId>com.google.protobuf</groupId>
  <artifactId>protobuf-java</artifactId>
  <version>4.34.0</version>
</dependency>

2. Generating a New Keyset

TinkConfig.register();
// Generate a new keyset for AES‑128‑GCM
KeysetHandle handle = KeysetHandle.generateNew(PredefinedAeadParameters.AES128_GCM);
// Serialize the keyset for storage
String serializedKeyset = TinkJsonProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get());
System.err.println(serializedKeyset);
// Parse the keyset back
handle = TinkJsonProtoKeysetFormat.parseKeyset(serializedKeyset, InsecureSecretKeyAccess.get());

The resulting JSON contains fields such as primaryKeyId, typeUrl, and keyMaterialType, ensuring each key uniquely identifies a cryptographic function.

3. Symmetric AEAD Encryption & Decryption

AeadConfig.register();
KeysetHandle handle = KeysetHandle.generateNew(PredefinedAeadParameters.AES128_GCM);
String serializedKeyset = TinkJsonProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get());
String plaintext = "Spring全家桶实战案例";
String associatedData = "Pack_xg";
Aead aead = handle.getPrimitive(RegistryConfiguration.get(), Aead.class);
byte[] ciphertext = aead.encrypt(plaintext.getBytes(), associatedData.getBytes());
String encBase64 = Base64.getEncoder().encodeToString(ciphertext);
System.err.println(encBase64);
// Decrypt
handle = TinkJsonProtoKeysetFormat.parseKeyset(serializedKeyset, InsecureSecretKeyAccess.get());
aead = handle.getPrimitive(RegistryConfiguration.get(), Aead.class);
byte[] decrypted = aead.decrypt(Base64.getDecoder().decode(encBase64), associatedData.getBytes(StandardCharsets.UTF_8));
System.err.println(new String(decrypted, StandardCharsets.UTF_8));

The second parameter, associatedData, acts as an authentication tag that must be identical during decryption; it is not encrypted but bound to the ciphertext.

4. Encrypting Large Files or Streams

For large files, use the streaming AEAD primitive AES128_GCM_HKDF_1MB. Example:

String keyset = "<em>generated keyset JSON</em>";
Path inputFile = Paths.get("E:\\test\\key\\data.txt");
Path outputFile = Paths.get("E:\\test\\key\\data_encrypt.txt");
byte[] associatedData = "xxxooo".getBytes();
StreamingAeadConfig.register();
KeysetHandle handle = TinkJsonProtoKeysetFormat.parseKeyset(keyset, InsecureSecretKeyAccess.get());
StreamingAead streamingAead = handle.getPrimitive(RegistryConfiguration.get(), StreamingAead.class);
// Encrypt
encryptFile(streamingAead, inputFile, outputFile, associatedData);
// Decrypt
Path encrypted = Paths.get("E:\\test\\key\\data_encrypt.txt");
Path decrypted = Paths.get("E:\\test\\key\\data_plain.txt");
decryptFile(streamingAead, encrypted, decrypted, associatedData);

public static void encryptFile(StreamingAead streamingAead, Path inputFile, Path outputFile, byte[] associatedData) throws GeneralSecurityException, IOException {
    try (WritableByteChannel encryptingChannel = streamingAead.newEncryptingChannel(
            FileChannel.open(outputFile, StandardOpenOption.WRITE, StandardOpenOption.CREATE), associatedData);
         FileChannel inputChannel = FileChannel.open(inputFile, StandardOpenOption.READ)) {
        ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
        while (true) {
            int read = inputChannel.read(buffer);
            if (read <= 0) return;
            buffer.flip();
            while (buffer.hasRemaining()) encryptingChannel.write(buffer);
            buffer.clear();
        }
    }
}

public static void decryptFile(StreamingAead streamingAead, Path inputFile, Path outputFile, byte[] associatedData) throws GeneralSecurityException, IOException {
    try (ReadableByteChannel decryptingChannel = streamingAead.newDecryptingChannel(
            FileChannel.open(inputFile, StandardOpenOption.READ), associatedData);
         FileChannel outputChannel = FileChannel.open(outputFile, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
        ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
        while (true) {
            int read = decryptingChannel.read(buffer);
            if (read <= 0) return;
            buffer.flip();
            while (buffer.hasRemaining()) outputChannel.write(buffer);
            buffer.clear();
        }
    }
}

The accompanying image shows the before‑and‑after size of an encrypted file.

File encryption before and after
File encryption before and after

5. Message Authentication (MAC)

For integrity‑only protection, use the HMAC_SHA256 MAC primitive. Example:

String keyset = "<em>generated keyset JSON</em>";
byte[] msg = "Spring Boot3实战案例300讲".getBytes(StandardCharsets.UTF_8);
MacConfig.register();
KeysetHandle handle = TinkJsonProtoKeysetFormat.parseKeyset(keyset, InsecureSecretKeyAccess.get());
Mac mac = handle.getPrimitive(RegistryConfiguration.get(), Mac.class);
String macData = Base64.getEncoder().encodeToString(mac.computeMac(msg));
System.err.println(macData);
// Verify (throws if invalid)
mac.verifyMac(Base64.getDecoder().decode(macData), msg);

In most scenarios, using AEAD (which combines encryption and MAC) is preferable to MAC alone.

6. Digital Signatures

For non‑repudiation, the library provides ECDSA P256 signatures. Example:

String privateKeyset = "<em>private key JSON</em>";
byte[] msg = "Spring Boot3实战案例300讲".getBytes(StandardCharsets.UTF_8);
SignatureConfig.register();
KeysetHandle handle = TinkJsonProtoKeysetFormat.parseKeyset(privateKeyset, InsecureSecretKeyAccess.get());
PublicKeySign signer = handle.getPrimitive(RegistryConfiguration.get(), PublicKeySign.class);
byte[] signature = signer.sign(msg);
System.err.println("Signature: %s".formatted(Base64.getEncoder().encodeToString(signature)));

String publicKeyset = "<em>public key JSON</em>";
handle = TinkJsonProtoKeysetFormat.parseKeyset(publicKeyset, InsecureSecretKeyAccess.get());
PublicKeyVerify verifier = handle.getPrimitive(RegistryConfiguration.get(), PublicKeyVerify.class);
verifier.verify(signature, msg); // throws if verification fails

Note that the private key is used for signing while the public key is required for verification.

Conclusion

Google Tink provides a clean, opinionated API that abstracts away low‑level cryptographic details while offering strong guarantees through well‑tested primitives, keyset management, and support for both symmetric and asymmetric operations. With just a few lines of code developers can achieve end‑to‑end encryption, integrity, and authenticity across a wide range of use cases.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaMACdigital signaturecryptographyAEADGoogle Tinkstreaming encryption
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.