Crypto API
Cryptographic primitives backed by mbedTLS: random byte generation, RSA key pairs, self-signed X.509 certificates, signing and verification, asymmetric encryption, HMAC digests, and constant-time byte comparison.
Overview
The global identifier Crypto is a constructor namespace. Calling one of its constructors returns a Crypto, CryptoKey, or X509Certificate handle whose methods are invoked as h.method(...). A Crypto instance from Crypto.create() is the entry point for everything that needs a working RNG: random bytes, RSA generation, signing, encryption, and HMAC. The CryptoKey and X509Certificate constructors produce empty handles for parsing PEM material received from elsewhere. For symmetric encryption, see the AES API.
Conventions
Byte payloads
All binary inputs and outputs are exchanged through the Zym Buffer native: random bytes, hashes, signatures, ciphertexts, and keys for HMAC. Use Buffer.fromString(...) to lift script strings into buffers, and b.size() / b[i] to inspect results.
Hash identifiers
Methods that name a hash take a string identifier. The lookup is case-insensitive.
| Identifier | Digest size | sign / verify | hmacDigest |
|---|---|---|---|
"sha256" | 32 bytes | supported | supported |
"sha1" | 20 bytes | supported | supported |
"md5" | 16 bytes | supported | raises a runtime error |
PEM strings vs. file paths
Keys and certificates serialize either to a PEM string (saveToString / loadFromString) or to a file path (save / load). The string form is convenient when piping through script values; the file form is convenient when interoperating with tools that read PEM from disk.
The publicOnly flag
CryptoKey.load, CryptoKey.save, CryptoKey.loadFromString, and CryptoKey.saveToString take an optional publicOnly boolean (default false). When true, only the public component of the key is written or expected. That is the form used to verify signatures or perform RSA encryption.
Errors
Wrong-type arguments raise a Zym runtime error of the form Crypto.method(args) .... Operations the engine handles gracefully, such as parsing a malformed PEM, return false or null instead of raising; engine-level diagnostic messages may still be printed to stderr in those cases.
k2 = k1) makes k2 refer to the same underlying key as k1. Loading a new PEM through one name is visible through the other.
Construction
Creates a Crypto instance backed by mbedTLS. This is the entry point for everything that needs a working RNG: random bytes, RSA generation, signing, encryption, and HMAC.
Returns: A Crypto instance, or null if the engine refuses to create one.
Creates an empty CryptoKey ready for load / loadFromString. Useful for parsing a PEM received from somewhere else, such as a file, the network, or user input.
Returns: An empty CryptoKey instance.
Creates an empty X509Certificate ready for load / loadFromString.
Returns: An empty X509Certificate instance.
Random Bytes
Generates n cryptographically random bytes.
n(number) — byte count (must be 0 or greater)
Returns: A Buffer of n random bytes.
var c = Crypto.create() var token = c.generateRandomBytes(32) // Buffer of 32 random bytes
RSA Keys & Certificates
Generates a fresh RSA key pair of size bits. Common sizes: 2048 for production, 1024 for tests.
bits(number) — key size in bits
Returns: A CryptoKey holding the new pair, or null on failure.
Issues a self-signed X.509 certificate using key.
key(CryptoKey) — a key with private materialissuer(string) — distinguished-name string (e.g."CN=example")notBefore(string) — validity start timestamp inYYYYMMDDHHMMSSformatnotAfter(string) — validity end timestamp inYYYYMMDDHHMMSSformat
Returns: An X509Certificate, or null on failure.
var c = Crypto.create() var key = c.generateRsa(2048) var cert = c.generateSelfSignedCertificate( key, "CN=zym example", "20230101000000", "20330101000000") cert.save("/tmp/zym.pem")
Signing & Verification
sign and verify operate on a digest, not on the raw message. Use hmacDigest (with an empty / public key value) or a separate hashing step to produce the digest before signing.
Signs the precomputed hash using the private key. The hash must be the exact length expected by the hash algorithm: 32 bytes for "sha256", 20 for "sha1", 16 for "md5".
hashType(string) —"sha256","sha1", or"md5"hash(Buffer) — the precomputed digest to signkey(CryptoKey) — a key with private material
Returns: A Buffer holding the signature, or null if signing fails.
Verifies that signature was produced for hash by the private counterpart of key. The public component of key is sufficient.
hashType(string) —"sha256","sha1", or"md5"hash(Buffer) — the digest the signature coverssignature(Buffer) — the signature to checkkey(CryptoKey) — the signer's key; public component suffices
Returns: true if the signature checks out, false otherwise.
Asymmetric Encryption
RSA-encrypts plaintext using key's public component. The ciphertext is randomized (OAEP), so two encryptions of the same plaintext differ. The plaintext must be small enough for the key size.
key(CryptoKey) — recipient's key; public component sufficesplaintext(Buffer) — the bytes to encrypt
Returns: A Buffer holding the ciphertext, or null on failure.
Decrypts ciphertext using key's private component.
key(CryptoKey) — a key with private materialciphertext(Buffer) — the bytes to decrypt
Returns: A Buffer holding the plaintext, or null on failure (e.g. wrong key, corrupted ciphertext).
HMAC
Computes the HMAC of msg keyed with key, using the named hash. Output is 20 bytes for "sha1" and 32 bytes for "sha256". "md5" is not supported by the underlying engine and raises a runtime error.
hashType(string) —"sha1"or"sha256"key(Buffer) — the HMAC keymsg(Buffer) — the message to authenticate
Returns: A Buffer holding the digest.
Constant-Time Comparison
Returns true only when trusted and received are byte-for-byte equal. The implementation does not short-circuit on the first mismatch, making it safe for comparing MACs and tokens against attacker-supplied input. Buffers of different lengths compare false.
trusted(Buffer) — the known-good valuereceived(Buffer) — the value to check
CryptoKey
A CryptoKey is returned by c.generateRsa(...) and created empty by Crypto.CryptoKey(). PEMs round-trip both through file paths and through string values: a key saved to pem and re-parsed via loadFromString(pem, ...) produces an equivalent handle, and re-saving it yields the same PEM.
Reads a PEM-encoded key from path.
path(string) — file to readpublicOnly(boolean, optional) — expect only the public component (default:false)
Returns: true on success, false if the file cannot be read or parsed.
Writes the key to path as PEM. With publicOnly = true only the public component is written.
path(string) — file to writepublicOnly(boolean, optional) — write only the public component (default:false)
Returns: true on success, false otherwise.
Returns the PEM representation of the key. With publicOnly = true only the public component is included.
publicOnly(boolean, optional) — include only the public component (default:false)
Returns: The PEM string.
Parses a PEM string.
pem(string) — PEM-encoded key materialpublicOnly(boolean, optional) — expect only the public component (default:false)
Returns: true on success, false on invalid input.
Returns true when only the public component is loaded, false when private material is present.
var c = Crypto.create() var key = c.generateRsa(2048) var pem = key.saveToString(false) // private PEM var loaded = Crypto.CryptoKey() loaded.loadFromString(pem, false) // true
X509Certificate
An X509Certificate is returned by c.generateSelfSignedCertificate(...) and created empty by Crypto.X509Certificate().
Parses a PEM-encoded certificate (or chain) from path.
path(string) — file to read
Returns: true on success, false otherwise.
Writes the certificate to path as PEM.
path(string) — file to write
Returns: true on success, false otherwise.
Returns the PEM representation of the certificate.
Parses a PEM string.
pem(string) — PEM-encoded certificate material
Returns: true on success, false otherwise.
Examples
Sign and Verify a Message
var c = Crypto.create() var key = c.generateRsa(2048) // Crypto.sign expects a precomputed digest, not the raw message. var hashKey = Buffer.fromString("") var digest = c.hmacDigest("sha256", hashKey, Buffer.fromString("hello")) var sig = c.sign("sha256", digest, key) print(c.verify("sha256", digest, sig, key)) // true
HMAC for Token Comparison
var c = Crypto.create() var hmacKey = Buffer.fromString("server-secret") var expected = c.hmacDigest("sha256", hmacKey, Buffer.fromString("payload")) var received = c.hmacDigest("sha256", hmacKey, Buffer.fromString("payload")) if (c.constantTimeCompare(expected, received)) { print("token ok") }
RSA Encrypt / Decrypt
var c = Crypto.create() var key = c.generateRsa(2048) var ct = c.encrypt(key, Buffer.fromString("secret payload")) var pt = c.decrypt(key, ct) // pt is a Buffer holding the original bytes.