passes basic reciprical test

This commit is contained in:
AJ ONeal 2016-08-02 16:42:44 -04:00
parent 5de4362c6c
commit fdd30294d8
6 changed files with 83 additions and 40 deletions

View File

@ -65,6 +65,7 @@ API
---
* `RSA.generateKeypair(bitlen, exp, options, cb)`
* `RSA.import(keypair, options)`
* `RSA.exportPrivatePem(keypair)`
* `RSA.exportPublicPem(keypair)`
* `RSA.exportPrivateJwk(keypair)`
@ -100,6 +101,20 @@ RSA.generateKeypair(1024, 65537, { pem: false, public: false, internal: false },
}
```
### RSA.import(keypair, options)
Imports keypair as JWKs and internal values `_ursa` and `_forge`.
```javascript
var keypair = RSA.import({ privateKeyPem: '...'});
console.log(keypair);
```
```javascript
{ privateKeyPem: ..., privateKeyJwk: ..., _ursa: ..., _forge: ... }
```
### RSA.export*(keypair)
You put in an object like `{ privateKeyPem: '...' }` or `{ publicKeyJwk: {} }`

View File

@ -1,9 +1,33 @@
'use strict';
function binstrToB64Url(binstr) {
return new Buffer(binstr, 'binary').toString('base64')
.replace(/[+]/g, "-").replace(/\//g, "_").replace(/=/g,"");
// for forge
function _bigIntToBase64Url(fbin) {
var hex = fbin.toRadix(16);
if (hex.length % 2) {
// Invalid hex string
hex = '0' + hex;
}
var buf = Buffer.from(hex, 'hex');
var b64 = buf.toString('base64');
var b64Url = b64.replace(/[+]/g, "-").replace(/\//g, "_").replace(/=/g,"");
return b64Url;
}
/*
// I think this doesn't work because toByteArray() returns signed bytes
function _xxx_bigIntToBase64Url(fbin) {
if (!fbin.toByteArray) {
console.log('fbin');
console.log(fbin);
}
var byteArray = fbin.toByteArray();
var buf = Buffer.from(byteArray);
var b64 = buf.toString('base64');
var b64Url = b64.replace(/[+]/g, "-").replace(/\//g, "_").replace(/=/g,"");
return b64Url;
}
*/
var extrac = module.exports = {
//
@ -14,22 +38,22 @@ var extrac = module.exports = {
return {
kty: "RSA"
, n: binstrToB64Url(k.n.toByteArray())
, e: binstrToB64Url(k.e.toByteArray())
, d: binstrToB64Url(k.d.toByteArray())
, p: binstrToB64Url(k.p.toByteArray())
, q: binstrToB64Url(k.q.toByteArray())
, dp: binstrToB64Url(k.dP.toByteArray())
, dq: binstrToB64Url(k.dQ.toByteArray())
, qi: binstrToB64Url(k.qInv.toByteArray())
, n: _bigIntToBase64Url(k.n)
, e: _bigIntToBase64Url(k.e)
, d: _bigIntToBase64Url(k.d)
, p: _bigIntToBase64Url(k.p)
, q: _bigIntToBase64Url(k.q)
, dp: _bigIntToBase64Url(k.dP)
, dq: _bigIntToBase64Url(k.dQ)
, qi: _bigIntToBase64Url(k.qInv)
};
}
, _forgeToPublicJwk: function (keypair) {
var k = keypair._forge || keypair._forgePublic;
return {
kty: "RSA"
, n: binstrToB64Url(k.n.toByteArray())
, e: binstrToB64Url(k.e.toByteArray())
, n: _bigIntToBase64Url(k.n)
, e: _bigIntToBase64Url(k.e)
};
}

View File

@ -23,7 +23,7 @@ var forgec = module.exports = {
return b64;
}
, _base64ToBin: function (base64) {
, _base64UrlToBin: function (base64) {
var std64 = forgec._toStandardBase64(base64);
var hex = new Buffer(std64, 'base64').toString("hex");
@ -34,7 +34,7 @@ var forgec = module.exports = {
// [ 'n', 'e', 'd', 'p', 'q', 'dP', 'dQ', 'qInv' ]
[ 'n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi' ].forEach(function (key) {
components.push(forgec._base64ToBin(jwk[key]));
components.push(forgec._base64UrlToBin(jwk[key]));
});
return components;
@ -42,7 +42,7 @@ var forgec = module.exports = {
, _publicJwkToComponents: function (jwk) {
var components = [];
[ 'n', 'e' ].forEach(function (key) {
components.push(new Buffer(jwk[key], 'base64'));
components.push(forgec._base64UrlToBin(jwk[key]));
});
return components;
@ -55,13 +55,15 @@ var forgec = module.exports = {
//
, generateKeypair: function (bitlen, exp, options, cb) {
var fkeypair = forge.pki.rsa.generateKeyPair({ bits: bitlen || 1024, e: exp || 0x10001 });
fkeypair.toJSON = notToJson;
cb(null, {
var result = {
_forge: fkeypair.privateKey
, _forgePublic: fkeypair.publicKey
});
};
result._forge.toJSON = notToJson;
result._forgePublic.toJSON = notToJson;
cb(null, result);
}
@ -75,8 +77,8 @@ var forgec = module.exports = {
forge.pki.rsa
, forgec._privateJwkToComponents(keypair.privateKeyJwk)
);
keypair._forge.toJSON = notToJson;
}
keypair._forge.toJSON = notToJson;
forgec._forgeImportPublicJwk(keypair);
}
@ -94,13 +96,15 @@ var forgec = module.exports = {
, forgec._publicJwkToComponents(keypair.publicKeyJwk || keypair.privateKeyJwk)
);
}
keypair._forgePublic.toJSON = notToJson;
if (keypair._forgePublic) {
keypair._forgePublic.toJSON = notToJson;
}
}
, _forgeImportPem: function (keypair) {
if (!keypair._forge && keypair.privateKeyPem) {
keypair._forge = forge.pki.privateKeyFromPem(keypair.privateKeyPem);
keypair._forge.toJSON = notToJson;
}
keypair._forge.toJSON = notToJson;
forgec._forgeImportPublicPem(keypair);
}
@ -115,7 +119,9 @@ var forgec = module.exports = {
else if (keypair.publicKeyPem) {
keypair._forgePublic = keypair._forgePublic || forge.pki.publicKeyFromPem(keypair.publicKeyPem);
}
keypair._forgePublic.toJSON = notToJson;
if (keypair._forgePublic) {
keypair._forgePublic.toJSON = notToJson;
}
}
, import: function (keypair) {
// no-op since this must be done anyway in extra

View File

@ -115,19 +115,22 @@ var ursac = module.exports = {
//
// Export Public / Private PEMs
//
, _pemBinToPem: function (pem) {
return pem.toString('ascii').replace(/[\n\r]+/g, '\r\n');
}
, exportPrivatePem: function (keypair) {
if (keypair.privateKeyPem) {
return keypair.privateKeyPem;
}
if (keypair._ursa) {
return keypair._ursa.toPrivatePem().toString('ascii');
return ursac._pemBinToPem(keypair._ursa.toPrivatePem());
}
if (keypair.privateKeyJwk) {
ursac._ursaImportJwk(keypair);
return keypair._ursa.toPrivatePem().toString('ascii');
return ursac._pemBinToPem(keypair._ursa.toPrivatePem());
}
throw new Error("None of privateKeyPem, _ursa, or privateKeyJwk found. No way to export private key PEM");
@ -138,25 +141,25 @@ var ursac = module.exports = {
}
if (keypair._ursa || keypair._ursaPublic) {
return (keypair._ursa || keypair._ursaPublic).toPublicPem().toString('ascii');
return ursac._pemBinToPem((keypair._ursa || keypair._ursaPublic).toPublicPem());
}
if (keypair.publicKeyJwk) {
ursac._ursaImportPublicJwk(keypair);
return keypair._ursaPublic.toPublicPem().toString('ascii');
return ursac._pemBinToPem(keypair._ursaPublic.toPublicPem());
}
if (keypair.privateKeyJwk) {
ursac._ursaImportJwk(keypair);
return keypair._ursa.toPublicPem().toString('ascii');
return ursac._pemBinToPem(keypair._ursa.toPublicPem());
}
if (keypair.privateKeyPem) {
ursac._ursaImportPem(keypair);
return keypair._ursa.toPublicPem().toString('ascii');
return ursac._pemBinToPem(keypair._ursa.toPublicPem());
}
throw new Error("None of publicKeyPem, _ursa, publicKeyJwk, privateKeyPem, or privateKeyJwk found. No way to export public key PEM");

View File

@ -110,6 +110,8 @@ function create(deps) {
};
RSA.import = function (keypair/*, options*/) {
keypair = RSA._internal.import(keypair, { internal: true });
keypair = RSA._internal.importForge(keypair, { internal: true });
//options = options || NOBJ; // ignore
if (keypair.privateKeyJwk || keypair.privateKeyPem || keypair._ursa || keypair._forge) {
keypair.privateKeyJwk = RSA._internal.exportPrivateJwk(keypair, { internal: true });

View File

@ -28,7 +28,6 @@ try {
// PEM tests
//
//
console.log('');
console.log('JWK -> PEM ?', privkeyPemRef === refs.privPem);
if (privkeyPemRef !== refs.privPem) {
// Watch out for tricky whitespaces (\n instead of \r\n, trailing \r\n, etc)
@ -39,7 +38,6 @@ if (privkeyPemRef !== refs.privPem) {
throw new Error("Failed to validate importedJwk against referencePem");
}
console.log('');
console.log('PEM -> _ -> PEM ?', privkeyPemRef === refs.privPem);
if (hasUrsa) {
imported = RSA.import({ privateKeyPem: privkeyPemRef });
@ -57,17 +55,13 @@ if (privkeyPemRef !== refs.privPem2) {
throw new Error("Failed to validate importedPem against referencePem");
}
console.log('');
//
//
// JWK tests
//
//
console.log('');
console.log('PEM -> JWK', privkeyJwkRef.n === refs.privJwk.n);
console.log('PEM -> JWK ?', privkeyJwkRef.n === refs.privJwk.n);
if (privkeyJwkRef.n !== refs.privJwk.n) {
console.log('REF:');
console.log(privkeyJwkRef);
@ -76,10 +70,9 @@ if (privkeyJwkRef.n !== refs.privJwk.n) {
throw new Error("Failed to validate importedPem against referenceJwk");
}
console.log('');
console.log('JWK -> _ -> JWK', privkeyJwkRef.n === refs.privJwk2.n);
imported = RSA.import({ privateKeyJwk: privkeyJwkRef });
refs.privJwk2 = RSA.exportPrivateJwk({ _forge: imported._forge });
console.log('JWK -> _ -> JWK ?', privkeyJwkRef.n === refs.privJwk2.n);
if (privkeyJwkRef.n !== refs.privJwk2.n) {
console.log('REF:');
console.log(privkeyJwkRef);