crypto
Operations involving a key, a secret, or authentication. The security sibling of cx-stdlib/hash, which fingerprints public data: if it involves a key, a secret, or authentication it lives here; a bare fingerprint lives in hash. Covers HMAC, keyed-BLAKE3, HKDF, constant-time MAC verification, AEAD, Ed25519/X25519, RSA and ECDSA signing and verification (PKCS#1 v1.5 and PSS; P-256/P-384/P-521), Argon2id password hashing, and fail-closed JWT/JWKS verification plus client-authentication JWS signing. Keys, messages, MACs, and other byte material are all CXDM bytes — convert hex or base64 via cx-stdlib/bytes before passing in.
crypto:hmac-sha256
[$crypto:hmac-sha256] -> bytes — Compute the HMAC-SHA-256 (RFC 2104) of a message under a key — 32 bytes, key of any length.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:to-hex [$crypto:hmac-sha256 [$bytes:from-string-utf8 "Jefe"] [$bytes:from-string-utf8 "what do ya want for nothing?"]]]
'5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843'
crypto:hmac-sha384
[$crypto:hmac-sha384] -> bytes — Compute the HMAC-SHA-384 (RFC 2104) of a message under a key — 48 bytes, key of any length.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:to-hex [$crypto:hmac-sha384 [$bytes:from-string-utf8 "Jefe"] [$bytes:from-string-utf8 "what do ya want for nothing?"]]]
af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649
crypto:hmac-sha512
[$crypto:hmac-sha512] -> bytes — Compute the HMAC-SHA-512 (RFC 2104) of a message under a key — 64 bytes, key of any length.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:to-hex [$crypto:hmac-sha512 [$bytes:from-string-utf8 "Jefe"] [$bytes:from-string-utf8 "what do ya want for nothing?"]]]
'164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737'
crypto:hmac-new
[$crypto:hmac-new] -> element — Start a streaming HMAC hasher for the named algorithm and key (sha256/sha384/sha512).
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:equals [$crypto:hmac-finalize [$crypto:hmac-update [$crypto:hmac-update [$crypto:hmac-new "sha256" [$bytes:from-string-utf8 "Jefe"]] [$bytes:from-string-utf8 "what do ya want "]] [$bytes:from-string-utf8 "for nothing?"]]] [$crypto:hmac-sha256 [$bytes:from-string-utf8 "Jefe"] [$bytes:from-string-utf8 "what do ya want for nothing?"]]]
true
crypto:hmac-update
[$crypto:hmac-update] -> element — Feed a chunk into a streaming HMAC hasher, returning a new hasher — the input is unchanged.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:equals [$crypto:hmac-finalize [$crypto:hmac-update [$crypto:hmac-update [$crypto:hmac-new "sha256" [$bytes:from-string-utf8 "Jefe"]] [$bytes:from-string-utf8 "what do ya want "]] [$bytes:from-string-utf8 "for nothing?"]]] [$crypto:hmac-sha256 [$bytes:from-string-utf8 "Jefe"] [$bytes:from-string-utf8 "what do ya want for nothing?"]]]
true
crypto:hmac-finalize
[$crypto:hmac-finalize] -> bytes — Finish a streaming HMAC hasher and return the MAC — equal to the single-shot HMAC over the concatenated chunks.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:equals [$crypto:hmac-finalize [$crypto:hmac-update [$crypto:hmac-update [$crypto:hmac-new "sha256" [$bytes:from-string-utf8 "Jefe"]] [$bytes:from-string-utf8 "what do ya want "]] [$bytes:from-string-utf8 "for nothing?"]]] [$crypto:hmac-sha256 [$bytes:from-string-utf8 "Jefe"] [$bytes:from-string-utf8 "what do ya want for nothing?"]]]
true
crypto:blake3-keyed
[$crypto:blake3-keyed] -> bytes — Compute the keyed-BLAKE3 MAC of a message — exactly-32-byte key, 32-byte output.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:length [$crypto:blake3-keyed [$bytes:from-hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"] [$bytes:from-string-utf8 "abc"]]]
32
crypto:blake3-mac-verify
[$crypto:blake3-mac-verify] -> bool — Verify a keyed-BLAKE3 MAC in constant time — returns true on match, raises CXER3701 otherwise.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $k [$bytes:from-hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"]] [= $m [$bytes:from-string-utf8 "abc"]] [$crypto:blake3-mac-verify $k $m [$crypto:blake3-keyed $k $m]]]
true
crypto:hkdf-extract
[$crypto:hkdf-extract] -> bytes — Concentrate input keying material into a fixed-length SHA-256 PRK (HKDF-Extract, RFC 5869); empty salt allowed.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:to-hex [$crypto:hkdf-extract [$bytes:from-hex "000102030405060708090a0b0c"] [$bytes:from-hex "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"]]]
'077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5'
crypto:hkdf-expand
[$crypto:hkdf-expand] -> bytes — Stretch a SHA-256 PRK into length bytes domain-separated by info (HKDF-Expand, RFC 5869).
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:to-hex [$crypto:hkdf-expand [$bytes:from-hex "077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"] [$bytes:from-hex "f0f1f2f3f4f5f6f7f8f9"] 42]]
'3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865'
crypto:hkdf
[$crypto:hkdf] -> bytes — Derive length bytes of key material from one secret in a single SHA-256 extract-then-expand step (RFC 5869).
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:to-hex [$crypto:hkdf [$bytes:from-hex "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"] [$bytes:from-hex "000102030405060708090a0b0c"] [$bytes:from-hex "f0f1f2f3f4f5f6f7f8f9"] 42]]
'3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865'
crypto:hkdf-extract-sha512
[$crypto:hkdf-extract-sha512] -> bytes — HKDF-Extract over SHA-512 — concentrate input keying material into a 64-byte PRK.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $ikm [$bytes:from-hex "0b0b0b0b0b0b0b0b0b0b0b"]] [= $salt [$bytes:from-hex "000102030405060708090a0b0c"]] [$bytes:length [$crypto:hkdf-extract-sha512 $salt $ikm]]]
64
crypto:hkdf-expand-sha512
[$crypto:hkdf-expand-sha512] -> bytes — HKDF-Expand over SHA-512 — stretch a PRK into length bytes domain-separated by info.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $ikm [$bytes:from-hex "0b0b0b0b0b0b0b0b0b0b0b"]] [= $salt [$bytes:from-hex "000102030405060708090a0b0c"]] [= $info [$bytes:from-hex "f0f1f2f3f4f5f6f7f8f9"]] [$bytes:equals [$crypto:hkdf-sha512 $ikm $salt $info 42] [$crypto:hkdf-expand-sha512 [$crypto:hkdf-extract-sha512 $salt $ikm] $info 42]]]
true
crypto:hkdf-sha512
[$crypto:hkdf-sha512] -> bytes — One-shot HKDF over SHA-512 — extract-then-expand a secret into length bytes of key material.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $ikm [$bytes:from-hex "0b0b0b0b0b0b0b0b0b0b0b"]] [= $salt [$bytes:from-hex "000102030405060708090a0b0c"]] [= $info [$bytes:from-hex "f0f1f2f3f4f5f6f7f8f9"]] [$bytes:length [$crypto:hkdf-sha512 $ikm $salt $info 42]]]
42
crypto:hmac-verify
[$crypto:hmac-verify] -> bool — Recompute and compare an HMAC in constant time — returns true on match, raises CXER3701 otherwise, never false.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $k [$bytes:from-string-utf8 "secret"]] [= $m [$bytes:from-string-utf8 "raw-body"]] [$crypto:hmac-verify "sha256" $k $m [$crypto:hmac-sha256 $k $m]]]
true
crypto:aead-encrypt
[$crypto:aead-encrypt] -> element — Authenticated-encrypt plaintext with associated data (AES-256-GCM or ChaCha20-Poly1305), generating a fresh nonce per call.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $k [$bytes:from-hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"]] [= $pt [$bytes:from-string-utf8 "attack at dawn"]] [= $ct [$crypto:aead-encrypt "aes-256-gcm" $k $pt [$bytes:from-string-utf8 "hdr"]]] [$bytes:equals [$crypto:aead-decrypt "aes-256-gcm" $k $ct [$bytes:from-string-utf8 "hdr"]] $pt]]
cx-err:CXER0271
crypto:aead-decrypt
[$crypto:aead-decrypt] -> bytes — Verify the tag in constant time before returning any plaintext — auth failure raises CXER3704.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $k [$bytes:from-hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"]] [= $pt [$bytes:from-string-utf8 "attack at dawn"]] [= $ct [$crypto:aead-encrypt "aes-256-gcm" $k $pt [$bytes:from-string-utf8 "hdr"]]] [$bytes:equals [$crypto:aead-decrypt "aes-256-gcm" $k $ct [$bytes:from-string-utf8 "hdr"]] $pt]]
cx-err:CXER0271
crypto:cbc-encrypt
[$crypto:cbc-encrypt] -> element — AES-CBC encrypt with an internally generated IV — [cbc algo= iv= ciphertext=], PKCS#7 padded by default. CBC carries no integrity of its own: sign or MAC the ciphertext, or you have built a padding oracle (RULED: 1400-a).
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $k [$bytes:from-hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"]]
[= $c [$crypto:cbc-encrypt "aes-256-cbc" $k [$bytes:from-string-utf8 "the quick brown fox"] {}]]
[$bytes:to-string-utf8 [$crypto:cbc-decrypt $c@algo $k $c@iv $c@ciphertext {}]]]
cx-err:CXER0271
crypto:cbc-decrypt
[$crypto:cbc-decrypt] -> bytes — AES-CBC decrypt with the IV the wire handed over; opts.padding is "pkcs7" (default) or "none", and a padding failure raises CXER3720.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:to-string-utf8 [$crypto:cbc-decrypt "aes-256-cbc" [$bytes:from-hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"] [$bytes:from-hex "0f0e0d0c0b0a09080706050403020100"] [$bytes:from-hex "68a0d3a3e9c5c9690444740f118e867dd62bf64a50f3743d3d9a0eaaa9648aae"] {}]]
'the quick brown fox'
crypto:ed25519-keypair
[$crypto:ed25519-keypair] -> element — Sample a fresh Ed25519 keypair — 32-byte public key and 32-byte private seed.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $kp [$crypto:ed25519-keypair]] [$bytes:length $kp@public]]
cx-err:CXER0271
crypto:ed25519-sign
[$crypto:ed25519-sign] -> bytes — Sign a message with an Ed25519 private key (RFC 8032) — deterministic per the standard.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $kp [$crypto:ed25519-keypair]] [= $m [$bytes:from-string-utf8 "sign me"]] [$crypto:ed25519-verify $kp@public $m [$crypto:ed25519-sign $kp@private $m]]]
cx-err:CXER0271
crypto:ed25519-verify
[$crypto:ed25519-verify] -> bool — Verify an Ed25519 signature — returns true on success, raises CXER3705 on an invalid or malformed signature.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $kp [$crypto:ed25519-keypair]] [= $m [$bytes:from-string-utf8 "sign me"]] [$crypto:ed25519-verify $kp@public $m [$crypto:ed25519-sign $kp@private $m]]]
cx-err:CXER0271
crypto:x25519-keypair
[$crypto:x25519-keypair] -> element — Sample a fresh X25519 keypair for key exchange — both keys 32 bytes.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $kp [$crypto:x25519-keypair]] [$bytes:length $kp@public]]
cx-err:CXER0271
crypto:rsa-verify
[$crypto:rsa-verify] -> bool — Verify an RSASSA-PKCS1-v1_5 signature (RFC 8017) backing the JWT RS256/384/512 families — true or raise.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$crypto:rsa-verify [rsa-public-key [n [$bytes:from-hex "8ddc3005c68c6502e848d6063449b7974dc7210aa9448bf47aa2d43540a4cafef2b15c388babd981d63171d5340f7912bd40888c7fa272a9383c20f1e40c2478da79e4daadeb02970eff531f9a6bf96737056999d6c10e130c8df10948f3fe44a58de2d70e6dcac0dd785ba247b04e8e9903e3d459cc5d186a39a872c078fe35e865c95d54d08e0a15c06c47cec3e06d8c5251374377124b32985e1ace47b2f10deb5f4eec5e44476af45f00e9e8c07d75f512f557e5e693f0d45fcc1247edb3765a7c1718ad2563e06cc9a7b33b1380442b4e14f0b2e32b9ddab327f9d0ec74e7b8ad8b5c41661705f0f4d003b29ab666742666237b0979c4606f16080a73c7"]] [e [$bytes:from-hex "010001"]]] [$bytes:from-hex "68656c6c6f2063782063727970746f"] [$bytes:from-hex "1569ad4ad6ac4d94167dc7dcac1bbfe8e263bdc974defeaa98ec51e45ff74ba1eb9084228b0914f3379f719af1fbb7f6848cfca6e89c37ea30511b06ab4cf9c25d1d39b930b4888d7d8b486c59d4b909c07594e37a087b3255c9c9396def19d2d897212a5a5b021c8ab49bd9071b27867b680b05f195081c2bd447ea961d3603aadb4cd5b28a5986df112ef2b04ed59326a78d5c03923dba456d7a5936b25d2b34c43b8ce4c9d76825236b33f91984a98a1d02df3ed64b1ef78ad1fef673f14e403da8e0fd4f713faf355b417a948de48ba64ab7718aeb0a61f2f90bb964fb07818d022c3bcebb0ae7866b65876390b8d8a3c11188973e0bfff1fde3c05e6a49"] {hash: "sha256"}]
true
crypto:ecdsa-verify
[$crypto:ecdsa-verify] -> bool — Verify an ECDSA P-256 signature over a JOSE raw r-concat-s pair (RFC 7518 §3.4) backing JWT ES256 — true or raise.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$crypto:ecdsa-verify [ec-public-key crv="P-256" [x [$bytes:from-hex "97d49c2f327683c64795ce33c7a8ea90b6ebc3d341fe3ece449d874d006019e4"]] [y [$bytes:from-hex "b29043a977e05ce76a0c6b38fd67a7644991166cbbd6ab6cd5d304a7cc6b83a3"]]] [$bytes:from-hex "68656c6c6f2063782063727970746f"] [$bytes:from-hex "5db3b4f367aa22dfa532452151d8a2bb9ecf0fdc968b82a0ad1ac5ed0b8a42cc15b1ce90768ccc59116297c0866874c416823cf92ed1d55b75ca828083d19920"] {curve: "P-256" hash: "sha256"}]
true
crypto:rsa-sign
[$crypto:rsa-sign] -> bytes — Sign with a caller-supplied RSA private key (PKCS#1 v1.5 or PSS); deterministic, so equal inputs give equal bytes.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $k [rsa-private-key [n [$bytes:from-hex "af24194e7e300fd4082219687729562e74f2802e325ed689e372f7e8f829fbb2cc18150067f739c9b11f4ddfa8f6eee3c3d593cb369e571e29771ae0c2a10bc4925e9dbe1b25c4f0f613ab88d45882862390ff2b2a192a8c5306017a7fd285ebf4c49ce75b994013599731ae9531a41136f9b4eefddd0f0f9968b5a56434224f"]] [e [$bytes:from-hex "010001"]] [d [$bytes:from-hex "17c81c139778e93d4e596affcf6672885e62eb5ada861c359f07e677e0f2ba75bdd6eb4b21d2e52ae8fd2a32db9ba4369349f6069b050729565210f9421462277683546a5ce091d57065d1854b68e50874b76b79f493ca4d54119bbb4160c0ed4ae2aeace272f535ee49ad755b0a0addf6b8006eb93ba0baf8375b7c92b03311"]]]]
[= $m [$bytes:from-string-utf8 "sign me"]]
[$bytes:equals [$crypto:rsa-sign $k $m {hash: "sha256"}] [$crypto:rsa-sign $k $m {hash: "sha256"}]]]
true
crypto:rsa-encrypt
[$crypto:rsa-encrypt] -> bytes — RSA key transport: OAEP by default (opts.hash "sha1" — the XML-Enc 1.0 identifier's meaning — mgf1-hash and label optional), or "pkcs1-v1_5". Impure because the OAEP seed and the v1.5 padding are drawn fresh.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $k [rsa-private-key [n [$bytes:from-hex "a0bd273ec9b6cbce2e72d3a74b374b1aa1b374451bd4fb73eaadb81bc437c17fed6c319dbc4d7276230afa1131035a3407bb0c4667242d4641dadd1566c8e48823f844b122915f4c2c50166fee5934ab5762e0121e7d9ac4db7887a25c5ecdcc399257aca6d8ee5454eb78cd0d907ee72c1f940f03815474d7554564abeb7f877bd0d6f37b23142a2451c22109547e11800610297bfc0019755b2ca8a7f2169edc0c23b361d7fe6434a7b74135ddeb37b48c78750db305fc40a465ef31250ad7d555778210787c2821aa347cf44951610bda5d80452cebe2be0217bc6e09733ee17e105be46d468e9195752f4cc36c7bd65b7988ccf45708d45ced8cf702d175"]] [e [$bytes:from-hex "010001"]] [d [$bytes:from-hex "03e9d45d5c0f5f830fa5f0df133ecf77b5eff6ce2243eb48529d1ea24c6d6d6b062bdac1b9492b16d30fc170043662ee93dbf061516c5e797b5679b350f090ac7b85b549c3bff026f1b2e9cceeabb77e2419ee947a5a10027d73bfdcf52c98b6ec1592f2b63adf58931b0add4bd87f57ca544d7d97c0abbea429cf0f48fbea3ba76640db96d4e8c212ba375c36b8311d66e9abb752c9cec34b0c3d97a4f34b53f74b7718b011e60ae447998775b90005b781f94d062ffe06bd08d096e858ffb75ad9e2f0b4cc8d4d3774fc1c4d64eb61a8195146d672958d0df8fe4d7f6bd1823953103ab54b37b1367060ebc117a2da8bcf2bb8f254162b436b449fa6490a59"]]]]
[= $c [$crypto:rsa-encrypt $k [$bytes:from-string-utf8 "a 32-byte AES content key here!"] {hash: "sha1"}]]
[$bytes:to-string-utf8 [$crypto:rsa-decrypt $k $c {hash: "sha1"}]]]
cx-err:CXER0271
crypto:rsa-decrypt
[$crypto:rsa-decrypt] -> bytes — RSA key transport, the other way. OAEP failures raise CXER3720; the "pkcs1-v1_5" arm NEVER raises — it answers a deterministic pseudo-random plaintext of opts.expected-length (default 32), which is what keeps it from being a Bleichenbacher oracle.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[$bytes:to-string-utf8 [$crypto:rsa-decrypt [rsa-private-key [n [$bytes:from-hex "a0bd273ec9b6cbce2e72d3a74b374b1aa1b374451bd4fb73eaadb81bc437c17fed6c319dbc4d7276230afa1131035a3407bb0c4667242d4641dadd1566c8e48823f844b122915f4c2c50166fee5934ab5762e0121e7d9ac4db7887a25c5ecdcc399257aca6d8ee5454eb78cd0d907ee72c1f940f03815474d7554564abeb7f877bd0d6f37b23142a2451c22109547e11800610297bfc0019755b2ca8a7f2169edc0c23b361d7fe6434a7b74135ddeb37b48c78750db305fc40a465ef31250ad7d555778210787c2821aa347cf44951610bda5d80452cebe2be0217bc6e09733ee17e105be46d468e9195752f4cc36c7bd65b7988ccf45708d45ced8cf702d175"]] [e [$bytes:from-hex "010001"]] [d [$bytes:from-hex "03e9d45d5c0f5f830fa5f0df133ecf77b5eff6ce2243eb48529d1ea24c6d6d6b062bdac1b9492b16d30fc170043662ee93dbf061516c5e797b5679b350f090ac7b85b549c3bff026f1b2e9cceeabb77e2419ee947a5a10027d73bfdcf52c98b6ec1592f2b63adf58931b0add4bd87f57ca544d7d97c0abbea429cf0f48fbea3ba76640db96d4e8c212ba375c36b8311d66e9abb752c9cec34b0c3d97a4f34b53f74b7718b011e60ae447998775b90005b781f94d062ffe06bd08d096e858ffb75ad9e2f0b4cc8d4d3774fc1c4d64eb61a8195146d672958d0df8fe4d7f6bd1823953103ab54b37b1367060ebc117a2da8bcf2bb8f254162b436b449fa6490a59"]]] [$bytes:from-hex "5ce2357f027fc091d6007166f827ffe5f6893052d8a08a73caf260cd2a50dae0be065f3bfda511d82a5caaf1db941eb62a8579282faa8fca157a8b76967b8b045682f459465a063bd3ab451233d76ef384513b3d28dd8cdc60950ce98ba67e3df665cb80e96a4e584b243c18bd9f5b42d9bedf5022874eeee48e28629f383f1bd670c7159a8e71bfecc7dc6a4933357dd39647462fea2d6eaae03a2ec5994814aa55d4430843cf89321ca3842a7179d98a2967e450ca12eea07c1e8aec55512444aced1df4a4878b508f972c631f1016ad511e7f8fb5be6f275ded561f3722b5bee84ca9eabd601f46c1635da6efd3e41f5692bc0656fc8a8b4ff86ea33fb961"] {hash: "sha1"}]]
'attack at dawn'
crypto:ecdsa-sign
[$crypto:ecdsa-sign] -> bytes — Sign with a caller-supplied EC private key; the nonce is RFC 6979 deterministic, and the signature is JOSE fixed-width r||s.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $m [$bytes:from-string-utf8 "sign me"]]
[= $sig [$crypto:ecdsa-sign [ec-private-key crv="P-256" [d [$bytes:from-hex "e4219571384fcb5e48a3093856cb2a801453f0ebd002b4021688c593418963be"]]] $m {curve: "P-256" hash: "sha256"}]]
[$crypto:ecdsa-verify [ec-public-key crv="P-256" [x [$bytes:from-hex "e0c83536ab21a881b5db66713c0838e91a2b72e25ade65dc638535f9e445798f"]] [y [$bytes:from-hex "5c646af734c3666d0c8951ec1b5fb5afcacaa730a0187cf0129dbb7934654065"]]] $m $sig {curve: "P-256" hash: "sha256"}]]
true
crypto:password-hash
[$crypto:password-hash] -> string — Hash a password with Argon2id and a fresh salt, returning a self-describing PHC-string.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $enc [$crypto:password-hash [$bytes:from-string-utf8 "correct horse battery staple"] [argon2-cost memory-kib=65536 iterations=3 parallelism=4]]] [$starts-with $enc "$argon2id$v=19$"]]
cx-err:CXER0271
crypto:password-verify
[$crypto:password-verify] -> bool — Verify a password against an Argon2id PHC-string — true on match, raises CXER3706 otherwise.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $pw [$bytes:from-string-utf8 "correct horse battery staple"]] [$crypto:password-verify $pw [$crypto:password-hash $pw [argon2-cost memory-kib=65536 iterations=3 parallelism=4]]]]
cx-err:CXER0271
crypto:jwt-verify
[$crypto:jwt-verify] -> element — Fail-closed verify a JWT against a key set at a given time, returning a [claims] value or raising — never false, never unverified claims.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/time']
[$crypto:claim [$crypto:jwt-verify "eyJhbGciOiJSUzI1NiIsImtpZCI6InJzYS0xIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL2lkcC5leGFtcGxlIiwic3ViIjoidXNlci0xIiwiYXVkIjoibXktYXBpIiwiZXhwIjoxNzAwMDAzNjAwLCJuYmYiOjE2OTk5OTk5OTAsImlhdCI6MTY5OTk5OTk5MH0.e4bn1A_a5Q0_4IZxKWipmmrUCCdmNkiTUs071mBMtMVXb68RGPtV2FTR1nRWvM3Zw2XTMuBsk_Y1HPinat_2JQkm3s90lltrErpYOky6Nwm6ha57BxQ0Sg5kWxuQF5KhWUqHzePIVDTfkr0WeN591nDTDn6VuajLaHn2pjXBsaJ0reT6mh6v40UQcBW-yy-XOfrsMeGVj_qZd1UmlE81XN957rjPENcPpH2E1SHfVhu3fQP3QZapxtdMADgWmryw_z5O2lDIIWb7miT0siXRCDjVEhDzKH6Hsf1aUPcYx9x44o1B5OBpX6z1uM1SP0qaOZu6x26H0AbHj84nIISE1A" [$crypto:jwks-parse "{\"keys\":[{\"kid\":\"rsa-1\",\"kty\":\"RSA\",\"alg\":\"RS256\",\"n\":\"jdwwBcaMZQLoSNYGNEm3l03HIQqpRIv0eqLUNUCkyv7ysVw4i6vZgdYxcdU0D3kSvUCIjH-icqk4PCDx5AwkeNp55Nqt6wKXDv9TH5pr-Wc3BWmZ1sEOEwyN8QlI8_5EpY3i1w5tysDdeFuiR7BOjpkD49RZzF0YajmocsB4_jXoZcldVNCOChXAbEfOw-BtjFJRN0N3EksymF4azkey8Q3rX07sXkRHavRfAOnowH119RL1V-Xmk_DUX8wSR-2zdlp8FxitJWPgbMmnszsTgEQrThTwsuMrndqzJ_nQ7HTnuK2LXEFmFwXw9NADspq2ZnQmZiN7CXnEYG8WCApzxw\",\"e\":\"AQAB\"},{\"kid\":\"ec-1\",\"kty\":\"EC\",\"crv\":\"P-256\",\"alg\":\"ES256\",\"x\":\"l9ScLzJ2g8ZHlc4zx6jqkLbrw9NB_j7ORJ2HTQBgGeQ\",\"y\":\"spBDqXfgXOdqDGs4_WenZEmRFmy71qts1dMEp8xrg6M\"},{\"kid\":\"ed-1\",\"kty\":\"OKP\",\"crv\":\"Ed25519\",\"alg\":\"EdDSA\",\"x\":\"W7aFRt4kKu7VuwPv6oBWPpxSwy9jCzk2QqawxURsnsk\"}]}"] [$time:datetime 2023 11 14 22 13 20] {}] "iss"]
'https://idp.example'
crypto:jwt-sign
[$crypto:jwt-sign] -> string — Sign a claim-set into a compact JWS — the client-authentication assertion (private_key_jwt); pure, and reads no clock.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?lib 'cx-stdlib/time']
[?let [= $key [ec-private-key crv="P-256" [d [$bytes:from-hex "e4219571384fcb5e48a3093856cb2a801453f0ebd002b4021688c593418963be"]]]]
[= $pub [ec-public-key crv="P-256" [x [$bytes:from-hex "e0c83536ab21a881b5db66713c0838e91a2b72e25ade65dc638535f9e445798f"]] [y [$bytes:from-hex "5c646af734c3666d0c8951ec1b5fb5afcacaa730a0187cf0129dbb7934654065"]]]]
[= $t [$crypto:jwt-sign {iss: "client-1", sub: "client-1", aud: "https://idp.example/token", exp: 1700003600} $key {alg: "ES256"}]]
[$crypto:claim [$crypto:jwt-verify $t $pub [$time:datetime 2023 11 14 22 13 20] {}] "aud"]]
'https://idp.example/token'
crypto:jwks-fetch
[$crypto:jwks-fetch] -> element — GET a JWKS document over http and return a parsed [jwks] — non-2xx, transport fault, or non-JWKS body raises CXER3716.
[?lib 'cx-stdlib/crypto']
[$crypto:jwks-fetch "https://idp.example/.well-known/jwks.json" {}]
cx-err:CXER0271
crypto:jwks-parse
[$crypto:jwks-parse] -> element — Parse already-fetched JWKS JSON into a [jwks] value — malformed or inconsistent alg/kty raises CXER3717.
[?lib 'cx-stdlib/crypto']
[?let [= $k [$crypto:jwk-by-kid [$crypto:jwks-parse "{\"keys\":[{\"kid\":\"rsa-1\",\"kty\":\"RSA\",\"alg\":\"RS256\",\"n\":\"jdwwBcaMZQLoSNYGNEm3l03HIQqpRIv0eqLUNUCkyv7ysVw4i6vZgdYxcdU0D3kSvUCIjH-icqk4PCDx5AwkeNp55Nqt6wKXDv9TH5pr-Wc3BWmZ1sEOEwyN8QlI8_5EpY3i1w5tysDdeFuiR7BOjpkD49RZzF0YajmocsB4_jXoZcldVNCOChXAbEfOw-BtjFJRN0N3EksymF4azkey8Q3rX07sXkRHavRfAOnowH119RL1V-Xmk_DUX8wSR-2zdlp8FxitJWPgbMmnszsTgEQrThTwsuMrndqzJ_nQ7HTnuK2LXEFmFwXw9NADspq2ZnQmZiN7CXnEYG8WCApzxw\",\"e\":\"AQAB\"},{\"kid\":\"ec-1\",\"kty\":\"EC\",\"crv\":\"P-256\",\"alg\":\"ES256\",\"x\":\"l9ScLzJ2g8ZHlc4zx6jqkLbrw9NB_j7ORJ2HTQBgGeQ\",\"y\":\"spBDqXfgXOdqDGs4_WenZEmRFmy71qts1dMEp8xrg6M\"},{\"kid\":\"ed-1\",\"kty\":\"OKP\",\"crv\":\"Ed25519\",\"alg\":\"EdDSA\",\"x\":\"W7aFRt4kKu7VuwPv6oBWPpxSwy9jCzk2QqawxURsnsk\"}]}"] "ec-1"]] $k@kty]
EC
crypto:certificate-key
[$crypto:certificate-key] -> element — Read an X.509 certificate's SubjectPublicKeyInfo into an [rsa-public-key] / [ec-public-key] — DER bytes, PEM, or the bare base64 an IdP's <ds:X509Certificate> carries. No chain, no validity window, no revocation: trusting the certificate happened when it was configured (RULED: 1287-Q1).
[?lib 'cx-stdlib/crypto' as=crypto]
[?lib 'cx-stdlib/bytes' as=bytes]
[?let [= $k [$crypto:certificate-key "MIIBhjCCAS2gAwIBAgIUeiYVce7ieSYJfQHqrDFWv4cv8AwwCgYIKoZIzj0EAwIwGTEXMBUGA1UEAwwOaWRwLWVjLmV4YW1wbGUwHhcNMjYwOTA1MTQyNTM3WhcNMzYwOTAyMTQyNTM3WjAZMRcwFQYDVQQDDA5pZHAtZWMuZXhhbXBsZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFBopgvqME1BHXMxZD8KIpAaNI1vv5F1BnkXFDeyIud11EsfmqTgJJ2CDHNnQLdNDRvnqaa12nWLEhcgnXi/iH6jUzBRMB0GA1UdDgQWBBSrcc4H0O84aTC8mlGdcebpdAc6gzAfBgNVHSMEGDAWgBSrcc4H0O84aTC8mlGdcebpdAc6gzAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0cAMEQCIFoZwyPzqZ138Bvmm+fxVi2nlgKQ4xyMu7rm9UDtqDykAiASj4+iWZ8I6/MFyROL4HYosee6Fc3nlksTIIzB/Ae/zQ=="]]
[key crv=$k@crv x=[$bytes:to-hex $k@x] y=[$bytes:to-hex $k@y]]]
[key crv=P-256 x='5068a60bea304d411d7331643f0a22901a348d6fbf91750679171437b222e775' y=d44b1f9aa4e0249d820c736740b74d0d1be7a9a6b5da758b1217209d78bf887e]
crypto:certificate-validity
[$crypto:certificate-validity] -> map — Read an X.509 certificate's validity window into {not-before, not-after} datetimes — RFC 5280 UTCTime with the 50-year pivot, or GeneralizedTime. It REPORTS; it never decides, and it reads no clock: saml:metadata publishes each key's window and the administrator importing the document acts on an expiry (RULED: 1402-a, 1410-b).
[?lib 'cx-stdlib/crypto' as=crypto]
[?lib 'cx-stdlib/map' as=map]
[?let [= $w [$crypto:certificate-validity "MIIBhjCCAS2gAwIBAgIUeiYVce7ieSYJfQHqrDFWv4cv8AwwCgYIKoZIzj0EAwIwGTEXMBUGA1UEAwwOaWRwLWVjLmV4YW1wbGUwHhcNMjYwOTA1MTQyNTM3WhcNMzYwOTAyMTQyNTM3WjAZMRcwFQYDVQQDDA5pZHAtZWMuZXhhbXBsZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFBopgvqME1BHXMxZD8KIpAaNI1vv5F1BnkXFDeyIud11EsfmqTgJJ2CDHNnQLdNDRvnqaa12nWLEhcgnXi/iH6jUzBRMB0GA1UdDgQWBBSrcc4H0O84aTC8mlGdcebpdAc6gzAfBgNVHSMEGDAWgBSrcc4H0O84aTC8mlGdcebpdAc6gzAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0cAMEQCIFoZwyPzqZ138Bvmm+fxVi2nlgKQ4xyMu7rm9UDtqDykAiASj4+iWZ8I6/MFyROL4HYosee6Fc3nlksTIIzB/Ae/zQ=="]]
([$map:get $w "not-before"], [$map:get $w "not-after"])]
(2026-09-05T14:25:37Z, 2036-09-02T14:25:37Z)
crypto:claim
[$crypto:claim] -> element — Read a named claim from a verified [claims] value — absent yields the absence channel, never null.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/time']
[$crypto:claim [$crypto:jwt-verify "eyJhbGciOiJSUzI1NiIsImtpZCI6InJzYS0xIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL2lkcC5leGFtcGxlIiwic3ViIjoidXNlci0xIiwiYXVkIjoibXktYXBpIiwiZXhwIjoxNzAwMDAzNjAwLCJuYmYiOjE2OTk5OTk5OTAsImlhdCI6MTY5OTk5OTk5MH0.e4bn1A_a5Q0_4IZxKWipmmrUCCdmNkiTUs071mBMtMVXb68RGPtV2FTR1nRWvM3Zw2XTMuBsk_Y1HPinat_2JQkm3s90lltrErpYOky6Nwm6ha57BxQ0Sg5kWxuQF5KhWUqHzePIVDTfkr0WeN591nDTDn6VuajLaHn2pjXBsaJ0reT6mh6v40UQcBW-yy-XOfrsMeGVj_qZd1UmlE81XN957rjPENcPpH2E1SHfVhu3fQP3QZapxtdMADgWmryw_z5O2lDIIWb7miT0siXRCDjVEhDzKH6Hsf1aUPcYx9x44o1B5OBpX6z1uM1SP0qaOZu6x26H0AbHj84nIISE1A" [$crypto:jwks-parse "{\"keys\":[{\"kid\":\"rsa-1\",\"kty\":\"RSA\",\"alg\":\"RS256\",\"n\":\"jdwwBcaMZQLoSNYGNEm3l03HIQqpRIv0eqLUNUCkyv7ysVw4i6vZgdYxcdU0D3kSvUCIjH-icqk4PCDx5AwkeNp55Nqt6wKXDv9TH5pr-Wc3BWmZ1sEOEwyN8QlI8_5EpY3i1w5tysDdeFuiR7BOjpkD49RZzF0YajmocsB4_jXoZcldVNCOChXAbEfOw-BtjFJRN0N3EksymF4azkey8Q3rX07sXkRHavRfAOnowH119RL1V-Xmk_DUX8wSR-2zdlp8FxitJWPgbMmnszsTgEQrThTwsuMrndqzJ_nQ7HTnuK2LXEFmFwXw9NADspq2ZnQmZiN7CXnEYG8WCApzxw\",\"e\":\"AQAB\"},{\"kid\":\"ec-1\",\"kty\":\"EC\",\"crv\":\"P-256\",\"alg\":\"ES256\",\"x\":\"l9ScLzJ2g8ZHlc4zx6jqkLbrw9NB_j7ORJ2HTQBgGeQ\",\"y\":\"spBDqXfgXOdqDGs4_WenZEmRFmy71qts1dMEp8xrg6M\"},{\"kid\":\"ed-1\",\"kty\":\"OKP\",\"crv\":\"Ed25519\",\"alg\":\"EdDSA\",\"x\":\"W7aFRt4kKu7VuwPv6oBWPpxSwy9jCzk2QqawxURsnsk\"}]}"] [$time:datetime 2023 11 14 22 13 20] {}] "iss"]
'https://idp.example'
crypto:xml-sign
[$crypto:xml-sign] -> string — Insert an enveloped XML-DSig ds:Signature into a document, over the element opts.id names: exclusive C14N with the enveloped-signature transform, SHA-256 digest, rsa-sha256 or ecdsa-sha256 chosen from the key, and KeyInfo :none / :x509 / :key-name. The answer is the caller's own octets with one signature spliced in — nothing else moves. opts.references — a list of reference ids, resolved against ID / Id / wsu:Id — selects the DETACHED mode instead: one Reference per named node in list order, exclusive C14N as each Reference's only transform, and the ds:Signature answered STANDALONE for the caller to place, which is what WS-Security needs. Pure and deterministic, so a signed request is reproducible (RULED: 1394-b, 1502-a).
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?lib 'cx-stdlib/strings']
[?let [= $signed [$crypto:xml-sign '<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_a1" Version="2.0" IssueInstant="2026-09-12T12:00:00Z" Destination="https://idp.example/sso"><saml:Issuer>https://sp.example</saml:Issuer></samlp:AuthnRequest>' [ec-private-key crv="P-256" [d [$bytes:from-hex "0bd5ce1d4dd3f581558f42c420be72b9247d1d9a780bf3079ad18557abe6e98f"]]] {id: "_a1", key-info: :none}]]
[$strings:contains $signed '<ds:Reference URI="#_a1">']]
true
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?lib 'cx-stdlib/strings']
[?let [= $sig [$crypto:xml-sign '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><soap:Header><wsu:Timestamp wsu:Id="_ts"><wsu:Created>2026-09-15T00:00:00Z</wsu:Created></wsu:Timestamp></soap:Header><soap:Body wsu:Id="_body"><t:Ping xmlns:t="urn:example:t">hello</t:Ping></soap:Body></soap:Envelope>' [ec-private-key crv="P-256" [d [$bytes:from-hex "0bd5ce1d4dd3f581558f42c420be72b9247d1d9a780bf3079ad18557abe6e98f"]]] {references: ("_body")}]]
[$strings:contains $sig '<ds:Reference URI="#_body">']]
true
crypto:xml-verify
[$crypto:xml-verify] -> element — Verify one XML-DSig signature in the shapes xml-sign writes — enveloped (one Reference over the element the signature sits in) or detached (opts.signature, the standalone ds:Signature; or one placed in the document) — under the caller's key or keys alone, KeyInfo never trusted; exclusive C14N, rsa-sha256/384/512 or ecdsa-sha256/384/512, SHA-1 refused. Answers [xml-verified mode=… [reference id=…] …]; opts.references names ids the signature must cover. Any failure is CXER3722.
[?lib 'cx-stdlib/crypto']
[?lib 'cx-stdlib/bytes']
[?let [= $signed [$crypto:xml-sign '<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_a1" Version="2.0" IssueInstant="2026-09-12T12:00:00Z"><saml:Issuer>https://sp.example</saml:Issuer></samlp:AuthnRequest>' [ec-private-key crv="P-256" [d [$bytes:from-hex "0bd5ce1d4dd3f581558f42c420be72b9247d1d9a780bf3079ad18557abe6e98f"]]] {id: "_a1"}]]
[= $v [$crypto:xml-verify $signed [ec-public-key crv="P-256" [x [$bytes:from-hex "e016ea4fdb3d5d5ceecee126633cbf6f52661359f05eef034bd2140f36ac0f28"]] [y [$bytes:from-hex "27a9f49e325cbdcefb594e57ce6cc6980d0db1360402625f8fa0cb247f8e7e2e"]]] {references: ("_a1")}]]
($v@mode, $v/reference@id)]
(enveloped, _a1)
crypto:jwk-by-kid
[$crypto:jwk-by-kid] -> element — Select a [jwk] from a [jwks] by key id — no match yields the absence channel.
[?lib 'cx-stdlib/crypto']
[?let [= $k [$crypto:jwk-by-kid [$crypto:jwks-parse "{\"keys\":[{\"kid\":\"rsa-1\",\"kty\":\"RSA\",\"alg\":\"RS256\",\"n\":\"jdwwBcaMZQLoSNYGNEm3l03HIQqpRIv0eqLUNUCkyv7ysVw4i6vZgdYxcdU0D3kSvUCIjH-icqk4PCDx5AwkeNp55Nqt6wKXDv9TH5pr-Wc3BWmZ1sEOEwyN8QlI8_5EpY3i1w5tysDdeFuiR7BOjpkD49RZzF0YajmocsB4_jXoZcldVNCOChXAbEfOw-BtjFJRN0N3EksymF4azkey8Q3rX07sXkRHavRfAOnowH119RL1V-Xmk_DUX8wSR-2zdlp8FxitJWPgbMmnszsTgEQrThTwsuMrndqzJ_nQ7HTnuK2LXEFmFwXw9NADspq2ZnQmZiN7CXnEYG8WCApzxw\",\"e\":\"AQAB\"},{\"kid\":\"ec-1\",\"kty\":\"EC\",\"crv\":\"P-256\",\"alg\":\"ES256\",\"x\":\"l9ScLzJ2g8ZHlc4zx6jqkLbrw9NB_j7ORJ2HTQBgGeQ\",\"y\":\"spBDqXfgXOdqDGs4_WenZEmRFmy71qts1dMEp8xrg6M\"},{\"kid\":\"ed-1\",\"kty\":\"OKP\",\"crv\":\"Ed25519\",\"alg\":\"EdDSA\",\"x\":\"W7aFRt4kKu7VuwPv6oBWPpxSwy9jCzk2QqawxURsnsk\"}]}"] "ec-1"]] $k@kty]
EC