Cryptography API Reference

Updated May 17, 20259 min read

The Cryptography API enables secure cryptographic operations within your TERE applications. All operations occur within the Trusted Execution Environment, ensuring that sensitive keys and data remain protected even if the host system is compromised. TERE now supports both software-based cryptography and hardware security modules (HSM) for enhanced security.

Getting Started

Prerequisites

To use the Cryptography API, you need:

  • The TERE SDK installed (npm install @praecise/tere)
  • A deployed TERE application (see the Runtime API)
  • For HSM features: TERE deployed on a compatible Confidential VM

How Cryptography is Used

The Cryptography API allows your applications to:

  • Encrypt and decrypt sensitive data
  • Generate secure cryptographic hashes
  • Create and manage encryption keys
  • Generate cryptographically strong random numbers
  • Integrate with cloud key management services (KMS)
  • Utilize hardware security modules (HSM) for enhanced protection

Working with Cryptography

The Cryptography API is used through the TERE SDK. Here's how to use it:

Using Cryptography in TypeScript/JavaScript

For JavaScript or TypeScript applications, use the TERE SDK:

typescript
1// Import the TERE SDK
2import { Crypto, State } from '@praecise/tere';
3
4// Encrypt data
5export function encryptSensitiveData(data) {
6 // Generate a new encryption key
7 const key = Crypto.generateKey();
8
9 // Convert string to bytes if needed
10 const dataBytes = typeof data === 'string'
11 ? new TextEncoder().encode(data)
12 : data;
13
14 // Encrypt the data
15 const encryptedData = Crypto.encrypt(dataBytes, key);
16
17 // Store the key securely
18 State.set('encryption_key', key);
19
20 // Return the encrypted data
21 return encryptedData;
22}
23
24// Decrypt data
25export function decryptSensitiveData(encryptedData) {
26 // Retrieve the key from secure storage
27 const key = State.get('encryption_key');
28 if (!key) {
29 throw new Error('Encryption key not found');
30 }
31
32 // Decrypt the data
33 const decryptedBytes = Crypto.decrypt(encryptedData, key);
34
35 // Convert back to string if it was a string originally
36 return new TextDecoder().decode(decryptedBytes);
37}
38
39// Generate a secure hash
40export function hashData(data) {
41 // Convert string to bytes if needed
42 const dataBytes = typeof data === 'string'
43 ? new TextEncoder().encode(data)
44 : data;
45
46 // Generate SHA-256 hash
47 return Crypto.hash(dataBytes);
48}
Using cryptography in TypeScript

Client-side Usage

From your client application, you interact with crypto functions through function execution:

javascript
1import { TereClient } from '@praecise/tere';
2
3// Initialize client
4const client = new TereClient({
5 endpoint: 'https://api.tere.praecise.com',
6 apiKey: 'your-api-key'
7});
8
9async function secureDataProcessing() {
10 // Sensitive data to protect
11 const sensitiveData = {
12 personalId: '123-45-6789',
13 creditCard: '4111-1111-1111-1111',
14 address: '123 Main St, Anytown, USA'
15 };
16
17 // Encrypt the data in the TEE
18 const encryptResult = await client.execute({
19 scriptId: 'script_abc123',
20 function: 'encryptSensitiveData',
21 arguments: [JSON.stringify(sensitiveData)]
22 });
23
24 console.log('Data encrypted securely in the TEE');
25
26 // Store the encrypted data reference
27 const encryptedDataRef = encryptResult.result;
28
29 // Later, decrypt the data when needed
30 const decryptResult = await client.execute({
31 scriptId: 'script_abc123',
32 function: 'decryptSensitiveData',
33 arguments: [encryptedDataRef]
34 });
35
36 console.log('Decrypted data:', JSON.parse(decryptResult.result));
37}
Working with cryptography from client code

Cryptography API Reference

The following API is available within your code running in the TEE:

Crypto.encrypt

Encrypts data using AES-GCM with a 256-bit key.

Parameters

data: Uint8ArrayRequired

The data to encrypt

key: Uint8ArrayRequired

The 32-byte (256-bit) encryption key

options: object

Optional configuration for encryption

Returns

Uint8Array

The encrypted data with the nonce prepended (first 12 bytes)

Examples

Basic encryption

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export function encryptMessage(message, key) {
5 // Convert message to bytes
6 const messageBytes = new TextEncoder().encode(message);
7
8 // Encrypt the data
9 return Crypto.encrypt(messageBytes, key);
10}

