Encryption, hashing, CSRF protection, and secure operations.

Uses the Web Crypto API for:

  • Hybrid RSA-OAEP + AES-256-GCM encryption for PII at rest
  • HMAC-SHA256 for webhooks and CSRF tokens
  • Argon2-style password hashing
  • Constant-time comparison for timing-safe checks

Functions

f
base64ToBase64Url(b64: string): string

Convert standard base64 to base64url (no padding). Works on both strings and Uint8Array (bytes are first encoded to base64).

f
clearEncryptionKeyCache(): void

Clear all crypto caches (encryption key, HMAC key, private key, hybrid decrypt LRU) Called on key rotation and during test setup/teardown

f
computeHmacSha256(
data: Uint8Array,
secret: string
): Promise<ArrayBuffer>

Compute HMAC-SHA256 using Web Crypto API, returning raw ArrayBuffer

f
computeTicketTokenIndex(token: string): Promise<string>

Compute ticket token index using HMAC for blind lookups Similar to slug_index for events - allows lookup without decrypting

f
constantTimeEqual(
a: string,
b: string
): boolean

Constant-time string comparison to prevent timing attacks Always iterates over the longer string and XORs the lengths so that different-length inputs don't leak via an early return.

f
decrypt(encrypted: string): Promise<string>

Decrypt a string value encrypted with encrypt() Expects format: enc:1:$base64iv:$base64ciphertext

f
decryptAttendeePII(
encrypted: string,
privateKey: CryptoKey
): Promise<string>

Decrypt attendee PII using the private key Used in admin views after obtaining private key from session

f
decryptBytes(encrypted: Uint8Array): Promise<Uint8Array>

Decrypt binary data encrypted with encryptBytes(). Expects ENCB binary format: magic + version + IV + ciphertext.

f
deriveKEK(passwordHash: string): Promise<CryptoKey>

Derive a Key Encryption Key (KEK) from password hash and DB_ENCRYPTION_KEY Uses PBKDF2 with the password hash as input and DB_ENCRYPTION_KEY as salt

f
encrypt(plaintext: string): Promise<string>

Encrypt a string value using AES-256-GCM via Web Crypto API Returns format: enc:1:$base64iv:$base64ciphertext Note: ciphertext includes auth tag appended (Web Crypto API does this automatically)

f
encryptAttendeePII(
plaintext: string,
publicKeyJwk: string
): Promise<string>

Encrypt attendee PII using the public key from settings This can be called without authentication (for public ticket forms)

f
encryptBytes(data: Uint8Array): Promise<Uint8Array>

Encrypt binary data with AES-256-GCM using compact binary format. Output: ENCB + version byte + 12-byte IV + ciphertext (with GCM auth tag). Overhead is only 33 bytes (vs ~76% bloat in the legacy text format).

f
encryptWithKey(
plaintext: string,
key: CryptoKey
): Promise<string>

Encrypt data with a symmetric key (for wrapping private key with DATA_KEY)

f
generateDataKey(): Promise<CryptoKey>

Generate a random 256-bit symmetric key for data encryption

f
generateKeyPair(): Promise<{ publicKey: string; privateKey: string; }>

Generate an RSA key pair for asymmetric encryption Returns { publicKey, privateKey } as exportable JWK strings

f
generateSecureToken(): string

Generate a cryptographically secure random token Uses Web Crypto API getRandomValues

f
generateTicketToken(): string

Generate a 5-byte uppercase hex ticket token for public ticket URLs

f
getCurrentCsrfToken(): string

Get the most recently generated CSRF token (for synchronous JSX rendering)

f
getPrivateKeyFromSession(
sessionToken: string,
wrappedDataKey: string,
wrappedPrivateKey: string
): Promise<CryptoKey>

Derive the private key from session credentials Used to decrypt attendee PII in admin views Results are cached per session token for 10 seconds

f
hashPassword(password: string): Promise<string>

Hash a password using PBKDF2 Returns format: pbkdf2:iterations:$base64salt:$base64hash

f
hashSessionToken(token: string): Promise<string>

Hash a session token using SHA-256 Used to store session lookups without exposing the actual token

f
hmacHash(value: string): Promise<string>

HMAC-SHA256 hash using DB_ENCRYPTION_KEY Used for blind indexes and hashing limited keyspace values Returns deterministic output for same input (unlike encrypt)

f
hmacToBase64(buf: ArrayBuffer): string

Convert ArrayBuffer to base64 string

f
hmacToHex(buf: ArrayBuffer): string

Convert ArrayBuffer to hex string

f
hybridDecrypt(
encrypted: string,
privateKey: CryptoKey
): Promise<string>

Decrypt data using hybrid encryption Expects format: hyb:1:$base64WrappedKey:$base64iv:$base64ciphertext Results are cached in a bounded LRU (ciphertext -> plaintext)

f
hybridEncrypt(
plaintext: string,
publicKey: CryptoKey
): Promise<string>

Encrypt data using hybrid encryption (RSA + AES)

f
f
f
isSignedCsrfToken(token: string): boolean

Check whether a token uses the signed format

f
secureCompare(
a: string,
b: string
): boolean

Constant-time string comparison to prevent timing attacks

f
setEncryptionKeyForTest(key: string | null): void

Explicitly set or clear the encryption key for testing. Bypasses Deno.env to avoid races between parallel test workers.

f
signCsrfToken(): Promise<string>

Create a signed CSRF token: s1.{timestamp}.{nonce}.{hmac}

f
toBase64(bytes: Uint8Array): string

Convert Uint8Array to base64 string

f
unwrapKey(
wrapped: string,
unwrappingKey: CryptoKey
): Promise<CryptoKey>

Unwrap a symmetric key Expects format: wk:1:$base64iv:$base64wrapped

f
validateEncryptionKey(): void

Validate encryption key is present and valid Call this on startup to fail fast if key is missing

f
verifyPassword(
password: string,
storedHash: string
): Promise<boolean>

Verify a password against a hash Uses constant-time comparison to prevent timing attacks

f
verifySignedCsrfToken(
token: string,
maxAge?
): Promise<boolean>

Verify a signed CSRF token's signature and expiry

f
wrapKey(
keyToWrap: CryptoKey,
wrappingKey: CryptoKey
): Promise<string>

Wrap a symmetric key with another key using AES-GCM Returns format: wk:1:$base64iv:$base64wrapped

f
wrapKeyWithToken(
keyToWrap: CryptoKey,
sessionToken: string
): Promise<string>

Wrap a key using a session token (derives a wrapping key from the token)

Variables

v
CSRF_INVALID_FORM_MESSAGE: "Invalid or expired form. Please try again."

Default message for invalid/expired CSRF form submissions