generate ec and rsa keypiars for web
This commit is contained in:
parent
7591e3fbdd
commit
9537737d19
|
@ -0,0 +1,134 @@
|
||||||
|
;(function (exports) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var PromiseA;
|
||||||
|
try {
|
||||||
|
/*global Promise*/
|
||||||
|
PromiseA = Promise;
|
||||||
|
} catch(e) {
|
||||||
|
PromiseA = require('bluebird');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/40314257/export-webcrypto-key-to-pem-format
|
||||||
|
function derToPem(keydata, pemName, privacy){
|
||||||
|
var keydataS = arrayBufferToString(keydata);
|
||||||
|
var keydataB64 = window.btoa(keydataS);
|
||||||
|
var keydataB64Pem = formatAsPem(keydataB64, pemName, privacy);
|
||||||
|
return keydataB64Pem;
|
||||||
|
}
|
||||||
|
|
||||||
|
function arrayBufferToString( buffer ) {
|
||||||
|
var binary = [];
|
||||||
|
var bytes = new Uint8Array( buffer );
|
||||||
|
var len = bytes.byteLength;
|
||||||
|
for (var i = 0; i < len; i++) {
|
||||||
|
binary.push(String.fromCharCode( bytes[ i ] ));
|
||||||
|
}
|
||||||
|
return binary.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatAsPem(str, pemName, privacy) {
|
||||||
|
var privstr = (privacy ? privacy + ' ' : '');
|
||||||
|
var finalString = '-----BEGIN ' + pemName + ' ' + privstr + 'KEY-----\n';
|
||||||
|
|
||||||
|
while (str.length > 0) {
|
||||||
|
finalString += str.substring(0, 64) + '\n';
|
||||||
|
str = str.substring(64);
|
||||||
|
}
|
||||||
|
|
||||||
|
finalString = finalString + '-----END ' + pemName + ' ' + privstr + 'KEY-----';
|
||||||
|
|
||||||
|
return finalString;
|
||||||
|
}
|
||||||
|
|
||||||
|
var Keypairs = exports.Keypairs = {
|
||||||
|
generate: function(opts) {
|
||||||
|
if (!opts) { opts = {}; }
|
||||||
|
if (!opts.type) { opts.type = 'EC'; }
|
||||||
|
|
||||||
|
var supported = [ 'EC', 'RSA' ];
|
||||||
|
if (-1 === supported.indexOf(opts.type)) {
|
||||||
|
return PromiseA.reject(new Error("'" + opts.type + "' not implemented. Try one of " + supported.join(', ')));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('EC' === opts.type) {
|
||||||
|
return Keypairs._generateEc(opts);
|
||||||
|
}
|
||||||
|
if ('RSA' === opts.type) {
|
||||||
|
return Keypairs._generateRsa(opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, _generateEc: function (opts) {
|
||||||
|
if (!opts.namedCurve) { opts.namedCurve = 'P-256'; }
|
||||||
|
if ('P-256' !== opts.namedCurve) {
|
||||||
|
console.warn("'" + opts.namedCurve + "' is not supported, but it _might_ happen to work anyway.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/diafygi/webcrypto-examples#ecdsa---generatekey
|
||||||
|
var extractable = true;
|
||||||
|
|
||||||
|
return window.crypto.subtle.generateKey(
|
||||||
|
{ name: "ECDSA", namedCurve: opts.namedCurve }
|
||||||
|
, extractable
|
||||||
|
, [ 'sign', 'verify' ]
|
||||||
|
).then(function (result) {
|
||||||
|
return window.crypto.subtle.exportKey(
|
||||||
|
"jwk"
|
||||||
|
, result.privateKey
|
||||||
|
).then(function (jwk) {
|
||||||
|
return window.crypto.subtle.exportKey(
|
||||||
|
"pkcs8"
|
||||||
|
, result.privateKey
|
||||||
|
).then(function (keydata) {
|
||||||
|
return {
|
||||||
|
type: 'EC'
|
||||||
|
, privateJwk: jwk
|
||||||
|
, privatePem: derToPem(keydata, 'EC', 'PRIVATE')
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
, _generateRsa: function (opts) {
|
||||||
|
if (!opts.bitlength) { opts.bitlength = 2048; }
|
||||||
|
if (-1 === [ 2048, 4096 ].indexOf(opts.bitlength)) {
|
||||||
|
return PromiseA.reject("opts.bitlength = (" + typeof opts.bitlength + ") " + opts.bitlength + ": Are you serious?");
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/diafygi/webcrypto-examples#rsa---generatekey
|
||||||
|
var extractable = true;
|
||||||
|
|
||||||
|
return window.crypto.subtle.generateKey(
|
||||||
|
{ name: "RSASSA-PKCS1-v1_5"
|
||||||
|
, modulusLength: opts.bitlength
|
||||||
|
, publicExponent: new Uint8Array([0x01, 0x00, 0x01])
|
||||||
|
, hash: { name: "SHA-256" }
|
||||||
|
}
|
||||||
|
, extractable
|
||||||
|
, [ 'sign', 'verify' ]
|
||||||
|
).then(function (result) {
|
||||||
|
return window.crypto.subtle.exportKey(
|
||||||
|
"jwk"
|
||||||
|
, result.privateKey
|
||||||
|
).then(function (jwk) {
|
||||||
|
return window.crypto.subtle.exportKey(
|
||||||
|
"pkcs8"
|
||||||
|
, result.privateKey
|
||||||
|
).then(function (keydata) {
|
||||||
|
return {
|
||||||
|
type: 'RSA'
|
||||||
|
, privateJwk: jwk
|
||||||
|
, privatePem: derToPem(keydata, 'RSA', 'PRIVATE')
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}('undefined' === typeof module ? window : module.exports));
|
||||||
|
|
||||||
|
// How we might use this
|
||||||
|
// var Keypairs = require('keypairs').Keypairs
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "keypairs",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Interchangeably use RSA & ECDSA with PEM and JWK for Signing, Verifying, CSR generation and JOSE. Ugh... that was a mouthful.",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.coolaj86.com/coolaj86/keypairs.js"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"EC",
|
||||||
|
"RSA",
|
||||||
|
"ECDSA",
|
||||||
|
"PEM",
|
||||||
|
"JWK",
|
||||||
|
"CSR",
|
||||||
|
"JOSE"
|
||||||
|
],
|
||||||
|
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
||||||
|
"license": "(MIT OR Apache-2.0)"
|
||||||
|
}
|
Loading…
Reference in New Issue