Tink for TypeScript HOW-TO

This document presents instructions and TypeScript code snippets for common tasks in Tink.

Depending on the specifics of your build setup, you may need to alter these snippets to use a different import syntax. Both ES modules and UMD are supported.

WARNING: Tink for TypeScript/JavaScript is still in an alpha state! Breaking changes are likely.

Setup instructions

To add Tink to a TypeScript/JavaScript project, just run:

npm install tink-crypto

Or, if you're using Yarn:

yarn add tink-crypto

Generating new keys and keysets

To take advantage of key rotation and other key management features, you usually do not work with single keys, but with keysets, which you can use via a wrapper called KeysetHandle. Keysets are just sets of keys with some additional parameters and metadata. You can generate a new keyset and obtain its handle using a KeyTemplate (example in below code snippet).

To avoid accidental leakage of sensitive key material, you should usually avoid mixing keyset generation and usage in code. To support the separation of these activities Tink provides a command-line tool, Tinkey, which can be used for common key management tasks. Still, if there is a need to generate a KeysetHandle with fresh key material directly in TypeScript code, you can use generateNewKeysetHandle:

import {aead, generateNewKeysetHandle} from 'tink-crypto';
const {aes256GcmKeyTemplate} = aead;

(async () => {
  const keyTemplate = aes256GcmKeyTemplate()
  const keysetHandle = await generateNewKeysetHandle(keyTemplate);
  // use the keyset...
})();

Currently, key templates are only available for AEAD encryption, digital signatures, and hybrid encryption.

| Key | Key Template | : Template : : : Type : : | --------- | ---------------------------------------------------------------- | | AEAD | aead.aes128GcmKeyTemplate() | | AEAD | aead.aes256GcmKeyTemplate() | | AEAD | aead.aes256GcmNoPrefixKeyTemplate() | | Signature | signature.ecdsaP256KeyTemplate() | | Signature | signature.ecdsaP256IeeeEncodingKeyTemplate() | | Signature | signature.ecdsaP384KeyTemplate() | | Signature | signature.ecdsaP384IeeeEncodingKeyTemplate() | | Signature | signature.ecdsaP521KeyTemplate() | | Signature | signature.ecdsaP521IeeeEncodingKeyTemplate() | | Hybrid | hybrid.eciesP256HkdfHmacSha256Aes128GcmKeyTemplate() | | Hybrid | hybrid.eciesP256HkdfHmacSha256Aes128CtrHmacSha256KeyTemplate() |

Storing and loading existing keysets

After generating key material, you might want to persist it to LocalStorage or IndexedDB, or send it to a server to be stored there. The binary and binaryInsecure subpackages can be used to serialize and deserialize keysets to and from UInt8Array. binary handles only public keys; binaryInsecure can additionally handle private and symmetric keys. With these, you must be careful not to leak the raw key material.

import {aead, binaryInsecure, generateNewKeysetHandle} from 'tink-crypto';

const {Aead, register, aes256GcmKeyTemplate} = aead;
const {deserializeKeyset, serializeKeyset} = binaryInsecure;

register();

(async () => {
  const keysetHandle = await generateNewKeysetHandle(aes256GcmKeyTemplate());
  // Serialize keyset to send/store
  const serializedKeyset = serializeKeyset(keysetHandle);

  const deserializedKeyset = deserializeKeyset(serializedKeyset)
  const aead = await deserializedKeyset.getPrimitive(Aead);
  // Use deserialization... (i.e. to decrypt a ciphertext)
})();

Obtaining and using primitives

Primitives represent cryptographic operations offered by Tink, hence they form the core of Tink API. A primitive is just an interface that specifies what operations are offered by the primitive. A primitive can have multiple implementations, and you choose a desired implementation by using a key of corresponding type (see the this section for details).

A list of primitives and their implementations currently supported by Tink in TypeScript/JavaScript can be found here. Note that there are currently a few additional limitations:

  • MAC is supported only via the subtle API, not the keyset API.
  • It's not possible to generate a fresh new asymmetric keyset using the keyset API and then use it without going through the subtle API. (The public key is not directly accessible yet)

AEAD

AEAD encryption assures the confidentiality and authenticity of the data. This primitive is CPA secure.

// See live on StackBlitz: https://stackblitz.com/edit/tink-typescript?file=index.ts

import {aead, generateNewKeysetHandle} from 'tink-crypto';

const {Aead, register, aes256GcmKeyTemplate} = aead;

register();

(async () => {
  const keysetHandle = await generateNewKeysetHandle(aes256GcmKeyTemplate());
  const aead = await keysetHandle.getPrimitive(Aead);
  const ciphertext = await aead.encrypt(
      new TextEncoder().encode('this data needs to be encrypted'),
      new TextEncoder().encode('associated data'));
  const plaintext = new TextDecoder().decode(await aead.decrypt(
      ciphertext, new TextEncoder().encode('associated data')));
  console.log('Ciphertext:', ciphertext);
  console.log('Plaintext:', plaintext);
})();