Crypto primitives

Elide ships a shared cryptographic primitives layer in dev.elide.lang.javascript.crypto.primitives. It is host-internal — guest JavaScript does not see it directly. The Node crypto module and the WHATWG crypto.subtle global consume it.

Coverage

FamilyAlgorithmsBackend
HashSHA-1, SHA-2 (224 / 256 / 384 / 512 / 512-224 / 512-256), SHA-3 (224 / 256 / 384 / 512), MD5JCE
HashBLAKE2b, BLAKE2s, BLAKE3Native
HMACMD5, SHA-1, SHA-2 (224 / 256 / 384 / 512), SHA-3 (224 / 256 / 384 / 512) — not 512-224, 512-256, or BLAKE; no MD5 PRF for KDFsJCE
KDFPBKDF2 (any HMAC PRF), HKDF (any HMAC PRF)JCE
KDFscrypt (RFC 7914), Argon2 (Argon2d / 2i / 2id)Native
SymmetricAES-{128, 192, 256}-{CBC, CTR, GCM, KW}JCE
AEADAES-{128, 192, 256}-GCM (already covered above)JCE
AEADChaCha20-Poly1305, XChaCha20-Poly1305, AES-{128, 256}-GCM-SIVNative
SignatureRSA PKCS#1 v1.5 over SHA-{1, 256, 384, 512}; RSA-PSS over SHA-{256, 384, 512}JCE
SignatureECDSA on P-256 / P-384 / P-521JCE
SignatureEd25519Native
Key agreementECDH on P-256 / P-384 / P-521JCE
Key agreementX25519Native
RandomrandomBytes, fill, randomInt (rejection sampling, no modulo bias)JCE
Constant-time eqTimingSafeEqual.equals(...)JCE
Key import/exportPKCS#8 (private), SubjectPublicKeyInfo (public) for RSA / ECJCE

Public types

CryptoException                       // RuntimeException for malformed input / auth failure
HashAlgorithm                         // SHA*, SHA3*, MD5, BLAKE2b/2s, BLAKE3
HmacAlgorithm                         // HMAC over MD5, SHA-1, SHA-2 (224-512), SHA-3
SymmetricAlgorithm                    // AES variants + ChaCha20-Poly1305 + AES-GCM-SIV
SignatureAlgorithm                    // RSA-PKCS1, RSA-PSS, ECDSA-P{256,384,521}, Ed25519
KeyAgreementAlgorithm                 // ECDH-P{256,384,521}, X25519
Argon2Type                            // ARGON2D, ARGON2I, ARGON2ID

Hash, Hmac                            // streaming digester / MAC, AutoCloseable
Pbkdf2, Hkdf                          // one-shot KDFs (JCE-served)
Scrypt, Argon2                        // one-shot KDFs (native-served)
SymmetricCipher                       // seal / open
Signer                                // sign / verify, plus signEd25519 / verifyEd25519 / generateEd25519KeyPair
KeyExchange                           // agree (ECDH), agreeX25519, generateX25519KeyPair, x25519PublicFromSecret
KeyMaterial                           // PKCS#8 / SPKI parse + encode, RSA / EC keypair generation
SecureRandomSource                    // randomBytes, fill, randomInt
TimingSafeEqual                       // constant-time compare

CryptoBackends                        // registry holding the optional native backend
NativeCryptoBackend                   // SPI for the FFM-backed engine
NativeCrypto                          // FFM bridge + tryInstall()

Backend model

JCE-served algorithms call into the JDK directly — no provider hook is needed because JCE itself is pluggable at the JVM level. Native-served algorithms route through the optional [NativeCryptoBackend] installed on [CryptoBackends]. The runtime calls [NativeCrypto.tryInstall()][NativeCrypto] during startup; before that runs (and on systems where libelideruntime is missing), every native-only operation surfaces a clear UnsupportedOperationException explaining what is missing.

The native side is a Rust shim around RustCrypto crates: blake2, blake3, chacha20poly1305, aes-gcm-siv, ed25519-dalek, x25519-dalek, scrypt, argon2. The Java-Rust ABI is the same dual-path Panama / @CFunction pattern as the URL and compression layers; output buffers are caller-allocated at known sizes.

Streaming vs one-shot

Hash and Hmac are streaming (update / digest / doFinal); both also expose static one-shot helpers when the entire input is already in hand.

KDFs (Pbkdf2, Hkdf, Scrypt, Argon2) are intentionally one-shot — they take their input all at once and have no reason to stream.

Symmetric ciphers and AEADs are exposed only one-shot via SymmetricCipher.seal / open. Streaming AEAD is not surfaced at this layer: cutting AEAD payloads at arbitrary boundaries is incompatible with the engines' tag computation, and the public modules (node:crypto.createCipheriv for non-AEAD modes, WHATWG crypto.subtle which is one-shot anyway) do not need it.

Threading

Stateless one-shot operations (everything but Hash / Hmac authenticator instances) are safe from any thread. Hash and Hmac instances are not safe for concurrent use — same model as the rest of the runtime, matching the graal-js single-thread-per-realm contract.

[NativeCryptoBackend]: NativeCryptoBackend.java [CryptoBackends]: CryptoBackends.java [NativeCrypto]: NativeCrypto.java