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;
 |