# [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 &lt; 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 &lt; 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)
