March Docs

Crypto

Crypto module: general-purpose cryptographic primitives.

Exposes hashing, HMAC, password hashing/verification, random generation, and Base64 encoding as a public API. The underlying implementations are provided by the March runtime (Digestif SHA-256/512, PBKDF2, CSPRNG).

Password hashing uses PBKDF2-SHA256 with a 16-byte random salt and

  1. The stored format is:

"pbkdf2:sha256:100000:<salt_hex>:<hash_hex>" This is intentionally simple to verify without external libraries.

All hex output is lowercase.

Functions

fnsha256sha256(data)#

Compute the SHA-256 hash of data, returning a lowercase hex string.

Crypto.sha256("hello") -- "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"

The argument may be a String or Bytes value.

fnsha512sha512(data)#

Compute the SHA-512 hash of data, returning a lowercase hex string.

The argument may be a String or Bytes value.

fnhmachmac(algo, key, data)#

Compute an HMAC using the given algorithm.

Crypto.hmac(:sha256, "secret", "message") -- lowercase hex string of the HMAC-SHA256 result

Supported algorithms: :sha256. Returns the HMAC as a lowercase hex string. The key and data may each be a String or Bytes value.

fnhash_passwordhash_password(plain)#

Hash a plaintext password using PBKDF2-SHA256 with a random salt.

let h = Crypto.hash_password("my-secret") -- "pbkdf2:sha256:100000:<salt_hex>:<hash_hex>"

The result is safe to store in a database. Use verify_password/2 to check a candidate password against the stored hash.

Uses 100 000 PBKDF2 iterations with a 16-byte random salt and 32-byte output.

fnverify_passwordverify_password(plain, stored)#

Verify a plaintext password against a stored hash produced by hash_password/1.

let h = Crypto.hash_password("correct-horse-battery-staple") Crypto.verify_password("correct-horse-battery-staple", h) -- true Crypto.verify_password("wrong-password", h) -- false

Returns false if the hash format is unrecognised.

fnrandom_bytesrandom_bytes(n)#

Generate n cryptographically random bytes.

Crypto.random_bytes(16) -- Bytes value with 16 random bytes

fnrandom_hexrandom_hex(n)#

Generate n random bytes and return them as a lowercase hex string (2n chars).

Crypto.random_hex(16) -- 32-character lowercase hex string

fnsecure_comparesecure_compare(a, b)#

Compare two strings in constant time with respect to their length.

Prevents timing attacks when comparing secrets such as tokens or HMAC digests. Returns true if the strings are equal, false otherwise.

Note: the interpreter does not guarantee constant time at the machine level; this function nonetheless avoids early exits that would reveal prefix length.

Crypto.secure_compare("abc", "abc") -- true Crypto.secure_compare("abc", "abd") -- false

fnbase64_encodebase64_encode(data)#

Base64-encode a Bytes value (standard alphabet with padding).

let b = Crypto.random_bytes(12) Crypto.base64_encode(b) -- 16-character Base64 string

fnbase64_decodebase64_decode(s)#

Decode a standard Base64 string to Bytes.

Crypto.base64_decode("SGVsbG8=") -- Ok(Bytes for "Hello") Crypto.base64_decode("!!") -- Err("base64_decode: ...")

fnbase64_url_encodebase64_url_encode(data)#

Base64-encode using the URL-safe alphabet (- and _ instead of + and /), with no padding characters.

Crypto.base64_url_encode(Crypto.random_bytes(16)) -- URL-safe 22-character string

fnbase64_url_decodebase64_url_decode(s)#

Decode a URL-safe Base64 string (- and _, no padding) to Bytes.

Crypto.base64_url_decode("SGVsbG8") -- Ok(Bytes) Crypto.base64_url_decode("!!") -- Err(...)