halite-ts
v5.0.0
Published
High-level cryptography interface powered by libsodium — TypeScript port of ParagonIE Halite
Maintainers
Readme
halite-ts
Version 5.0.0
A TypeScript port of ParagonIE Halite — a high-level cryptography library providing a safe, ergonomic API for common cryptographic operations, powered by libsodium.
import { ready, SymmetricCrypto, EncryptionKey } from 'halite-ts';
await ready();
const key = EncryptionKey.generate();
const encrypted = SymmetricCrypto.encrypt(key, 'hello world');
const decrypted = SymmetricCrypto.decrypt(encrypted, key);
console.log(decrypted.getString()); // "hello world"Requirements
- Node.js >= 22
Install
npm install halite-tsBuild
npm run build # compiles src/ → dist/Test
npm test # runs node --test dist/test/**/*.test.jsQuick Reference
| Category | Import | Key Classes |
|---|---|---|
| Symmetric encryption | SymmetricCrypto | EncryptionKey |
| Symmetric auth | SymmetricCrypto | AuthenticationKey |
| Asymmetric encryption | AsymmetricCrypto | EncryptionSecretKey, EncryptionPublicKey |
| Anonymous sealing | AsymmetricCrypto | EncryptionPublicKey / EncryptionSecretKey |
| Digital signatures | AsymmetricCrypto | SignatureSecretKey, SignaturePublicKey |
| Sign + encrypt | AsymmetricCrypto | SignatureSecretKey + EncryptionPublicKey |
| Password hashing | Password | EncryptionKey |
| Key derivation | KeyFactory | Various key types |
| File operations | HaliteFile | Various key types |
| Merkle trees | MerkleTree, TrimmedMerkleTree | Node |
| Secure cookies | Cookie | EncryptionKey |
| Utilities | Util | — |
API
Initialization
import { ready } from 'halite-ts';
// Must call once before using any crypto operations
await ready();HiddenString
Wraps plaintext strings to prevent accidental leakage through debug output or logs.
import { HiddenString } from 'halite-ts';
const secret = new HiddenString('sensitive data');
secret.getString(); // "sensitive data"
console.log(secret); // { value: '**protected**' }Key Generation
import {
EncryptionKey, AuthenticationKey,
EncryptionKeyPair, SignatureKeyPair,
EncryptionSecretKey, EncryptionPublicKey,
SignatureSecretKey, SignaturePublicKey,
} from 'halite-ts';
// Symmetric keys
const encKey = EncryptionKey.generate(); // 32 bytes
const authKey = AuthenticationKey.generate(); // 32 bytes
// Asymmetric key pairs
const encKeyPair = EncryptionKeyPair.generate(); // X25519
const sigKeyPair = SignatureKeyPair.generate(); // Ed25519Key Import / Export
Keys are exported as hex-encoded strings with a version prefix and checksum.
import { KeyFactory, HiddenString } from 'halite-ts';
// Export
const exported = KeyFactory.export(encKey);
console.log(exported.getString()); // hex string with version + checksum
// Import
const imported = KeyFactory.importEncryptionKey(exported);
// Other import methods:
KeyFactory.importAuthenticationKey(data: HiddenString)
KeyFactory.importEncryptionPublicKey(data: HiddenString)
KeyFactory.importEncryptionSecretKey(data: HiddenString)
KeyFactory.importSignaturePublicKey(data: HiddenString)
KeyFactory.importSignatureSecretKey(data: HiddenString)
KeyFactory.importEncryptionKeyPair(data: HiddenString)
KeyFactory.importSignatureKeyPair(data: HiddenString)Key Derivation (from password)
Derive keys from passwords using scrypt with configurable security levels.
import { KeyFactory, HiddenString } from 'halite-ts';
const password = new HiddenString('correct horse battery staple');
const salt = sodium.randombytes_buf(16); // 16-byte salt
// Security levels
KeyFactory.INTERACTIVE // ops=2, mem=64MB — for interactive use
KeyFactory.MODERATE // ops=3, mem=256MB — for moderate security
KeyFactory.SENSITIVE // ops=4, mem=1024MB — for high-security
const encKey = KeyFactory.deriveEncryptionKey(password, salt, KeyFactory.INTERACTIVE);
const authKey = KeyFactory.deriveAuthenticationKey(password, salt);
const encKeyPair = KeyFactory.deriveEncryptionKeyPair(password, salt);
const sigKeyPair = KeyFactory.deriveSignatureKeyPair(password, salt);Symmetric Encryption
XChaCha20-Poly1305 (Halite v5) or XSalsa20 (compatible with older Halite versions).
import { SymmetricCrypto, EncryptionKey } from 'halite-ts';
const key = EncryptionKey.generate();
// Encrypt / Decrypt
const ciphertext = SymmetricCrypto.encrypt(new HiddenString('hello'), key);
const plaintext = SymmetricCrypto.decrypt(ciphertext, key);
// With additional authenticated data
const ad = '{"context":"user-registration"}';
const enc = SymmetricCrypto.encryptWithAD(new HiddenString('data'), key, ad);
const dec = SymmetricCrypto.decryptWithAD(enc, key, ad);
// Encoding options (default: base64urlsafe)
SymmetricCrypto.encrypt(data, key, 'hex');
SymmetricCrypto.encrypt(data, key, 'base64');
SymmetricCrypto.encrypt(data, key, 'base64urlsafe');Symmetric Authentication
BLAKE2b message authentication codes.
import { SymmetricCrypto, AuthenticationKey } from 'halite-ts';
const key = AuthenticationKey.generate();
const message = new TextEncoder().encode('authenticate me');
const mac = SymmetricCrypto.authenticate(message, key);
const valid = SymmetricCrypto.verify(message, key, mac);
// trueAsymmetric Encryption
X25519 key agreement + symmetric encryption.
import { AsymmetricCrypto, EncryptionKeyPair, HiddenString } from 'halite-ts';
const alice = EncryptionKeyPair.generate();
const bob = EncryptionKeyPair.generate();
// Alice encrypts to Bob
const ciphertext = AsymmetricCrypto.encrypt(
new HiddenString('secret message'),
alice.getSecretKey(), // Alice's secret key
bob.getPublicKey() // Bob's public key
);
// Bob decrypts
const plaintext = AsymmetricCrypto.decrypt(
ciphertext,
bob.getSecretKey(), // Bob's secret key
alice.getPublicKey() // Alice's public key
);
// With additional authenticated data
AsymmetricCrypto.encryptWithAD(data, senderSk, recipientPk, aad);
AsymmetricCrypto.decryptWithAD(ct, recipientSk, senderPk, aad);Anonymous Sealing
Encrypt to a public key without sender authentication (crypto_box_seal).
import { AsymmetricCrypto, EncryptionKeyPair, HiddenString } from 'halite-ts';
const recipient = EncryptionKeyPair.generate();
const sealed = AsymmetricCrypto.seal(
new HiddenString('anonymous message'),
recipient.getPublicKey()
);
const opened = AsymmetricCrypto.unseal(sealed, recipient.getSecretKey());Digital Signatures
Ed25519 detached signatures.
import { AsymmetricCrypto, SignatureKeyPair } from 'halite-ts';
const signer = SignatureKeyPair.generate();
const message = new TextEncoder().encode('important document');
const signature = AsymmetricCrypto.sign(message, signer.getSecretKey());
const ok = AsymmetricCrypto.verify(message, signer.getPublicKey(), signature);
// trueSign-and-Encrypt / Verify-and-Decrypt
Combined authenticated encryption: sign with Ed25519, then encrypt the signed message.
import {
AsymmetricCrypto,
SignatureKeyPair, EncryptionKeyPair,
HiddenString
} from 'halite-ts';
const sender = SignatureKeyPair.generate();
const recipient = EncryptionKeyPair.generate();
// Sender: sign + encrypt
const enc = AsymmetricCrypto.signAndEncrypt(
new HiddenString('authenticated message'),
sender.getSecretKey(),
recipient.getPublicKey()
);
// Recipient: verify + decrypt
const dec = AsymmetricCrypto.verifyAndDecrypt(
enc,
sender.getPublicKey(), // verify signature
recipient.getSecretKey() // decrypt
);Password Hashing
Argon2id password hashing with encrypted hash storage.
import { Password, EncryptionKey, HiddenString, KeyFactory } from 'halite-ts';
const key = EncryptionKey.generate();
const password = new HiddenString('user password');
// Hash
const stored = await Password.hash(password, key, KeyFactory.INTERACTIVE);
// Verify
const match = await Password.verify(password, stored, key);
// true
// Check if rehashing is needed
const needsRehash = Password.needsRehash(stored, key, KeyFactory.MODERATE);File Operations
Encrypt, seal, sign, or checksum files on disk.
import { HaliteFile, EncryptionKey, EncryptionKeyPair, SignatureKeyPair } from 'halite-ts';
const key = EncryptionKey.generate();
// Symmetric encrypt / decrypt
HaliteFile.encrypt('plain.txt', 'encrypted.txt', key);
HaliteFile.decrypt('encrypted.txt', 'decrypted.txt', key);
// Asymmetric encrypt / decrypt
const kp = EncryptionKeyPair.generate();
HaliteFile.asymmetricEncrypt('plain.txt', 'enc.asc', kp.getPublicKey(), kp.getSecretKey());
HaliteFile.asymmetricDecrypt('enc.asc', 'dec.txt', kp.getSecretKey(), kp.getPublicKey());
// Anonymous seal / unseal
HaliteFile.seal('plain.txt', 'sealed.txt', kp.getPublicKey());
HaliteFile.unseal('sealed.txt', 'open.txt', kp.getSecretKey());
// Digital signature (detached)
const signer = SignatureKeyPair.generate();
const sig = HaliteFile.sign('document.txt', signer.getSecretKey());
const verified = HaliteFile.verify('document.txt', signer.getPublicKey(), sig);
// Checksum (BLAKE2b)
const hash = HaliteFile.checksum('document.txt'); // keyed hash
const hashKeyed = HaliteFile.checksum('document.txt', encryptionKey);Merkle Trees
Binary hash trees using BLAKE2b. Supports configurable hash size and personalization strings.
import { MerkleTree, TrimmedMerkleTree, Node } from 'halite-ts';
const leaf1 = new Node(new TextEncoder().encode('transaction1'));
const leaf2 = new Node(new TextEncoder().encode('transaction2'));
const leaf3 = new Node(new TextEncoder().encode('transaction3'));
const tree = new MerkleTree(leaf1, leaf2, leaf3);
const root = tree.getRoot();
// Configurable hash size and personalization
tree.setHashSize(64).setPersonalizationString('MyApp');
// Trimmed Merkle Tree (supports subtree expansion)
const trimmed = new TrimmedMerkleTree(leaf1, leaf2);
const expanded = trimmed.getExpandedTree(leaf3);Secure Cookies
Encrypted cookie value generation.
import { Cookie, EncryptionKey } from 'halite-ts';
const key = EncryptionKey.generate();
const cookie = new Cookie(key);
const encryptedValue = cookie.store('session', {
userId: 42,
role: 'admin'
});Utilities
import { Util } from 'halite-ts';
// Hashing
Util.hash(data); // BLAKE2b (default 32 bytes)
Util.rawHash(data, 64); // custom output length
Util.keyedHash(data, key); // keyed BLAKE2b
// HKDF-BLAKE2b key derivation
Util.hkdfBlake2b(inputKeyMaterial, length, info, salt);
// Pre-Authentication Encoding
Util.PAE(piece1, piece2, piece3);
// XOR two equal-length byte arrays
Util.xorStrings(a, b);
// Constant-time memory zeroing
Util.memzero(sensitiveData);
// Safe copy
Util.safeStrcpy(data);
// Concatenate byte arrays
Util.concat(a, b, c);Encoding
import { Halite } from 'halite-ts';
Halite.hexEncode(data); // Uint8Array → hex string
Halite.hexDecode(str); // hex string → Uint8Array
Halite.base64Encode(data); // Uint8Array → base64
Halite.base64Decode(str); // base64 string → Uint8Array
Halite.base64UrlSafeEncode(data); // Uint8Array → base64url
Halite.base64UrlSafeDecode(str); // base64url string → Uint8ArrayError Handling
All errors extend HaliteAlert:
| Error | Thrown When |
|---|---|
| InvalidKey | Key material validation fails |
| InvalidMessage | Ciphertext is malformed or integrity check fails |
| InvalidSignature | Signature verification fails |
| InvalidSalt | Salt has wrong length |
| InvalidDigestLength | Requested digest length is out of range |
| InvalidType | Invalid encoding or type parameter |
| CannotPerformOperation | Operation cannot be completed |
| ConfigDirectiveNotFound | Configuration key is missing |
| FileAccessDenied | File access is denied |
| FileModified | File integrity check fails |
| CannotSerializeKey | Key object cannot be serialized |
| CannotCloneKey | Key object cannot be cloned |
import {
HaliteAlert, InvalidKey, InvalidMessage,
InvalidSignature, InvalidSalt, InvalidType,
CannotPerformOperation, FileAccessDenied
} from 'halite-ts';
try {
SymmetricCrypto.decrypt(tamperedCiphertext, key);
} catch (e) {
if (e instanceof InvalidMessage) {
console.error('Data integrity violation');
}
}Architecture
The library uses a versioned message format: every ciphertext and exported key includes a 4-byte version prefix (0x31 0x42 0x05 0x00 for Halite v5), enabling backward-compatible config resolution and format evolution.
For symmetric encryption, the library splits a master key into separate encryption and authentication sub-keys using HKDF-BLAKE2b (v5) or a simpler keyed BLAKE2b split (v4/v3), with domain separation strings to prevent key reuse across different operations.
License
MPL-2.0
