Compare commits
11 Commits
f0adccbc31
...
aae4ad4e3f
Author | SHA1 | Date |
---|---|---|
AJ ONeal | aae4ad4e3f | |
AJ ONeal | 023b0b7948 | |
AJ ONeal | 3d6b6e7f5e | |
AJ ONeal | f34332b5a6 | |
AJ ONeal | c145c8afc1 | |
Maciej Krüger | 5e1b014940 | |
AJ ONeal | 81f5961d8e | |
AJ ONeal | ab5e7bea1b | |
AJ ONeal | b3f02b480e | |
AJ ONeal | 8cee5a1b4e | |
AJ ONeal | 0dc03f86e5 |
84
README.md
84
README.md
|
@ -1,6 +1,9 @@
|
||||||
# rsa-compat.js
|
# 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")
|
||||||
|
|
||||||
| Sponsored by [ppl](https://ppl.family). Created at [Daplie](https://dapliefounder.com).
|
| Sponsored by [ppl](https://ppl.family).
|
||||||
|
|
||||||
JavaScript RSA utils that work on Windows, Mac, and Linux with or without C compiler
|
JavaScript RSA utils that work on Windows, Mac, and Linux with or without C compiler
|
||||||
|
|
||||||
|
@ -14,15 +17,31 @@ This is useful for **certbot** and **letsencrypt**.
|
||||||
Install
|
Install
|
||||||
=======
|
=======
|
||||||
|
|
||||||
```
|
node.js
|
||||||
# node.js
|
|
||||||
npm install --save rsa-compat
|
|
||||||
|
|
||||||
# CLI
|
```bash
|
||||||
|
npm install --save rsa-compat
|
||||||
|
```
|
||||||
|
|
||||||
|
For **more efficient** RSA key generation:
|
||||||
|
<small>(I dropped `ursa` as an "optional dependency" because the non-fatal error messages on unsupported platforms and node versions were confusing people, but I still recommend installing it)</small>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install --save ursa
|
||||||
|
```
|
||||||
|
|
||||||
|
**Node < v6** support:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install --save buffer-v6-polyfill
|
||||||
|
```
|
||||||
|
|
||||||
|
### CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
npm install --global rsa-compat
|
npm install --global rsa-compat
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
=====
|
=====
|
||||||
|
|
||||||
|
@ -44,11 +63,9 @@ Generate an RSA Keypair:
|
||||||
```javascript
|
```javascript
|
||||||
var RSA = require('rsa-compat').RSA;
|
var RSA = require('rsa-compat').RSA;
|
||||||
|
|
||||||
var bitlen = 2048;
|
var options = { bitlen: 2048, exp: 65537, public: true, pem: true, internal: true };
|
||||||
var exp = 65537;
|
|
||||||
var options = { public: true, pem: true, internal: true };
|
|
||||||
|
|
||||||
RSA.generateKeypair(bitlen, exp, options, function (err, keypair) {
|
RSA.generateKeypair(options, function (err, keypair) {
|
||||||
console.log(keypair);
|
console.log(keypair);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
@ -88,11 +105,32 @@ NOTE: this object is JSON safe as _ursa and _forge will be ignored
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
API
|
API
|
||||||
---
|
---
|
||||||
|
|
||||||
* `RSA.generateKeypair(bitlen, exp, options, cb)`
|
* `RSA.generateKeypair(options, cb)`
|
||||||
* `RSA.import(keypair, options)`
|
* (deprecated `RSA.generateKeypair(bitlen, exp, options, cb)`)
|
||||||
|
* `RSA.import(options)`
|
||||||
|
* (deprecated `RSA.import(keypair, options)`)
|
||||||
* `RSA.exportPrivatePem(keypair)`
|
* `RSA.exportPrivatePem(keypair)`
|
||||||
* `RSA.exportPublicPem(keypair)`
|
* `RSA.exportPublicPem(keypair)`
|
||||||
* `RSA.exportPrivateJwk(keypair)`
|
* `RSA.exportPrivateJwk(keypair)`
|
||||||
|
@ -104,20 +142,18 @@ API
|
||||||
|
|
||||||
`keypair` can be any object with any of these keys `publicKeyPem, privateKeyPem, publicKeyJwk, privateKeyJwk`
|
`keypair` can be any object with any of these keys `publicKeyPem, privateKeyPem, publicKeyJwk, privateKeyJwk`
|
||||||
|
|
||||||
### RSA.generateKeypair(bitlen, exp, options, cb)
|
### RSA.generateKeypair(options, cb)
|
||||||
|
|
||||||
Create a private keypair and export it as PEM, JWK, and/or internal formats
|
Create a private keypair and export it as PEM, JWK, and/or internal formats
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
RSA.generateKeypair(null, null, null, function (keypair) { /*...*/ });
|
RSA.generateKeypair(null, function (keypair) { /*...*/ });
|
||||||
|
|
||||||
RSA.generateKeypair(2048, 65537, { pem: false, public: false, internal: false }, function (keypair) { /*...*/ });
|
RSA.generateKeypair({
|
||||||
|
bitlen: 2048, exp: 65537, pem: false, public: false, internal: false
|
||||||
|
}, function (keypair) { /*...*/ });
|
||||||
```
|
```
|
||||||
|
|
||||||
`bitlen`: 2048 or 4096
|
|
||||||
|
|
||||||
`exp`: *65537* (default)
|
|
||||||
|
|
||||||
`options`:
|
`options`:
|
||||||
```javascript
|
```javascript
|
||||||
{ public: false // export public keys
|
{ public: false // export public keys
|
||||||
|
@ -129,12 +165,12 @@ RSA.generateKeypair(2048, 65537, { pem: false, public: false, internal: false },
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### RSA.import(keypair, options)
|
### RSA.import(options)
|
||||||
|
|
||||||
Imports keypair as JWKs and internal values `_ursa` and `_forge`.
|
Imports keypair as JWKs and internal values `_ursa` and `_forge`.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var keypair = RSA.import({ privateKeyPem: '...'});
|
var keypair = RSA.import({ type: 'RSA', privateKeyPem: '...' });
|
||||||
|
|
||||||
console.log(keypair);
|
console.log(keypair);
|
||||||
```
|
```
|
||||||
|
@ -211,3 +247,9 @@ var web64 = RSA.generateCsrDerWeb64(keypair, [ 'example.com', 'www.example.com'
|
||||||
|
|
||||||
console.log(web64);
|
console.log(web64);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
ChangeLog:
|
||||||
|
|
||||||
|
* v1.4.0
|
||||||
|
* remove ursa as dependency (just causes confusion), but note in docs
|
||||||
|
* drop node < v6 support
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var ursa = require('ursa');
|
var ursa;
|
||||||
|
try {
|
||||||
|
ursa = require('ursa');
|
||||||
|
} catch(e) {
|
||||||
|
try {
|
||||||
|
ursa = require('ursa-optional');
|
||||||
|
} catch(e2) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function notToJson() {
|
function notToJson() {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
33
node.js
33
node.js
|
@ -5,10 +5,16 @@
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
try {
|
||||||
require('buffer-v6-polyfill');
|
require('buffer-v6-polyfill');
|
||||||
|
} catch(e) {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
|
||||||
var RSA = {};
|
var RSA = {};
|
||||||
var NOBJ = {};
|
var NOBJ = {};
|
||||||
|
var DEFAULT_BITLEN = 2048;
|
||||||
|
var DEFAULT_EXPONENT = 65537;
|
||||||
|
|
||||||
function create(deps) {
|
function create(deps) {
|
||||||
var crypto = require('crypto');
|
var crypto = require('crypto');
|
||||||
|
@ -19,9 +25,13 @@ function create(deps) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
RSA._URSA = require('ursa');
|
RSA._URSA = require('ursa');
|
||||||
|
} catch(e) {
|
||||||
|
try {
|
||||||
|
RSA._URSA = require('ursa-optional');
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RSA.utils = require('./lib/key-utils.js');
|
RSA.utils = require('./lib/key-utils.js');
|
||||||
RSA.utils.toWebsafeBase64 = function (b64) {
|
RSA.utils.toWebsafeBase64 = function (b64) {
|
||||||
|
@ -51,7 +61,20 @@ function create(deps) {
|
||||||
return RSA.utils.toWebsafeBase64(base64Digest);
|
return RSA.utils.toWebsafeBase64(base64Digest);
|
||||||
};
|
};
|
||||||
|
|
||||||
RSA.generateKeypair = function (length, exponent, options, cb) {
|
// length, exponent, options, cb
|
||||||
|
RSA.generateKeypair = function (options, cb, extra1, extra2) {
|
||||||
|
var length;
|
||||||
|
var exponent;
|
||||||
|
if ('function' === typeof extra2) {
|
||||||
|
length = options || DEFAULT_BITLEN;
|
||||||
|
exponent = cb || DEFAULT_EXPONENT;
|
||||||
|
options = extra1 || NOBJ;
|
||||||
|
cb = extra2;
|
||||||
|
} else {
|
||||||
|
if (!options) { options = NOBJ; }
|
||||||
|
length = options.bitlen || DEFAULT_BITLEN;
|
||||||
|
exponent = options.exp || DEFAULT_EXPONENT;
|
||||||
|
}
|
||||||
if (!RSA._URSA && /arm|mips/i.test(require('os').arch) && !RSA._SLOW_WARN) {
|
if (!RSA._URSA && /arm|mips/i.test(require('os').arch) && !RSA._SLOW_WARN) {
|
||||||
console.warn("================================================================");
|
console.warn("================================================================");
|
||||||
console.warn(" WARNING");
|
console.warn(" WARNING");
|
||||||
|
@ -80,8 +103,6 @@ function create(deps) {
|
||||||
, _forgePublic: undefined
|
, _forgePublic: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
options = options || NOBJ;
|
|
||||||
|
|
||||||
RSA._internal.generateKeypair(length, exponent, options, function (err, keys) {
|
RSA._internal.generateKeypair(length, exponent, options, function (err, keys) {
|
||||||
if (false !== options.jwk || options.thumbprint) {
|
if (false !== options.jwk || options.thumbprint) {
|
||||||
keypair.privateKeyJwk = RSA._internal.exportPrivateJwk(keys);
|
keypair.privateKeyJwk = RSA._internal.exportPrivateJwk(keys);
|
||||||
|
@ -113,7 +134,11 @@ function create(deps) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
RSA.import = function (keypair/*, options*/) {
|
RSA.import = function (options/*, options*/) {
|
||||||
|
var keypair = options;
|
||||||
|
if (keypair.key) {
|
||||||
|
keypair = keypair.key;
|
||||||
|
}
|
||||||
keypair = RSA._internal.import(keypair, { internal: true });
|
keypair = RSA._internal.import(keypair, { internal: true });
|
||||||
keypair = RSA._internal.importForge(keypair, { internal: true });
|
keypair = RSA._internal.importForge(keypair, { internal: true });
|
||||||
//options = options || NOBJ; // ignore
|
//options = options || NOBJ; // ignore
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "rsa-compat",
|
"name": "rsa-compat",
|
||||||
"version": "1.3.2",
|
"version": "1.5.1",
|
||||||
"description": "RSA utils that work on Windows, Mac, and Linux with or without C compiler",
|
"description": "RSA utils that work on Windows, Mac, and Linux with or without C compiler",
|
||||||
"main": "node.js",
|
"main": "node.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -39,10 +39,13 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://git.coolaj86.com/coolaj86/rsa-compat.js#readme",
|
"homepage": "https://git.coolaj86.com/coolaj86/rsa-compat.js#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buffer-v6-polyfill": "^1.0.3",
|
|
||||||
"node-forge": "^0.6.41"
|
"node-forge": "^0.6.41"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"ursa": "^0.9.4"
|
},
|
||||||
|
"trulyOptionalDependencies": {
|
||||||
|
"buffer-v6-polyfill": "^1.0.3",
|
||||||
|
"ursa": "^0.9.4",
|
||||||
|
"ursa-optional": "^0.9.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var RSA = require('../').RSA;
|
||||||
|
|
||||||
|
RSA.generateKeypair(null, function (err, keys) {
|
||||||
|
if (!keys || !keys.privateKeyJwk) {
|
||||||
|
throw new Error("Expected privateKeyJwk, but it is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
keys.publicKeyJwk
|
||||||
|
|| keys.privateKeyPem
|
||||||
|
|| keys.publicKeyPem
|
||||||
|
|| keys.thumbprint
|
||||||
|
|| keys._ursa
|
||||||
|
|| keys._forge
|
||||||
|
) {
|
||||||
|
console.error(Object.keys(keys));
|
||||||
|
throw new Error("Got unexpected keys");
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
public: true // export public keys
|
||||||
|
, pem: true // export pems
|
||||||
|
, jwk: false // export jwks
|
||||||
|
, internal: true // preserve internal intermediate formats (_ursa, _forge)
|
||||||
|
//, thumbprint: true // JWK sha256 thumbprint
|
||||||
|
, bitlen: 2048
|
||||||
|
, exp: 65537
|
||||||
|
};
|
||||||
|
RSA.generateKeypair(options, function (err, keys) {
|
||||||
|
if (
|
||||||
|
(keys.publicKeyJwk && !keys.thumbprint)
|
||||||
|
|| !keys.privateKeyPem
|
||||||
|
|| !keys.publicKeyPem
|
||||||
|
//|| !keys.thumbprint
|
||||||
|
|| !(keys._ursa || keys._forge)
|
||||||
|
) {
|
||||||
|
console.error(Object.keys(keys));
|
||||||
|
throw new Error("Missing expected keys");
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('All is well!');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue