std.crypto
std.crypto provides authenticated (AES-GCM) and legacy (AES-CBC)
encryption, file encryption, key pairs, signatures, certificates, and secure
random bytes. It is available only when the engine was built with
OpenSSL — otherwise calls throw UNSUPPORTED.
Reference
aes_gcm_encrypt(data, passphrase[, bits = 256])
aes_gcm_decrypt(payload, passphrase)
aes_encrypt(data, passphrase[, bits = 256]) # legacy CBC, kept for old payloads
aes_decrypt(payload, passphrase)
encrypt_file(in, out, passphrase[, bits = 256])
decrypt_file(in, out, passphrase) # bits and format read from the file header
random_bytes(n)
rsa_generate([bits = 2048])
ec_generate([curve = "P-256"])
sign(data, private_pem[, hash = "sha256"])
verify(data, signature, public_pem[, hash = "sha256"])
x509_self_signed(common_name, private_pem[, public_pem[, days = 365]])
| Function | Description |
|---|---|
aes_gcm_encrypt(data, pass[, bits]) |
AES-128/256-GCM, random salt + nonce → authenticated binary payload. Prefer this for new code |
aes_gcm_decrypt(payload, pass) |
Reverse aes_gcm_encrypt; throws on wrong password or any tampering |
aes_encrypt(data, pass[, bits]) |
Legacy AES-128/256-CBC payload (for old files) |
aes_decrypt(payload, pass) |
Reverse legacy aes_encrypt; throws on wrong password |
encrypt_file(in, out, pass[, bits]) |
File variant — new files use GCM |
decrypt_file(in, out, pass) |
File variant — format read from the file header (GCM or legacy CBC) |
random_bytes(n) |
n cryptographically secure random bytes |
rsa_generate([bits]) |
RSA key pair → {private, public} PEM strings (default 2048) |
ec_generate([curve]) |
EC key pair → {private, public} PEM strings (P-256, P-384, P-521, secp256k1) |
sign(data, priv[, hash]) |
Sign with an RSA/EC private key → raw signature |
verify(data, sig, pub[, hash]) |
Verify a signature → true/false |
x509_self_signed(cn, priv[, pub[, days]]) |
Self-signed v3 X.509 certificate → PEM string (default 365 days; pass pub only to pin a specific public key, which must match the private key — otherwise it is derived from priv) |
bits is 128 or 256 (default 256). The payload/header encodes salt,
nonce/IV, and mode so decrypt does not need the bit size repeated. Keys are
derived with PBKDF2-HMAC-SHA256 and wiped from memory after use.
Examples
# AEAD round-trip (preferred)
var payload = std.crypto.aes_gcm_encrypt("secret", "my-pass")
print(std.crypto.aes_gcm_decrypt(payload, "my-pass")) # secret
# print(std.crypto.aes_gcm_decrypt(payload, "wrong")) # throws
# print(std.crypto.aes_gcm_decrypt(tampered, "my-pass")) # throws: authentication failed
# file round-trip (writes GCM; reads GCM or legacy CBC)
std.crypto.encrypt_file("plain.txt", "plain.enc", "my-pass")
std.crypto.decrypt_file("plain.enc", "plain2.txt", "my-pass")
# random material → hash it
var bytes = std.crypto.random_bytes(16)
print(std.hash.sha256(bytes))
# RSA: generate, sign, verify
var k = std.crypto.rsa_generate(2048)
var sig = std.crypto.sign("payload", k.private)
print(std.crypto.verify("payload", sig, k.public)) # true
print(std.crypto.verify("tampered", sig, k.public)) # false
# EC + self-signed certificate
var e = std.crypto.ec_generate("P-256")
var cert = std.crypto.x509_self_signed("example.com", e.private)
std.file.write("cert.pem", cert)
# legacy CBC (old payloads only)
var p128 = std.crypto.aes_encrypt("hi", "pass", 128)
print(std.crypto.aes_decrypt(p128, "pass"))
File paths accept ~ and $VAR expansion, like std.file.
PEM private keys are unencrypted strings — guard them like any secret, and
prefer verify()'s boolean over comparing signatures yourself (ECDSA
signatures are randomized and differ every call).
Availability
Check at runtime whether the engine was built with OpenSSL:
# std.crypto itself is always present as an object;
# its functions throw UNSUPPORTED if OpenSSL was not linked.
print(std.crypto.random_bytes(4)) # throws UNSUPPORTED without OpenSSL
Without OpenSSL, std.hash still works (its digests are built in), but every
std.crypto call throws UNSUPPORTED.