116 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			116 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | /*! | ||
|  |  * letiny-core | ||
|  |  * Copyright(c) 2015 AJ ONeal <aj@daplie.com> https://daplie.com
 | ||
|  |  * Apache-2.0 OR MIT (and hence also MPL 2.0) | ||
|  | */ | ||
|  | 'use strict'; | ||
|  | 
 | ||
|  | var crypto = require('crypto'); | ||
|  | var forge = require('node-forge'); | ||
|  | 
 | ||
|  | function binstrToB64(binstr) { | ||
|  |   return new Buffer(binstr, 'binary').toString('base64'); | ||
|  | } | ||
|  | 
 | ||
|  | function b64ToBinstr(b64) { | ||
|  |   return new Buffer(b64, 'base64').toString('binary'); | ||
|  | } | ||
|  | 
 | ||
|  | function toAcmePrivateKey(forgePrivkey) { | ||
|  |   //var forgePrivkey = forge.pki.privateKeyFromPem(privkeyPem);
 | ||
|  | 
 | ||
|  |   return { | ||
|  |     kty: "RSA" | ||
|  |   , n: binstrToB64(forgePrivkey.n) | ||
|  |   , e: binstrToB64(forgePrivkey.e) | ||
|  |   , d: binstrToB64(forgePrivkey.d) | ||
|  |   , p: binstrToB64(forgePrivkey.p) | ||
|  |   , q: binstrToB64(forgePrivkey.q) | ||
|  |   , dp: binstrToB64(forgePrivkey.dP) | ||
|  |   , dq: binstrToB64(forgePrivkey.dQ) | ||
|  |   , qi: binstrToB64(forgePrivkey.qInv) | ||
|  |   }; | ||
|  | } | ||
|  | 
 | ||
|  | function toForgePrivateKey(forgePrivkey) { | ||
|  |   return forge.pki.rsa.setPrivateKey( | ||
|  |     b64ToBinstr(forgePrivkey.n) | ||
|  |   , b64ToBinstr(forgePrivkey.e) | ||
|  |   , b64ToBinstr(forgePrivkey.d) | ||
|  |   , b64ToBinstr(forgePrivkey.p) | ||
|  |   , b64ToBinstr(forgePrivkey.q) | ||
|  |   , b64ToBinstr(forgePrivkey.dp) | ||
|  |   , b64ToBinstr(forgePrivkey.dq) | ||
|  |   , b64ToBinstr(forgePrivkey.qi) | ||
|  |   ); | ||
|  | } | ||
|  | 
 | ||
|  | // WARNING: with forge this takes 20+ minutes on a Raspberry Pi!!!
 | ||
|  | // It takes SEVERAL seconds even on a nice macbook pro
 | ||
|  | function generateRsaKeypair(bitlen, exp, cb) { | ||
|  |   var pki = forge.pki; | ||
|  |   var keypair = pki.rsa.generateKeyPair({ bits: bitlen, e: exp }); | ||
|  |   var pems = { | ||
|  |     publicKeyPem: pki.publicKeyToPem(keypair.publicKey)     // ascii PEM: ----BEGIN...
 | ||
|  |   , privateKeyPem: pki.privateKeyToPem(keypair.privateKey)  // ascii PEM: ----BEGIN...
 | ||
|  |   }; | ||
|  | 
 | ||
|  |   // I would have chosen sha1 or sha2... but whatever
 | ||
|  |   pems.publicKeyMd5 = crypto.createHash('md5').update(pems.publicKeyPem).digest('hex'); | ||
|  |   // json { n: ..., e: ..., iq: ..., etc }
 | ||
|  |   pems.privateKeyJwk = toAcmePrivateKey(keypair.privateKey); | ||
|  |   // deprecate
 | ||
|  |   pems.privateKeyJson = pems.privateKeyJwk; | ||
|  | 
 | ||
|  |   // TODO thumbprint
 | ||
|  | 
 | ||
|  |   cb(null, pems); | ||
|  | } | ||
|  | 
 | ||
|  | function parseAccountPrivateKey(pkj, cb) { | ||
|  |   var pki = forge.pki; | ||
|  | 
 | ||
|  |   Object.keys(pkj).forEach(function (key) { | ||
|  |     pkj[key] = new Buffer(pkj[key], 'base64'); | ||
|  |   }); | ||
|  | 
 | ||
|  |   var priv; | ||
|  |   var pubPem; | ||
|  | 
 | ||
|  |   try { | ||
|  |     priv = toForgePrivateKey( | ||
|  |       pkj.n // modulus
 | ||
|  |     , pkj.e // exponent
 | ||
|  |     , pkj.p | ||
|  |     , pkj.q | ||
|  |     , pkj.dp | ||
|  |     , pkj.dq | ||
|  |     , pkj.qi | ||
|  |     , pkj.d | ||
|  |     ); | ||
|  |   } catch(e) { | ||
|  |     cb(e); | ||
|  |     return; | ||
|  |   } | ||
|  | 
 | ||
|  |   pubPem = pki.publicKeyToPem(priv.publicKey); | ||
|  |   cb(null, { | ||
|  |     publicKeyPem: pubPem                                  // ascii PEM: ----BEGIN...
 | ||
|  |   , privateKeyPem: pki.privateKeyToPem(priv.privateKey)   // ascii PEM: ----BEGIN...
 | ||
|  |     // json { n: ..., e: ..., iq: ..., etc }
 | ||
|  |   , privateKeyJwt: pkj | ||
|  |     // deprecate
 | ||
|  |   , privateKeyJson: pkj | ||
|  |     // I would have chosen sha1 or sha2... but whatever
 | ||
|  |   , publicKeyMd5: crypto.createHash('md5').update(pubPem).digest('hex') | ||
|  |   }); | ||
|  | } | ||
|  | 
 | ||
|  | module.exports.generateRsaKeypair = generateRsaKeypair; | ||
|  | module.exports.privateJwkToPems = parseAccountPrivateKey; | ||
|  | module.exports.privatePemToJwk = toAcmePrivateKey; | ||
|  | 
 | ||
|  | // TODO deprecate
 | ||
|  | module.exports.toAcmePrivateKey = toAcmePrivateKey; | ||
|  | module.exports.parseAccountPrivateKey = parseAccountPrivateKey; |