NAME
std/secure - Secure runtime services and capability inspection.
SYNOPSIS
from std/secure import
Secure,
SecureRandom,
PasswordHash,
KeyDerivation,
Cipher,
KeyAgreement,
SigningKey,
Certificate,
PrivateKey,
PublicKey,
SealedBox,
TlsIdentity;
let caps := Secure.capabilities();
Secure.require( "random", "bytes" );
IMPLEMENTATION SUPPORT
This module is supported by all implementations of ZuzuScript, though the ciphers, hashes, and other algorithms supported by the module vary from platform to platform. Many synchronous operations are unsupported by zuzu-js on the browser; using async variants is recommended if you need to support that platform.
DESCRIPTION
This runtime-supported module is the public namespace for secure random generation, key derivation, authenticated encryption, password hashing, signing, key agreement, certificate handling, and TLS identity objects.
It implements secure random bytes, URL-safe random tokens, unbiased random integers, host identification, capability queries, HKDF-SHA256 key derivation, AES-256-GCM authenticated encryption, password hashing, Ed25519 and ECDSA signing, and X25519 key agreement.
EXPORTS
Classes
SecureModule-level inspection and policy namespace. It currently exposes
capabilities(),has(area, name), andrequire(area, name).SecureRandomNamespace for CSPRNG byte, token, and integer helpers.
PasswordHashNamespace for password hashing, verification, rehash detection, and passphrase key derivation.
KeyDerivationNamespace for future high-entropy key derivation helpers such as HKDF-SHA256.
CipherNamespace for authenticated symmetric encryption helpers. It currently supports AES-256-GCM envelopes.
KeyAgreementNamespace and object type for X25519 key agreement.
SigningKeyandPublicKeyNamespaces and object types for Ed25519 and ECDSA asymmetric signing, verification, and key material handling.
PrivateKeyPlaceholder object type for future non-signing private-key handling.
CertificateandTlsIdentityCertificateis the X.509 parsing and inspection object type.TlsIdentitystores client certificate identity material for future TLS integrations.SealedBoxNamespace for future public-key sealed-box encryption recipes.
Capability Reporting
Secure.capabilities() returns a Dict with stable keys:
{
host: "perl",
random: true,
password_hash: [ "argon2id", "crypt", "pbkdf2-sha256", "scrypt" ],
kdf: [ "hkdf-sha256" ],
cipher: [
"aes-128-gcm",
"aes-192-gcm",
"aes-256-gcm",
"chacha20-poly1305",
],
key_agreement: [ "x25519" ],
signing: [
"ed25519",
"ecdsa-p256-sha256",
"ecdsa-p384-sha384",
"ecdsa-p521-sha512",
],
certificate: [
"fingerprint-sha256",
"fingerprint-sha384",
"fingerprint-sha512",
"parse-x509",
"parse-x509-der",
"public-key",
"verify-chain",
],
tls_identity: [ "pem", "pkcs12" ],
async_required: {
cipher: false,
kdf: false,
password_hash: false,
signing: false,
key_agreement: false,
},
}
host identifies the runtime host that produced the report. The current host names are perl, rust, node, and browser.
Later phases will turn on additional capabilities only after the corresponding runtime has a real implementation.
Browser hosts do not advertise ed25519 in signing and reject it in this phase even when a specific Web Crypto implementation exposes it. Browser hosts advertise ECDSA signing and report async_required.signing as true. Browser hosts also report async_required.key_agreement as true when X25519 is available through Web Crypto.
Capability Vocabulary
Capability areas and names are stable strings. random currently supports bytes, token, and int. password_hash always supports pbkdf2-sha256; hosts may additionally report argon2id, scrypt, or legacy crypt. kdf currently supports hkdf-sha256. cipher always supports aes-256-gcm; hosts may add aes-128-gcm, aes-192-gcm, or chacha20-poly1305. key_agreement currently supports x25519. signing may include ed25519, ecdsa-p256-sha256, ecdsa-p384-sha384, and ecdsa-p521-sha512. The certificate area reports X.509 parsing, fingerprinting, public-key extraction, and chain verification support. tls_identity reports pem and, where available, pkcs12.
Secure.has(String area, String name)Returns
trueif the current host supportsnamewithinarea. Unknown, missing, or null values returnfalse.Secure.require(String area, String name)Returns
trueif the current host supportsnamewithinarea. Otherwise it throws a runtime exception with the unsupportedarea/namepair and the current host name in the message.
Password Hashing
PasswordHash.default_algorithm()Returns
pbkdf2-sha256. This is the portable password-hash baseline for every host. Hosts may report stronger additional password-hash algorithms throughSecure.capabilities(){password_hash}.scryptand especiallycryptare exposed for compatibility only and are not preferred for new password storage. Treatcryptas a legacy, inadequate password-hash mechanism.PasswordHash.hash(String password, Dict options = {})Returns an encoded password hash.
options.algorithmdefaults topbkdf2-sha256.options.saltmay provide aBinaryStringsalt for tests and deterministic fixtures; ordinary callers should omit it.The portable encoded PBKDF2 form is:
$zuzu-pbkdf2-sha256$v=1$i=600000,l=32$base64url_salt$base64url_hashArgon2id uses PHC-style Argon2id encoding:
$argon2id$v=19$m=19456,t=2,p=1$base64salt$base64hashScrypt uses:
$scrypt$ln=17,r=8,p=1,l=32$base64url_salt$base64url_hashLegacy
crypthashes use a host-specific format and are only for compatibility with existing password stores.PasswordHash.hash_async(...)Returns a
Taskresolving to the same encoded hash. Browser hosts require this method for password hashing and currently supportpbkdf2-sha256only.PasswordHash.verify(String password, String encoded_hash)Returns
truewhenpasswordmatchesencoded_hash. Unknown, malformed, or unsupported encoded hashes returnfalse.PasswordHash.verify_async(...)Returns a
Taskresolving to the same boolean result. Browser hosts require this method for password verification.PasswordHash.needs_rehash(String encoded_hash, Dict options = {})Returns
trueifencoded_hashis malformed, uses a different algorithm fromoptions.algorithm, uses weaker parameters than the current options, or usescrypt.PasswordHash.derive_key(String password, Dict options)Derives raw key material from a passphrase and returns it as a
BinaryString.options.saltis required and must be aBinaryString. This method supports PBKDF2, Argon2id, and scrypt where the host reports those capabilities; it does not supportcrypt.PasswordHash.derive_key_async(...)Returns a
Taskresolving to the sameBinaryString. Browser hosts require this method for passphrase key derivation.
Key Derivation
KeyDerivation.hkdf_sha256(input_key_material, length, salt, info)Returns
lengthbytes of HKDF-SHA256 output as aBinaryString.input_key_materialmust already be high-entropy key material. This is not the password-hashing API.lengthmust be an integer from0through8160.saltandinfomust beBinaryStringvalues ornull. Null salt and info are treated as empty values.KeyDerivation.hkdf_sha256_async(...)Returns a
Taskresolving to the sameBinaryStringoutput. Browser hosts may use Web Crypto promises internally; CLI hosts may return an already fulfilled task.
Cipher
Cipher.generate_key(String algorithm = "aes-256-gcm")Returns a
BinaryStringkey for the requested cipher algorithm.aes-128-gcmuses 16-byte keys,aes-192-gcmuses 24-byte keys, andaes-256-gcmandchacha20-poly1305use 32-byte keys. CheckSecure.capabilities()before relying on optional cipher algorithms.Cipher.encrypt(BinaryString plaintext, BinaryString key, Dict options = {})Encrypts and authenticates
plaintext.keymust match the selected algorithm length.options.algorithmdefaults toaes-256-gcm; hosts may advertise additional algorithms throughSecure.capabilities().options.aadmay provide additional authenticated data as aBinaryString. The runtime generates a fresh 12-byte nonce for each call.The returned envelope is a
Dict:{ version: 1, algorithm: "aes-256-gcm", nonce: b"...", ciphertext: b"...", tag: b"...", }nonceis 12 bytes andtagis 16 bytes for the currently supported AEAD ciphers.Cipher.decrypt(Dict envelope, BinaryString key, Dict options = {})Verifies and decrypts a cipher envelope. If
options.algorithmis provided, it must matchenvelope.algorithm. Authentication failure, including a wrong key, wrong AAD, or tampered envelope, throws an exception.Cipher.encrypt_async(...)Cipher.decrypt_async(...)Return
Taskvalues resolving to the corresponding synchronous result. Browser hosts use Web Crypto and require the async methods for cipher operations. CLI hosts may return already fulfilled tasks.
Signing
Signing algorithms are reported through Secure.capabilities(). ECDSA P-256 with SHA-256 and ECDSA P-384 with SHA-384 are the portable ECDSA names. Some hosts also support Ed25519 or ECDSA P-521 with SHA-512. Browser hosts may require async signing methods.
SigningKey.generate(String algorithm = "ed25519")Generates a new signing key. Common algorithms are
ed25519,ecdsa-p256-sha256,ecdsa-p384-sha384, andecdsa-p521-sha512. The default ised25519.SigningKey.generate_async(...)returns aTaskresolving to the same kind of key.SigningKey.import_private(key, Dict options = {})Imports a private signing key.
options.formatmay beraworpem; when it is omitted,BinaryStringkeys default torawandStringkeys default topem. Raw private keys are 32-byte Ed25519 seeds, 32-byte P-256 scalars, 48-byte P-384 scalars, or 66-byte P-521 scalars where supported. Raw ECDSA private-key import should passoptions.algorithmto avoid ambiguity with Ed25519. PEM private keys are importable as Ed25519 PKCS#8, ECDSA PKCS#8, or traditional EC private-key PEM where the host supports it.SigningKey.import_private_async(...)returns aTaskresolving to the same kind of key.SigningKey.import_public(key, Dict options = {})Imports a public key. Raw Ed25519 public keys are 32 bytes. Raw P-256 public keys are 65-byte SEC1 uncompressed points, and raw P-384 public keys are 97-byte SEC1 uncompressed points. Compressed EC points are not supported. PEM public keys use SPKI.
options.formatfollows the same rules asimport_private.SigningKey.import_public_async(...)returns aTaskresolving to aPublicKey.SigningKey.public_key()Returns the matching
PublicKey.SigningKey.sign(BinaryString message)Signs
messageand returns aBinaryStringsignature. Ed25519 signatures are 64 bytes. ECDSA signatures are DER encoded.SigningKey.sign_async(...)returns aTaskresolving to the same signature.SigningKey.export_private(Dict options = {})Exports private signing-key material. The default
rawformat returns a 32-byte Ed25519 seed, 32-byte P-256 scalar, or 48-byte P-384 scalar as aBinaryString.format: "pem"returns PEM text where supported.PublicKey.verify(BinaryString message, BinaryString signature)Returns
truewhensignatureis a valid signature formessage. Wrong messages, wrong keys, malformed DER, invalid ECDSA points, and algorithm mismatches returnfalse.PublicKey.verify_async(...)returns aTaskresolving to the same boolean result.PublicKey.export(Dict options = {})Exports public key material. The default
rawformat returns a 32-byte Ed25519 public key, a 65-byte P-256 SEC1 uncompressed point, or a 97-byte P-384 SEC1 uncompressed point. For X25519 public keys, it returns the 32-byte Montgomery public key.format: "pem"returns SPKI PEM as aStringfor signing keys; X25519 public keys only supportrawin this phase.
Key Agreement
X25519 key agreement is available as the key_agreement/x25519 capability. It produces a raw 32-byte shared secret, which applications should normally pass through KeyDerivation.hkdf_sha256 with protocol-specific info before using it as an encryption key.
Browser hosts require the async key-agreement methods when X25519 is available through Web Crypto.
KeyAgreement.generate(String algorithm = "x25519")Generates a new X25519 key-agreement object. The only supported algorithm is
x25519.KeyAgreement.generate_async(...)returns aTaskresolving to the same kind of object.KeyAgreement.import_private(BinaryString key, Dict options = {})Imports a raw 32-byte X25519 private key.
options.algorithmmay bex25519, andoptions.formatmay beraw. PEM import is not part of this phase.KeyAgreement.import_private_async(...)returns aTaskresolving to the same kind of object.KeyAgreement.import_public(BinaryString key, Dict options = {})Imports a raw 32-byte X25519 public key and returns a
PublicKey.KeyAgreement.import_public_async(...)returns aTaskresolving to aPublicKey.KeyAgreement.public_key()Returns the matching X25519
PublicKey.KeyAgreement.export_private(Dict options = {})Exports the raw 32-byte X25519 private key as a
BinaryString. Onlyformat: "raw"is supported.KeyAgreement.derive(PublicKey peer)Derives a raw 32-byte shared secret using a peer X25519
PublicKeyand returns it as aBinaryString. Signing public keys and other algorithms are rejected.KeyAgreement.derive_async(...)returns aTaskresolving to the same shared secret.
Certificates
X.509 certificate parsing is available as certificate capabilities. Hosts may support PEM text, DER bytes, or both. Unsupported formats throw clear errors.
Certificate.parse(String pem)Parses one PEM certificate and returns a
Certificate. This is not available on browser hosts.Certificate.parse(BinaryString der)Parses one DER certificate and returns a
Certificate.Certificate.parse_chain(String pem)Parses one or more PEM certificates and returns an
ArrayofCertificateobjects. This is not available on browser hosts.Certificate.parse_chain(BinaryString der)Parses one DER certificate and returns a one-element
Array.Certificate.subject()andCertificate.issuer()Return string renderings of the certificate subject and issuer names. Structured distinguished-name dictionaries are deferred.
Certificate.serial_number()Returns the serial number as uppercase hexadecimal text with no separators.
Certificate.not_before()andCertificate.not_after()Return
std/timeTimeobjects for the certificate validity bounds.Certificate.fingerprint(String algorithm = "sha256")Returns the certificate fingerprint as a
BinaryString.sha256is the portable baseline; hosts may also supportsha384andsha512.Certificate.to_der()Returns the original DER certificate bytes as a
BinaryString.Certificate.to_pem()Returns canonical
CERTIFICATEPEM text.Certificate.public_key()Returns a
PublicKeyfor supported certificate public-key algorithms. Unsupported algorithms throw clearly.Certificate.verify_chain(Array chain, Dict options = {})Verifies an X.509 chain where the host supports chain verification.
chain[0]is the leaf certificate; later entries are intermediates. Trust roots are supplied throughoptions.roots, which may be aCertificate, PEMString,Arrayof those values, ornull.options.use_system_rootsdefaults tofalse; when true, CLI hosts also use the host system trust store.options.hostnamemay be aStringornull.options.timemay be astd/timeTime, numeric epoch seconds, ornull; omitted or null values use the current time.The method returns a
Dictwithvalid,reason,error,hostname,verified_at, andchain_length. Validation failures returnvalid: falsewith a stable reason such asuntrusted-root,expired,not-yet-valid,hostname-mismatch, orinvalid-chain. Bad argument types throw.
TLS Identities
TLS identity objects are parsed and inspected by std/secure and can be supplied to std/net/http UserAgent or Request objects for mutual-TLS client authentication. PEM certificate input may contain a chain; the first certificate is treated as the leaf certificate. The full chain is retained internally for HTTP TLS use, but this phase does not expose a public chain accessor.
TlsIdentity.from_pem(String certificate_pem, String private_key_pem, String password = null)Parses PEM identity material and returns a
TlsIdentity.passwordnullmeans an empty passphrase. Browser hosts accept PEM identities, but the identity is inert for signing-key extraction.TlsIdentity.from_pkcs12(BinaryString bytes, String password = null)Parses PKCS#12 identity material where supported.
passwordnullmeans an empty passphrase.TlsIdentity.certificate()Returns the leaf certificate as a
Certificate.TlsIdentity.private_key()Returns a
SigningKeyfor supported private-key algorithms. Unsupported key algorithms throw clearly.
Secure Random
SecureRandom.bytes(Number length)Returns a
BinaryStringof exactlylengthbytes from the host CSPRNG.lengthmust be a non-negative integer.SecureRandom.token(Number bytes = 32)Returns URL-safe Base64 text with no padding, generated from
bytesrandom bytes.bytesmust be a non-negative integer.SecureRandom.int(Number max)Returns a number in the range
0tomax - 1.maxmust be a positive integer no greater than2^53. The implementation uses rejection sampling to avoid modulo bias.
Async Contract
Every supported asynchronous secure operation will expose an async method on every runtime. Browser implementations may need async methods for Web Crypto promises. CLI implementations may return already completed tasks when an operation is naturally synchronous.
async_required reports which areas need asynchronous APIs on the current host. The keys are stable even before those areas are implemented.
COPYRIGHT AND LICENCE
std/secure is copyright Toby Inkster.
It is free software; you may redistribute it and/or modify it under the terms of either the Artistic License 1.0 or the GNU General Public License version 2.