# [rsa-compat.js](https://git.coolaj86.com/coolaj86/rsa-compat.js) !["Lifetime Downloads"](https://img.shields.io/npm/dt/rsa-compat.svg "Lifetime Download Count can't be shown") !["Monthly Downloads"](https://img.shields.io/npm/dm/rsa-compat.svg "Monthly Download Count can't be shown") !["Weekly Downloads"](https://img.shields.io/npm/dw/rsa-compat.svg "Weekly Download Count can't be shown") | A [Root](https://therootcompany.com) Project. JavaScript RSA utils that work on Windows, Mac, and Linux with or without C compiler This was built for the [ACME.js](https://git.coolaj86.com/coolaj86/acme.js) and [Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js) **Let's Encrypt** clients and is particularly suitable for building **certbot**-like clients. (if you're looking for similar tools in the browser, consider [Bluecrypt](https://www.npmjs.com/search?q=bluecrypt)) # Install node.js ```bash npm install --save rsa-compat ``` If you need compatibility with older versions of node, you may need to `npm install --save ursa-optional node-forge`. ### CLI ```bash npm install --global rsa-compat ``` # Usage CLI --- You can generate keypairs on Windows, Mac, and Linux using rsa-keygen-js: ```bash # generates a new keypair in the current directory rsa-keypiar-js ``` Examples -------- Generate an RSA Keypair: ```javascript var RSA = require('rsa-compat').RSA; var options = { bitlen: 2048, exp: 65537, public: true, pem: true, internal: true }; RSA.generateKeypair(options, function (err, keypair) { console.log(keypair); }); ``` Here's what the object might look like: `console.log(keypair)`: ```javascript { publicKeyPem: '-----BEGIN RSA PUBLIC KEY-----\n/*base64 pem-encoded string*/' , privateKeyPem: '-----BEGIN RSA PRIVATE KEY-----\n/*base64 pem-encoded string*/' , privateKeyJwk: { kty: "RSA" , n: '/*base64 modulus n = pq*/' , e: '/*base64 exponent (usually 65537)*/' , d: '/*base64 private exponent (d = e^−1 (mod ϕ(n))/' , p: '/*base64 first prime*/' , q: '/*base64 second prime*/' , dp: '/*base64 first exponent for Chinese remainder theorem (dP = d (mod p−1))*/' , dq: '/*base64 Second exponent, used for CRT (dQ = d (mod q−1))/' , qi: '/*base64 Coefficient, used for CRT (qinv = q^−1 (mod p))*/' } , publicKeyJwk: { kty: "RSA" , n: '/*base64 modulus n = pq*/' , e: '/*base64 exponent (usually 65537)*/' } } ``` See http://crypto.stackexchange.com/questions/6593/what-data-is-saved-in-rsa-private-key to learn a little more about the meaning of the specific fields in the JWK. # API Summary * `RSA.generateKeypair(options, cb)` * (deprecated `RSA.generateKeypair(bitlen, exp, options, cb)`) * `RSA.import(options)` * (deprecated `RSA.import(keypair, options)`) * `RSA.exportPrivatePem(keypair)` * `RSA.exportPublicPem(keypair)` * `RSA.exportPrivateJwk(keypair)` * `RSA.exportPublicJwk(keypair)` * `RSA.signJws(keypair, header, protect, payload)` * (deprecated `RSA.signJws(keypair, payload, nonce)`) * `RSA.generateCsrPem(keypair, names)` * `RSA.generateCsrDerWeb64(keypair, names)` * `RSA.thumbprint(keypair)` `keypair` can be any object with any of these keys `publicKeyPem, privateKeyPem, publicKeyJwk, privateKeyJwk` ### RSA.generateKeypair(options, cb) Create a private keypair and export it as PEM, JWK, and/or internal formats ```javascript RSA.generateKeypair(null, function (keypair) { /*...*/ }); RSA.generateKeypair({ bitlen: 2048, exp: 65537, pem: false, public: false, internal: false }, function (keypair) { /*...*/ }); ``` `options`: ```javascript { public: false // export public keys , pem: false // export pems , jwk: true // export jwks , internal: false // preserve internal intermediate formats (_ursa, _forge) , thumbprint: false // JWK sha256 thumbprint , fingerprint: false // NOT IMPLEMENTED (RSA key fingerprint) } ``` ### RSA.import(options) Imports keypair as JWKs and internal values `_ursa` and `_forge`. ```javascript var keypair = RSA.import({ type: 'RSA', privateKeyPem: '...' }); console.log(keypair); ``` ```javascript { privateKeyPem: ..., privateKeyJwk: ..., _ursa: ..., _forge: ... } ``` ### RSA.export*(keypair) You put in an object like `{ privateKeyPem: '...' }` or `{ publicKeyJwk: {} }` and you get back the keys in the format you requested. Note: * Private keys **can** be used to export both private and public keys * Public keys can **NOT** be used to generate private keys Example: ```javascript var keypair = { privateKeyPem: '...' }; keypair.publicKeyJwk = RSA.exportPublicJwk(keypair); console.log(keypair); ``` ### RSA.signJws(keypair, payload, nonce) Generates a signature in JWS format (necessary for **certbot**/**letsencrypt**). ```javascript var message = "Hello, World!" var nonce = crypto.randomBytes(16).toString('hex'); var jws = RSA.signJws(keypair, message, nonce); console.log(jws); ``` The result looks like this: ```javascript { "header": { "alg": "RS256", "jwk": { "kty": "RSA", "n": "AMJubTfOtAarnJytLE8fhNsEI8wnpjRvBXGK/Kp0675J10ORzxyMLqzIZF3tcrUkKBrtdc79u4X0GocDUgukpfkY+2UPUS/GxehUYbYrJYWOLkoJWzxn7wfoo9X1JgvBMY6wHQnTKvnzZdkom2FMhGxkLaEUGDSfsNznTTZNBBg9", "e": "AQAB" } }, "protected": "eyJub25jZSI6IjhlZjU2MjRmNWVjOWQzZWYifQ", "payload": "JLzF1NBNCV3kfbJ5sFaFyX94fJuL2H-IzaoBN-ciiHk", "signature": "Wb2al5SDyh5gjmkV79MK9m3sfNBBPjntSKor-34BBoGwr6n8qEnBmqB1Y4zbo-5rmvsoPmJsnRlP_hRiUY86zSAQyfbisTGrGBl0IQ7ditpkfYVm0rBWJ8WnYNqYNp8K3qcD7NW72tsy-XoWEjNlz4lWJeRdEG2Nt4CJgnREH4Y" } ``` ### RSA.thumbprint(keypair) Generates a JWK thumbprint. `RSA.thumbprint(keypair)`: ```javascript var thumb = RSA.thumbprint(keypair); console.log(thumb); ``` ``` // kK4OXp5CT1FEkHi6WkegldmeTJecSTyJN-DxZ91nQ30 ``` ### RSA.generateCsr*(keypair, names) You can generate the CSR in human-readable or binary / base64 formats: `RSA.generateCsrPem(keypair, names)`: ```javascript var pem = RSA.generateCsrPem(keypair, [ 'example.com', 'www.example.com' ]); console.log(pem); ``` web-safe base64 for **certbot**/**letsencrypt**: `RSA.generateCsrDerWeb64(keypair, names)`: ```javascript var web64 = RSA.generateCsrDerWeb64(keypair, [ 'example.com', 'www.example.com' ]); console.log(web64); ``` # Old Node Versions In recent versions of node >= v10.12 native RSA key generation is fairly quick for 2048-bit keys (though it may still be too slow for some applications with 4096-bit keys). In old versions, however, and especially on ARM and/or MIPS procesors, RSA key generation can be very, very slow. In old node versions `ursa` can provide faster key generation, but it must be compiled. `ursa` will not compile for new node versions, but they already include the same openssl bindings anyawy. ```bash npm install --save ursa ``` Also, if you need **Node < v6** support: ```bash npm install --save buffer-v6-polyfill ``` ## Security and Compatibility **TL;DR**: Use the default values 2048 and 65537 unless you have a really, really good reason to do otherwise. Various platforms *require* these values. Most security experts agree that 4096-bit is no more "secure" than 2048-bit - a fundamental vulnerability in the RSA algorithm which causes 2048 to be broken will most likely also cause 4096 to be broken (i.e. if someone can prove mathematically prove P=NP or a way to predict prime numbers). Also, many platforms only support 2048 bit keys due to the insecurity of 1024-bit keys (which are not 1/2 secure but rather 1/(2^1028) less secure) and the excess computational cost of 4096-bit keys (it's not a 2x increase, it's more like a 2^2048 increase). As to why 65537 is even optional as a prime exponent or why it matters... no idea, but it does matter. # ChangeLog: * v2.0 * remove ursa and node-forge deps * mark for node v10.11+ * v1.9 * consistently handle key generation across node crypto, ursa, and forge * move all other operations to rasha.js and rsa-csr.js * bugfix non-standard JWKs output (which *mostly* worked) * move dependencies to optional * v1.4.0 * remove ursa as dependency (just causes confusion), but note in docs * drop node < v6 support # Legal rsa-compat.js directly includes code from [Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js) and [RSA-CSR.js](https://git.coolaj86.com/coolaj86/rsa-csr.js) (also [Root](https://therootcompany.com) projects), retrofitted for rsa-compat. [rsa-compat.js](https://git.coolaj86.com/coolaj86/rsa-compat.js) | MPL-2.0 | [Terms of Use](https://therootcompany.com/legal/#terms) | [Privacy Policy](https://therootcompany.com/legal/#privacy)