Tinklj
A Cryptographic Clojure Api for the Google Tink library
Install / Use
/learn @perkss/TinkljREADME
Tinklj a Clojure api for Google Tink cryptographic library, offering simplistic and secure cryptography for Clojure.
Installation
Leiningen/Boot
[tinklj "0.1.21-SNAPSHOT"]
Clojure CLI/deps.edn
tinklj {:mvn/version "0.1.21-SNAPSHOT"}
Gradle
compile 'tinklj:tinklj:0.1.21-SNAPSHOT'
Maven
<dependency>
<groupId>tinklj</groupId>
<artifactId>tinklj</artifactId>
<version>0.1.21-SNAPSHOT</version>
</dependency>
Getting Started
The best way to find example use cases for the encryption techniques is to check the Acceptance Tests.
Initialize Tinklj
First we need to call register to register the encryption techniques. If you want to use all implementations of all primitives in tinklj then you call as follows:
(:require [tinklj.config :refer [register])
(register)
If you wish to use a specific implementation such as AEAD you use:
(:require [tinklj.config :refer [register])
(register :aead)
Available options are:
:aead:daead:mac:signature:streaming
To do custom initialization then registration proceeds directly with a Registry class.
(:require [tinklj.config :refer [register-key-manager])
(register-key-manager (MyAeadKeyManager.)
Generating New Key(set)s
Below shows how you can generate a keyset containing a randomly generated AES128-GCM specified.
(:require [tinklj.keys.keyset-handle :as keyset-handles])
(keyset-handles/generate-new :aes128-gcm)
Storing Keysets
Once you have generated the keyset you can store it down for future use. Cleartext and encrypted keysets can be stored. Obviously encrypted is recommended.
(:require [tinklj.keys.keyset-handle :as keyset-handles]
[tinklj.keysets.keyset-storage :as keyset-storage])
(def filename "my_keyset.json")
(def keyset-handle (keyset-handles/generate-new :aes128-gcm)
(keyset-storage/write-clear-text-keyset-handle keyset-handle filename)
Tinklj supports encrypting keysets with master keys stored in a remote key management systems. Lets see how to write these remote KMS keys.
(:require [tinklj.keys.keyset-handle :as keyset-handles]
[tinklj.keysets.keyset-storage :as keyset-storage]
[tinklj.keysets.integration.gcp-kms-client :refer [gcp-kms-client])
;; Generate the key material...
(def keyset-handle (keyset-handles/generate-new :aes128-gcm)
;; and write it to a file...
(def filename "my_keyset.json")
;; encrypted with the this key in GCP KMS
(def master-key-uri = "gcp-kms://projects/tinklj-examples/locations/global/keyRings/foo/cryptoKeys/bar")
(def kms-client (gcp-kms-client))
(keyset-storage/write-remote-kms-keyset-handle
keyset-handle
kms-client
filename
master-key-uri)
Loading Existing Keysets
Once the keyset is stored it can be reloaded as follows:
(:require [tinklj.keysets.keyset-storage :as keyset-storage])
(keyset-storage/load-clear-text-keyset-handle filename)
Loading remote encrypted keys:
(:require [tinklj.keys.keyset-handle :as keyset-handles]
[tinklj.keysets.keyset-storage :as keyset-storage]
[tinklj.keysets.integration.gcp-kms-client :refer [gcp-kms-client])
(def filename "my_keyset.json")
;; encrypted with the this key in GCP KMS
(def master-key-uri = "gcp-kms://projects/tinklj-examples/locations/global/keyRings/foo/cryptoKeys/bar")
(def kms-client (gcp-kms-client))
(keyset-storage/load-remote-kms-keyset-handle
kms-client
filename
master-key-uri)
Obtaining and Using Primitives
We then get the primitive of the keyset-handle and can use this to encrypt and decypt.
(keyset-handles/get-primitive keyset-handle)
Symmetric Key Encryption
Authenticated Encryption with Associated Data
(:require [tinklj.encryption.aead :refer [encrypt decrypt]
[tinklj.keys.keyset-handle :as keyset-handle]
[tinklj.primitives :as primitives])
;; 1. Generate the key material.
(def keyset-handle (keyset-handle/generate-new :aes128-gcm))
;; 2. Get the primitive.
(def aead (primitives/aead keyset-handle))
;; 3. Use the primitive to encrypt a plaintext,
(def ciphertext (encrypt aead (.getBytes data-to-encrypt) aad))
;; ... or to decrypt a ciphertext.
(def decrypted (decrypt aead ciphertext aad))
Deterministic Symmetric Key Encryption
Deterministic Authenticated Encryption with Associated Data
(:require [tinklj.encryption.daead :refer [encrypt decrypt]
[tinklj.keys.keyset-handle :as keyset-handle]
[tinklj.primitives :as primitives])
;; 1. Generate the key material.
(def keyset-handle (keyset-handle/generate-new :aes256-siv))
;; 2. Get the primitive.
(def daead (primitives/deterministic keyset-handle))
;; 3. Use the primitive to deterministically encrypt a plaintext,
(def ciphertext (encrypt daead (.getBytes data-to-encrypt) aad))
;; ... or to deterministically decrypt a ciphertext.
(def decrypted (decrypt daead ciphertext aad))
Symmetric Key Encryption of Streaming Data
;; 1. Generate the key material.
(def keyset-handle (keyset-handles/generate-new :aes128-ctr-hmac-sha256-4kb))
;; 2. Get the primitive.
(def streaming-primitive (primitives/streaming keyset-handle))
;; 3. Get the Encrypting Channel
(def encrypting-channel (streaming/encrypting-channel
streaming-primitive
ciphertext-destination
associated-data))
;; 4. Write Encrypting Data
(streaming/encrypting-channel-write encrypting-channel byte-buffer)
;; 5. Get the Decrypting Channel
(def decrypting-channel (streaming/decrypting-channel
streaming-primitive
(.getChannel file-input-stream)
associated-data))
;; 6. Read the Decrypted Data
(streaming/decrypting-channel-read decrypting-channel buf)
Message Authentication Code
How to compute or verify a MAC (Message Authentication Code)
(:require [tinklj.primitives :as primitives]
[tinklj.keys.keyset-handle :as keyset-handles]
[tinklj.mac.message-authentication-code :as mac])
;; 1. Generate the key material.
(def keyset-handle (keyset-handles/generate-new :hmac-sha256-128bittag))
;; 2. Get the primitive.
(def mac-primitive (primitives/mac keyset-handle))
;; 3. Use the primitive to compute a tag,
(mac/compute mac-primitive data)
;; ... or to verify a tag.
(mac/verify mac-primitive tag data)
Digital Signatures
Here is an example of how to sign or verify a digital signature:
(:require [tinklj.primitives :as primitives]
[tinklj.keys.keyset-handle :as keyset-handles]
[tinklj.signature.digital-signature :refer [sign verify])
;; SIGNING
;; 1. Generate the private key material.
(def private-keyset-handle (keyset-handles/generate-new :ecdsa-p256))
;; 2. Sign the data.
(def signature (sign private-keyset-handle data)
;; VERIFYING
;; 1. Obtain a handle for the public key material.
(def public-key-set-handle (get-public-keyset-handle private-keyset-handle))
;; 2. Use the primitive to verify.
(verify public-key-set-handle
signature
data)
Hybrid Encryption
To encrypt or decrypt using a combination of public key encryption and symmetric key encryption one can use the following:
(:require [tinklj.config :refer [register]]
[tinklj.keys.keyset-handle :as keyset]
[tinklj.primitives :as primitives]
[tinklj.encryption.aead :refer [encrypt decrypt]])
(register)
;; 1. Generate the private key material.
(def private-keyset-handle (keyset/generate-new :ecies-p256-hkdf-hmac-sha256-aes128-gcm))
;; Obtain the public key material.
(def public-keyset-handle (keyset/get-public-keyset-handle private-keyset-handle))
;; ENCRYPTING
;; 2. Get the primitive.
(def hybrid-encrypt (primitives/hybrid-encryption public-keyset-handle))
;; 3. Use the primitive.
(def encrypted-data (encrypt hybrid-encrypt
(.getBytes plain-text)
aad))
;; DECRYPTING
;; 2. Get the primitive.
(def hybrid-decrypt (primitives/hybrid-decryption private-keyset-handle))
;; 3. Use the primitive.
(def decrypted-data (decrypt hybrid-decrypt
encrypted-data
aad))
Envelope Encryption
(:require [tinklj.keys.keyset-handle :as keyset]
[tinklj.primitives :as primitives]
[tinklj.encryption.aead :refer [encrypt]]
[tinklj.keysets.integration.kms-client :as client]
[tinklj.keysets.integration.gcp-kms-client :refer [gcp-kms-client])
;; 1. Generate the key material.
(def kmsKeyUri
"gcp-kms://projects/tink-examples/locations/global/keyRings/foo/cryptoKeys/bar")
(def keysetHandle (keyset/generate-new
(keyset/create-kms-envelope-aead-key-template kmsKeyUri :aes128-gcm)))
;; 2. Register the KMS client.
(def gcp-client (gcp-kms-client))
(client/with-credentials gcp-client "credentials.json")
(client/kms-client-add gcp-client)
;; 3. Get the primitive.
(def
Related Skills
healthcheck
339.3kHost security hardening and risk-tolerance configuration for OpenClaw deployments
node-connect
339.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
prose
339.3kOpenProse VM skill pack. Activate on any `prose` command, .prose files, or OpenProse mentions; orchestrates multi-agent workflows.
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