With custom options

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export function encryptMessageWithOptions(message, key) {
5 // Convert message to bytes
6 const messageBytes = new TextEncoder().encode(message);
7
8 // Encrypt with custom options
9 return Crypto.encrypt(messageBytes, key, {
10 associatedData: new TextEncoder().encode('context-info'),
11 nonceLength: 16 // Optional custom nonce length
12 });
13}
Crypto.decrypt

Decrypts data that was encrypted using AES-GCM.

Parameters

encryptedData: Uint8ArrayRequired

The encrypted data with nonce prepended (first 12 bytes)

key: Uint8ArrayRequired

The 32-byte (256-bit) encryption key

options: object

Optional configuration for decryption

Returns

Uint8Array

The decrypted data

Examples

Decrypting data

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export function decryptMessage(encryptedData, key) {
5 // Decrypt the data
6 const decryptedBytes = Crypto.decrypt(encryptedData, key);
7
8 // Convert bytes back to string
9 return new TextDecoder().decode(decryptedBytes);
10}

With associated data

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export function decryptMessageWithContext(encryptedData, key) {
5 // Decrypt with the same associated data used during encryption
6 const decryptedBytes = Crypto.decrypt(encryptedData, key, {
7 associatedData: new TextEncoder().encode('context-info')
8 });
9
10 // Convert bytes back to string
11 return new TextDecoder().decode(decryptedBytes);
12}
Crypto.hash

Computes a SHA-256 hash of the input data.

Parameters

data: Uint8ArrayRequired

The data to hash

Returns

Uint8Array

The 32-byte SHA-256 hash value

Examples

Computing a hash

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export function computeHash(data) {
5 // Convert to bytes if it's a string
6 const dataBytes = typeof data === 'string'
7 ? new TextEncoder().encode(data)
8 : data;
9
10 // Compute the hash
11 return Crypto.hash(dataBytes);
12}
Crypto.generateKey

Generates a cryptographically secure random key for AES-256 encryption.

Parameters

options: object

Optional configuration for key generation

Returns

Uint8Array

A 32-byte (256-bit) random key

Examples

Generating a software key

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export function createEncryptionKey() {
5 // Generate a secure key
6 return Crypto.generateKey();
7}

Generating an HSM-backed key

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export function createHsmKey() {
5 // Generate a key in HSM
6 return Crypto.generateKey({
7 provider: 'hsm',
8 keyId: 'my-encryption-key', // Optional custom key ID
9 protection: 'hsm' // Use hardware protection
10 });
11}
Crypto.deriveKeyFromPassword

Derives an encryption key from a password using PBKDF2-HMAC-SHA256.

Parameters

password: stringRequired

The password to derive the key from

salt: Uint8ArrayRequired

Random salt value for key derivation (16 bytes recommended)

iterations: numberRequired

Number of iterations (recommend at least 100,000)

options: object

Optional configuration for key derivation

Returns

Uint8Array

A 32-byte (256-bit) derived key

Examples

Deriving a key from a password

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export function deriveKey(password) {
5 // Generate a random salt
6 const salt = Crypto.randomBytes(16);
7
8 // Use at least 100,000 iterations for security
9 const iterations = 100000;
10
11 // Derive the key
12 const key = Crypto.deriveKeyFromPassword(password, salt, iterations);
13
14 // Store the salt for later use
15 State.set('password_salt', salt);
16
17 return key;
18}
Crypto.randomBytes

Generates cryptographically secure random bytes.

Parameters

length: numberRequired

The number of random bytes to generate

Returns

Uint8Array

An array of random bytes

Examples

Generating random data

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export function generateRandomId() {
5 // Generate 16 random bytes
6 const randomBytes = Crypto.randomBytes(16);
7
8 // Convert to hex for a readable ID
9 return Array.from(randomBytes)
10 .map(b => b.toString(16).padStart(2, '0'))
11 .join('');
12}

Hardware Security Module (HSM) API

TERE now supports Google Cloud HSM for hardware-backed cryptographic operations. This provides FIPS 140-2 Level 3 certified protection for your most sensitive keys and operations.

HSM features are only available when your TERE application is deployed on a compatible Confidential VM with HSM support.

Crypto.withHsmProvider

Creates a cryptography provider that uses HSM for operations.

Parameters

options: object

Configuration for the HSM provider

Returns

CryptoProvider

A provider object for HSM-backed operations

Examples

