{"id":15634543,"url":"https://github.com/paulmillr/noble-ciphers","last_synced_at":"2025-12-07T05:01:42.651Z","repository":{"id":176943771,"uuid":"659761312","full_name":"paulmillr/noble-ciphers","owner":"paulmillr","description":"Audited \u0026 minimal JS implementation of Salsa20, ChaCha and AES","archived":false,"fork":false,"pushed_at":"2025-11-18T14:26:06.000Z","size":2264,"stargazers_count":332,"open_issues_count":4,"forks_count":18,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-11-18T16:39:11.917Z","etag":null,"topics":["aes","aes-siv","chacha","chacha20","chacha20-poly1305","chacha20poly1305","cipher","cryptography","encryption","ff1","gcm","nacl","rfc8452","salsa20","secretbox","sodium","xsalsa20poly1305"],"latest_commit_sha":null,"homepage":"https://paulmillr.com/noble","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paulmillr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/funding.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":"audit/2024-09-cure53-audit-nbl4.pdf","citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"paulmillr"}},"created_at":"2023-06-28T13:57:13.000Z","updated_at":"2025-11-18T14:26:10.000Z","dependencies_parsed_at":"2023-09-26T00:14:36.380Z","dependency_job_id":"bb854d47-b9a4-444c-afe5-71627365175c","html_url":"https://github.com/paulmillr/noble-ciphers","commit_stats":{"total_commits":185,"total_committers":5,"mean_commits":37.0,"dds":"0.032432432432432434","last_synced_commit":"47116a6a589acc25ac3d546b47fd6825a4f51fd6"},"previous_names":["paulmillr/noble-ciphers"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/paulmillr/noble-ciphers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fnoble-ciphers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fnoble-ciphers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fnoble-ciphers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fnoble-ciphers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paulmillr","download_url":"https://codeload.github.com/paulmillr/noble-ciphers/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fnoble-ciphers/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27501403,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-04T02:00:07.142Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aes","aes-siv","chacha","chacha20","chacha20-poly1305","chacha20poly1305","cipher","cryptography","encryption","ff1","gcm","nacl","rfc8452","salsa20","secretbox","sodium","xsalsa20poly1305"],"created_at":"2024-10-03T10:53:56.513Z","updated_at":"2025-12-07T05:01:42.643Z","avatar_url":"https://github.com/paulmillr.png","language":"TypeScript","funding_links":["https://github.com/sponsors/paulmillr"],"categories":["Frameworks and Libs"],"sub_categories":["JavaScript"],"readme":"# noble-ciphers\n\nAudited \u0026 minimal JS implementation of Salsa20, ChaCha and AES.\n\n- 🔒 [**Audited**](#security) by an independent security firm\n- 🔻 Tree-shakeable: unused code is excluded from your builds\n- 🏎 Fast: hand-optimized for caveats of JS engines\n- 🔍 Reliable: property-based / cross-library / wycheproof tests ensure correctness\n- 💼 AES: ECB, CBC, CTR, CFB, GCM, SIV (nonce misuse-resistant), AESKW, AESKWP\n- 💃 Salsa20, ChaCha, XSalsa20, XChaCha, ChaCha8, ChaCha12, Poly1305\n- 🥈 Two AES implementations: pure JS or friendly WebCrypto wrapper\n- 🪶 11KB (gzipped) for everything, 3KB for ChaCha-only build\n\nCheck out [Upgrading](#upgrading) for information about upgrading from previous versions.\nTake a glance at [GitHub Discussions](https://github.com/paulmillr/noble-ciphers/discussions) for questions and support.\n\n### This library belongs to _noble_ cryptography\n\n\u003e **noble cryptography** — high-security, easily auditable set of contained cryptographic libraries and tools.\n\n- Zero or minimal dependencies\n- Highly readable TypeScript / JS code\n- PGP-signed releases and transparent NPM builds\n- All libraries:\n  [ciphers](https://github.com/paulmillr/noble-ciphers),\n  [curves](https://github.com/paulmillr/noble-curves),\n  [hashes](https://github.com/paulmillr/noble-hashes),\n  [post-quantum](https://github.com/paulmillr/noble-post-quantum),\n  5kb [secp256k1](https://github.com/paulmillr/noble-secp256k1) /\n  [ed25519](https://github.com/paulmillr/noble-ed25519)\n- [Check out homepage](https://paulmillr.com/noble/)\n  for reading resources, documentation and apps built with noble\n\n## Usage\n\n\u003e `npm install @noble/ciphers`\n\n\u003e `deno add jsr:@noble/ciphers`\n\nWe support all major platforms and runtimes.\nFor React Native, you may need a\n[polyfill for getRandomValues](https://github.com/LinusU/react-native-get-random-values).\nA standalone file\n[noble-ciphers.js](https://github.com/paulmillr/noble-ciphers/releases) is also available.\n\n```ts\n// import * from '@noble/ciphers'; // Error: use sub-imports, to ensure small app size\nimport { gcm, gcmsiv } from '@noble/ciphers/aes.js';\nimport { chacha20poly1305, xchacha20poly1305 } from '@noble/ciphers/chacha.js';\nimport { xsalsa20poly1305 } from '@noble/ciphers/salsa.js';\n\n// Unauthenticated encryption: make sure to use HMAC or similar\nimport { ctr, cfb, cbc, ecb } from '@noble/ciphers/aes.js';\nimport { salsa20, xsalsa20 } from '@noble/ciphers/salsa.js';\nimport { chacha20, xchacha20, chacha8, chacha12 } from '@noble/ciphers/chacha.js';\nimport { aeskw, aeskwp } from '@noble/ciphers/aes.js'; // KW\nimport { bytesToHex, hexToBytes, managedNonce, randomBytes } from '@noble/ciphers/utils.js';\n```\n\n- [Examples](#examples)\n  - [XChaCha20-Poly1305 encryption](#xchacha20-poly1305-encryption)\n  - [AES-256-GCM encryption](#aes-256-gcm-encryption)\n  - [managedNonce: automatic nonce handling](#managednonce-automatic-nonce-handling)\n  - [AES: gcm, siv, ctr, cfb, cbc, ecb, aeskw](#aes-gcm-siv-ctr-cfb-cbc-ecb-aeskw)\n  - [AES: friendly WebCrypto wrapper](#aes-friendly-webcrypto-wrapper)\n  - [Reuse array for input and output](#reuse-array-for-input-and-output)\n  - [Use password for encryption](#use-password-for-encryption)\n- [Internals](#internals)\n  - [Picking a cipher](#picking-a-cipher)\n  - [How to encrypt properly](#how-to-encrypt-properly)\n  - [Nonces](#nonces)\n  - [Encryption limits](#encryption-limits)\n  - [AES block modes](#aes-block-modes)\n  - [Implemented primitives](#implemented-primitives)\n- [Security](#security)\n- [Speed](#speed)\n- [Upgrading](#upgrading)\n- [Contributing \u0026 testing](#contributing--testing)\n- [License](#license)\n\n## Examples\n\n\u003e [!NOTE]\n\u003e Use different nonce every time `encrypt()` is done.\n\n#### XChaCha20-Poly1305 encryption\n\n```js\nimport { xchacha20poly1305 } from '@noble/ciphers/chacha.js';\nimport { randomBytes } from '@noble/ciphers/utils.js';\nconst key = randomBytes(32); // random key\n// const key = new Uint8Array([ // existing key\n//   169, 88, 160, 139, 168, 29, 147, 196, 14, 88, 237, 76, 243, 177, 109, 140,\n//   195, 140, 80, 10, 216, 134, 215, 71, 191, 48, 20, 104, 189, 37, 38, 55,\n// ]);\n// import { hexToBytes } from '@noble/ciphers/utils.js'; // hex key\n// const key = hexToBytes('4b7f89bac90a1086fef73f5da2cbe93b2fae9dfbf7678ae1f3e75fd118ddf999');\nconst nonce = randomBytes(24);\nconst chacha = xchacha20poly1305(key, nonce);\nconst data = new TextEncoder().encode('hello noble');\nconst ciphertext = chacha.encrypt(data);\nconst data_ = chacha.decrypt(ciphertext); // new TextDecoder().decode(data_) === data\n```\n\n#### AES-256-GCM encryption\n\n```js\nimport { gcm } from '@noble/ciphers/aes.js';\nimport { randomBytes } from '@noble/ciphers/utils.js';\nconst key = randomBytes(32);\nconst nonce = randomBytes(24);\nconst data = new TextEncoder().encode('hello noble');\nconst aes = gcm(key, nonce);\nconst ciphertext = aes.encrypt(data);\nconst data_ = aes.decrypt(ciphertext); // new TextDecoder().decode(data_) === data\n```\n\n#### managedNonce: automatic nonce handling\n\nWe provide API that manages nonce internally instead of exposing them to library's user.\n\nFor `encrypt`: a `nonceBytes`-length buffer is fetched from CSPRNG and prenended to encrypted ciphertext.\n\nFor `decrypt`: first `nonceBytes` of ciphertext are treated as nonce.\n\n\u003e [!NOTE]\n\u003e AES-GCM \u0026 ChaCha (NOT XChaCha) [limit amount of messages](#encryption-limits)\n\u003e encryptable under the same key.\n\n```js\nimport { xchacha20poly1305 } from '@noble/ciphers/chacha.js';\nimport { hexToBytes, managedNonce } from '@noble/ciphers/utils.js';\nconst key = hexToBytes('fa686bfdffd3758f6377abbc23bf3d9bdc1a0dda4a6e7f8dbdd579fa1ff6d7e1');\nconst chacha = managedNonce(xchacha20poly1305)(key); // manages nonces for you\nconst data = new TextEncoder().encode('hello noble');\nconst ciphertext = chacha.encrypt(data);\nconst data_ = chacha.decrypt(ciphertext);\n```\n\n#### AES: gcm, siv, ctr, cfb, cbc, ecb, aeskw\n\n```js\nimport { gcm, gcmsiv, aessiv, ctr, cfb, cbc, ecb } from '@noble/ciphers/aes.js';\nimport { randomBytes } from '@noble/ciphers/utils.js';\nconst plaintext = new Uint8Array(32).fill(16);\nfor (let cipher of [gcm, gcmsiv, aessiv]) {\n  const key = randomBytes(32); // 24 for AES-192, 16 for AES-128\n  const nonce = randomBytes(12);\n  const ciphertext_ = cipher(key, nonce).encrypt(plaintext);\n  const plaintext_ = cipher(key, nonce).decrypt(ciphertext_);\n}\nfor (const cipher of [ctr, cbc, cfb]) {\n  const key = randomBytes(32); // 24 for AES-192, 16 for AES-128\n  const nonce = randomBytes(16);\n  const ciphertext_ = cipher(key, nonce).encrypt(plaintext);\n  const plaintext_ = cipher(key, nonce).decrypt(ciphertext_);\n}\nfor (const cipher of [ecb]) {\n  const key = randomBytes(32); // 24 for AES-192, 16 for AES-128\n  const ciphertext_ = cipher(key).encrypt(plaintext);\n  const plaintext_ = cipher(key).decrypt(ciphertext_);\n}\n\n// AESKW, AESKWP\nimport { aeskw, aeskwp } from '@noble/ciphers/aes.js';\nimport { hexToBytes } from '@noble/ciphers/utils.js';\n\nconst kek = hexToBytes('000102030405060708090A0B0C0D0E0F');\nconst keyData = hexToBytes('00112233445566778899AABBCCDDEEFF');\nconst ciphertext = aeskw(kek).encrypt(keyData);\n```\n\n#### AES: friendly WebCrypto wrapper\n\nNoble implements AES. Sometimes people want to use built-in `crypto.subtle` instead. However, it has terrible API. We simplify access to built-ins.\n\n\u003e [!NOTE]\n\u003e Webcrypto methods are always async.\n\n```js\nimport { gcm, ctr, cbc, randomBytes } from '@noble/ciphers/utils.js';\nconst plaintext = new Uint8Array(32).fill(16);\nconst key = randomBytes(32);\nfor (const cipher of [gcm]) {\n  const nonce = randomBytes(12);\n  const ciphertext_ = await cipher(key, nonce).encrypt(plaintext);\n  const plaintext_ = await cipher(key, nonce).decrypt(ciphertext_);\n}\nfor (const cipher of [ctr, cbc]) {\n  const nonce = randomBytes(16);\n  const ciphertext_ = await cipher(key, nonce).encrypt(plaintext);\n  const plaintext_ = await cipher(key, nonce).decrypt(ciphertext_);\n}\n```\n\n#### Reuse array for input and output\n\nTo avoid additional allocations, Uint8Array can be reused\nbetween encryption and decryption calls.\n\n\u003e [!NOTE]\n\u003e Some ciphers don't support unaligned (`byteOffset % 4 !== 0`) Uint8Array as\n\u003e destination. It can decrease performance, making the optimization pointless.\n\n```js\nimport { chacha20poly1305 } from '@noble/ciphers/chacha.js';\nimport { randomBytes } from '@noble/ciphers/utils.js';\n\nconst key = randomBytes(32);\nconst nonce = randomBytes(12);\nconst chacha = chacha20poly1305(key, nonce);\n\nconst input = new TextEncoder().encode('hello noble'); // length == 12\nconst inputLength = input.length;\nconst tagLength = 16;\n\nconst buf = new Uint8Array(inputLength + tagLength);\nconst start = buf.subarray(0, inputLength);\nstart.set(input); // copy input to buf\n\nchacha.encrypt(start, buf); // encrypt into `buf`\nchacha.decrypt(buf, start); // decrypt into `start`\n```\n\nxsalsa20poly1305 also supports this, but requires 32 additional bytes for encryption / decryption,\ndue to its inner workings.\n\n#### Randomness generation\n\nWe provide userspace CSPRNG (cryptographically secure pseudorandom number generator).\nIt's best to limit their usage to non-production, non-critical cases: for example, test-only usage.\nChaCha-based CSPRNG does not have a specification as per 2025, which makes it less secure.\n\n```js\nimport { randomBytes } from '@noble/ciphers/utils.js';\nimport { rngAesCtrDrbg256 } from '@noble/ciphers/aes.js';\nimport { rngChacha8, rngChacha20 } from '@noble/ciphers/chacha.js';\n\n// 1. Best: WebCrypto\nconst rnd1 = randomBytes(32);\n// 2. AES-CTR DRBG\nconst rnd2 = rngAesCtrDrbg256(randomBytes(32)).randomBytes(1024);\n// 3. ChaCha8 CSPRNG\nconst rnd3 = rngChacha8(randomBytes(32)).randomBytes(1024);\n```\n\n#### Use password for encryption\n\nIt is not safe to convert password into Uint8Array.\nInstead, KDF stretching function like PBKDF2 / Scrypt / Argon2id\nshould be applied to convert password to AES key.\nMake sure to use salt (app-specific secret) in addition to password.\n\n```js\nimport { xchacha20poly1305 } from '@noble/ciphers/chacha.js';\nimport { managedNonce } from '@noble/ciphers/utils.js';\nimport { scrypt } from '@noble/hashes/scrypt.js';\n\n// Convert password into 32-byte key using scrypt\nconst PASSWORD = 'correct-horse-battery-staple';\nconst APP_SPECIFIC_SECRET = 'salt-12345678-secret';\nconst SECURITY_LEVEL = 2 ** 20; // requires 1GB of RAM to calculate\n// sync, but scryptAsync is also available\nconst key = scrypt(PASSWORD, APP_SPECIFIC_SECRET, { N: SECURITY_LEVEL, r: 8, p: 1, dkLen: 32 });\n\n// Use random, managed nonce\nconst chacha = managedNonce(xchacha20poly1305)(key);\n\nconst data = new TextEncoder().encode('hello noble');\nconst ciphertext = chacha.encrypt(data);\nconst data_ = chacha.decrypt(ciphertext);\n```\n\n## Internals\n\n### Picking a cipher\n\nWe suggest to use **XChaCha20-Poly1305** because it's very fast and allows random keys.\n**AES-GCM-SIV** is also a good idea, because it provides resistance against nonce reuse.\n**AES-GCM** is a good option when those two are not available.\n\n### How to encrypt properly\n\n- Use unpredictable key with enough entropy\n  - Random key must be using cryptographically secure random number generator (CSPRNG), not `Math.random` etc.\n  - Non-random key generated from KDF is fine\n  - Re-using key is fine, but be aware of rules for cryptographic key wear-out and [encryption limits](#encryption-limits)\n- Use new nonce every time and [don't repeat it](#nonces)\n  - chacha and salsa20 are fine for sequential counters that _never_ repeat: `01, 02...`\n  - xchacha and xsalsa20 can use random nonces instead\n  - AES-GCM should use 12-byte nonces: smaller nonces are security risk\n- Prefer authenticated encryption (AEAD)\n  - Good: chacha20poly1305, GCM, GCM-SIV, ChaCha+HMAC, CTR+HMAC, CBC+HMAC\n  - Bad: chacha20, raw CTR, raw CBC\n  - Flipping bits or ciphertext substitution won't be detected in unauthenticated ciphers\n  - Polynomial MACs are not perfect for every situation:\n    they lack Random Key Robustness: the MAC can be forged, and can't\n    be used in PAKE schemes. See\n    [invisible salamanders attack](https://keymaterial.net/2020/09/07/invisible-salamanders-in-aes-gcm-siv/).\n    To combat salamanders, `hash(key)` can be included in ciphertext,\n    however, this would violate ciphertext indistinguishability:\n    an attacker would know which key was used - so `HKDF(key, i)`\n    could be used instead.\n- Don't re-use keys between different protocols\n  - For example, using ECDH key in AES can be bad\n  - Use hkdf or, at least, a hash function to create sub-key instead\n\n### Nonces\n\nMost ciphers need a key and a nonce (aka initialization vector / IV) to encrypt a data.\nRepeating (key, nonce) pair with different plaintexts would allow an attacker to decrypt it.\n\n    ciphertext_a = encrypt(plaintext_a, key, nonce)\n    ciphertext_b = encrypt(plaintext_b, key, nonce)\n    stream_diff = xor(ciphertext_a, ciphertext_b)    # Break encryption\n\nOne way of not repeating nonces is using counters:\n\n    for i in 0..:\n        ciphertext[i] = encrypt(plaintexts[i], key, i)\n\nAnother is generating random nonce every time:\n\n    for i in 0..:\n        rand_nonces[i] = random()\n        ciphertext[i] = encrypt(plaintexts[i], key, rand_nonces[i])\n\n- Counters are OK, but it's not always possible to store current counter value:\n  e.g. in decentralized, unsyncable systems.\n- Randomness is OK, but there's a catch:\n  ChaCha20 and AES-GCM use 96-bit / 12-byte nonces, which implies higher chance of collision.\n  In the example above, `random()` can collide and produce repeating nonce.\n  Chance is even higher for 64-bit nonces, which GCM allows - don't use them.\n- To safely use random nonces, utilize XSalsa20 or XChaCha:\n  they increased nonce length to 192-bit, minimizing a chance of collision.\n  AES-SIV is also fine. In situations where you can't use eXtended-nonce\n  algorithms, key rotation is advised. hkdf would work great for this case.\n\n### Encryption limits\n\nA \"protected message\" would mean a probability of `2**-50` that a passive attacker\nsuccessfully distinguishes the ciphertext outputs of the AEAD scheme from the outputs\nof a random function.\n\n- Max message size:\n  - AES-GCM: ~68GB, `2**36-256`\n  - Salsa, ChaCha, XSalsa, XChaCha: ~256GB, `2**38-64`\n- Max amount of protected messages, under same key:\n  - AES-GCM: `2**32.5`\n  - Salsa, ChaCha: `2**46`, but only integrity (MAC) is affected, not confidentiality (encryption)\n  - XSalsa, XChaCha: `2**72`\n- Max amount of protected messages, across all keys:\n  - AES-GCM: `2**69/B` where B is max blocks encrypted by a key. Meaning\n    `2**59` for 1KB, `2**49` for 1MB, `2**39` for 1GB\n  - Salsa, ChaCha, XSalsa, XChaCha: `2**100`\n- Max amount of protected messages, under same key, using **random nonce**:\n  - Relevant for 12-byte nonces with `managedNonce`: AES-GCM, ChaCha\n  - `2**23` (8M) messages for `2**-50` chance, `2**32.5` (4B) for `2**-32.5` chance\n\nCheck out [draft-irtf-cfrg-aead-limits](https://datatracker.ietf.org/doc/draft-irtf-cfrg-aead-limits/) for details.\n\n### Implemented primitives\n\n- Salsa20 stream cipher, released in 2005.\n  Salsa's goal was to implement AES replacement that does not rely on S-Boxes,\n  which are hard to implement in a constant-time manner.\n  Salsa20 is usually faster than AES, a big deal on slow, budget mobile phones.\n  - [XSalsa20](https://cr.yp.to/snuffle/xsalsa-20110204.pdf), extended-nonce\n    variant was released in 2008. It switched nonces from 96-bit to 192-bit,\n    and became safe to be picked at random.\n  - Nacl / Libsodium popularized term \"secretbox\", - which is just xsalsa20poly1305.\n    We provide the alias and corresponding seal / open methods.\n    \"crypto_box\" and \"sealedbox\" are available in package [noble-sodium](https://github.com/serenity-kit/noble-sodium).\n  - Check out [PDF](https://cr.yp.to/snuffle/salsafamily-20071225.pdf)\n    and [website](https://cr.yp.to/snuffle.html).\n- ChaCha20 stream cipher, released in 2008. Developed after Salsa20,\n  ChaCha aims to increase diffusion per round.\n  - [XChaCha20](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha)\n    extended-nonce variant is also provided. Similar to XSalsa, it's safe to use with\n    randomly-generated nonces.\n  - Check out\n    [RFC 8439](https://www.rfc-editor.org/rfc/rfc8439),\n    [PDF](http://cr.yp.to/chacha/chacha-20080128.pdf) and\n    [website](https://cr.yp.to/chacha.html).\n- AES is a variant of Rijndael block cipher, standardized by NIST in 2001.\n  We provide the fastest available pure JS implementation.\n  - We support AES-128, AES-192 and AES-256: the mode is selected dynamically,\n    based on key length (16, 24, 32).\n  - AES-GCM-SIV nonce-misuse-resistant mode is also provided. Our implementation of SIV\n    has the same speed as GCM: there is no performance hit.\n    The mode is described in [RFC 8452](https://www.rfc-editor.org/rfc/rfc8452).\n  - There is a separate AES-SIV mode, described in [RFC 5297](https://www.rfc-editor.org/rfc/rfc5297)\n  - We also have AESKW and AESKWP from\n    [RFC 3394](https://www.rfc-editor.org/rfc/rfc3394) \u0026 [RFC 5649](https://www.rfc-editor.org/rfc/rfc5649)\n  - Format-preserving encryption algorithm (FPE-FF1) specified in\n    [NIST SP 800-38G](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38G.pdf).\n  - Check out [AES block modes](#aes-block-modes),\n    [FIPS 197](https://csrc.nist.gov/files/pubs/fips/197/final/docs/fips-197.pdf) and\n    [original proposal](https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/aes-development/rijndael-ammended.pdf).\n- Polynomial-evaluation MACs are available: Poly1305, AES-GCM's GHash and AES-SIV's Polyval.\n  - Poly1305 ([PDF](https://cr.yp.to/mac/poly1305-20050329.pdf),\n    [website](https://cr.yp.to/mac.html))\n    is a fast and parallel secret-key message-authentication code suitable for\n    a wide variety of applications. It was standardized in\n    [RFC 8439](https://www.rfc-editor.org/rfc/rfc8439) and is now used in TLS 1.3.\n  - Ghash is used in AES-GCM: see NIST SP 800-38G\n  - Polyval is used in AES-GCM-SIV: see [RFC 8452](https://www.rfc-editor.org/rfc/rfc8452)\n\n##### AES block modes\n\nFor non-deterministic (not ECB) schemes, initialization vector (IV) is mixed to block/key;\nand each new round either depends on previous block's key, or on some counter.\n\n- **ECB** (Electronic Codebook): Deterministic encryption; identical plaintext blocks yield identical ciphertexts. Not secure due to pattern leakage. due to pattern leakage.\n  See [AES Penguin](https://words.filippo.io/the-ecb-penguin/)\n- **CBC** (Cipher Block Chaining): Each plaintext block is XORed with the previous block of ciphertext\n  before encryption. Hard to use: requires proper padding and an IV. Unauthenticated: needs MAC.\n- **CTR** (Counter Mode): Turns a block cipher into a stream cipher using a counter and IV (nonce).\n  Efficient and parallelizable. Requires a unique nonce per encryption. Unauthenticated: needs MAC.\n- **GCM** (Galois/Counter Mode): Combines CTR mode with polynomial MAC. Efficient and widely used. Not perfect:\n  a) conservative key wear-out is `2**32` (4B) msgs.\n  b) key wear-out under random nonces is even smaller: `2**23` (8M) messages for `2**-50` chance.\n  c) MAC can be forged: see Poly1305 documentation.\n- **SIV** (Synthetic IV): GCM with nonce-misuse resistance; repeating nonces reveal only the fact plaintexts\n  are identical. Also suffers from GCM issues: key wear-out limits \u0026 MAC forging.\n- **XTS**: Designed for disk encryption.\n  Similar to ECB (deterministic), but has `[i][j]` tweak arguments corresponding to\n  sector i and 16-byte block (part of sector) j. Lacks MAC.\n\n## Security\n\nThe library has been independently audited:\n\n- at version 1.0.0, in Sep 2024, by [cure53](https://cure53.de)\n  - PDFs: [website](https://cure53.de/audit-report_noble-crypto-libs.pdf), [in-repo](./audit/2024-09-cure53-audit-nbl4.pdf)\n  - [Changes since audit](https://github.com/paulmillr/noble-ciphers/compare/1.0.0..main)\n  - Scope: everything\n  - The audit has been funded by [OpenSats](https://opensats.org)\n\nIt is tested against property-based, cross-library and Wycheproof vectors,\nand is being fuzzed in [the separate repo](https://github.com/paulmillr/fuzzing).\n\nIf you see anything unusual: investigate and report.\n\n### Constant-timeness\n\nWe're targetting algorithmic constant time. _JIT-compiler_ and _Garbage Collector_ make \"constant time\"\nextremely hard to achieve [timing attack](https://en.wikipedia.org/wiki/Timing_attack) resistance\nin a scripting language. Which means _any other JS library can't have\nconstant-timeness_. Even statically typed Rust, a language without GC,\n[makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security)\nfor some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones.\nUse low-level libraries \u0026 languages.\n\nThe library uses T-tables for AES, which\n[leak access timings](https://cr.yp.to/antiforgery/cachetiming-20050414.pdf).\nThis is also done in [OpenSSL](https://github.com/openssl/openssl/blob/2f33265039cdbd0e4589c80970e02e208f3f94d2/crypto/aes/aes_core.c#L706) and\n[Go stdlib](https://cs.opensource.google/go/go/+/refs/tags/go1.22.6:src/crypto/aes/const.go;l=90) for performance reasons.\nThe analysis was mentioned in [hal-04652991](https://hal.science/hal-04652991/document).\n\n### Supply chain security\n\n- **Commits** are signed with PGP keys, to prevent forgery. Make sure to verify commit signatures\n- **Releases** are transparent and built on GitHub CI.\n  Check out [attested checksums of single-file builds](https://github.com/paulmillr/noble-ciphers/attestations)\n  and [provenance logs](https://github.com/paulmillr/noble-ciphers/actions/workflows/release.yml)\n- **Rare releasing** is followed to ensure less re-audit need for end-users\n- **Dependencies** are minimized and locked-down: any dependency could get hacked and users will be downloading malware with every install.\n  - We make sure to use as few dependencies as possible\n  - Automatic dep updates are prevented by locking-down version ranges; diffs are checked with `npm-diff`\n- **Dev Dependencies** are disabled for end-users; they are only used to develop / build the source code\n\nFor this package, there are 0 dependencies; and a few dev dependencies:\n\n- jsbt is used for benchmarking / testing / build tooling and developed by the same author\n- prettier, fast-check and typescript are used for code quality / test generation / ts compilation. It's hard to audit their source code thoroughly and fully because of their size\n\n### Randomness\n\nWe're deferring to built-in\n[crypto.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues)\nwhich is considered cryptographically secure (CSPRNG).\n\nIn the past, browsers had bugs that made it weak: it may happen again.\nImplementing a userspace CSPRNG to get resilient to the weakness\nis even worse: there is no reliable userspace source of quality entropy.\n\n### Quantum computers\n\nCryptographically relevant quantum computer, if built, will allow to\nutilize Grover's algorithm to break ciphers in 2^n/2 operations, instead of 2^n.\n\nThis means AES128 should be replaced with AES256. Salsa and ChaCha are already safe.\n\nAustralian ASD prohibits AES128 [after 2030](https://www.cyber.gov.au/resources-business-and-government/essential-cyber-security/ism/cyber-security-guidelines/guidelines-cryptography).\n\n## Speed\n\n```sh\nnpm run bench\n```\n\nTo summarize, noble is the fastest JS implementation of Salsa, ChaCha and AES.\nYou can gain additional speed-up and\navoid memory allocations by passing `output`\nuint8array into encrypt / decrypt methods.\n\nBenchmarks measured on Apple M4:\n\n```\n64B\nxsalsa20poly1305 x 735,835 ops/sec @ 1μs/op\nchacha20poly1305 x 581,395 ops/sec @ 1μs/op\nxchacha20poly1305 x 468,384 ops/sec @ 2μs/op\naes-256-gcm x 201,126 ops/sec @ 4μs/op\naes-256-gcm-siv x 162,284 ops/sec @ 6μs/op\n# Unauthenticated encryption\nsalsa20 x 1,655,629 ops/sec @ 604ns/op\nxsalsa20 x 1,400,560 ops/sec @ 714ns/op\nchacha20 x 1,996,007 ops/sec @ 501ns/op\nxchacha20 x 1,404,494 ops/sec @ 712ns/op\nchacha8 x 2,145,922 ops/sec @ 466ns/op\nchacha12 x 2,036,659 ops/sec @ 491ns/op\naes-ecb-256 x 1,019,367 ops/sec @ 981ns/op\naes-cbc-256 x 931,966 ops/sec @ 1μs/op\naes-ctr-256 x 954,198 ops/sec @ 1μs/op\n\n1MB\nxsalsa20poly1305 x 334 ops/sec @ 2ms/op\nchacha20poly1305 x 333 ops/sec @ 2ms/op\nxchacha20poly1305 x 334 ops/sec @ 2ms/op\naes-256-gcm x 94 ops/sec @ 10ms/op\naes-256-gcm-siv x 90 ops/sec @ 11ms/op\n# Unauthenticated encryption\nsalsa20 x 831 ops/sec @ 1ms/op\nxsalsa20 x 830 ops/sec @ 1ms/op\nchacha20 x 804 ops/sec @ 1ms/op\nxchacha20 x 797 ops/sec @ 1ms/op\nchacha8 x 1,495 ops/sec @ 668μs/op\nchacha12 x 1,148 ops/sec @ 871μs/op\naes-ecb-256 x 289 ops/sec @ 3ms/op\naes-cbc-256 x 114 ops/sec @ 8ms/op\naes-ctr-256 x 127 ops/sec @ 7ms/op\n# Wrapper over built-in webcrypto\nwebcrypto ctr-256 x 6,508 ops/sec @ 153μs/op\nwebcrypto cbc-256 x 1,820 ops/sec @ 549μs/op\nwebcrypto gcm-256 x 5,106 ops/sec @ 195μs/op\n```\n\nCompare to other implementations:\n\n```\nxsalsa20poly1305 (encrypt, 1MB)\n├─tweetnacl x 196 ops/sec\n└─noble x 305 ops/sec\n\nchacha20poly1305 (encrypt, 1MB)\n├─node x 1,668 ops/sec\n├─stablelib x 202 ops/sec\n└─noble x 319 ops/sec\n\naes-ctr-256 (encrypt, 1MB)\n├─stablelib x 123 ops/sec\n├─aesjs x 42 ops/sec\n├─noble-webcrypto x 5,965 ops/sec\n└─noble x 124 ops/sec\n```\n\n## Upgrading\n\nSupported node.js versions:\n\n- v2: v20.19+ (ESM-only)\n- v1: v14.21+ (ESM \u0026 CJS)\n\nChangelog of v2, when upgrading from ciphers v1:\n\n- The package is now ESM-only. ESM can finally be loaded from common.js on node v20.19+\n- `.js` extension must be used for all modules\n    - Old: `@noble/ciphers/aes`\n    - New: `@noble/ciphers/aes.js`\n    - This simplifies working in browsers natively without transpilers\n- webcrypto: move `randomBytes` and `managedNonce` to `utils.js`\n- ghash, poly1305, polyval: only allow Uint8Array as hash inputs, prohibit `string`\n- utils: new abytes; remove ahash, toBytes\n- Remove modules `_assert` (use `utils`), `_micro` and `crypto` (use `webcrypto`)\n- Bump TS compilation target from es2020 to es2022\n- Massively improve error messages, make them more descriptive\n\n## Contributing \u0026 testing\n\n- `npm install \u0026\u0026 npm run build \u0026\u0026 npm test` will build the code and run tests.\n- `npm run lint` / `npm run format` will run linter / fix linter issues.\n- `npm run bench` will run benchmarks\n- `npm run build:release` will build single file\n\nSee [paulmillr.com/noble](https://paulmillr.com/noble/)\nfor useful resources, articles, documentation and demos\nrelated to the library.\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2023 Paul Miller [(https://paulmillr.com)](https://paulmillr.com)\nCopyright (c) 2016 Thomas Pornin \u003cpornin@bolet.org\u003e\n\nSee LICENSE file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulmillr%2Fnoble-ciphers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaulmillr%2Fnoble-ciphers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulmillr%2Fnoble-ciphers/lists"}