{"id":15674065,"url":"https://github.com/paulmillr/micro-rsa-dsa-dh","last_synced_at":"2025-08-20T04:12:39.609Z","repository":{"id":246983877,"uuid":"824139488","full_name":"paulmillr/micro-rsa-dsa-dh","owner":"paulmillr","description":"Minimal JS implementation of older cryptography algorithms: RSA, DSA, DH.","archived":false,"fork":false,"pushed_at":"2025-03-25T10:19:51.000Z","size":13837,"stargazers_count":15,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-29T01:41:26.007Z","etag":null,"topics":["cryptography","dh","diffie-hellman","dsa","elgamal","noble","prime-numbers","rsa"],"latest_commit_sha":null,"homepage":"","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":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"paulmillr"}},"created_at":"2024-07-04T12:48:15.000Z","updated_at":"2025-03-25T10:19:56.000Z","dependencies_parsed_at":"2024-07-06T02:57:01.297Z","dependency_job_id":"3482e208-870f-462c-9327-c9c12e2e4f60","html_url":"https://github.com/paulmillr/micro-rsa-dsa-dh","commit_stats":null,"previous_names":["paulmillr/micro-rsa-dsa-dh"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fmicro-rsa-dsa-dh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fmicro-rsa-dsa-dh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fmicro-rsa-dsa-dh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paulmillr%2Fmicro-rsa-dsa-dh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paulmillr","download_url":"https://codeload.github.com/paulmillr/micro-rsa-dsa-dh/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249160608,"owners_count":21222459,"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","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":["cryptography","dh","diffie-hellman","dsa","elgamal","noble","prime-numbers","rsa"],"created_at":"2024-10-03T15:43:31.852Z","updated_at":"2025-08-20T04:12:39.597Z","avatar_url":"https://github.com/paulmillr.png","language":"TypeScript","funding_links":["https://github.com/sponsors/paulmillr"],"categories":["Frameworks and Libs"],"sub_categories":["JavaScript"],"readme":"# micro-rsa-dsa-dh\n\nMinimal implementation of older cryptography algorithms: RSA, DSA, DH.\n\n- 🔻 Tree-shakeable: unused code is excluded from your builds\n- 🔑 RSA (Rivest-Shamir-Adleman) public-key cryptosystem, with OAEP, PSS, PKCS1\n- ✍️ DSA (Digital Signature Algorithm) signatures\n- 🤝 DH (Diffie-Hellman) key exchange\n- 📦 ElGamal encryption\n- 5️⃣ Primality tests\n- 🪶 16KB (gzipped)\n\n\u003e [!WARNING]\n\u003e Like in all JS implementations, keep in mind [timing leaks](#security)\n\n## Usage\n\n\u003e `npm install micro-rsa-dsa-dh`\n\nWe support all major platforms and runtimes.\n\nA standalone file [micro-rsa-dsa-dh.js](https://github.com/paulmillr/micro-rsa-dsa-dh/releases) is also available.\n\n- [All imports](#all-imports)\n- [RSA](#rsa)\n  - [OAEP](#oaep)\n  - [PSS](#pss)\n  - [PKCS1](#pkcs1)\n- [DSA](#dsa)\n- [DH](#dh)\n- [ElGamal](#elgamal)\n- [Primality tests](#primality-tests)\n- [Security](#security)\n\n## All imports\n\n```js\nimport { DH, DHGroups } from 'micro-rsa-dsa-dh/dh.js';\nimport { DSA } from 'micro-rsa-dsa-dh/dsa.js';\nimport { ElGamal, genElGamalParams } from 'micro-rsa-dsa-dh/elgamal.js';\nimport {\n  millerRabin,\n  jacobi,\n  lucas,\n  bailliePSW,\n  isProbablePrime,\n  isProbablePrimeRSA,\n  isProbablySafePrime,\n  IFCPrimes,\n} from 'micro-rsa-dsa-dh/primality.js';\nimport {\n  keygen,\n  mgf1,\n  OAEP,\n  PSS,\n  PKCS1_KEM,\n  PKCS1_SHA1,\n  PKCS1_SHA224,\n  PKCS1_SHA256,\n  PKCS1_SHA384,\n  PKCS1_SHA512,\n  PKCS1_SHA512_224,\n  PKCS1_SHA512_256,\n  PKCS1_SHA3_224,\n  PKCS1_SHA3_256,\n  PKCS1_SHA3_384,\n  PKCS1_SHA3_512,\n} from 'micro-rsa-dsa-dh/rsa.js';\n```\n\n## RSA\n\nRSA is most common example of integer factorization cryptography (IFC).\n\nKEM version of RSA (encrypt/decrypt) is slow and usually used to exchange AES/ChaCha keys.\n\n### OAEP\n\nOAEP is Optimal Asymmetric Encryption Padding.\n\nUse if you need KEM (encrypt/decrypt).\n\n```ts\nimport * as rsa from 'micro-rsa-dsa-dh/rsa.js';\nimport { sha256 } from '@noble/hashes/sha2';\nconst alice = rsa.keygen(2048);\nconst oaep = rsa.OAEP(sha256, rsa.mgf1(sha256));\nconst msg = new Uint8Array([1, 2, 3]);\nconst encrypted = oaep.encrypt(alice.publicKey, msg);\ndeepStrictEqual(oaep.decrypt(alice.privateKey, encrypted), msg);\n```\n\n### PSS\n\nUse if you need signatures (sign/verify).\n\n```ts\nimport * as rsa from 'micro-rsa-dsa-dh/rsa.js';\nimport { sha256 } from '@noble/hashes/sha2';\nconst alice = rsa.keygen(2048);\nconst pss = rsa.PSS(sha256, rsa.mgf1(sha256));\nconst msg = new Uint8Array([1, 2, 3]);\nconst sig = pss.sign(alice.privateKey, msg);\ndeepStrictEqual(pss.verify(alice.publicKey, msg, sig), true);\n```\n\n### PKCS1\n\nThis is old standard, OAEP/PSS is better.\n\nSignatures:\n\n```ts\nimport * as rsa from 'micro-rsa-dsa-dh/rsa.js';\nconst alice = rsa.keygen(2048);\nconst pkcs = rsa.PKCS1_SHA256;\nconst msg = new Uint8Array([1, 2, 3]);\nconst sig = pkcs.sign(alice.privateKey, msg);\ndeepStrictEqual(pkcs.verify(alice.publicKey, msg, sig), true);\n```\n\nKEM (vulnerable [[1]](https://crypto.stackexchange.com/questions/12688/can-you-explain-bleichenbachers-cca-attack-on-pkcs1-v1-5),\n[[2]](https://security.stackexchange.com/questions/183179/what-is-rsa-oaep-rsa-pss-in-simple-terms)\n):\n\n```ts\nimport * as rsa from 'micro-rsa-dsa-dh/rsa.js';\nconst alice = rsa.keygen(2048);\nconst pkcs = rsa.PKCS1_KEM;\nconst msg = new Uint8Array([1, 2, 3]);\nconst encrypted = pkcs.encrypt(alice.publicKey, msg);\ndeepStrictEqual(pkcs.decrypt(alice.privateKey, encrypted), msg);\n```\n\n## DH\n\nSame as ECDH, seems safe if pre-defined groups are used. Cons:\n\n- Long keys\n- Harder to protect from timing attacks\n- Using custom non-standard groups can make algorithm weak\n\n```ts\nimport { DH, DHGroups } from 'micro-rsa-dsa-dh/dh.js';\nconst dh = DH('modp18');\nconst alicePriv = dh.randomPrivateKey();\nconst alicePub = dh.getPublicKey(alicePriv);\n\nconst bobPriv = dh.randomPrivateKey();\nconst bobPub = dh.getPublicKey(bobPriv);\n\ndeepStrictEqual(dh.getSharedSecret(alicePriv, bobPub), dh.getSharedSecret(bobPriv, alicePub));\n```\n\n## DSA\n\n\u003e [!NOTE]\n\u003e DSA was deprecated in FIPS186-5.\n\nSame as ECDSA, but with big numbers. Cons:\n\n- Deprecated\n- No pre-defined groups: need to generate and send params\n- Long keys\n- Harder to protect from timing attacks\n\n```ts\nimport * as dsa from 'micro-rsa-dsa-dh/dsa.js';\nimport { sha256 } from '@noble/hashes/sha2';\n// 1. Params\n// Carol generates random params\nconst carolParams = dsa.genDSAParams(2048, 256, sha256, 1);\n// Instead of sending primes to Alice and Bob (which can be insecure), she sends seed\n// This ensures that params are not constructed primes, but generated randomly:\n// Alice and Bob can use these params without trusting Carol.\nconst seed = carolParams.domainParameterSeed;\n\nconst aliceParams = dsa.genDSAParams(2048, 256, sha256, 1, seed);\ndeepStrictEqual(aliceParams, carolParams); // Same params as Carol!\n\nconst bobParams = dsa.genDSAParams(2048, 256, sha256, 1, seed);\ndeepStrictEqual(aliceParams, bobParams); // Now Bob has same params too!\n\n// 2. Keys\nconst aliceDSA = dsa.DSA(aliceParams);\nconst alicePrivKey = aliceDSA.randomPrivateKey();\nconst alicePubKey = aliceDSA.getPublicKey(alicePrivKey); // Alice generates public key and sends to Bob\nconst msg = new Uint8Array([1, 2, 3, 4, 5]);\nconst sig = aliceDSA.sign(alicePrivKey, msg); // Alice signs message\n\nconst bobDSA = dsa.DSA(bobParams);\n// Now Bob can verify that message was sent by Alice (and not Carol for example).\ndeepStrictEqual(bobDSA.verify(alicePubKey, msg, sig), true);\n```\n\n## ElGamal\n\nMostly for educational purpose: almost nobody uses it.\n\n```ts\nimport { ElGamal, genElGamalParams } from 'micro-rsa-dsa-dh/elgamal.js';\n// NOTE: this is super slow! 512: 1s, 1024: 20s, 2048: 1046s\nconst params = genElGamalParams(512);\nconst elgamal = ElGamal(params);\n\nconst alicePriv = elgamal.randomPrivateKey();\nconst alicePub = elgamal.getPublicKey(alicePriv);\n// Encryption\nconst msg = 12345n; // bigint, because there is not spec for padding/hashing\nconst cipherText = elgamal.encrypt(alicePub, msg); // Somebody encrypts message using Alice public key\ndeepStrictEqual(elgamal.decrypt(alicePriv, cipherText), msg); // Alice can decrypt message using private key\n// Sign\nconst sig = elgamal.sign(alicePriv, msg); // Alice sings message using private key\ndeepStrictEqual(elgamal.verify(alicePub, msg, sig), true); // Other parties can verify it using Alice public key\n```\n\n## Primality tests\n\nA bunch of primality tests.\n\n```ts\nimport * as primality from 'micro-rsa-dsa-dh/primality.js';\ndeepStrictEqual(primality.millerRabin(7n, 10), true);\ndeepStrictEqual(primality.lucas(7n), true);\ndeepStrictEqual(primality.bailliePSW(7n), true);\ndeepStrictEqual(primality.isProbablePrime(7n, 30), true); // Tests 30 random bases\ndeepStrictEqual(primality.isProbablySafePrime(7n, 10), true);\n```\n\n|                     | Reliable | Deterministic | Note                                                                                                                                                                      |\n| ------------------- | -------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| millerRabin         | No       | No            | Non-deterministic Miller-Rabin test over random bases (multiple iterations).                                                                                              |\n| lucas               | No       | Yes           | Deterministic Lucas test. Generally slower than the Miller-Rabin test but can be more reliable for certain numbers.                                                       |\n| bailliePSW          | Yes      | Yes           | Deterministic test which consists of Miller-Rabin with base 2 and Lucas test. Suitable for critical applications where the highest reliability is required.               |\n| isProbablePrime     | Yes      | No            | Non-deterministic test from FIPS186-5. This is an enhanced version of the Baillie-PSW test, incorporating multiple rounds of the Miller-Rabin test with random bases      |\n| isProbablySafePrime | Yes      | No            | Non-deterministic safe prime test. Slow. Tests if a number is a probable safe prime. A safe prime is a prime number of the form p = 2q + 1, where both p and q are prime. |\n\n- _Reliable:_ no false positives are known\n- _Deterministic:_ it does not rely on randomness\n\n## Security\n\nAll algorithms use JS bigints, which are not constant-time. When timing attacks could be mounted, they will reveal sensitive information.\n\nThat generally means:\n\n- Document, mail, messaging encryption, like PGP, is probably OK. It's hard for an attacker to measure timings: they don't know how long it took to create a msg\n- Public APIs are NOT safe. Consider something like \"send us document and we will auto-sign it\". These cases can leak private keys\n\nFor comparison, bigint-based elliptic curve implementations will leak much less info. That's because they operate over much smaller numbers: think 2^256, instead of 2^2048.\n\n## Links\n\n- https://datatracker.ietf.org/doc/html/rfc3447 - old RSA\n- https://datatracker.ietf.org/doc/html/rfc8017 - OAEP/PSS/PKCS1\n- https://datatracker.ietf.org/doc/html/rfc8702 - RSA-PSS + Shake\n- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf - Prime generation\n- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - DSA\n- https://datatracker.ietf.org/doc/html/rfc2631 - DH\n- https://datatracker.ietf.org/doc/html/rfc3526 - DH groups\n- https://datatracker.ietf.org/doc/html/rfc6979 - DSA\n\n## License\n\nMIT (c) Paul Miller [(https://paulmillr.com)](https://paulmillr.com), see LICENSE file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulmillr%2Fmicro-rsa-dsa-dh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaulmillr%2Fmicro-rsa-dsa-dh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaulmillr%2Fmicro-rsa-dsa-dh/lists"}