Using an HSM provider

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export function createHsmProvider() {
5 // Create an HSM crypto provider
6 const hsmProvider = Crypto.withHsmProvider({
7 keyRing: 'my-key-ring', // Optional custom key ring
8 location: 'us-central1' // Optional GCP location
9 });
10
11 return hsmProvider;
12}
CryptoProvider.createKey

Creates a new key in the HSM.

Parameters

keyId: stringRequired

ID for the key

purpose: stringRequired

Key purpose: 'encrypt', 'sign', or 'decrypt'

algorithm: string

Optional algorithm specification

Returns

Promise<object>

Information about the created key

Examples

Creating an HSM key

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export async function createEncryptionKey(keyId) {
5 // Get HSM provider
6 const hsmProvider = Crypto.withHsmProvider();
7
8 // Create a symmetric encryption key
9 const keyInfo = await hsmProvider.createKey(
10 keyId,
11 'encrypt'
12 );
13
14 return keyInfo;
15}

Creating a signing key

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export async function createSigningKey(keyId) {
5 // Get HSM provider
6 const hsmProvider = Crypto.withHsmProvider();
7
8 // Create an asymmetric signing key
9 const keyInfo = await hsmProvider.createKey(
10 keyId,
11 'sign',
12 'ec-p256-sha256' // Optional algorithm specification
13 );
14
15 return keyInfo;
16}
CryptoProvider.encrypt

Encrypts data using an HSM-backed key.

Parameters

data: Uint8ArrayRequired

Data to encrypt

keyId: stringRequired

ID of the HSM key to use

Returns

Promise<Uint8Array>

The encrypted data

Examples

Encrypting with HSM

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export async function encryptWithHsm(data, keyId) {
5 // Convert to bytes if needed
6 const dataBytes = typeof data === 'string'
7 ? new TextEncoder().encode(data)
8 : data;
9
10 // Get HSM provider
11 const hsmProvider = Crypto.withHsmProvider();
12
13 // Encrypt with HSM key
14 const encrypted = await hsmProvider.encrypt(dataBytes, keyId);
15
16 return encrypted;
17}
CryptoProvider.decrypt

Decrypts data using an HSM-backed key.

Parameters

encryptedData: Uint8ArrayRequired

Data to decrypt

keyId: stringRequired

ID of the HSM key to use

Returns

Promise<Uint8Array>

The decrypted data

Examples

Decrypting with HSM

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export async function decryptWithHsm(encryptedData, keyId) {
5 // Get HSM provider
6 const hsmProvider = Crypto.withHsmProvider();
7
8 // Decrypt with HSM key
9 const decrypted = await hsmProvider.decrypt(encryptedData, keyId);
10
11 // Convert to string if needed
12 return new TextDecoder().decode(decrypted);
13}
CryptoProvider.sign

Creates a signature using an HSM-backed key.

Parameters

data: Uint8ArrayRequired

Data to sign

keyId: stringRequired

ID of the HSM signing key to use

Returns

Promise<Uint8Array>

The signature

Examples

Signing with HSM

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export async function signWithHsm(data, keyId) {
5 // Convert to bytes if needed
6 const dataBytes = typeof data === 'string'
7 ? new TextEncoder().encode(data)
8 : data;
9
10 // Get HSM provider
11 const hsmProvider = Crypto.withHsmProvider();
12
13 // Sign with HSM key
14 const signature = await hsmProvider.sign(dataBytes, keyId);
15
16 return signature;
17}
CryptoProvider.verify

Verifies a signature using an HSM-backed key.

Parameters

data: Uint8ArrayRequired

Original data that was signed

signature: Uint8ArrayRequired

Signature to verify

keyId: stringRequired

ID of the HSM signing key to use

Returns

Promise<boolean>

True if the signature is valid

Examples

Verifying signatures with HSM

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export async function verifyWithHsm(data, signature, keyId) {
5 // Convert to bytes if needed
6 const dataBytes = typeof data === 'string'
7 ? new TextEncoder().encode(data)
8 : data;
9
10 // Get HSM provider
11 const hsmProvider = Crypto.withHsmProvider();
12
13 // Verify with HSM key
14 const isValid = await hsmProvider.verify(dataBytes, signature, keyId);
15
16 return isValid;
17}
CryptoProvider.listKeys

Lists all keys in the HSM key ring.

Returns

Promise<Array<object>>

Array of key information objects

Examples

Listing HSM keys

