sjcl
A compact, high-level JavaScript library for AES encryption, hashing, and public-key cryptography — now officially deprecated.
Repository Health
Technical Analysis
The Stanford Javascript Crypto Library (SJCL) is a small, self-contained cryptography library built to bring strong encryption to the browser without pulling in a large runtime footprint. It implements AES with CCM, OCB2, CTR, CBC, and GCM modes, SHA-256/512 and RIPEMD-160 hashing, HMAC and PBKDF2 key derivation, scrypt, elliptic-curve Diffie-Hellman and ElGamal, ECDSA signatures, and the SRP protocol, all wrapped behind a JSON-based encryption format that hides most of the parameter bookkeeping from callers.
SJCL was widely used for a decade as one of the first practical high-level crypto libraries for JavaScript, but the project has not seen active development in years. Its maintainers have formally marked it deprecated, and a 2026 security advisory (fixed in 1.0.9) affecting elliptic-curve Diffie-Hellman underscores why new projects should reach for an actively maintained alternative such as WebCrypto, libsodium.js, or noble-crypto instead.
What You Get
- A single-file, dependency-free AES implementation supporting 128/192/256-bit keys with CCM, OCB2, CTR, CBC, and GCM modes
- SHA-256, SHA-512, and RIPEMD-160 hash implementations plus HMAC for message authentication
- Password-based key derivation via PBKDF2 and scrypt, with a cached PBKDF2 helper to avoid redundant work across calls
- Elliptic-curve cryptography: ECDH key exchange, ElGamal encryption, and ECDSA signatures over NIST curves
- A high-level
sjcl.encrypt/sjcl.decryptJSON encapsulation API that bundles IV, salt, and cipher parameters so callers don’t have to manage them by hand - A Fortuna-derived random number generator that collects entropy from browser events (mouse movement, timing jitter) into multiple pools
Common Use Cases
- Client-side encryption of form data or file contents before it is sent to a server
- Deriving encryption keys from user passwords with PBKDF2 or scrypt in legacy browser-based apps
- Implementing password-authenticated key exchange via the built-in SRP protocol
- Computing HMAC-based message integrity checks in older Node.js or browser codebases
- Studying a compact, readable reference implementation of common cryptographic primitives
Under The Hood
Architecture
SJCL is organized as a flat collection of independent modules under core/ (aes.js, sha256.js, ecc.js, random.js, and others) that all attach themselves to a single global sjcl namespace defined in core/sjcl.js, with core/exports.js handling CommonJS/AMD registration; there is no dependency injection or layering, modules simply populate the sjcl.cipher, sjcl.hash, sjcl.mode, and sjcl.codec namespaces they expect to already exist, and the Makefile concatenates the chosen module list from config.mk into a single file before optional Closure/YUI compression produces the shipped sjcl.js. The convenience layer (core/convenience.js) sits on top of the primitives and implements the JSON encrypt/decrypt encapsulation, delegating cipher and mode selection to whatever modules are present, so the core bitArray representation is the universal data interchange format threading through every codec, cipher, and hash — changing it would ripple across the whole library.
Tech Stack
SJCL ships with zero runtime dependencies; package.json lists only eslint and jsdoc as devDependencies. It’s distributed as a single concatenated sjcl.js file built via a Perl/shell-driven Makefile, with optional Closure Compiler or YUI Compressor minification invoked through scripts under compress/. A ./configure script and config.mk let consumers opt out of unwanted primitives (such as big-number ECC support) to control bundle size, and core/exports.js bridges to CommonJS and AMD manually rather than relying on a modern bundler-native module system.
Code Quality
The test/ directory pairs known-answer test files with vector files for essentially every primitive (aes_test.js/aes_vectors.js, ecdsa_test.js/ecdsa_vectors.js, ccm_test.js, scrypt tests, and more), each written as an sjcl.test.TestCase asserting bit-array equality against official test vectors — a solid, custom in-house harness rather than a standard framework. There is no TypeScript and no runtime type checking; the code relies on "use strict" and jslint directives, and while .eslintrc configures linting, the npm run lint script is wired as eslint . || true, so lint failures never fail CI. Error handling is explicit via a small sjcl.exception hierarchy (invalid, corrupt, notReady) thrown on bad parameters, but the project has had no commits or releases in years, so these quality signals are frozen at whatever state the code reached before development stopped.
API Design
SJCL’s main ergonomic contribution is hiding parameter management behind sjcl.encrypt/sjcl.decrypt, which auto-generates the IV and salt, applies sane defaults (AES-CCM, 10,000 PBKDF2 iterations), and accepts/returns a single JSON object — a real convenience compared to assembling IV, cipher, mode, and key by hand. The lower-level primitives underneath still require understanding SJCL’s own bitArray representation before they’re usable directly, so the ergonomic gain is concentrated in the convenience layer rather than the full API surface, and documentation beyond an external jsdoc site and inline comments is limited. The library predates promises and async patterns entirely, exposing purely synchronous calls throughout.