Compare commits

..

No commits in common. "aae4ad4e3f8c5183c2ffe571e10033948bb6379f" and "f0adccbc31d660c04637415d77a70b5e99474e02" have entirely different histories.

5 changed files with 30 additions and 156 deletions

View File

@ -1,9 +1,6 @@
# 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). | Sponsored by [ppl](https://ppl.family). Created at [Daplie](https://dapliefounder.com).
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
@ -17,31 +14,15 @@ This is useful for **certbot** and **letsencrypt**.
Install Install
======= =======
node.js ```
# node.js
```bash
npm install --save rsa-compat npm install --save rsa-compat
```
For **more efficient** RSA key generation: # CLI
<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 &lt; v6** support:
```bash
npm install --save buffer-v6-polyfill
```
### CLI
```bash
npm install --global rsa-compat npm install --global rsa-compat
``` ```
Usage Usage
===== =====
@ -63,9 +44,11 @@ Generate an RSA Keypair:
```javascript ```javascript
var RSA = require('rsa-compat').RSA; var RSA = require('rsa-compat').RSA;
var options = { bitlen: 2048, exp: 65537, public: true, pem: true, internal: true }; var bitlen = 2048;
var exp = 65537;
var options = { public: true, pem: true, internal: true };
RSA.generateKeypair(options, function (err, keypair) { RSA.generateKeypair(bitlen, exp, options, function (err, keypair) {
console.log(keypair); console.log(keypair);
}); });
``` ```
@ -105,32 +88,11 @@ 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(options, cb)` * `RSA.generateKeypair(bitlen, exp, options, cb)`
* (deprecated `RSA.generateKeypair(bitlen, exp, options, cb)`) * `RSA.import(keypair, options)`
* `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)`
@ -142,18 +104,20 @@ 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(options, cb) ### RSA.generateKeypair(bitlen, exp, 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, function (keypair) { /*...*/ }); RSA.generateKeypair(null, null, null, function (keypair) { /*...*/ });
RSA.generateKeypair({ RSA.generateKeypair(2048, 65537, { pem: false, public: false, internal: false }, function (keypair) { /*...*/ });
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
@ -165,12 +129,12 @@ RSA.generateKeypair({
} }
``` ```
### RSA.import(options) ### RSA.import(keypair, 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({ type: 'RSA', privateKeyPem: '...' }); var keypair = RSA.import({ privateKeyPem: '...'});
console.log(keypair); console.log(keypair);
``` ```
@ -247,9 +211,3 @@ 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 &lt; v6 support

View File

@ -1,16 +1,6 @@
'use strict'; 'use strict';
var ursa; var ursa = require('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
View File

@ -5,16 +5,10 @@
*/ */
'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');
@ -25,13 +19,9 @@ 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) {
@ -61,20 +51,7 @@ function create(deps) {
return RSA.utils.toWebsafeBase64(base64Digest); return RSA.utils.toWebsafeBase64(base64Digest);
}; };
// length, exponent, options, cb RSA.generateKeypair = function (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");
@ -103,6 +80,8 @@ 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);
@ -134,11 +113,7 @@ function create(deps) {
}); });
}; };
RSA.import = function (options/*, options*/) { RSA.import = function (keypair/*, 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

View File

@ -1,6 +1,6 @@
{ {
"name": "rsa-compat", "name": "rsa-compat",
"version": "1.5.1", "version": "1.3.2",
"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,13 +39,10 @@
}, },
"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"
} }
} }

View File

@ -1,46 +0,0 @@
'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!');
});
});