Skip to main content
Rehydra uses AES-256-GCM encryption via the Web Crypto API for securing PII maps.

Key Providers

InMemoryKeyProvider

Generates a random key in memory. Key is lost when the process ends.
import { InMemoryKeyProvider } from 'rehydra';

const keyProvider = new InMemoryKeyProvider();
const key = await keyProvider.getKey();  // Uint8Array (32 bytes)
Only for development/testing. The key is not persisted.

ConfigKeyProvider

Uses a pre-configured key from your environment.
import { ConfigKeyProvider } from 'rehydra';

// Generate key: openssl rand -base64 32
const keyBase64 = process.env.PII_ENCRYPTION_KEY;
const keyProvider = new ConfigKeyProvider(keyBase64);

KeyProvider Interface

interface KeyProvider {
  getKey(): Promise<Uint8Array>;
}
Implement for custom key storage:
class VaultKeyProvider implements KeyProvider {
  async getKey(): Promise<Uint8Array> {
    const secret = await vault.getSecret('pii-encryption-key');
    return base64ToUint8Array(secret);
  }
}

Encryption Functions

encryptPIIMap()

Encrypts a PII map.
import { encryptPIIMap } from 'rehydra';

const piiMap = new Map([
  ['EMAIL:1', '[email protected]'],
  ['PERSON:1', 'John Smith'],
]);

const encrypted = await encryptPIIMap(piiMap, key);
// { ciphertext: '...', iv: '...', authTag: '...' }

decryptPIIMap()

Decrypts a PII map.
import { decryptPIIMap } from 'rehydra';

const piiMap = await decryptPIIMap(encrypted, key);
// Map { 'EMAIL:1' => '[email protected]', ... }

Key Generation

generateKey()

Generate a random 256-bit key.
import { generateKey } from 'rehydra';

const key = generateKey();  // Uint8Array (32 bytes)

generateSalt()

Generate a random salt for key derivation.
import { generateSalt } from 'rehydra';

const salt = generateSalt();  // Uint8Array (16 bytes)

deriveKey()

Derive a key from a password using PBKDF2.
import { deriveKey, generateSalt } from 'rehydra';

const password = 'user-password';
const salt = generateSalt();

const key = await deriveKey(password, salt);
// Store salt with encrypted data for later derivation

Utility Functions

validateKey()

Check if a key is valid.
import { validateKey } from 'rehydra';

if (validateKey(key)) {
  console.log('Key is valid');
} else {
  throw new Error('Invalid key');
}

secureCompare()

Constant-time comparison to prevent timing attacks.
import { secureCompare } from 'rehydra';

if (secureCompare(key1, key2)) {
  console.log('Keys match');
}

uint8ArrayToBase64()

Convert Uint8Array to Base64.
import { uint8ArrayToBase64 } from 'rehydra';

const base64 = uint8ArrayToBase64(key);
// Store this string securely

base64ToUint8Array()

Convert Base64 to Uint8Array.
import { base64ToUint8Array } from 'rehydra';

const key = base64ToUint8Array(base64);

EncryptedPIIMap Structure

interface EncryptedPIIMap {
  ciphertext: string;  // Base64-encoded encrypted data
  iv: string;          // Base64-encoded initialization vector
  authTag: string;     // Base64-encoded authentication tag
}

Complete Example

import { 
  generateKey,
  encryptPIIMap,
  decryptPIIMap,
  uint8ArrayToBase64,
  base64ToUint8Array
} from 'rehydra';

// Generate and store key
const key = generateKey();
const keyBase64 = uint8ArrayToBase64(key);
// Store keyBase64 securely (env var, keychain, etc.)

// Later: encrypt
const piiMap = new Map([['EMAIL:1', '[email protected]']]);
const encrypted = await encryptPIIMap(piiMap, key);

// Later: decrypt
const restoredKey = base64ToUint8Array(keyBase64);
const decrypted = await decryptPIIMap(encrypted, restoredKey);

Security Notes

  • Never commit keys to version control
  • Use environment variables or secrets managers
  • Consider platform keystores (iOS Keychain, Android Keystore)
Implement key rotation for long-running applications:
// Re-encrypt with new key
const piiMap = await decryptPIIMap(encrypted, oldKey);
const newEncrypted = await encryptPIIMap(piiMap, newKey);
In browsers:
  • Keys in memory can be accessed by malicious scripts
  • Consider using SubtleCrypto key wrapping
  • Clear keys when no longer needed