generate RSA keys with node 10.12+

This commit is contained in:
AJ ONeal 2018-11-24 01:33:12 -07:00
parent 40bb9a0fdd
commit 6cd0c28b86
5 changed files with 131 additions and 9 deletions

View file

@ -5,27 +5,51 @@ Sponsored by [Root](https://therootcompany.com).
Built for [ACME.js](https://git.coolaj86.com/coolaj86/acme.js)
and [Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js)
RSA tools. Lightweight. Zero Dependencies. Universal compatibility.
| ~550 lines of code | 3kb gzipped | 10kb minified | 18kb with comments |
RSA tools. Lightweight. Zero Dependencies. Universal compatibility.
* [x] Fast and Easy RSA Key Generation
* [x] PEM-to-JWK
* [x] JWK-to-PEM
* [x] SSH "pub" format
* [ ] ECDSA
* **Need EC or ECDSA tools?** Check out [Eckles.js](https://git.coolaj86.com/coolaj86/eckles.js)
This project is fully functional and tested (and the code is pretty clean).
## Generate RSA Key
It is considered to be complete, but if you find a bug please open an issue.
Achieves the *fastest possible key generation* using node's native RSA bindings to OpenSSL,
then converts to JWK for ease-of-use.
## Looking for ECDSA as well?
```
Rasha.generate({ format: 'jwk' }).then(function (keypair) {
console.log(keypair.private);
console.log(keypair.public);
});
```
Check out [Eckles.js](https://git.coolaj86.com/coolaj86/eckles.js)
**options**
* `format` defaults to `'jwk'`
* `'pkcs1'` (traditional)
* `'pkcs8'`
* `modulusLength` defaults to 2048 (must not be lower)
* generally you shouldn't pick a larger key size - they're slow
* **2048** is more than sufficient
* 3072 is way, way overkill and takes a few seconds to generate
* 4096 can take about a minute to generate and is just plain wasteful
**advanced options**
These options are provided for debugging and should not be used.
* `publicExponent` defaults to 65537 (`0x10001`)
## PEM-to-JWK
* [x] PKCS#1 (traditional)
* [x] PKCS#8, SPKI/PKIX
* [x] 2048-bit, 4096-bit (and ostensibily all others)
* [x] 2048-bit, 3072-bit, 4096-bit (and ostensibily all others)
* [x] SSH (RFC4716), (RFC 4716/SSH2)
```js

View file

@ -9,6 +9,22 @@ var ASN1 = require('../lib/asn1.js');
var infile = process.argv[2];
var format = process.argv[3];
if (!infile) {
infile = 'jwk';
}
if (-1 !== [ 'jwk', 'pem', 'json', 'der', 'pkcs1', 'pkcs8', 'spki' ].indexOf(infile)) {
console.log("Generating new key...");
Rasha.generate({
format: infile
, modulusLength: parseInt(format, 10) || 2048
, encoding: parseInt(format, 10) ? null : format
}).then(function (key) {
console.log(key.private);
console.log(key.public);
});
return;
}
var key = fs.readFileSync(infile, 'ascii');
try {

View file

@ -7,6 +7,77 @@ var x509 = require('./x509.js');
var ASN1 = require('./asn1.js');
/*global Promise*/
RSA.generate = function (opts) {
return Promise.resolve().then(function () {
var typ = 'rsa';
var format = opts.format;
var encoding = opts.encoding;
var priv;
var pub;
if (!format) {
format = 'jwk';
}
if ('spki' === format || 'pkcs8' === format) {
format = 'pkcs8';
pub = 'spki';
}
if ('pem' === format) {
format = 'pkcs1';
encoding = 'pem';
} else if ('der' === format) {
format = 'pkcs1';
encoding = 'der';
}
if ('jwk' === format || 'json' === format) {
format = 'jwk';
encoding = 'json';
} else {
priv = format;
pub = pub || format;
}
if (!encoding) {
encoding = 'pem';
}
if (priv) {
priv = { type: priv, format: encoding };
pub = { type: pub, format: encoding };
} else {
// jwk
priv = { type: 'pkcs1', format: 'pem' };
pub = { type: 'pkcs1', format: 'pem' };
}
return new Promise(function (resolve, reject) {
return require('crypto').generateKeyPair(typ, {
modulusLength: opts.modulusLength || 2048
, publicExponent: opts.publicExponent || 0x10001
, privateKeyEncoding: priv
, publicKeyEncoding: pub
}, function (err, pubkey, privkey) {
if (err) { reject(err); }
resolve({
private: privkey
, public: pubkey
});
});
}).then(function (keypair) {
if ('jwk' !== format) {
return keypair;
}
return {
private: RSA.importSync({ pem: keypair.private, format: priv.format })
, public: RSA.importSync({ pem: keypair.public, format: pub.format, public: true })
};
});
});
};
RSA.importSync = function (opts) {
if (!opts || !opts.pem || 'string' !== typeof opts.pem) {
throw new Error("must pass { pem: pem } as a string");

View file

@ -1,6 +1,6 @@
{
"name": "rasha",
"version": "1.0.5",
"version": "1.1.0",
"description": "💯 PEM-to-JWK and JWK-to-PEM for RSA keys in a lightweight, zero-dependency library focused on perfect universal compatibility.",
"homepage": "https://git.coolaj86.com/coolaj86/rasha.js",
"main": "index.js",

13
test.sh
View file

@ -121,6 +121,18 @@ rndkey() {
pemtojwk ""
jwktopem ""
echo ""
echo "testing node key generation"
node bin/rasha.js > /dev/null
node bin/rasha.js jwk > /dev/null
node bin/rasha.js json 2048 > /dev/null
node bin/rasha.js der > /dev/null
node bin/rasha.js pkcs8 der > /dev/null
node bin/rasha.js pem > /dev/null
node bin/rasha.js pkcs1 pem > /dev/null
node bin/rasha.js spki > /dev/null
echo "PASS"
echo ""
echo ""
echo "Re-running tests with random keys of varying sizes"
@ -140,7 +152,6 @@ echo ""
echo "Note:"
echo "Keys larger than 2048 have been tested and work, but are omitted from automated tests to save time."
rm fixtures/*.1.*
echo ""