A cryptography library for Gleam targeting both Erlang and JavaScript runtimes.
- Runs on both Erlang and JavaScript (Node.js), wrapping each platform's native crypto APIs for consistent behavior.
- All cryptographic operations delegate to the runtime's implementations (Erlang's
cryptomodule, Node.jscryptomodule). - Inspired by Go's crypto library, the API guides you toward safe defaults and makes dangerous operations explicit.
- Validated against Wycheproof test vectors to catch edge-case vulnerabilities.
Note
Browser JavaScript is not supported. The WebCrypto API is promise-based, which doesn't fit the synchronous FFI model. For browser crypto, see plinth which provides Gleam bindings to WebCrypto using promises.
gleam add kryptos
- Erlang/OTP 27 or later for the Erlang target
- Node.js 22 or later for the JavaScript target
| Module | Algorithms |
|---|---|
| aead | AES-GCM, AES-CCM, ChaCha20-Poly1305, XChaCha20-Poly1305 |
| block | AES-128, AES-192, AES-256, AES Key Wrap (RFC 3394) |
| crypto | HKDF, PBKDF2, random bytes |
| ec | Key generation, import/export, introspection |
| ecdh | P-256, P-384, P-521, secp256k1 |
| ecdsa | P-256, P-384, P-521, secp256k1 |
| eddsa | Ed25519, Ed448 |
| hash | SHA-1, SHA-2, SHA-3, SHAKE, BLAKE2 |
| hmac | All hash algorithms |
| mldsa | ML-DSA-44, ML-DSA-65, ML-DSA-87 |
| rsa | OAEP, PKCS#1 v1.5, PSS, PKCS#1 v1.5 signatures |
| x509/certificate | Certificate parsing and self-signed generation |
| x509/csr | CSR generation with ECDSA/RSA/EdDSA/ML-DSA, SANs |
| xdh | X25519, X448 |
Encrypt and decrypt data using AES-GCM:
import kryptos/aead import kryptos/block import kryptos/crypto pub fn main() { // Generate a random 256-bit key let assert Ok(cipher) = block.aes_256(crypto.random_bytes(32)) let ctx = aead.gcm(cipher) // Generate a random nonce (never reuse with the same key!) let nonce = crypto.random_bytes(aead.nonce_size(ctx)) // Encrypt let plaintext = <<"hello, world!":utf8>> let assert Ok(#(ciphertext, tag)) = aead.seal(ctx, nonce:, plaintext:) // Decrypt let assert Ok(decrypted) = aead.open(ctx, nonce:, ciphertext:, tag:) // decrypted == plaintext }
Tip
If you're looking for a higher-level library for simple encryption, check out amaro.
For guidance on choosing cryptographic primitives, see Cryptographic Right Answers.