back to home

paulmillr / noble-ciphers

Audited & minimal JS implementation of Salsa20, ChaCha and AES

374 stars
23 forks
4 issues
TypeScriptJavaScript

AI Architecture Analysis

This repository is indexed by RepoMind. By analyzing paulmillr/noble-ciphers in our AI interface, you can instantly generate complete architecture diagrams, visualize control flows, and perform automated security audits across the entire codebase.

Our Agentic Context Augmented Generation (Agentic CAG) engine loads full source files into context on-demand, avoiding the fragmentation of traditional RAG systems. Ask questions about the architecture, dependencies, or specific features to see it in action.

Source files are only loaded when you start an analysis to optimize performance.

Embed this Badge

Showcase RepoMind's analysis directly in your repository's README.

[![Analyzed by RepoMind](https://img.shields.io/badge/Analyzed%20by-RepoMind-4F46E5?style=for-the-badge)](https://repomind.in/repo/paulmillr/noble-ciphers)
Preview:Analyzed by RepoMind

Repository Overview (README excerpt)

Crawler view

noble-ciphers Audited & minimal JS implementation of Salsa20, ChaCha and AES. • 🔒 **Audited** by an independent security firm • 🔻 Tree-shakeable: unused code is excluded from your builds • 🏎 Fast: hand-optimized for caveats of JS engines • 🔍 Reliable: property-based / cross-library / wycheproof tests ensure correctness • 💼 AES: ECB, CBC, CTR, CFB, GCM, SIV (nonce misuse-resistant), AESKW, AESKWP • 💃 Salsa20, ChaCha, XSalsa20, XChaCha, ChaCha8, ChaCha12, Poly1305 • 🥈 Two AES implementations: pure JS or friendly WebCrypto wrapper • 🪶 11KB (gzipped) for everything, 3KB for ChaCha-only build Check out Upgrading for information about upgrading from previous versions. Take a glance at GitHub Discussions for questions and support. This library belongs to _noble_ cryptography > **noble cryptography** — high-security, easily auditable set of contained cryptographic libraries and tools. • Zero or minimal dependencies • Highly readable TypeScript / JS code • PGP-signed releases and transparent NPM builds • All libraries: ciphers, curves, hashes, post-quantum, 5kb secp256k1 / ed25519 • Check out the homepage for reading resources, documentation, and apps built with noble Usage > > We support all major platforms and runtimes. For React Native, you may need a polyfill for getRandomValues. A standalone file noble-ciphers.js is also available. • Examples • XChaCha20-Poly1305 encryption • AES-256-GCM encryption • managedNonce: automatic nonce handling • AES: gcm, siv, ctr, cfb, cbc, ecb, aeskw • AES: friendly WebCrypto wrapper • Reuse array for input and output • Use password for encryption • Internals • Picking a cipher • How to encrypt properly • Nonces • Encryption limits • AES block modes • Implemented primitives • Security • Speed • Upgrading • Contributing & testing • License Examples > [!NOTE] > Use different nonce every time is done. XChaCha20-Poly1305 encryption AES-256-GCM encryption managedNonce: automatic nonce handling We provide API that manages nonce internally instead of exposing them to library's user. For : a -length buffer is fetched from CSPRNG and prenended to encrypted ciphertext. For : first of ciphertext are treated as nonce. > [!NOTE] > AES-GCM & ChaCha (NOT XChaCha) limit amount of messages > encryptable under the same key. AES: gcm, siv, ctr, cfb, cbc, ecb, aeskw AES: friendly WebCrypto wrapper Noble implements AES. Sometimes people want to use built-in instead. However, it has terrible API. We simplify access to built-ins. > [!NOTE] > Webcrypto methods are always async. Reuse array for input and output To avoid additional allocations, Uint8Array can be reused between encryption and decryption calls. > [!NOTE] > Some ciphers don't support unaligned ( ) Uint8Array as > destination. It can decrease performance, making the optimization pointless. xsalsa20poly1305 also supports this, but requires 32 additional bytes for encryption / decryption, due to its inner workings. Randomness generation We provide userspace CSPRNG (cryptographically secure pseudorandom number generator). It's best to limit their usage to non-production, non-critical cases: for example, test-only usage. ChaCha-based CSPRNG does not have a specification as per 2025, which makes it less secure. Use password for encryption It is not safe to convert password into Uint8Array. Instead, KDF stretching function like PBKDF2 / Scrypt / Argon2id should be applied to convert password to AES key. Make sure to use salt (app-specific secret) in addition to password. Internals Picking a cipher We suggest to use **XChaCha20-Poly1305** because it's very fast and allows random keys. **AES-GCM-SIV** is also a good idea, because it provides resistance against nonce reuse. **AES-GCM** is a good option when those two are not available. How to encrypt properly • Use unpredictable key with enough entropy • Random key must be using cryptographically secure random number generator (CSPRNG), not etc. • Non-random key generated from KDF is fine • Re-using key is fine, but be aware of rules for cryptographic key wear-out and encryption limits • Use new nonce every time and don't repeat it • chacha and salsa20 are fine for sequential counters that _never_ repeat: • xchacha and xsalsa20 can use random nonces instead • AES-GCM should use 12-byte nonces: smaller nonces are security risk • Prefer authenticated encryption (AEAD) • Good: chacha20poly1305, GCM, GCM-SIV, ChaCha+HMAC, CTR+HMAC, CBC+HMAC • Bad: chacha20, raw CTR, raw CBC • Flipping bits or ciphertext substitution won't be detected in unauthenticated ciphers • Polynomial MACs are not perfect for every situation: they lack Random Key Robustness: the MAC can be forged, and can't be used in PAKE schemes. See invisible salamanders attack. To combat salamanders, can be included in ciphertext, however, this would violate ciphertext indistinguishability: an attacker would know which key was used - so could be used instead. • Don't re-use keys between different protocols • For example, using ECDH key in AES can be bad • Use hkdf or, at least, a hash function to create sub-key instead Nonces Most ciphers need a key and a nonce (aka initialization vector / IV) to encrypt a data. Repeating (key, nonce) pair with different plaintexts would allow an attacker to decrypt it. ciphertext_a = encrypt(plaintext_a, key, nonce) ciphertext_b = encrypt(plaintext_b, key, nonce) stream_diff = xor(ciphertext_a, ciphertext_b) # Break encryption One way of not repeating nonces is using counters: for i in 0..: ciphertext[i] = encrypt(plaintexts[i], key, i) Another is generating random nonce every time: for i in 0..: rand_nonces[i] = random() ciphertext[i] = encrypt(plaintexts[i], key, rand_nonces[i]) • Counters are OK, but it's not always possible to store current counter value: e.g. in decentralized, unsyncable systems. • Randomness is OK, but there's a catch: ChaCha20 and AES-GCM use 96-bit / 12-byte nonces, which implies higher chance of c…