passes basic reciprical test
This commit is contained in:
parent
5de4362c6c
commit
fdd30294d8
15
README.md
15
README.md
|
@ -65,6 +65,7 @@ API
|
||||||
---
|
---
|
||||||
|
|
||||||
* `RSA.generateKeypair(bitlen, exp, options, cb)`
|
* `RSA.generateKeypair(bitlen, exp, options, cb)`
|
||||||
|
* `RSA.import(keypair, options)`
|
||||||
* `RSA.exportPrivatePem(keypair)`
|
* `RSA.exportPrivatePem(keypair)`
|
||||||
* `RSA.exportPublicPem(keypair)`
|
* `RSA.exportPublicPem(keypair)`
|
||||||
* `RSA.exportPrivateJwk(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)
|
### RSA.export*(keypair)
|
||||||
|
|
||||||
You put in an object like `{ privateKeyPem: '...' }` or `{ publicKeyJwk: {} }`
|
You put in an object like `{ privateKeyPem: '...' }` or `{ publicKeyJwk: {} }`
|
||||||
|
|
|
@ -1,9 +1,33 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function binstrToB64Url(binstr) {
|
// for forge
|
||||||
return new Buffer(binstr, 'binary').toString('base64')
|
function _bigIntToBase64Url(fbin) {
|
||||||
.replace(/[+]/g, "-").replace(/\//g, "_").replace(/=/g,"");
|
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 = {
|
var extrac = module.exports = {
|
||||||
//
|
//
|
||||||
|
@ -14,22 +38,22 @@ var extrac = module.exports = {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
kty: "RSA"
|
kty: "RSA"
|
||||||
, n: binstrToB64Url(k.n.toByteArray())
|
, n: _bigIntToBase64Url(k.n)
|
||||||
, e: binstrToB64Url(k.e.toByteArray())
|
, e: _bigIntToBase64Url(k.e)
|
||||||
, d: binstrToB64Url(k.d.toByteArray())
|
, d: _bigIntToBase64Url(k.d)
|
||||||
, p: binstrToB64Url(k.p.toByteArray())
|
, p: _bigIntToBase64Url(k.p)
|
||||||
, q: binstrToB64Url(k.q.toByteArray())
|
, q: _bigIntToBase64Url(k.q)
|
||||||
, dp: binstrToB64Url(k.dP.toByteArray())
|
, dp: _bigIntToBase64Url(k.dP)
|
||||||
, dq: binstrToB64Url(k.dQ.toByteArray())
|
, dq: _bigIntToBase64Url(k.dQ)
|
||||||
, qi: binstrToB64Url(k.qInv.toByteArray())
|
, qi: _bigIntToBase64Url(k.qInv)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
, _forgeToPublicJwk: function (keypair) {
|
, _forgeToPublicJwk: function (keypair) {
|
||||||
var k = keypair._forge || keypair._forgePublic;
|
var k = keypair._forge || keypair._forgePublic;
|
||||||
return {
|
return {
|
||||||
kty: "RSA"
|
kty: "RSA"
|
||||||
, n: binstrToB64Url(k.n.toByteArray())
|
, n: _bigIntToBase64Url(k.n)
|
||||||
, e: binstrToB64Url(k.e.toByteArray())
|
, e: _bigIntToBase64Url(k.e)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ var forgec = module.exports = {
|
||||||
|
|
||||||
return b64;
|
return b64;
|
||||||
}
|
}
|
||||||
, _base64ToBin: function (base64) {
|
, _base64UrlToBin: function (base64) {
|
||||||
var std64 = forgec._toStandardBase64(base64);
|
var std64 = forgec._toStandardBase64(base64);
|
||||||
var hex = new Buffer(std64, 'base64').toString("hex");
|
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', 'qInv' ]
|
||||||
[ 'n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi' ].forEach(function (key) {
|
[ '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;
|
return components;
|
||||||
|
@ -42,7 +42,7 @@ var forgec = module.exports = {
|
||||||
, _publicJwkToComponents: function (jwk) {
|
, _publicJwkToComponents: function (jwk) {
|
||||||
var components = [];
|
var components = [];
|
||||||
[ 'n', 'e' ].forEach(function (key) {
|
[ 'n', 'e' ].forEach(function (key) {
|
||||||
components.push(new Buffer(jwk[key], 'base64'));
|
components.push(forgec._base64UrlToBin(jwk[key]));
|
||||||
});
|
});
|
||||||
|
|
||||||
return components;
|
return components;
|
||||||
|
@ -55,13 +55,15 @@ var forgec = module.exports = {
|
||||||
//
|
//
|
||||||
, generateKeypair: function (bitlen, exp, options, cb) {
|
, generateKeypair: function (bitlen, exp, options, cb) {
|
||||||
var fkeypair = forge.pki.rsa.generateKeyPair({ bits: bitlen || 1024, e: exp || 0x10001 });
|
var fkeypair = forge.pki.rsa.generateKeyPair({ bits: bitlen || 1024, e: exp || 0x10001 });
|
||||||
|
var result = {
|
||||||
fkeypair.toJSON = notToJson;
|
|
||||||
|
|
||||||
cb(null, {
|
|
||||||
_forge: fkeypair.privateKey
|
_forge: fkeypair.privateKey
|
||||||
, _forgePublic: fkeypair.publicKey
|
, _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
|
forge.pki.rsa
|
||||||
, forgec._privateJwkToComponents(keypair.privateKeyJwk)
|
, forgec._privateJwkToComponents(keypair.privateKeyJwk)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
keypair._forge.toJSON = notToJson;
|
keypair._forge.toJSON = notToJson;
|
||||||
|
}
|
||||||
|
|
||||||
forgec._forgeImportPublicJwk(keypair);
|
forgec._forgeImportPublicJwk(keypair);
|
||||||
}
|
}
|
||||||
|
@ -94,13 +96,15 @@ var forgec = module.exports = {
|
||||||
, forgec._publicJwkToComponents(keypair.publicKeyJwk || keypair.privateKeyJwk)
|
, forgec._publicJwkToComponents(keypair.publicKeyJwk || keypair.privateKeyJwk)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (keypair._forgePublic) {
|
||||||
keypair._forgePublic.toJSON = notToJson;
|
keypair._forgePublic.toJSON = notToJson;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
, _forgeImportPem: function (keypair) {
|
, _forgeImportPem: function (keypair) {
|
||||||
if (!keypair._forge && keypair.privateKeyPem) {
|
if (!keypair._forge && keypair.privateKeyPem) {
|
||||||
keypair._forge = forge.pki.privateKeyFromPem(keypair.privateKeyPem);
|
keypair._forge = forge.pki.privateKeyFromPem(keypair.privateKeyPem);
|
||||||
}
|
|
||||||
keypair._forge.toJSON = notToJson;
|
keypair._forge.toJSON = notToJson;
|
||||||
|
}
|
||||||
|
|
||||||
forgec._forgeImportPublicPem(keypair);
|
forgec._forgeImportPublicPem(keypair);
|
||||||
}
|
}
|
||||||
|
@ -115,8 +119,10 @@ var forgec = module.exports = {
|
||||||
else if (keypair.publicKeyPem) {
|
else if (keypair.publicKeyPem) {
|
||||||
keypair._forgePublic = keypair._forgePublic || forge.pki.publicKeyFromPem(keypair.publicKeyPem);
|
keypair._forgePublic = keypair._forgePublic || forge.pki.publicKeyFromPem(keypair.publicKeyPem);
|
||||||
}
|
}
|
||||||
|
if (keypair._forgePublic) {
|
||||||
keypair._forgePublic.toJSON = notToJson;
|
keypair._forgePublic.toJSON = notToJson;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
, import: function (keypair) {
|
, import: function (keypair) {
|
||||||
// no-op since this must be done anyway in extra
|
// no-op since this must be done anyway in extra
|
||||||
return keypair;
|
return keypair;
|
||||||
|
|
|
@ -115,19 +115,22 @@ var ursac = module.exports = {
|
||||||
//
|
//
|
||||||
// Export Public / Private PEMs
|
// Export Public / Private PEMs
|
||||||
//
|
//
|
||||||
|
, _pemBinToPem: function (pem) {
|
||||||
|
return pem.toString('ascii').replace(/[\n\r]+/g, '\r\n');
|
||||||
|
}
|
||||||
, exportPrivatePem: function (keypair) {
|
, exportPrivatePem: function (keypair) {
|
||||||
if (keypair.privateKeyPem) {
|
if (keypair.privateKeyPem) {
|
||||||
return keypair.privateKeyPem;
|
return keypair.privateKeyPem;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keypair._ursa) {
|
if (keypair._ursa) {
|
||||||
return keypair._ursa.toPrivatePem().toString('ascii');
|
return ursac._pemBinToPem(keypair._ursa.toPrivatePem());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keypair.privateKeyJwk) {
|
if (keypair.privateKeyJwk) {
|
||||||
ursac._ursaImportJwk(keypair);
|
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");
|
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) {
|
if (keypair._ursa || keypair._ursaPublic) {
|
||||||
return (keypair._ursa || keypair._ursaPublic).toPublicPem().toString('ascii');
|
return ursac._pemBinToPem((keypair._ursa || keypair._ursaPublic).toPublicPem());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keypair.publicKeyJwk) {
|
if (keypair.publicKeyJwk) {
|
||||||
ursac._ursaImportPublicJwk(keypair);
|
ursac._ursaImportPublicJwk(keypair);
|
||||||
|
|
||||||
return keypair._ursaPublic.toPublicPem().toString('ascii');
|
return ursac._pemBinToPem(keypair._ursaPublic.toPublicPem());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keypair.privateKeyJwk) {
|
if (keypair.privateKeyJwk) {
|
||||||
ursac._ursaImportJwk(keypair);
|
ursac._ursaImportJwk(keypair);
|
||||||
|
|
||||||
return keypair._ursa.toPublicPem().toString('ascii');
|
return ursac._pemBinToPem(keypair._ursa.toPublicPem());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keypair.privateKeyPem) {
|
if (keypair.privateKeyPem) {
|
||||||
ursac._ursaImportPem(keypair);
|
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");
|
throw new Error("None of publicKeyPem, _ursa, publicKeyJwk, privateKeyPem, or privateKeyJwk found. No way to export public key PEM");
|
||||||
|
|
2
node.js
2
node.js
|
@ -110,6 +110,8 @@ function create(deps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
RSA.import = function (keypair/*, options*/) {
|
RSA.import = function (keypair/*, options*/) {
|
||||||
|
keypair = RSA._internal.import(keypair, { internal: true });
|
||||||
|
keypair = RSA._internal.importForge(keypair, { internal: true });
|
||||||
//options = options || NOBJ; // ignore
|
//options = options || NOBJ; // ignore
|
||||||
if (keypair.privateKeyJwk || keypair.privateKeyPem || keypair._ursa || keypair._forge) {
|
if (keypair.privateKeyJwk || keypair.privateKeyPem || keypair._ursa || keypair._forge) {
|
||||||
keypair.privateKeyJwk = RSA._internal.exportPrivateJwk(keypair, { internal: true });
|
keypair.privateKeyJwk = RSA._internal.exportPrivateJwk(keypair, { internal: true });
|
||||||
|
|
|
@ -28,7 +28,6 @@ try {
|
||||||
// PEM tests
|
// PEM tests
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
console.log('');
|
|
||||||
console.log('JWK -> PEM ?', privkeyPemRef === refs.privPem);
|
console.log('JWK -> PEM ?', privkeyPemRef === refs.privPem);
|
||||||
if (privkeyPemRef !== refs.privPem) {
|
if (privkeyPemRef !== refs.privPem) {
|
||||||
// Watch out for tricky whitespaces (\n instead of \r\n, trailing \r\n, etc)
|
// 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");
|
throw new Error("Failed to validate importedJwk against referencePem");
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('');
|
|
||||||
console.log('PEM -> _ -> PEM ?', privkeyPemRef === refs.privPem);
|
console.log('PEM -> _ -> PEM ?', privkeyPemRef === refs.privPem);
|
||||||
if (hasUrsa) {
|
if (hasUrsa) {
|
||||||
imported = RSA.import({ privateKeyPem: privkeyPemRef });
|
imported = RSA.import({ privateKeyPem: privkeyPemRef });
|
||||||
|
@ -57,17 +55,13 @@ if (privkeyPemRef !== refs.privPem2) {
|
||||||
throw new Error("Failed to validate importedPem against referencePem");
|
throw new Error("Failed to validate importedPem against referencePem");
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// JWK tests
|
// 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) {
|
if (privkeyJwkRef.n !== refs.privJwk.n) {
|
||||||
console.log('REF:');
|
console.log('REF:');
|
||||||
console.log(privkeyJwkRef);
|
console.log(privkeyJwkRef);
|
||||||
|
@ -76,10 +70,9 @@ if (privkeyJwkRef.n !== refs.privJwk.n) {
|
||||||
throw new Error("Failed to validate importedPem against referenceJwk");
|
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 });
|
imported = RSA.import({ privateKeyJwk: privkeyJwkRef });
|
||||||
refs.privJwk2 = RSA.exportPrivateJwk({ _forge: imported._forge });
|
refs.privJwk2 = RSA.exportPrivateJwk({ _forge: imported._forge });
|
||||||
|
console.log('JWK -> _ -> JWK ?', privkeyJwkRef.n === refs.privJwk2.n);
|
||||||
if (privkeyJwkRef.n !== refs.privJwk2.n) {
|
if (privkeyJwkRef.n !== refs.privJwk2.n) {
|
||||||
console.log('REF:');
|
console.log('REF:');
|
||||||
console.log(privkeyJwkRef);
|
console.log(privkeyJwkRef);
|
||||||
|
|
Loading…
Reference in New Issue