ESC
Type to search...
S
Soli Docs

Cryptography Functions

Hash functions (SHA-256, SHA-512, MD5, HMAC), password hashing with Argon2, X25519 key exchange, Ed25519 signatures, TOTP codes, and Base64 encoding.

Crypto Class

All cryptographic functions are available as static methods on the Crypto class. Standalone function aliases are also provided for convenience.

Hash Functions

Not for password storage. SHA-256, SHA-512, and MD5 are general-purpose hashes — they are fast by design, which is exactly the wrong property for a password store (an attacker brute-forces them just as fast). For passwords, use Crypto.argon2_hash. For verifying tokens / MACs in constant time, use secure_compare.

Crypto.sha256(data)

Compute SHA-256 hash of a string. Also available as sha256(). Use for file checksums, ETags, content addressing — not for password hashing (use argon2_hash).

Parameters

data : String - The data to hash

Returns

String - 64-character hex string (32 bytes)
hash = Crypto.sha256("hello")
# "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
Crypto.sha512(data)

Compute SHA-512 hash of a string. Also available as sha512(). Same caveats as SHA-256 — not for password hashing (use argon2_hash).

Parameters

data : String - The data to hash

Returns

String - 128-character hex string (64 bytes)
hash = Crypto.sha512("hello")
# 128-character hex string
Crypto.md5(data)

Compute MD5 hash of a string. Also available as md5(). Cryptographically broken — collisions can be constructed cheaply. Use only for non-security checksums (e.g. content fingerprinting where adversarial collisions don't matter). Never use for passwords or signatures.

Parameters

data : String - The data to hash

Returns

String - 32-character hex string (16 bytes)
hash = Crypto.md5("hello")
# "5d41402abc4b2a76b9719d911017c592"
Crypto.hmac(message, key)

Compute HMAC-SHA256 message authentication code. Also available as hmac().

Parameters

message : String - The message to authenticate
key : String - The secret key

Returns

String - 64-character hex string (32 bytes)
mac = Crypto.hmac("message", "secret_key")
# Use for API signature verification, webhook validation, etc.
Crypto.secure_compare(a, b)

Constant-time string equality. Also available as secure_compare(). Use whenever comparing two values where one comes from an untrusted source and timing-leak of the comparison would help an attacker — verifying an HMAC, a webhook signature, a CSRF token, a session-derived MAC. A naïve a == b short-circuits at the first differing byte and leaks the prefix length to a timing attacker.

Parameters

a : String
b : String

Returns

Bool - true only when both strings have the same length and bytes. Length is not secret; equal-length inputs run in time proportional only to the length, not the position of any differing byte.
expected = Crypto.hmac(payload, getenv("WEBHOOK_SECRET"))
if secure_compare(expected, request_signature)
  # Trust the request
end

Password Hashing

Crypto.argon2_hash(password)

Hash a password using Argon2id (recommended algorithm). Also available as argon2_hash() and password_hash().

Parameters

password : String - The plain text password to hash

Returns

String - The Argon2id hash string
hash = Crypto.argon2_hash("secretpassword")
# $argon2id$v=19$m=19456,t=2,p=1$...
Crypto.argon2_verify(password, hash)

Verify a password against an Argon2id hash. Also available as argon2_verify() and password_verify().

Parameters

password : String - The plain text password to verify
hash : String - The stored hash to verify against

Returns

Bool - true if password matches, false otherwise
if Crypto.argon2_verify(user_input, stored_hash)
  println("Password correct!")
else
  println("Invalid password")
end

X25519 Key Exchange

Crypto.x25519_keypair()

Generate an X25519 key pair for Diffie-Hellman key exchange. Also available as x25519_keypair().

Returns

Hash - { "private": String, "public": String } (hex-encoded, 64 chars each)
keypair = Crypto.x25519_keypair
println(keypair["public"])   # Hex-encoded public key
println(keypair["private"])  # Hex-encoded private key
Crypto.x25519_shared_secret(private_key, public_key)

Compute a shared secret from your private key and another party's public key. Also available as x25519_shared_secret().

Parameters

private_key : String - Your hex-encoded private key
public_key : String - Their hex-encoded public key

Returns

String - Hex-encoded shared secret
alice = Crypto.x25519_keypair
bob = Crypto.x25519_keypair

# Both compute the same shared secret
alice_secret = Crypto.x25519_shared_secret(alice["private"], bob["public"])
bob_secret = Crypto.x25519_shared_secret(bob["private"], alice["public"])
# alice_secret == bob_secret
Crypto.x25519_public_key(private_key)

Derive the public key from a private key. Also available as x25519_public_key().

Parameters

private_key : String - Hex-encoded private key

Returns

String - Hex-encoded public key
keypair = Crypto.x25519_keypair
derived_public = Crypto.x25519_public_key(keypair["private"])
# derived_public == keypair["public"]

Ed25519 Signatures

Crypto.ed25519_keypair()

Generate an Ed25519 signing key pair for digital signatures. Also available as ed25519_keypair().

Returns

Hash - { "private": String, "public": String } (hex-encoded, 64 chars each)
keypair = Crypto.ed25519_keypair
# Use keypair["private"] to sign messages
# Share keypair["public"] for verification

TOTP (Time-based One-Time Password)

RFC 6238 compliant TOTP generation and verification. Compatible with Google Authenticator, Authy, and other authenticator apps.

Crypto.totp_generate(secret, time?, period?)

Generate a TOTP code (6-digit time-based one-time password). Uses HMAC-SHA1 per RFC 6238.

Parameters

secret : String - Base32-encoded secret key
time : Int? - Optional Unix timestamp (defaults to current time)
period : Int? - Optional time window in seconds (defaults to 30)

Returns

String - 6-digit TOTP code
# Generate code for current time
code = Crypto.totp_generate("JBSWY3DPEHPK3PXP")

# Generate code for specific time
code = Crypto.totp_generate("JBSWY3DPEHPK3PXP", 1704067200, 30)

# Use RFC 6238 test vector
code = Crypto.totp_generate("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", 59, 30)
# Returns "287082"
Crypto.totp_verify(secret, code, time?, period?)

Verify a TOTP code against a secret. Accepts the current code and the previous/next code (1 step window) to handle clock drift.

Parameters

secret : String - Base32-encoded secret key
code : String - 6-digit TOTP code to verify
time : Int? - Optional Unix timestamp (defaults to current time)
period : Int? - Optional time window in seconds (defaults to 30)

Returns

Bool - true if code is valid, false otherwise
secret = "JBSWY3DPEHPK3PXP"
user_code = request.body["code"]

if Crypto.totp_verify(secret, user_code)
  println("Authentication successful!")
else
  println("Invalid code")
end
Crypto.totp_uri(secret, account_name?, issuer?, period?)

Generate an otpauth:// URI for easy TOTP setup in authenticator apps. This URI can be encoded into a QR code.

Parameters

secret : String - Base32-encoded secret key
account_name : String? - Optional account name (e.g., email)
issuer : String? - Optional service name (e.g., "MyApp")
period : Int? - Optional time window in seconds (defaults to 30)

Returns

String - otpauth:// URI
secret = "JBSWY3DPEHPK3PXP"
uri = Crypto.totp_uri(secret, "[email protected]", "MyApp", 30)

# Returns: otpauth://totp/MyApp:user%40example.com?secret=...&algorithm=SHA1&digits=6&period=30

# Use with QR code library
qr_data = QRCode.encode(uri)
# Display qr_data to user for scanning