Skip to content
Exposed docs1.11

Exposed Tink Encryption

Latest stable Based on Exposed release 1.11.0

Library module

This module encrypts Exposed VARCHAR, binary, and BLOB values at the column boundary with Google Tink AEAD or Deterministic AEAD. It maps plaintext application values to ciphertext columns; it does not provision, store, rotate, or recover keysets.

Use randomized AEAD for sensitive values that are read by id and do not need equality lookup. Use Deterministic AEAD only when equality search is required and the pattern-leakage trade-off is accepted. Hashing or tokenization may be a better search design for some identifiers.

dependencies {
implementation(platform("io.github.bluetape4k:bluetape4k-dependencies:<version>"))
implementation("io.github.bluetape4k.exposed:bluetape4k-exposed-tink")
}
  • AEAD produces different ciphertext for the same plaintext; equality predicates and ordinary indexes cannot match it.
  • Deterministic AEAD produces the same ciphertext for the same plaintext and associated data, enabling equality lookup while revealing repetition.
  • VARCHAR stores encoded ciphertext; binary and BLOB variants store bytes.
  • Default associated data binds ciphertext to bluetape4k-exposed-tink:v1:<table>:<column>.
  • Keyset lifecycle belongs to application secret/KMS infrastructure, separate from column mapping.
val aead = TinkAead(loadAeadKeysetFromKms())
val daead = TinkDeterministicAead(loadDaeadKeysetFromKms())
object Customers : LongIdTable("customers") {
val note = tinkAeadVarChar("note", 1024, aead)
val email = tinkDaeadVarChar("email", 512, daead).index()
}
transaction {
Customers.insert { row ->
row[note] = "private note"
row[email] = "ada@example.com"
}
}
TaskStable 1.11 API
Randomized text/bytes/blobtinkAeadVarChar, tinkAeadBinary, tinkAeadBlob
Searchable deterministic text/bytes/blobtinkDaeadVarChar, tinkDaeadBinary, tinkDaeadBlob
Associated-data domainTinkColumnAssociatedDataProvider, TableAndColumn, Empty
Low-level mappingTink*Aead*ColumnType and transformers; prefer table DSL

Load durable keysets from KMS or protected secret storage before defining tables. Prefer table DSL functions so associated data is bound consistently. Record a key id/version outside the ciphertext when migration needs it. Rotate by deploying a reader that can decrypt old data, rewriting rows with the new primary key, and retiring old key material only after coverage is proven.

The module uses bluetape4k-tink primitives and Exposed ColumnWithTransform. Encryption happens when Exposed converts the application value to the database representation; decryption happens while reading the column. The database never receives the plaintext for ordinary transformed writes.

Choose AEAD versus DAEAD, ciphertext length, keyset source, rotation policy, and associated-data provider. The default provider includes stable table and column names. Renaming either changes associated data, so existing ciphertext must be migrated/re-encrypted or read with a compatibility provider during migration.

  • A missing, regenerated, or wrong keyset makes stored rows undecryptable.
  • Changed associated data, including a table/column rename, causes authentication failure.
  • AEAD equality queries do not match because every encryption uses a new nonce.
  • DAEAD reveals repeated plaintext patterns and equality frequency.
  • A ciphertext longer than the declared VARCHAR/binary capacity is truncated or rejected by the database.
  • Blank names and non-positive lengths fail validation in the table DSL.

Back up keysets separately from the database and test recovery together. Audit key access and rotation without logging plaintext, ciphertext, or key material. Alert on decrypt/authentication failures. Plan rename and key rotation as data migrations with resumable backfill and rollback.

Test round trips, wrong-key failure, wrong-associated-data failure, tampered ciphertext, nullability, maximum payload size, and restart/node sharing with a persisted keyset. For DAEAD, prove equality lookup; for AEAD, prove repeated plaintext produces different ciphertext and is not queried by equality.

Terminal window
./gradlew :bluetape4k-exposed-tink:test

Read the serialization and encryption guide first, then inspect TinkTableTest for DSL validation and associated-data behavior, TinkColumnTypeTest for AEAD, and TinkDaeadColumnTypeTest for deterministic lookup behavior.

This is field encryption, not a key-management system, authorization layer, searchable-encryption scheme, or database-wide encryption replacement. It supports equality only through deterministic encryption; range, prefix, ordering, and substring queries are not preserved. Key loss is not recoverable by this module.

These diagrams are loaded directly from README assets published with the 1.11.0 release and pinned to its immutable commit. They describe this manual’s released structure and runtime flows, not later Snapshot changes. Select a preview to open the SVG at the same release commit.

Tink encrypted column boundary diagram

Release README: exposed/tink/README.md

AEAD and DAEAD behavior flow diagram

Release README: exposed/tink/README.md