typescript
1// In your TEE code
2import { Crypto } from '@praecise/tere';
3
4export async function listHsmKeys() {
5 // Get HSM provider
6 const hsmProvider = Crypto.withHsmProvider();
7
8 // List all keys
9 const keys = await hsmProvider.listKeys();
10
11 return keys;
12}

Advanced Usage

HSM-based Key Wrapping

For enhanced security, you can use the HSM to wrap (encrypt) and unwrap (decrypt) keys:

typescript
1// Import the TERE SDK
2import { Crypto, State } from '@praecise/tere';
3
4// Create and wrap a key with HSM
5export async function createWrappedKey() {
6 // Generate a local key
7 const dataKey = Crypto.generateKey();
8
9 // Use HSM to wrap (encrypt) the key
10 const hsmProvider = Crypto.withHsmProvider();
11
12 // Create or get a key-wrapping key
13 const keyWrappingId = 'master-key-encryption-key';
14 await hsmProvider.getOrCreateKey(keyWrappingId, 'encrypt');
15
16 // Wrap the data key
17 const wrappedKey = await hsmProvider.encrypt(dataKey, keyWrappingId);
18
19 // Store the wrapped key
20 State.set('wrapped_data_key', wrappedKey);
21
22 return { keyId: keyWrappingId, wrappedKey };
23}
24
25// Unwrap a key to use it
26export async function useWrappedKey(wrappedKey, keyWrappingId) {
27 // Get HSM provider
28 const hsmProvider = Crypto.withHsmProvider();
29
30 // Unwrap the key
31 const dataKey = await hsmProvider.decrypt(wrappedKey, keyWrappingId);
32
33 // Now the data key can be used for operations
34 return dataKey;
35}
HSM key wrapping example

Cloud Key Management Integration

For enterprise applications, TERE integrates with cloud key management services:

typescript
1// Import the TERE SDK
2import { CloudKms } from '@praecise/tere';
3
4// Encrypt with a cloud-managed key
5export async function encryptWithCloudKey(data, keyName) {
6 // Convert to bytes if needed
7 const dataBytes = typeof data === 'string'
8 ? new TextEncoder().encode(data)
9 : data;
10
11 // Use cloud KMS for encryption
12 return await CloudKms.encrypt(dataBytes, keyName);
13}
14
15// Decrypt with a cloud-managed key
16export async function decryptWithCloudKey(encryptedData, keyName) {
17 // Decrypt using cloud KMS
18 const decryptedBytes = await CloudKms.decrypt(encryptedData, keyName);
19
20 // Return as bytes, or convert to string if needed
21 return decryptedBytes;
22}
Using cloud key management

HSM-Protected Encrypted Store Example

A complete example of a secure encrypted object store with HSM protection:

typescript
1// Import the TERE SDK
2import { Crypto, State } from '@praecise/tere';
3
4// Create a secure HSM-protected encrypted object store
5export class HsmSecureStore {
6 private namespace: string;
7 private keyId: string;
8 private hsmProvider: any;
9
10 constructor(namespace?: string) {
11 this.namespace = namespace || 'hsm-secure-store';
12 this.keyId = `${this.namespace}-key`;
13
14 // Initialize HSM provider
15 this.initialize();
16 }
17
18 // Initialize and ensure key exists
19 private async initialize() {
20 this.hsmProvider = Crypto.withHsmProvider();
21
22 // Get or create the encryption key in HSM
23 await this.hsmProvider.getOrCreateKey(this.keyId, 'encrypt');
24 }
25
26 // Store an object securely
27 async put(id: string, object: any): Promise<boolean> {
28 const key = `${this.namespace}:${id}`;
29 const data = new TextEncoder().encode(JSON.stringify(object));
30
31 // Encrypt with HSM
32 const encryptedData = await this.hsmProvider.encrypt(data, this.keyId);
33
34 return State.set(key, encryptedData);
35 }
36
37 // Retrieve an object
38 async get(id: string): Promise<any> {
39 const key = `${this.namespace}:${id}`;
40 const encryptedData = State.get(key);
41
42 if (!encryptedData) {
43 return null;
44 }
45
46 // Decrypt with HSM
47 const decryptedData = await this.hsmProvider.decrypt(encryptedData, this.keyId);
48 return JSON.parse(new TextDecoder().decode(decryptedData));
49 }
50
51 // Check if an object exists
52 has(id: string): boolean {
53 const key = `${this.namespace}:${id}`;
54 return State.exists(key);
55 }
56
57 // Remove an object
58 remove(id: string): boolean {
59 const key = `${this.namespace}:${id}`;
60 return State.remove(key) !== null;
61 }
62}
63
64// Example usage
65export async function createHsmSecureUserStore() {
66 return new HsmSecureStore('users');
67}
68
69export async function saveSecureUserWithHsm(userId: string, userData: any) {
70 const store = await createHsmSecureUserStore();
71 return await store.put(userId, userData);
72}
73
74export async function getSecureUserWithHsm(userId: string) {
75 const store = await createHsmSecureUserStore();
76 return await store.get(userId);
77}
HSM-protected encrypted object store implementation

