rsa-compat
Advanced tools
Comparing version 1.0.1 to 1.1.0
@@ -9,2 +9,5 @@ 'use strict'; | ||
} | ||
function b64ToBinstr(b64) { | ||
return new Buffer(b64, 'b64').toString('binary'); | ||
} | ||
@@ -41,3 +44,3 @@ /* | ||
_forgeToPrivateJwk: function (keypair) { | ||
var k = keypair._forge.privateKey; | ||
var k = keypair._forge; | ||
@@ -57,3 +60,3 @@ return { | ||
, _forgeToPublicJwk: function (keypair) { | ||
var k = keypair._forge.privateKey || keypair._forge.publicKey; | ||
var k = keypair._forge || keypair._forgePublic; | ||
return { | ||
@@ -69,2 +72,26 @@ kty: "RSA" | ||
// | ||
// Import Forge | ||
// | ||
, _forgeImportJwk: require('./rsa-forge')._forgeImportJwk | ||
, _forgeImportPublicJwk: require('./rsa-forge')._forgeImportPublicJwk | ||
, _forgeImportPem: function (keypair) { | ||
keypair._forge = keypair._forge || forge.pki.privateKeyFromPem(keypair.privateKeyPem); | ||
} | ||
, _forgeImportPublicPem: function (keypair) { | ||
keypair._forgePublic = keypair._forgePublic || forge.pki.publicKeyFromPem(keypair.publicKeyPem); | ||
} | ||
, importForge: function (keypair) { | ||
extrac._forgeImportJwk(keypair); | ||
if (keypair.privateKeyPem) { | ||
extrac._forgeImportPem(keypair); | ||
} | ||
if (keypair.publicKeyPem) { | ||
extrac._forgeImportPublicPem(keypair); | ||
} | ||
return keypair; | ||
} | ||
// | ||
// Export JWK | ||
@@ -75,3 +102,3 @@ // | ||
var hasPrivatePem = keypair.privateKeyPem && true; | ||
var hasForgePrivate = keypair._forge && keypair._forge.privateKey && true; | ||
var hasForgePrivate = keypair._forge && keypair._forge && true; | ||
@@ -88,7 +115,7 @@ if (keypair.privateKeyJwk) { | ||
if (keypair.privateKeyPem) { | ||
keypair._forge = { privateKey: forge.pki.privateKeyFromPem(keypair.privateKeyPem) }; | ||
extrac._forgeImportPem(keypair); | ||
} | ||
} | ||
if (keypair._forge && keypair._forge.privateKey) { | ||
if (keypair._forge && keypair._forge) { | ||
return extrac._forgeToPrivateJwk(keypair); | ||
@@ -122,7 +149,7 @@ } | ||
if (keypair.publicKeyPem) { | ||
keypair._forge = { privateKey: forge.pki.publicKeyFromPem(keypair.publicKeyPem) }; | ||
extrac._forgeImportPublicPem(keypair); | ||
} | ||
} | ||
if (keypair._forge && keypair._forge.privateKey) { | ||
if (keypair._forge && keypair._forge) { | ||
return extrac._forgeToPublicJwk(keypair); | ||
@@ -129,0 +156,0 @@ } |
'use strict'; | ||
var forge = require('node-forge'); | ||
var utils = require('./key-utils.js'); | ||
@@ -38,5 +37,18 @@ function notToJson() { | ||
// | ||
_base64ToBn: function (base64) { | ||
return new forge.jsbn.BigInteger(utils.b64dec(base64).toString("hex"), 16); | ||
_toStandardBase64: function (str) { | ||
var b64 = str.replace(/-/g, "+").replace(/_/g, "/").replace(/=/g, ""); | ||
switch (b64.length % 4) { | ||
case 2: b64 += "=="; break; | ||
case 3: b64 += "="; break; | ||
} | ||
return b64; | ||
} | ||
, _base64ToBin: function (base64) { | ||
var std64 = forgec._toStandardBase64(base64); | ||
var hex = new Buffer(std64, 'base64').toString("hex"); | ||
return new forge.jsbn.BigInteger(hex, 16); | ||
} | ||
, _privateJwkToComponents: function (jwk) { | ||
@@ -47,3 +59,3 @@ var components = []; | ||
[ 'n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi' ].forEach(function (key) { | ||
components.push(new forgec._base64tobin(jwk[key])); | ||
components.push(forgec._base64ToBin(jwk[key])); | ||
}); | ||
@@ -68,8 +80,9 @@ | ||
, generateKeypair: function (bitlen, exp, options, cb) { | ||
var keypair = forge.pki.rsa.generateKeyPair({ bits: bitlen || 1024, e: exp || 0x10001 }); | ||
var fkeypair = forge.pki.rsa.generateKeyPair({ bits: bitlen || 1024, e: exp || 0x10001 }); | ||
keypair.toJSON = notToJson; | ||
fkeypair.toJSON = notToJson; | ||
cb(null, { | ||
_forge: keypair | ||
_forge: fkeypair.privateKey | ||
, _forgePublic: fkeypair.publicKey | ||
}); | ||
@@ -81,2 +94,26 @@ } | ||
// | ||
// Import (no-op) | ||
// | ||
, _forgeImportJwk: function (keypair) { | ||
keypair._forge = keypair._forge || forge.pki.rsa.setPrivateKey.apply( | ||
forge.pki.rsa | ||
, forgec._privateJwkToComponents(keypair.privateKeyJwk) | ||
); | ||
keypair._forge.toJSON = notToJson; | ||
} | ||
, _forgeImportPublicJwk: function (keypair) { | ||
keypair._forgePublic = keypair._forgePublic || forge.pki.rsa.setPublicKey.apply( | ||
forge.pki.rsa | ||
, forgec._publicJwkToComponents(keypair.publicKeyJwk) | ||
); | ||
keypair._forgePublic.toJSON = notToJson; | ||
} | ||
, import: function (keypair) { | ||
// no-op since this must be done anyway in extra | ||
return keypair; | ||
} | ||
// | ||
// Export Public / Private PEMs | ||
@@ -89,14 +126,8 @@ // | ||
if (keypair.privateKeyJwk && !(keypair._forge && keypair._forge.privateKey)) { | ||
keypair._forge = { | ||
privateKey: forge.pki.rsa.setPrivateKey.apply( | ||
forge.pki.rsa | ||
, forgec._privateJwkToComponents(keypair.privateKeyJwk) | ||
) | ||
}; | ||
keypair._forge.toJSON = notToJson; | ||
if (keypair.privateKeyJwk && !(keypair._forge && keypair._forge)) { | ||
forgec._forgeImportJwk(keypair); | ||
} | ||
if (keypair._forge && keypair._forge.privateKey) { | ||
return forge.pki.privateKeyToPem(keypair._forge.privateKey); | ||
if (keypair._forge && keypair._forge) { | ||
return forge.pki.privateKeyToPem(keypair._forge); | ||
} | ||
@@ -112,15 +143,9 @@ | ||
if ((keypair.privateKeyJwk || keypair.publicKeyJwk) | ||
&& !(keypair._forge && (keypair._forge.privateKey || keypair._forge.publicKey)) | ||
&& !(keypair._forge && (keypair._forge || keypair._forgePublic)) | ||
) { | ||
keypair._forge = { | ||
publicKey: forge.pki.rsa.setPublicKey.apply( | ||
forge.pki.rsa | ||
, forgec._publicJwkToComponents(keypair.publicKeyJwk) | ||
) | ||
}; | ||
keypair._forge.toJSON = notToJson; | ||
forgec._forgeImportPublicJwk(keypair); | ||
} | ||
if (keypair._forge) { | ||
return forge.pki.publicKeyToPem(keypair._forge.publicKey || keypair._forge.privateKey); | ||
return forge.pki.publicKeyToPem(keypair._forgePublic || keypair._forge); | ||
} | ||
@@ -127,0 +152,0 @@ |
@@ -52,11 +52,30 @@ 'use strict'; | ||
// | ||
// Export Public / Private PEMs | ||
// Import | ||
// | ||
, exportPrivatePem: function (keypair) { | ||
, _ursaImportPem: function (keypair) { | ||
if (keypair._ursa) { | ||
return; | ||
} | ||
if (keypair.privateKeyPem) { | ||
return keypair.privateKeyPem; | ||
keypair._ursa = ursa.createPrivateKey(keypair.privateKeyPem); | ||
keypair._ursa.toJSON = notToJson; | ||
} | ||
else if (keypair.publicKeyPem) { | ||
ursac._ursaImportPublicPem(keypair); | ||
} | ||
} | ||
, _ursaImportPublicPem: function (keypair) { | ||
if (keypair._ursa || keypair._ursaPublic) { | ||
return; | ||
} | ||
if (keypair.publicKeyPem) { | ||
keypair._ursaPublic = ursa.createPublicKey(keypair.publicKeyPem); | ||
keypair._ursaPublic.toJSON = notToJson; | ||
} | ||
} | ||
, _ursaImportJwk: function (keypair) { | ||
if (keypair._ursa) { | ||
return keypair._ursa.toPrivatePem().toString('ascii'); | ||
return; | ||
} | ||
@@ -70,6 +89,45 @@ | ||
keypair._ursa.toJSON = notToJson; | ||
} | ||
else if (keypair.publicKeyJwk) { | ||
ursac._ursaImportPublicJwk(keypair); | ||
} | ||
} | ||
, _ursaImportPublicJwk: function (keypair) { | ||
if (keypair._ursa || keypair._ursaPublic) { | ||
return; | ||
} | ||
keypair._ursaPublic = ursa.createPublicKeyFromComponents.apply( | ||
ursa | ||
, ursac._publicJwkToComponents(keypair.publicKeyJwk) | ||
); | ||
keypair._ursaPublic.toJSON = notToJson; | ||
} | ||
, import: function (keypair) { | ||
ursac._ursaImportJwk(keypair); | ||
ursac._ursaImportPem(keypair); | ||
return keypair; | ||
} | ||
// | ||
// Export Public / Private PEMs | ||
// | ||
, exportPrivatePem: function (keypair) { | ||
if (keypair.privateKeyPem) { | ||
return keypair.privateKeyPem; | ||
} | ||
if (keypair._ursa) { | ||
return keypair._ursa.toPrivatePem().toString('ascii'); | ||
} | ||
if (keypair.privateKeyJwk) { | ||
ursac._ursaImportJwk(keypair); | ||
return keypair._ursa.toPrivatePem().toString('ascii'); | ||
} | ||
throw new Error("None of privateKeyPem, _ursa, or privateKeyJwk found. No way to export private key PEM"); | ||
@@ -87,7 +145,3 @@ } | ||
if (keypair.publicKeyJwk) { | ||
keypair._ursaPublic = ursa.createPublicKeyFromComponents.apply( | ||
ursa | ||
, ursac._publicJwkToComponents(keypair.publicKeyJwk) | ||
); | ||
keypair._ursaPublic.toJSON = notToJson; | ||
ursac._ursaImportPublicJwk(keypair); | ||
@@ -98,7 +152,3 @@ return keypair._ursa.toPublicPem().toString('ascii'); | ||
if (keypair.privateKeyJwk) { | ||
keypair._ursa = ursa.createPrivateKeyFromComponents.apply( | ||
ursa | ||
, ursac._privateJwkToComponents(keypair.privateKeyJwk) | ||
); | ||
keypair._ursa.toJSON = notToJson; | ||
ursac._ursaImportJwk(keypair); | ||
@@ -109,4 +159,3 @@ return keypair._ursa.toPublicPem().toString('ascii'); | ||
if (keypair.privateKeyPem) { | ||
keypair._ursa = ursa.createPrivateKey(keypair.privateKeyPem); | ||
keypair._ursa.toJSON = notToJson; | ||
ursac._ursaImportPem(keypair); | ||
@@ -113,0 +162,0 @@ return keypair._ursa.toPublicPem().toString('ascii'); |
87
node.js
@@ -17,3 +17,12 @@ /*! | ||
try { | ||
RSA._URSA = require('ursa'); | ||
} catch(e) { | ||
// ignore | ||
} | ||
RSA.utils = require('./lib/key-utils.js'); | ||
RSA.utils.toWebsafeBase64 = function (b64) { | ||
return b64.replace(/[+]/g, "-").replace(/\//g, "_").replace(/=/g,""); | ||
}; | ||
@@ -32,3 +41,5 @@ RSA.utils._bytesToBuffer = function (bytes) { | ||
var input = RSA.utils._bytesToBuffer('{"e":"'+ jwk.e + '","kty":"RSA","n":"'+ jwk.n +'"}'); | ||
return RSA.util.b64enc(crypto.createHash('sha256').update(input).digest()); | ||
var base64Digest = crypto.createHash('sha256').update(input).digest('base64'); | ||
return RSA.utils.toWebsafeBase64(base64Digest); | ||
}; | ||
@@ -79,2 +90,76 @@ | ||
RSA.import = function (keypair/*, options*/) { | ||
//options = options || NOBJ; // ignore | ||
if (keypair.privateKeyJwk || keypair.privateKeyPem || keypair._ursa || (keypair._forge && keypair._forge)) { | ||
keypair.privateKeyJwk = RSA._internal.exportPrivateJwk(keypair, { internal: true }); | ||
//keypair.privateKeyPem = RSA._internal.exportPrivatePem(keypair, { internal: true }); | ||
return keypair; | ||
} | ||
if (keypair.publicKeyJwk || keypair.publicKeyPem || keypair._ursaPublic || (keypair._forge && keypair._forgePublic)) { | ||
keypair.publicKeyJwk = RSA._internal.exportPublicJwk(keypair, { internal: true }); | ||
//keypair.publicKeyPem = RSA._internal.exportPublicPem(keypair, { internal: true }); | ||
return keypair; | ||
} | ||
throw new Error('found neither private nor public keypair in any supported format'); | ||
}; | ||
RSA._ursaGenerateSig = function (keypair, sha256Buf) { | ||
var sig = keypair._ursa.sign('sha256', sha256Buf); | ||
var sig64 = RSA.utils.toWebsafeBase64(sig.toString('base64')); | ||
return sig64; | ||
}; | ||
RSA._forgeGenerateSig = function (keypair, sha256Buf) { | ||
var forge = require('node-forge'); | ||
var bufF = forge.util.createBuffer(sha256Buf.toString('binary'), 'binary'); | ||
var md = { | ||
algorithm: 'sha256' | ||
, blockLength: 64 | ||
, digestLength: 20 | ||
, digest: function () { | ||
return bufF; | ||
} | ||
}; | ||
var sigF = keypair._forge.sign(md); | ||
var sig64 = RSA.utils.toWebsafeBase64( | ||
new Buffer(forge.util.bytesToHex(sigF), "hex").toString('base64') | ||
); | ||
return sig64; | ||
}; | ||
RSA.generateSignatureJwk = function (keypair, payload, nonce) { | ||
keypair = RSA._internal.import(keypair); | ||
keypair = RSA._internal.importForge(keypair); | ||
keypair.publicKeyJwk = RSA.exportPublicJwk(keypair); | ||
// Compute JWS signature | ||
var protectedHeader = ""; | ||
if (nonce) { | ||
protectedHeader = JSON.stringify({nonce: nonce}); | ||
} | ||
var protected64 = RSA.utils.toWebsafeBase64(new Buffer(protectedHeader).toString('base64')); | ||
var payload64 = RSA.utils.toWebsafeBase64(payload.toString('base64')); | ||
var raw = protected64 + "." + payload64; | ||
var sha256Buf = crypto.createHash('sha256').update(raw).digest(); | ||
var sig64; | ||
if (RSA._URSA) { | ||
sig64 = RSA._ursaGenerateSig(keypair, sha256Buf); | ||
} else { | ||
sig64 = RSA._forgeGenerateSig(keypair, sha256Buf); | ||
} | ||
return { | ||
header: { | ||
alg: "RS256" | ||
, jwk: keypair.publicKeyJwk | ||
} | ||
, protected: protected64 | ||
, payload: payload64 | ||
, signature: sig64 | ||
}; | ||
}; | ||
RSA.exportPrivateKey = RSA._internal.exportPrivatePem; | ||
@@ -81,0 +166,0 @@ RSA.exportPublicKey = RSA._internal.exportPublicPem; |
{ | ||
"name": "rsa-compat", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "RSA utils that work on Windows, Mac, and Linux with or without C compiler", | ||
@@ -5,0 +5,0 @@ "main": "node.js", |
@@ -16,4 +16,3 @@ # rsa-compat.js | ||
```javascript | ||
var PromiseA = require('bluebird'); | ||
var RSA = PromiseA.promisify(require('rsa-compat').RSA); | ||
var RSA = require('rsa-compat').RSA; | ||
@@ -24,3 +23,3 @@ var bitlen = 1024; | ||
RSA.generateKeypair(bitlen, exp, options).then(function (keypair) { | ||
RSA.generateKeypair(bitlen, exp, options, function (err, keypair) { | ||
console.log(keypair); | ||
@@ -30,2 +29,4 @@ }); | ||
Here's what the object might look like: | ||
`console.log(keypair)`: | ||
@@ -36,4 +37,2 @@ ```javascript | ||
, privateKeyPem: '-----BEGIN RSA PRIVATE KEY-----\n/*base64 pem-encoded string*/' | ||
// http://crypto.stackexchange.com/questions/6593/what-data-is-saved-in-rsa-private-key | ||
, privateKeyJwk: { | ||
@@ -45,23 +44,24 @@ kty: "RSA" | ||
, p: '/*base64 first prime*/' | ||
, q: /*base64 second prime*/ | ||
, dp: /*base64 first exponent for Chinese remainder theorem (dP = d (mod p−1))*/ | ||
, dq: /*base64 Second exponent, used for CRT (dQ = d (mod q−1))/ | ||
, qi: /*base64 Coefficient, used for CRT (qinv = q^−1 (mod p))*/ | ||
, q: '/*base64 second prime*/' | ||
, dp: '/*base64 first exponent for Chinese remainder theorem (dP = d (mod p−1))*/' | ||
, dq: '/*base64 Second exponent, used for CRT (dQ = d (mod q−1))/' | ||
, qi: '/*base64 Coefficient, used for CRT (qinv = q^−1 (mod p))*/' | ||
} | ||
, publicKeyJwk: { | ||
kty: "RSA" | ||
, n: /*base64 modulus n = pq*/ | ||
, e: /base64 exponent (usually 65537)*/ | ||
, n: '/*base64 modulus n = pq*/' | ||
, e: '/*base64 exponent (usually 65537)*/' | ||
} | ||
, _ursa: /*undefined or intermediate ursa object*/ | ||
, _ursaPublic: /*undefined or intermediate ursa object*/ | ||
, _forge: /*undefined or intermediate forge object*/ | ||
, _forgePublic: /*undefined or intermediate forge object*/ | ||
, _ursa: '/*undefined or intermediate ursa object*/' | ||
, _ursaPublic: '/*undefined or intermediate ursa object*/' | ||
, _forge: '/*undefined or intermediate forge object*/' | ||
, _forgePublic: '/*undefined or intermediate forge object*/' | ||
} | ||
// NOTE: this object is JSON safe as _ursa and _forge will be ignored | ||
``` | ||
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. | ||
API | ||
@@ -68,0 +68,0 @@ --- |
@@ -5,10 +5,3 @@ 'use strict'; | ||
console.log('RSA'); | ||
console.log(RSA); | ||
RSA.generateKeypair(null, null, null, function (err, keys) { | ||
console.log(''); | ||
console.log('keys'); | ||
console.log(keys); | ||
if (!keys.privateKeyJwk) { | ||
@@ -26,3 +19,3 @@ throw new Error("Expected privateKeyJwk, but it is missing"); | ||
) { | ||
console.error(keys); | ||
console.error(Object.keys(keys)); | ||
throw new Error("Got unexpected keys"); | ||
@@ -36,22 +29,19 @@ } | ||
, internal: true // preserve internal intermediate formats (_ursa, _forge) | ||
, thumbprint: true // JWK sha256 thumbprint | ||
//, thumbprint: true // JWK sha256 thumbprint | ||
}; | ||
RSA.generateKeypair(512, 65537, options, function (err, keys) { | ||
console.log(''); | ||
console.log('keys'); | ||
console.log(keys); | ||
if ( | ||
keys.publicKeyJwk | ||
|| keys.privateKeyPem | ||
|| keys.publicKeyPem | ||
|| keys.thumbprint | ||
|| keys._ursa | ||
|| keys._forge | ||
(keys.publicKeyJwk && !keys.thumbprint) | ||
|| !keys.privateKeyPem | ||
|| !keys.publicKeyPem | ||
//|| !keys.thumbprint | ||
|| !(keys._ursa || keys._forge) | ||
) { | ||
console.error(keys); | ||
throw new Error("Got unexpected keys"); | ||
console.error(Object.keys(keys)); | ||
throw new Error("Missing expected keys"); | ||
} | ||
console.log('All is well!'); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
59056
17
1547