Best Practices

  • Use HSM for Critical Keys

    Store your most sensitive keys in hardware security modules. Use HSM for root keys, key-wrapping keys, and keys that protect high-value assets.

    javascript
    1// Create an HSM master key
    2async function createMasterKey() {
    3 const hsmProvider = Crypto.withHsmProvider();
    4
    5 // Create a key in HSM that will be used to protect other keys
    6 const keyInfo = await hsmProvider.createKey(
    7 'master-key',
    8 'encrypt'
    9 );
    10
    11 return keyInfo;
    12}
  • Secure Key Storage

    Always store encryption keys securely within the TEE using the State Management API. Never expose keys outside the secure environment.

  • Strong Password Policies

    When deriving keys from passwords, enforce strong password policies and use a high iteration count (at least 100,000) for PBKDF2 to resist brute-force attacks.

    javascript
    1// Properly derive a key from a password
    2function deriveSecureKey(password, salt = null) {
    3 // Validate password strength
    4 if (password.length < 12) {
    5 throw new Error('Password must be at least 12 characters');
    6 }
    7
    8 // Generate or use provided salt
    9 const keySalt = salt || Crypto.randomBytes(16);
    10
    11 // Use a high iteration count
    12 const iterations = 250000;
    13
    14 // Derive the key
    15 return {
    16 key: Crypto.deriveKeyFromPassword(password, keySalt, iterations),
    17 salt: keySalt
    18 };
    19}
  • Use Authenticated Encryption

    Always use authenticated encryption (AES-GCM) which is the default in TERE. This protects against tampering and ensures data integrity.

  • Implement Key Rotation and Management

    Regularly rotate encryption keys to limit the impact of potential key compromise. Store key version information alongside encrypted data.

    javascript
    1// Key rotation with HSM
    2async function rotateHsmKeyAndRewrapData() {
    3 const hsmProvider = Crypto.withHsmProvider();
    4 const keyId = 'encryption-master-key';
    5 const keyVersion = Date.now().toString();
    6 const newKeyId = `${keyId}-${keyVersion}`;
    7
    8 // Create a new key in HSM
    9 await hsmProvider.createKey(newKeyId, 'encrypt');
    10
    11 // Update the current key version reference
    12 State.set('current-key-version', keyVersion);
    13
    14 // Re-encrypt sensitive data with the new key
    15 // (implementation details would depend on your data structure)
    16
    17 return { keyId: newKeyId, version: keyVersion };
    18}
  • Use Key Hierarchies with HSM

    Implement a hierarchical key structure with HSM-protected keys at the root. Use these to protect data encryption keys that are used for actual data encryption.

    javascript
    1// Implementing a key hierarchy
    2async function createKeyHierarchy() {
    3 const hsmProvider = Crypto.withHsmProvider();
    4
    5 // 1. Root key - stored in HSM, rarely accessed
    6 await hsmProvider.getOrCreateKey('root-key', 'encrypt');
    7
    8 // 2. Key encryption keys (KEKs) - protected by root key
    9 const kekBytes = Crypto.generateKey();
    10 const wrappedKek = await hsmProvider.encrypt(kekBytes, 'root-key');
    11 State.set('wrapped-kek', wrappedKek);
    12
    13 // 3. Data encryption keys (DEKs) - protected by KEKs
    14 // These are used for actual data encryption
    15 const dekBytes = Crypto.generateKey();
    16
    17 // Unwrap the KEK to use it
    18 const kek = await hsmProvider.decrypt(wrappedKek, 'root-key');
    19
    20 // Encrypt the DEK with the KEK
    21 const encryptedDek = Crypto.encrypt(dekBytes, kek);
    22
    23 // Store the encrypted DEK
    24 State.set('encrypted-dek', encryptedDek);
    25
    26 return {
    27 rootKeyId: 'root-key',
    28 wrappedKek,
    29 encryptedDek
    30 };
    31}

Related Documentation