From 56791711a04c783105e32d550f7b37b3403b348c Mon Sep 17 00:00:00 2001 From: rzcoder Date: Thu, 27 Nov 2014 22:07:17 +0500 Subject: [PATCH 01/18] initial export/import formats --- src/NodeRSA.js | 90 ++++++++++++++++++++---------------------- src/formats/formats.js | 20 ++++++++++ src/formats/pkcs1.js | 65 ++++++++++++++++++++++++++++++ src/formats/pkcs8.js | 44 +++++++++++++++++++++ 4 files changed, 171 insertions(+), 48 deletions(-) create mode 100644 src/formats/formats.js create mode 100644 src/formats/pkcs1.js create mode 100644 src/formats/pkcs8.js diff --git a/src/NodeRSA.js b/src/NodeRSA.js index 97528e2..013faac 100644 --- a/src/NodeRSA.js +++ b/src/NodeRSA.js @@ -13,6 +13,7 @@ var ber = require('asn1').Ber; var _ = require('lodash'); var utils = require('./utils'); var schemes = require('./schemes/schemes.js'); +var formats = require('./formats/formats.js'); var PUBLIC_RSA_OID = '1.2.840.113549.1.1.1'; @@ -25,6 +26,9 @@ module.exports = (function () { var DEFAULT_ENCRYPTION_SCHEME = 'pkcs1_oaep'; var DEFAULT_SIGNING_SCHEME = 'pkcs1'; + var DEFAULT_EXPORT_PRIVATE_FORMAT = 'pkcs1'; + var DEFAULT_EXPORT_PUBLIC_FORMAT = 'pkcs8'; + /** * @param key {string|buffer|object} Key in PEM format, or data for generate key {b: bits, e: exponent} * @constructor @@ -142,7 +146,7 @@ module.exports = (function () { } this.keyPair.generate(bits, exp.toString(16)); - this.$recalculateCache(); + this.$cache = {}; return this; }; @@ -162,7 +166,7 @@ module.exports = (function () { } else throw Error('Invalid PEM format'); - this.$recalculateCache(); + this.$cache = {}; }; /** @@ -251,7 +255,7 @@ module.exports = (function () { */ NodeRSA.prototype.encrypt = function (buffer, encoding, source_encoding) { try { - var res = this.keyPair.encrypt(this.$getDataForEcrypt(buffer, source_encoding)); + var res = this.keyPair.encrypt(this.$getDataForEncrypt(buffer, source_encoding)); if (encoding == 'buffer' || !encoding) { return res; @@ -295,7 +299,7 @@ module.exports = (function () { if (!this.isPrivate()) { throw Error("It is not private key"); } - var res = this.keyPair.sign(this.$getDataForEcrypt(buffer, source_encoding)); + var res = this.keyPair.sign(this.$getDataForEncrypt(buffer, source_encoding)); if (encoding && encoding != 'buffer') { res = res.toString(encoding); @@ -317,21 +321,45 @@ module.exports = (function () { throw Error("It is not public key"); } signature_encoding = (!signature_encoding || signature_encoding == 'buffer' ? null : signature_encoding); - return this.keyPair.verify(this.$getDataForEcrypt(buffer, source_encoding), signature, signature_encoding); + return this.keyPair.verify(this.$getDataForEncrypt(buffer, source_encoding), signature, signature_encoding); }; - NodeRSA.prototype.exportPrivate = function () { + NodeRSA.prototype.exportPrivate = function (format) { if (!this.isPrivate()) { throw Error("It is not private key"); } - return this.$cache.privatePEM; + + format = format || DEFAULT_EXPORT_PRIVATE_FORMAT; + if (this.$cache.privateKey && this.$cache.privateKey[format]) { + return this.$cache.privateKey[format]; + } else { + var fmt = format.split('-'); + if (!formats.isPrivateExport(fmt[0])) { + throw Error('Unsupported private key export format'); + } + + this.$cache.privateKey = this.$cache.privateKey || {}; + return this.$cache.privateKey[format] = formats[fmt[0]].privateExport(this.keyPair, fmt[1]); + } }; - NodeRSA.prototype.exportPublic = function () { + NodeRSA.prototype.exportPublic = function (format) { if (!this.isPublic()) { throw Error("It is not public key"); } - return this.$cache.publicPEM; + + format = format || DEFAULT_EXPORT_PUBLIC_FORMAT; + if (this.$cache.publicKey && this.$cache.publicKey[format]) { + return this.$cache.publicKey[format]; + } else { + var fmt = format.split('-'); + if (!formats.isPublicExport(fmt[0])) { + throw Error('Unsupported public key export format'); + } + + this.$cache.publicKey = this.$cache.publicKey || {}; + return this.$cache.publicKey[format] = formats[fmt[0]].publicExport(this.keyPair, fmt[1]); + } }; NodeRSA.prototype.getKeySize = function () { @@ -349,7 +377,7 @@ module.exports = (function () { * @param encoding {string} - optional. Encoding for given string. Default utf8. * @returns {Buffer} */ - NodeRSA.prototype.$getDataForEcrypt = function (buffer, encoding) { + NodeRSA.prototype.$getDataForEncrypt = function (buffer, encoding) { if (_.isString(buffer) || _.isNumber(buffer)) { return new Buffer('' + buffer, encoding || 'utf8'); } else if (Buffer.isBuffer(buffer)) { @@ -383,16 +411,15 @@ module.exports = (function () { * private * Recalculating properties */ - NodeRSA.prototype.$recalculateCache = function () { + /*NodeRSA.prototype.$recalculateCache = function () { this.$cache.privatePEM = this.$makePrivatePEM(); - this.$cache.publicPEM = this.$makePublicPEM(); - }; + };*/ /** * private * @returns {string} private PEM string */ - NodeRSA.prototype.$makePrivatePEM = function () { + /*NodeRSA.prototype.$makePrivatePEM = function () { if (!this.isPrivate()) { return null; } @@ -424,40 +451,7 @@ module.exports = (function () { utils.linebrk(writer.buffer.toString('base64'), 64) + '\n-----END RSA PRIVATE KEY-----'; }; - - /** - * private - * @returns {string} public PEM string - */ - NodeRSA.prototype.$makePublicPEM = function () { - if (!this.isPublic()) { - return null; - } - - var n = this.keyPair.n.toBuffer(); - var length = n.length + 512; // magic - - var bodyWriter = new ber.Writer({size: length}); - bodyWriter.writeByte(0); - bodyWriter.startSequence(); - bodyWriter.writeBuffer(n, 2); - bodyWriter.writeInt(this.keyPair.e); - bodyWriter.endSequence(); - var body = bodyWriter.buffer; - - var writer = new ber.Writer({size: length}); - writer.startSequence(); - writer.startSequence(); - writer.writeOID(PUBLIC_RSA_OID); - writer.writeNull(); - writer.endSequence(); - writer.writeBuffer(body, 3); - writer.endSequence(); - - return '-----BEGIN PUBLIC KEY-----\n' + - utils.linebrk(writer.buffer.toString('base64'), 64) + - '\n-----END PUBLIC KEY-----'; - }; +*/ return NodeRSA; })(); diff --git a/src/formats/formats.js b/src/formats/formats.js new file mode 100644 index 0000000..da2205b --- /dev/null +++ b/src/formats/formats.js @@ -0,0 +1,20 @@ +module.exports = { + pkcs1: require('./pkcs1'), + pkcs8: require('./pkcs8'), + + isPrivateExport: function(format) { + return module.exports[format] && typeof module.exports[format].privateExport === 'function'; + }, + + isPrivateImport: function(format) { + return module.exports[format] && typeof module.exports[format].privateImport === 'function'; + }, + + isPublicExport: function(format) { + return module.exports[format] && typeof module.exports[format].publicExport === 'function'; + }, + + isPublicImport: function(format) { + return module.exports[format] && typeof module.exports[format].publicImport === 'function'; + } +}; \ No newline at end of file diff --git a/src/formats/pkcs1.js b/src/formats/pkcs1.js new file mode 100644 index 0000000..d437834 --- /dev/null +++ b/src/formats/pkcs1.js @@ -0,0 +1,65 @@ +var ber = require('asn1').Ber; +var utils = require('../utils'); + +module.exports = { + privateExport: function(key, options) { + options = options || {}; + + var der = module.exports.privateDerEncode(key); + if (options.binary) { + return der; + } else { + return '-----BEGIN RSA PRIVATE KEY-----\n' + utils.linebrk(der.toString('base64'), 64) + '\n-----END RSA PRIVATE KEY-----'; + } + }, + + publicExport: function(key, options) { + options = options || {}; + + var der = module.exports.publicDerEncode(key); + if (options.binary) { + return der; + } else { + return '-----BEGIN RSA PUBLIC KEY-----\n' + utils.linebrk(der.toString('base64'), 64) + '\n-----END RSA PUBLIC KEY-----'; + } + }, + + privateDerEncode: function(key) { + var n = key.n.toBuffer(); + var d = key.d.toBuffer(); + var p = key.p.toBuffer(); + var q = key.q.toBuffer(); + var dmp1 = key.dmp1.toBuffer(); + var dmq1 = key.dmq1.toBuffer(); + var coeff = key.coeff.toBuffer(); + + var length = n.length + d.length + p.length + q.length + dmp1.length + dmq1.length + coeff.length + 512; // magic + var writer = new ber.Writer({size: length}); + + writer.startSequence(); + writer.writeInt(0); + writer.writeBuffer(n, 2); + writer.writeInt(key.e); + writer.writeBuffer(d, 2); + writer.writeBuffer(p, 2); + writer.writeBuffer(q, 2); + writer.writeBuffer(dmp1, 2); + writer.writeBuffer(dmq1, 2); + writer.writeBuffer(coeff, 2); + writer.endSequence(); + + return writer.buffer; + }, + + publicDerEncode: function (key) { + var n = key.n.toBuffer(); + var length = n.length + 512; // magic + + var bodyWriter = new ber.Writer({size: length}); + bodyWriter.startSequence(); + bodyWriter.writeBuffer(n, 2); + bodyWriter.writeInt(key.e); + bodyWriter.endSequence(); + return bodyWriter.buffer; + } +}; \ No newline at end of file diff --git a/src/formats/pkcs8.js b/src/formats/pkcs8.js new file mode 100644 index 0000000..6d9d11b --- /dev/null +++ b/src/formats/pkcs8.js @@ -0,0 +1,44 @@ +var ber = require('asn1').Ber; +var PUBLIC_RSA_OID = '1.2.840.113549.1.1.1'; +var utils = require('../utils'); + +module.exports = { + publicExport: function(key, options) { + options = options || {}; + + var der = module.exports.publicDerEncode(key); + if (options.binary) { + return der; + } else { + return '-----BEGIN PUBLIC KEY-----\n' + utils.linebrk(der.toString('base64'), 64) + '\n-----END PUBLIC KEY-----'; + } + }, + + publicImport: function(key) { + + }, + + publicDerEncode: function (key) { + var n = key.n.toBuffer(); + var length = n.length + 512; // magic + + var bodyWriter = new ber.Writer({size: length}); + bodyWriter.writeByte(0); + bodyWriter.startSequence(); + bodyWriter.writeBuffer(n, 2); + bodyWriter.writeInt(key.e); + bodyWriter.endSequence(); + var body = bodyWriter.buffer; + + var writer = new ber.Writer({size: length}); + writer.startSequence(); + writer.startSequence(); + writer.writeOID(PUBLIC_RSA_OID); + writer.writeNull(); + writer.endSequence(); + writer.writeBuffer(body, 3); + writer.endSequence(); + + return writer.buffer; + } +}; \ No newline at end of file From 080df0a9b20a198ecf2259a3abb258e430c983bc Mon Sep 17 00:00:00 2001 From: rzcoder Date: Fri, 28 Nov 2014 04:15:03 +0500 Subject: [PATCH 02/18] auto detect key type for import --- src/NodeRSA.js | 46 ++++++++++++++-------- src/formats/formats.js | 34 ++++++++++++++-- src/formats/pkcs1.js | 88 ++++++++++++++++++++++++++++++------------ src/formats/pkcs8.js | 71 +++++++++++++++++++++++++++------- test/tests.js | 10 +---- 5 files changed, 180 insertions(+), 69 deletions(-) diff --git a/src/NodeRSA.js b/src/NodeRSA.js index 013faac..8cf6c2d 100644 --- a/src/NodeRSA.js +++ b/src/NodeRSA.js @@ -151,21 +151,13 @@ module.exports = (function () { }; /** - * Load key from PEM string - * @param pem {string} + * Importing key + * @param keyData {string|buffer} */ - NodeRSA.prototype.importKey = function (pem) { - if (Buffer.isBuffer(pem)) { - pem = pem.toString('utf8'); + NodeRSA.prototype.importKey = function (keyData, format) { + if(format === undefined && !formats.detectAndImport(this.keyPair, keyData, format)) { + throw Error("Key format must be specified"); } - - if (/^\s*-----BEGIN RSA PRIVATE KEY-----\s*([A-Za-z0-9+/=]+\s*)+-----END RSA PRIVATE KEY-----\s*$/g.test(pem)) { - this.$loadFromPrivatePEM(pem, 'base64'); - } else if (/^\s*-----BEGIN PUBLIC KEY-----\s*([A-Za-z0-9+/=]+\s*)+-----END PUBLIC KEY-----\s*$/g.test(pem)) { - this.$loadFromPublicPEM(pem, 'base64'); - } else - throw Error('Invalid PEM format'); - this.$cache = {}; }; @@ -174,7 +166,7 @@ module.exports = (function () { * * @param privatePEM {string} */ - NodeRSA.prototype.$loadFromPrivatePEM = function (privatePEM, encoding) { + /*NodeRSA.prototype.$loadFromPrivatePEM = function (privatePEM, encoding) { var pem = privatePEM .replace('-----BEGIN RSA PRIVATE KEY-----', '') .replace('-----END RSA PRIVATE KEY-----', '') @@ -194,14 +186,14 @@ module.exports = (function () { reader.readString(2, true) // coefficient -- (inverse of q) mod p ); - }; + };*/ /** * Make key form public PEM string * * @param publicPEM {string} */ - NodeRSA.prototype.$loadFromPublicPEM = function (publicPEM, encoding) { + /*NodeRSA.prototype.$loadFromPublicPEM = function (publicPEM, encoding) { var pem = publicPEM .replace('-----BEGIN PUBLIC KEY-----', '') .replace('-----END PUBLIC KEY-----', '') @@ -221,7 +213,7 @@ module.exports = (function () { body.readString(0x02, true), // modulus body.readString(0x02, true) // publicExponent ); - }; + };*/ /** * Check if key pair contains private key @@ -324,6 +316,12 @@ module.exports = (function () { return this.keyPair.verify(this.$getDataForEncrypt(buffer, source_encoding), signature, signature_encoding); }; + /** + * Exporting private key + * + * @param format + * @returns {*} + */ NodeRSA.prototype.exportPrivate = function (format) { if (!this.isPrivate()) { throw Error("It is not private key"); @@ -343,6 +341,12 @@ module.exports = (function () { } }; + /** + * Exporting public key + * + * @param format + * @returns {*} + */ NodeRSA.prototype.exportPublic = function (format) { if (!this.isPublic()) { throw Error("It is not public key"); @@ -362,10 +366,18 @@ module.exports = (function () { } }; + /** + * Returns key size in bits + * @returns {int} + */ NodeRSA.prototype.getKeySize = function () { return this.keyPair.keySize; }; + /** + * Returns max message length in bytes (for 1 chunk) depending on current encryption scheme + * @returns {int} + */ NodeRSA.prototype.getMaxMessageSize = function () { return this.keyPair.maxMessageLength; }; diff --git a/src/formats/formats.js b/src/formats/formats.js index da2205b..6d2b85f 100644 --- a/src/formats/formats.js +++ b/src/formats/formats.js @@ -1,20 +1,46 @@ +var _ = require('lodash'); module.exports = { pkcs1: require('./pkcs1'), pkcs8: require('./pkcs8'), - isPrivateExport: function(format) { + isPrivateExport: function (format) { return module.exports[format] && typeof module.exports[format].privateExport === 'function'; }, - isPrivateImport: function(format) { + isPrivateImport: function (format) { return module.exports[format] && typeof module.exports[format].privateImport === 'function'; }, - isPublicExport: function(format) { + isPublicExport: function (format) { return module.exports[format] && typeof module.exports[format].publicExport === 'function'; }, - isPublicImport: function(format) { + isPublicImport: function (format) { return module.exports[format] && typeof module.exports[format].publicImport === 'function'; + }, + + detectAndImport: function (key, data, format) { + if (format === undefined && _.isString(data)) { + for (var format in module.exports) { + if (typeof module.exports[format].autoImport === 'function' && module.exports[format].autoImport(key, data)) { + return true; + } + } + } else if (format) { + var fmt = format.split('-'); + var keyType = fmt[1] === 'private' || fmt[1] === 'public' ? fmt[1] : 'private'; + var keyOpt = fmt[2] === 'der' ? {binary: true} : null; + if (module.exports[fmt[0]]) { + if (keyType === 'private') { + module.exports[fmt[0]].privateImport(key, data, keyOpt); + } else { + module.exports[fmt[0]].publicImport(key, data, keyOpt); + } + } else { + throw Error('Unsupported key format'); + } + } + + return false; } }; \ No newline at end of file diff --git a/src/formats/pkcs1.js b/src/formats/pkcs1.js index d437834..2ffb19f 100644 --- a/src/formats/pkcs1.js +++ b/src/formats/pkcs1.js @@ -1,30 +1,11 @@ var ber = require('asn1').Ber; +var _ = require('lodash'); var utils = require('../utils'); module.exports = { - privateExport: function(key, options) { + privateExport: function (key, options) { options = options || {}; - var der = module.exports.privateDerEncode(key); - if (options.binary) { - return der; - } else { - return '-----BEGIN RSA PRIVATE KEY-----\n' + utils.linebrk(der.toString('base64'), 64) + '\n-----END RSA PRIVATE KEY-----'; - } - }, - - publicExport: function(key, options) { - options = options || {}; - - var der = module.exports.publicDerEncode(key); - if (options.binary) { - return der; - } else { - return '-----BEGIN RSA PUBLIC KEY-----\n' + utils.linebrk(der.toString('base64'), 64) + '\n-----END RSA PUBLIC KEY-----'; - } - }, - - privateDerEncode: function(key) { var n = key.n.toBuffer(); var d = key.d.toBuffer(); var p = key.p.toBuffer(); @@ -48,10 +29,45 @@ module.exports = { writer.writeBuffer(coeff, 2); writer.endSequence(); - return writer.buffer; + if (options.binary) { + return writer.buffer; + } else { + return '-----BEGIN RSA PRIVATE KEY-----\n' + utils.linebrk(writer.buffer.toString('base64'), 64) + '\n-----END RSA PRIVATE KEY-----'; + } }, - publicDerEncode: function (key) { + privateImport: function (key, data) { + var buffer; + + if (_.isString(data)) { + var pem = data.replace('-----BEGIN RSA PRIVATE KEY-----', '') + .replace('-----END RSA PRIVATE KEY-----', '') + .replace(/\s+|\n\r|\n|\r$/gm, ''); + buffer = new Buffer(pem, 'base64'); + } else if (Buffer.isBuffer(data)) { + buffer = data; + } else { + throw Error('Unsupported key format'); + } + + var reader = new ber.Reader(buffer); + reader.readSequence(); + reader.readString(2, true); // just zero + key.setPrivate( + reader.readString(2, true), // modulus + reader.readString(2, true), // publicExponent + reader.readString(2, true), // privateExponent + reader.readString(2, true), // prime1 + reader.readString(2, true), // prime2 + reader.readString(2, true), // exponent1 -- d mod (p1) + reader.readString(2, true), // exponent2 -- d mod (q-1) + reader.readString(2, true) // coefficient -- (inverse of q) mod p + ); + }, + + publicExport: function (key, options) { + options = options || {}; + var n = key.n.toBuffer(); var length = n.length + 512; // magic @@ -60,6 +76,30 @@ module.exports = { bodyWriter.writeBuffer(n, 2); bodyWriter.writeInt(key.e); bodyWriter.endSequence(); - return bodyWriter.buffer; + + if (options.binary) { + return bodyWriter.buffer; + } else { + return '-----BEGIN RSA PUBLIC KEY-----\n' + utils.linebrk(bodyWriter.buffer.toString('base64'), 64) + '\n-----END RSA PUBLIC KEY-----'; + } + }, + + /** + * Trying autodetect and import key + * @param key + * @param data + */ + autoImport: function (key, data) { + if (/^\s*-----BEGIN RSA PRIVATE KEY-----\s*([A-Za-z0-9+/=]+\s*)+-----END RSA PRIVATE KEY-----\s*$/g.test(data)) { + module.exports.privateImport(key, data); + return true; + } + + if (/^\s*-----BEGIN RSA PUBLIC KEY-----\s*([A-Za-z0-9+/=]+\s*)+-----END RSA PUBLIC KEY-----\s*$/g.test(data)) { + module.exports.publicImport(key, data); + return true; + } + + return false; } }; \ No newline at end of file diff --git a/src/formats/pkcs8.js b/src/formats/pkcs8.js index 6d9d11b..86e1fb4 100644 --- a/src/formats/pkcs8.js +++ b/src/formats/pkcs8.js @@ -1,4 +1,5 @@ var ber = require('asn1').Ber; +var _ = require('lodash'); var PUBLIC_RSA_OID = '1.2.840.113549.1.1.1'; var utils = require('../utils'); @@ -6,19 +7,6 @@ module.exports = { publicExport: function(key, options) { options = options || {}; - var der = module.exports.publicDerEncode(key); - if (options.binary) { - return der; - } else { - return '-----BEGIN PUBLIC KEY-----\n' + utils.linebrk(der.toString('base64'), 64) + '\n-----END PUBLIC KEY-----'; - } - }, - - publicImport: function(key) { - - }, - - publicDerEncode: function (key) { var n = key.n.toBuffer(); var length = n.length + 512; // magic @@ -39,6 +27,59 @@ module.exports = { writer.writeBuffer(body, 3); writer.endSequence(); - return writer.buffer; + if (options.binary) { + return writer.buffer; + } else { + return '-----BEGIN PUBLIC KEY-----\n' + utils.linebrk(writer.buffer.toString('base64'), 64) + '\n-----END PUBLIC KEY-----'; + } + }, + + publicImport: function(key, data) { + var buffer; + + if (_.isString(data)) { + var pem = data.replace('-----BEGIN PUBLIC KEY-----', '') + .replace('-----END PUBLIC KEY-----', '') + .replace(/\s+|\n\r|\n|\r$/gm, ''); + buffer = new Buffer(pem, 'base64'); + } else if (Buffer.isBuffer(data)) { + buffer = data; + } else { + throw Error('Unsupported key format'); + } + + var reader = new ber.Reader(buffer); + reader.readSequence(); + var header = new ber.Reader(reader.readString(0x30, true)); + if (header.readOID(0x06, true) !== PUBLIC_RSA_OID) { + throw Error('Invalid Public key format'); + } + + var body = new ber.Reader(reader.readString(0x03, true)); + body.readByte(); + body.readSequence(); + key.setPublic( + body.readString(0x02, true), // modulus + body.readString(0x02, true) // publicExponent + ); + }, + + /** + * Trying autodetect and import key + * @param key + * @param data + */ + autoImport: function (key, data) { + if (/^\s*-----BEGIN PRIVATE KEY-----\s*([A-Za-z0-9+/=]+\s*)+-----END PRIVATE KEY-----\s*$/g.test(data)) { + module.exports.privateImport(key, data); + return true; + } + + if (/^\s*-----BEGIN PUBLIC KEY-----\s*([A-Za-z0-9+/=]+\s*)+-----END PUBLIC KEY-----\s*$/g.test(data)) { + module.exports.publicImport(key, data); + return true; + } + + return false; } -}; \ No newline at end of file +}; diff --git a/test/tests.js b/test/tests.js index 90c1d76..c3b7e83 100644 --- a/test/tests.js +++ b/test/tests.js @@ -254,21 +254,13 @@ describe("NodeRSA", function(){ assert.equal(privateNodeRSA.exportPublic(), publicKeyPEM); }); - it("should create key from buffer/fs.readFileSync output", function(){ + it("should create and load key from buffer/fs.readFileSync output", function(){ var key = new NodeRSA(fs.readFileSync(fileKey)); assert.equal(key.exportPrivate(), fileKeyPEM); key = new NodeRSA(); key.importKey(fs.readFileSync(fileKey)); assert.equal(key.exportPrivate(), fileKeyPEM); }); - - it("should load PEM from buffer/fs.readFileSync output", function(){ - var key = new NodeRSA(); - assert.equal(key.isEmpty(), true); - key.importKey(fs.readFileSync(fileKey)); - assert.equal(key.isEmpty(), false); - assert.equal(key.exportPrivate(), fileKeyPEM); - }); }); describe("Bad cases", function () { From ef7ed7b374fa14cf6266e5e79427da8d55fe8a10 Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 02:53:51 +0500 Subject: [PATCH 03/18] new exporting key api --- src/NodeRSA.js | 183 +++---------------- src/formats/formats.js | 69 ++++++- src/formats/pkcs1.js | 23 ++- src/formats/pkcs8.js | 21 ++- src/libs/rsa.js | 15 ++ src/schemes/pkcs1.js | 4 +- test/keys/private_pkcs1.der | Bin 0 -> 608 bytes test/{private.key => keys/private_pkcs1.pem} | 0 test/keys/private_pkcs8.der | Bin 0 -> 634 bytes test/keys/private_pkcs8.pem | 16 ++ test/keys/public_pkcs1.der | Bin 0 -> 140 bytes test/keys/public_pkcs1.pem | 5 + test/keys/public_pkcs8.der | Bin 0 -> 162 bytes test/keys/public_pkcs8.pem | 6 + test/tests.js | 153 ++++++++++------ 15 files changed, 269 insertions(+), 226 deletions(-) create mode 100644 test/keys/private_pkcs1.der rename test/{private.key => keys/private_pkcs1.pem} (100%) create mode 100644 test/keys/private_pkcs8.der create mode 100644 test/keys/private_pkcs8.pem create mode 100644 test/keys/public_pkcs1.der create mode 100644 test/keys/public_pkcs1.pem create mode 100644 test/keys/public_pkcs8.der create mode 100644 test/keys/public_pkcs8.pem diff --git a/src/NodeRSA.js b/src/NodeRSA.js index 8cf6c2d..7c342ac 100644 --- a/src/NodeRSA.js +++ b/src/NodeRSA.js @@ -26,18 +26,26 @@ module.exports = (function () { var DEFAULT_ENCRYPTION_SCHEME = 'pkcs1_oaep'; var DEFAULT_SIGNING_SCHEME = 'pkcs1'; - var DEFAULT_EXPORT_PRIVATE_FORMAT = 'pkcs1'; - var DEFAULT_EXPORT_PUBLIC_FORMAT = 'pkcs8'; + var DEFAULT_EXPORT_FORMAT = 'private'; + var EXPORT_FORMAT_ALIASES = { + 'private': 'pkcs1-private-pem', + 'public': 'pkcs8-public-pem' + }; /** * @param key {string|buffer|object} Key in PEM format, or data for generate key {b: bits, e: exponent} * @constructor */ - function NodeRSA(key, options) { + function NodeRSA(key, format, options) { if (!this instanceof NodeRSA) { return new NodeRSA(key, options); } + if (_.isObject(format)) { + options = format; + format = undefined; + } + this.$options = { signingScheme: DEFAULT_SIGNING_SCHEME, signingSchemeOptions: { @@ -53,14 +61,14 @@ module.exports = (function () { rsaUtils: this }; this.keyPair = new rsa.Key(); - this.setOptions(options); this.$cache = {}; if (Buffer.isBuffer(key) || _.isString(key)) { - this.importKey(key); + this.importKey(key, format); } else if (_.isObject(key)) { this.generateKeyPair(key.b, key.e); } + this.setOptions(options); } /** @@ -153,73 +161,38 @@ module.exports = (function () { /** * Importing key * @param keyData {string|buffer} + * @param format {string} */ NodeRSA.prototype.importKey = function (keyData, format) { - if(format === undefined && !formats.detectAndImport(this.keyPair, keyData, format)) { + if (!keyData) { + throw Error("Empty key given"); + } + + if(!formats.detectAndImport(this.keyPair, keyData, format) && format === undefined) { throw Error("Key format must be specified"); } this.$cache = {}; }; /** - * Make key form private PEM string - * - * @param privatePEM {string} + * Exporting key + * @param format {string} */ - /*NodeRSA.prototype.$loadFromPrivatePEM = function (privatePEM, encoding) { - var pem = privatePEM - .replace('-----BEGIN RSA PRIVATE KEY-----', '') - .replace('-----END RSA PRIVATE KEY-----', '') - .replace(/\s+|\n\r|\n|\r$/gm, ''); - var reader = new ber.Reader(new Buffer(pem, 'base64')); - - reader.readSequence(); - reader.readString(2, true); // just zero - this.keyPair.setPrivate( - reader.readString(2, true), // modulus - reader.readString(2, true), // publicExponent - reader.readString(2, true), // privateExponent - reader.readString(2, true), // prime1 - reader.readString(2, true), // prime2 - reader.readString(2, true), // exponent1 -- d mod (p1) - reader.readString(2, true), // exponent2 -- d mod (q-1) - reader.readString(2, true) // coefficient -- (inverse of q) mod p - ); - - };*/ + NodeRSA.prototype.exportKey = function (format) { + format = format || DEFAULT_EXPORT_FORMAT; + format = EXPORT_FORMAT_ALIASES[format] || format; - /** - * Make key form public PEM string - * - * @param publicPEM {string} - */ - /*NodeRSA.prototype.$loadFromPublicPEM = function (publicPEM, encoding) { - var pem = publicPEM - .replace('-----BEGIN PUBLIC KEY-----', '') - .replace('-----END PUBLIC KEY-----', '') - .replace(/\s+|\n\r|\n|\r$/gm, ''); - var reader = new ber.Reader(new Buffer(pem, 'base64')); - - reader.readSequence(); - var header = new ber.Reader(reader.readString(0x30, true)); - if (header.readOID(0x06, true) !== PUBLIC_RSA_OID) { - throw Error('Invalid Public key PEM format'); + if (!this.$cache[format]) { + this.$cache[format] = formats.detectAndExport(this.keyPair, format); } - - var body = new ber.Reader(reader.readString(0x03, true)); - body.readByte(); - body.readSequence(); - this.keyPair.setPublic( - body.readString(0x02, true), // modulus - body.readString(0x02, true) // publicExponent - ); - };*/ + return this.$cache[format]; + }; /** * Check if key pair contains private key */ NodeRSA.prototype.isPrivate = function () { - return this.keyPair.n && this.keyPair.e && this.keyPair.d || false; + return this.keyPair.isPrivate(); }; /** @@ -227,7 +200,7 @@ module.exports = (function () { * @param strict {boolean} - public key only, return false if have private exponent */ NodeRSA.prototype.isPublic = function (strict) { - return this.keyPair.n && this.keyPair.e && !(strict && this.keyPair.d) || false; + return this.keyPair.isPublic(strict); }; /** @@ -316,56 +289,6 @@ module.exports = (function () { return this.keyPair.verify(this.$getDataForEncrypt(buffer, source_encoding), signature, signature_encoding); }; - /** - * Exporting private key - * - * @param format - * @returns {*} - */ - NodeRSA.prototype.exportPrivate = function (format) { - if (!this.isPrivate()) { - throw Error("It is not private key"); - } - - format = format || DEFAULT_EXPORT_PRIVATE_FORMAT; - if (this.$cache.privateKey && this.$cache.privateKey[format]) { - return this.$cache.privateKey[format]; - } else { - var fmt = format.split('-'); - if (!formats.isPrivateExport(fmt[0])) { - throw Error('Unsupported private key export format'); - } - - this.$cache.privateKey = this.$cache.privateKey || {}; - return this.$cache.privateKey[format] = formats[fmt[0]].privateExport(this.keyPair, fmt[1]); - } - }; - - /** - * Exporting public key - * - * @param format - * @returns {*} - */ - NodeRSA.prototype.exportPublic = function (format) { - if (!this.isPublic()) { - throw Error("It is not public key"); - } - - format = format || DEFAULT_EXPORT_PUBLIC_FORMAT; - if (this.$cache.publicKey && this.$cache.publicKey[format]) { - return this.$cache.publicKey[format]; - } else { - var fmt = format.split('-'); - if (!formats.isPublicExport(fmt[0])) { - throw Error('Unsupported public key export format'); - } - - this.$cache.publicKey = this.$cache.publicKey || {}; - return this.$cache.publicKey[format] = formats[fmt[0]].publicExport(this.keyPair, fmt[1]); - } - }; - /** * Returns key size in bits * @returns {int} @@ -419,51 +342,5 @@ module.exports = (function () { } }; - /** - * private - * Recalculating properties - */ - /*NodeRSA.prototype.$recalculateCache = function () { - this.$cache.privatePEM = this.$makePrivatePEM(); - };*/ - - /** - * private - * @returns {string} private PEM string - */ - /*NodeRSA.prototype.$makePrivatePEM = function () { - if (!this.isPrivate()) { - return null; - } - - var n = this.keyPair.n.toBuffer(); - var d = this.keyPair.d.toBuffer(); - var p = this.keyPair.p.toBuffer(); - var q = this.keyPair.q.toBuffer(); - var dmp1 = this.keyPair.dmp1.toBuffer(); - var dmq1 = this.keyPair.dmq1.toBuffer(); - var coeff = this.keyPair.coeff.toBuffer(); - - var length = n.length + d.length + p.length + q.length + dmp1.length + dmq1.length + coeff.length + 512; // magic - var writer = new ber.Writer({size: length}); - - writer.startSequence(); - writer.writeInt(0); - writer.writeBuffer(n, 2); - writer.writeInt(this.keyPair.e); - writer.writeBuffer(d, 2); - writer.writeBuffer(p, 2); - writer.writeBuffer(q, 2); - writer.writeBuffer(dmp1, 2); - writer.writeBuffer(dmq1, 2); - writer.writeBuffer(coeff, 2); - writer.endSequence(); - - return '-----BEGIN RSA PRIVATE KEY-----\n' + - utils.linebrk(writer.buffer.toString('base64'), 64) + - '\n-----END RSA PRIVATE KEY-----'; - }; -*/ - return NodeRSA; })(); diff --git a/src/formats/formats.js b/src/formats/formats.js index 6d2b85f..f38c648 100644 --- a/src/formats/formats.js +++ b/src/formats/formats.js @@ -20,7 +20,7 @@ module.exports = { }, detectAndImport: function (key, data, format) { - if (format === undefined && _.isString(data)) { + if (format === undefined) { for (var format in module.exports) { if (typeof module.exports[format].autoImport === 'function' && module.exports[format].autoImport(key, data)) { return true; @@ -28,8 +28,28 @@ module.exports = { } } else if (format) { var fmt = format.split('-'); - var keyType = fmt[1] === 'private' || fmt[1] === 'public' ? fmt[1] : 'private'; - var keyOpt = fmt[2] === 'der' ? {binary: true} : null; + var keyType = 'private'; + var keyOpt = {type: 'default'}; + + for(var i = 1; i < fmt.length; i++) { + if (fmt[i]) { + switch (fmt[i]) { + case 'public': + keyType = fmt[i]; + break; + case 'private': + keyType = fmt[i]; + break; + case 'pem': + keyOpt.type = fmt[i]; + break; + case 'der': + keyOpt.type = fmt[i]; + break; + } + } + } + if (module.exports[fmt[0]]) { if (keyType === 'private') { module.exports[fmt[0]].privateImport(key, data, keyOpt); @@ -42,5 +62,48 @@ module.exports = { } return false; + }, + + detectAndExport: function(key, format) { + if (format) { + var fmt = format.split('-'); + var keyType = 'private'; + var keyOpt = {type: 'default'}; + + for(var i = 1; i < fmt.length; i++) { + if (fmt[i]) { + switch (fmt[i]) { + case 'public': + keyType = fmt[i]; + break; + case 'private': + keyType = fmt[i]; + break; + case 'pem': + keyOpt.type = fmt[i]; + break; + case 'der': + keyOpt.type = fmt[i]; + break; + } + } + } + + if (module.exports[fmt[0]]) { + if (keyType === 'private') { + if (!key.isPrivate()) { + throw Error("It is not private key"); + } + return module.exports[fmt[0]].privateExport(key, keyOpt); + } else { + if (!key.isPublic()) { + throw Error("It is not public key"); + } + return module.exports[fmt[0]].publicExport(key, keyOpt); + } + } else { + throw Error('Unsupported key format'); + } + } } }; \ No newline at end of file diff --git a/src/formats/pkcs1.js b/src/formats/pkcs1.js index 2ffb19f..264e07c 100644 --- a/src/formats/pkcs1.js +++ b/src/formats/pkcs1.js @@ -29,21 +29,30 @@ module.exports = { writer.writeBuffer(coeff, 2); writer.endSequence(); - if (options.binary) { + if (options.type === 'der') { return writer.buffer; } else { return '-----BEGIN RSA PRIVATE KEY-----\n' + utils.linebrk(writer.buffer.toString('base64'), 64) + '\n-----END RSA PRIVATE KEY-----'; } }, - privateImport: function (key, data) { + privateImport: function (key, data, options) { + options = options || {}; var buffer; - if (_.isString(data)) { - var pem = data.replace('-----BEGIN RSA PRIVATE KEY-----', '') - .replace('-----END RSA PRIVATE KEY-----', '') - .replace(/\s+|\n\r|\n|\r$/gm, ''); - buffer = new Buffer(pem, 'base64'); + if (options.type !== 'der') { + if (Buffer.isBuffer(data)) { + data = data.toString('utf8'); + } + + if (_.isString(data)) { + var pem = data.replace('-----BEGIN RSA PRIVATE KEY-----', '') + .replace('-----END RSA PRIVATE KEY-----', '') + .replace(/\s+|\n\r|\n|\r$/gm, ''); + buffer = new Buffer(pem, 'base64'); + } else { + throw Error('Unsupported key format'); + } } else if (Buffer.isBuffer(data)) { buffer = data; } else { diff --git a/src/formats/pkcs8.js b/src/formats/pkcs8.js index 86e1fb4..5d0c715 100644 --- a/src/formats/pkcs8.js +++ b/src/formats/pkcs8.js @@ -27,21 +27,28 @@ module.exports = { writer.writeBuffer(body, 3); writer.endSequence(); - if (options.binary) { + if (options.type === 'der') { return writer.buffer; } else { return '-----BEGIN PUBLIC KEY-----\n' + utils.linebrk(writer.buffer.toString('base64'), 64) + '\n-----END PUBLIC KEY-----'; } }, - publicImport: function(key, data) { + publicImport: function(key, data, options) { + options = options || {}; var buffer; - if (_.isString(data)) { - var pem = data.replace('-----BEGIN PUBLIC KEY-----', '') - .replace('-----END PUBLIC KEY-----', '') - .replace(/\s+|\n\r|\n|\r$/gm, ''); - buffer = new Buffer(pem, 'base64'); + if (options.type !== 'der') { + if (Buffer.isBuffer(data)) { + data = data.toString('utf8'); + } + + if (_.isString(data)) { + var pem = data.replace('-----BEGIN PUBLIC KEY-----', '') + .replace('-----END PUBLIC KEY-----', '') + .replace(/\s+|\n\r|\n|\r$/gm, ''); + buffer = new Buffer(pem, 'base64'); + } } else if (Buffer.isBuffer(data)) { buffer = data; } else { diff --git a/src/libs/rsa.js b/src/libs/rsa.js index 245bb29..fe1dccd 100644 --- a/src/libs/rsa.js +++ b/src/libs/rsa.js @@ -278,6 +278,21 @@ module.exports.Key = (function() { return this.signingScheme.verify.apply(this.signingScheme, arguments); }; + /** + * Check if key pair contains private key + */ + RSAKey.prototype.isPrivate = function () { + return this.n && this.e && this.d || false; + }; + + /** + * Check if key pair contains public key + * @param strict {boolean} - public key only, return false if have private exponent + */ + RSAKey.prototype.isPublic = function (strict) { + return this.n && this.e && !(strict && this.d) || false; + }; + Object.defineProperty(RSAKey.prototype, 'keySize', { get: function() { return this.cache.keyBitLength; } }); diff --git a/src/schemes/pkcs1.js b/src/schemes/pkcs1.js index d46e297..d6907c6 100644 --- a/src/schemes/pkcs1.js +++ b/src/schemes/pkcs1.js @@ -115,7 +115,7 @@ module.exports.makeScheme = function (key, options) { } else { var signer = crypt.createSign('RSA-' + hashAlgorithm.toUpperCase()); signer.update(buffer); - return signer.sign(this.options.rsaUtils.exportPrivate()); + return signer.sign(this.options.rsaUtils.exportKey('private')); } }; @@ -137,7 +137,7 @@ module.exports.makeScheme = function (key, options) { } else { var verifier = crypt.createVerify('RSA-' + hashAlgorithm.toUpperCase()); verifier.update(buffer); - return verifier.verify(this.options.rsaUtils.exportPublic(), signature, signature_encoding); + return verifier.verify(this.options.rsaUtils.exportKey('public'), signature, signature_encoding); } }; diff --git a/test/keys/private_pkcs1.der b/test/keys/private_pkcs1.der new file mode 100644 index 0000000000000000000000000000000000000000..3afd0ad53eb1157a95532f334794b33654b3e4dc GIT binary patch literal 608 zcmV-m0-yabf&yFu0RRGlfdGPakA$Q!zr6Oh-}P}*!MM9 z{<)7CwB!osikyOgrsIY&a!zP04IkVTe$#F3Js+Sh5wjBEsOGIhDDV-C#0eM8a-w)g_P@G@GglZopM(kTC)S0RRC4fq)T& zccAy{6VvO>1lcz!_|D*k2w;SvvbBd-XQPdi)ec;{c6hWNUyHwM7tyRVS~PO-aLCql z6VDS~Eh%=nL|dtyJ_H4KaD~RRpeo-$8k4OfT=P`s^-!}1S>kblr5(L z!xXPd)$YAk<_ay%9g zX1YSAe6tsfCRk$sgR;L9B46UJA*yjG29OcQpl7w7V$^4W2LeF=tA-p0#QhAi7*Xbu z_>@+_v!0DkzpaO0#1a}BeWuX2Y5zXuEY9F>LHPn-yFBKjkOyZC$w3Yrv8aj1JB4ot z0zm+sxs1^%fY@q4s5wT)C>LZyVaR9sW7?nY%y7KMWcN5sTIS5D42Z7AJi+5Oi3vq~ zEA60TR0F|`K{D(c<2*qEKvRk0w+aI>9>8adL_?c{(IDz{>PW)OZ=J6%Rehs0eo#8c zxHzSqd$NZE*ZN9?4qt?;b#!u}+v(3MBZT738v;NBNXi-s-+Q2h+}j9=Cy>L+whPNS uKoOn1n*F&SMeIw7%$Ut{&AO&TW5QWLd2EE=90|r;Vlj_liyU`i$_J`&>mj26 literal 0 HcmV?d00001 diff --git a/test/private.key b/test/keys/private_pkcs1.pem similarity index 100% rename from test/private.key rename to test/keys/private_pkcs1.pem diff --git a/test/keys/private_pkcs8.der b/test/keys/private_pkcs8.der new file mode 100644 index 0000000000000000000000000000000000000000..633b0c000ec533cbd80b93d29fa735294744a43b GIT binary patch literal 634 zcmV-=0)_oBf&z8|0RS)!1_>&LNQUpU@(FLTmk_A0)c@5f_0CCq%gm{ z_P5`ed*@VvGsk%?{xjhQSK+rl4y4%kHCX<+j~TS&3g?QPf`F#uhB0zZXe&*n&H!1ke;DrcagrTyvhgWB# zjg!?5T)TF7v>soJziSuKtTb9Qa`14-)^rok6J9MTcDY1bshvIq1$S_T#y2F`7_I0PndgZ4S#(&j;0zm-6 zwfk%z-|4NmE<=HKl;x~1KYD5`e~xlI77%8-LZ*DP7mOxYV*i7(zY`)~;;td8aVQ3m z5yzlswVq(|U90$bx46+ze=92i7R=~5KjZVL>J}eK>|QiiQ=~k12G=J zXNyEbn}g9H>U8Qz!pv`-uP;@7qcna{I>)#;rJZ}ShXdF8N`wwygsXLQa-rMl&nqK@ z;>{ZZKm$n18VTQfpoHAp2#F_w&2!DVrbA=GSwMMg Ugx?$q##~}Ck70`(cVfy1s$%aZjsO4v literal 0 HcmV?d00001 diff --git a/test/keys/private_pkcs8.pem b/test/keys/private_pkcs8.pem new file mode 100644 index 0000000..af76cbe --- /dev/null +++ b/test/keys/private_pkcs8.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIJ1j4SkML+89rff +mXvnVIEzx3kt/jPhBlfhtz4OpNj3NVj+uY8ZtOQK54qcgoCm44Yxck5oLA0f3BR+ +023tPR+gTCOXXq4gLybiHBKOM0vlMqoxV7JLK/TigG6J2/vq7nI2IsLgnzmVuZbd +YDJiRMJub9UlkBc0m6oKbsBVaZAxAgMBAAECgYARhHeg9+sT0+vNBNk3KfjO4IUI +YIShsrWHV2ejjZPVDly7dni0Hl+Lv2sX0aw0WjRy8HDI1nQTzxNeLSl2uURbqZ0+ +BAV3cIXGs6Aq30Aak60jXPNU5vVR13LCr+ZYE/IRPAQrOruULacBwxSvSuUWusOZ +RPZ1p8d65acUxn/VgQJBAMK1+2wf3+mtuC5DgXaU5awvP3pqLH+OcjwWEGa6QqZ8 +sxeMJlhi/4OyvxMiX+KuIapxKAaQEcegZ7WeYtRngQcCQQCrhhwHxP0MshhR5pL4 +lFbAs56NTr+th2DEEhoafabQt2n/PuUszuBvQfkCX7s85qOQB2cNyUEOHLGoicc7 +hW8HAkEAnbmM0SmA2GpAqDlGxigXZENhyGf5Y9qf7sxwvMZk9zhMWubMqQyIrsY8 +weM2iQlFfCvtoGNUA8GMQTLsG+M8QQJAU4nitwoDMR7AZ4tEQ5uD0SDqdOpIwsxv +na8vVX2jNH5QOse4OKWde7KHA9f6SoQOX4SrdXRyodvpzysjhOLNGwJAA0jKGgnf +e6CE3NsIiSeQw8q2C8s5QBGdvJr9uR9F7EuJzJjNc826pkNjwllAeWyE3xwJxlxi +MY9hixx3YsoHqg== +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/test/keys/public_pkcs1.der b/test/keys/public_pkcs1.der new file mode 100644 index 0000000000000000000000000000000000000000..58891a8dfa4668043e2d190dc12858c503b162e3 GIT binary patch literal 140 zcmV;70CWE^fr$cvfdGPakA$Q!zr6Oh-}P}*!MM9{<)7C zwB!osikyOgrsIY&a!zP04IkVTe$#F3Js+Sh5wjBEsOGIhDDV-C#0eM8a-w)g_P@G@GglZopM(kTC)S0RRCRi$W0q literal 0 HcmV?d00001 diff --git a/test/keys/public_pkcs1.pem b/test/keys/public_pkcs1.pem new file mode 100644 index 0000000..8b6b542 --- /dev/null +++ b/test/keys/public_pkcs1.pem @@ -0,0 +1,5 @@ +-----BEGIN RSA PUBLIC KEY----- +MIGJAoGBAIJ1j4SkML+89rffmXvnVIEzx3kt/jPhBlfhtz4OpNj3NVj+uY8ZtOQK +54qcgoCm44Yxck5oLA0f3BR+023tPR+gTCOXXq4gLybiHBKOM0vlMqoxV7JLK/Ti +gG6J2/vq7nI2IsLgnzmVuZbdYDJiRMJub9UlkBc0m6oKbsBVaZAxAgMBAAE= +-----END RSA PUBLIC KEY----- \ No newline at end of file diff --git a/test/keys/public_pkcs8.der b/test/keys/public_pkcs8.der new file mode 100644 index 0000000000000000000000000000000000000000..5d2c1c3334816a5b0ef53666b7d1ed23b031f691 GIT binary patch literal 162 zcmV;T0A2qufuAr91_>&LNQU 1 ? " in " + env + " environment" : ""), function () { it("incorrect data for verifying", function () { - var key = new NodeRSA(generatedKeys[0].exportPrivate(), { + var key = new NodeRSA(generatedKeys[0].exportKey(), { signingScheme: scheme + '-sha256', environment: env }); @@ -393,7 +438,7 @@ describe("NodeRSA", function(){ }); it("incorrect key for signing", function () { - var key = new NodeRSA(generatedKeys[0].exportPublic(), { + var key = new NodeRSA(generatedKeys[0].exportKey('pkcs8-public'), { signingScheme: scheme + '-sha256', environment: env }); @@ -403,11 +448,11 @@ describe("NodeRSA", function(){ }); it("incorrect key for verifying", function () { - var key1 = new NodeRSA(generatedKeys[0].exportPrivate(), { + var key1 = new NodeRSA(generatedKeys[0].exportKey(), { signingScheme: scheme + '-sha256', environment: env }); - var key2 = new NodeRSA(generatedKeys[1].exportPublic(), { + var key2 = new NodeRSA(generatedKeys[1].exportKey('pkcs8-public'), { signingScheme: scheme + '-sha256', environment: env }); @@ -424,11 +469,11 @@ describe("NodeRSA", function(){ }); it("different algorithms", function () { - var singKey = new NodeRSA(generatedKeys[0].exportPrivate(), { + var singKey = new NodeRSA(generatedKeys[0].exportKey(), { signingScheme: scheme + '-md5', environment: env }); - var verifyKey = new NodeRSA(generatedKeys[0].exportPrivate(), { + var verifyKey = new NodeRSA(generatedKeys[0].exportKey(), { signingScheme: scheme + '-sha1', environment: env }); @@ -447,11 +492,11 @@ describe("NodeRSA", function(){ for (var alg in signHashAlgorithms['browser']) { (function (alg) { it("signing with custom algorithm (" + alg + ") (equal test)", function () { - var nodeKey = new NodeRSA(generatedKeys[5].exportPrivate(), { + var nodeKey = new NodeRSA(generatedKeys[5].exportKey(), { signingScheme: scheme + '-' + alg, environment: 'node' }); - var browserKey = new NodeRSA(generatedKeys[5].exportPrivate(), { + var browserKey = new NodeRSA(generatedKeys[5].exportKey(), { signingScheme: scheme + '-' + alg, environment: 'browser' }); @@ -460,11 +505,11 @@ describe("NodeRSA", function(){ }); it("sign in node & verify in browser (" + alg + ")", function () { - var nodeKey = new NodeRSA(generatedKeys[5].exportPrivate(), { + var nodeKey = new NodeRSA(generatedKeys[5].exportKey(), { signingScheme: scheme + '-' + alg, environment: 'node' }); - var browserKey = new NodeRSA(generatedKeys[5].exportPrivate(), { + var browserKey = new NodeRSA(generatedKeys[5].exportKey(), { signingScheme: scheme + '-' + alg, environment: 'browser' }); @@ -473,11 +518,11 @@ describe("NodeRSA", function(){ }); it("sign in browser & verify in node (" + alg + ")", function () { - var nodeKey = new NodeRSA(generatedKeys[5].exportPrivate(), { + var nodeKey = new NodeRSA(generatedKeys[5].exportKey(), { signingScheme: scheme + '-' + alg, environment: 'node' }); - var browserKey = new NodeRSA(generatedKeys[5].exportPrivate(), { + var browserKey = new NodeRSA(generatedKeys[5].exportKey(), { signingScheme: scheme + '-' + alg, environment: 'browser' }); From 4cc4e099d9f7b850ad3f17425aae6f87a38e8a34 Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 03:22:32 +0500 Subject: [PATCH 04/18] pkcs8 private export/import --- src/formats/pkcs1.js | 31 ++++++++++++++- src/formats/pkcs8.js | 92 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 3 deletions(-) diff --git a/src/formats/pkcs1.js b/src/formats/pkcs1.js index 264e07c..91ffe8d 100644 --- a/src/formats/pkcs1.js +++ b/src/formats/pkcs1.js @@ -86,13 +86,42 @@ module.exports = { bodyWriter.writeInt(key.e); bodyWriter.endSequence(); - if (options.binary) { + if (options.type === 'der') { return bodyWriter.buffer; } else { return '-----BEGIN RSA PUBLIC KEY-----\n' + utils.linebrk(bodyWriter.buffer.toString('base64'), 64) + '\n-----END RSA PUBLIC KEY-----'; } }, + publicImport: function(key, data, options) { + options = options || {}; + var buffer; + + if (options.type !== 'der') { + if (Buffer.isBuffer(data)) { + data = data.toString('utf8'); + } + + if (_.isString(data)) { + var pem = data.replace('-----BEGIN RSA PUBLIC KEY-----', '') + .replace('-----END RSA PUBLIC KEY-----', '') + .replace(/\s+|\n\r|\n|\r$/gm, ''); + buffer = new Buffer(pem, 'base64'); + } + } else if (Buffer.isBuffer(data)) { + buffer = data; + } else { + throw Error('Unsupported key format'); + } + + var body = new ber.Reader(buffer); + body.readSequence(); + key.setPublic( + body.readString(0x02, true), // modulus + body.readString(0x02, true) // publicExponent + ); + }, + /** * Trying autodetect and import key * @param key diff --git a/src/formats/pkcs8.js b/src/formats/pkcs8.js index 5d0c715..0c4fe37 100644 --- a/src/formats/pkcs8.js +++ b/src/formats/pkcs8.js @@ -4,6 +4,95 @@ var PUBLIC_RSA_OID = '1.2.840.113549.1.1.1'; var utils = require('../utils'); module.exports = { + privateExport: function (key, options) { + options = options || {}; + + var n = key.n.toBuffer(); + var d = key.d.toBuffer(); + var p = key.p.toBuffer(); + var q = key.q.toBuffer(); + var dmp1 = key.dmp1.toBuffer(); + var dmq1 = key.dmq1.toBuffer(); + var coeff = key.coeff.toBuffer(); + + var length = n.length + d.length + p.length + q.length + dmp1.length + dmq1.length + coeff.length + 512; // magic + var bodyWriter = new ber.Writer({size: length}); + + bodyWriter.startSequence(); + bodyWriter.writeInt(0); + bodyWriter.writeBuffer(n, 2); + bodyWriter.writeInt(key.e); + bodyWriter.writeBuffer(d, 2); + bodyWriter.writeBuffer(p, 2); + bodyWriter.writeBuffer(q, 2); + bodyWriter.writeBuffer(dmp1, 2); + bodyWriter.writeBuffer(dmq1, 2); + bodyWriter.writeBuffer(coeff, 2); + bodyWriter.endSequence(); + + var writer = new ber.Writer({size: length}); + writer.startSequence(); + writer.writeInt(0); + writer.startSequence(); + writer.writeOID(PUBLIC_RSA_OID); + writer.writeNull(); + writer.endSequence(); + writer.writeBuffer(bodyWriter.buffer, 4); + writer.endSequence(); + + if (options.type === 'der') { + return writer.buffer; + } else { + return '-----BEGIN PRIVATE KEY-----\n' + utils.linebrk(writer.buffer.toString('base64'), 64) + '\n-----END PRIVATE KEY-----'; + } + }, + + privateImport: function (key, data, options) { + options = options || {}; + var buffer; + + if (options.type !== 'der') { + if (Buffer.isBuffer(data)) { + data = data.toString('utf8'); + } + + if (_.isString(data)) { + var pem = data.replace('-----BEGIN PRIVATE KEY-----', '') + .replace('-----END PRIVATE KEY-----', '') + .replace(/\s+|\n\r|\n|\r$/gm, ''); + buffer = new Buffer(pem, 'base64'); + } else { + throw Error('Unsupported key format'); + } + } else if (Buffer.isBuffer(data)) { + buffer = data; + } else { + throw Error('Unsupported key format'); + } + + var reader = new ber.Reader(buffer); + reader.readSequence(); + reader.readInt(0); + var header = new ber.Reader(reader.readString(0x30, true)); + if (header.readOID(0x06, true) !== PUBLIC_RSA_OID) { + throw Error('Invalid Public key format'); + } + + var body = new ber.Reader(reader.readString(0x04, true)); + body.readSequence(); + body.readString(2, true); // just zero + key.setPrivate( + body.readString(2, true), // modulus + body.readString(2, true), // publicExponent + body.readString(2, true), // privateExponent + body.readString(2, true), // prime1 + body.readString(2, true), // prime2 + body.readString(2, true), // exponent1 -- d mod (p1) + body.readString(2, true), // exponent2 -- d mod (q-1) + body.readString(2, true) // coefficient -- (inverse of q) mod p + ); + }, + publicExport: function(key, options) { options = options || {}; @@ -16,7 +105,6 @@ module.exports = { bodyWriter.writeBuffer(n, 2); bodyWriter.writeInt(key.e); bodyWriter.endSequence(); - var body = bodyWriter.buffer; var writer = new ber.Writer({size: length}); writer.startSequence(); @@ -24,7 +112,7 @@ module.exports = { writer.writeOID(PUBLIC_RSA_OID); writer.writeNull(); writer.endSequence(); - writer.writeBuffer(body, 3); + writer.writeBuffer(bodyWriter.buffer, 3); writer.endSequence(); if (options.type === 'der') { From 20373fcc7d9ac80eb9194bf4612e2f75fb21ff8a Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 03:26:20 +0500 Subject: [PATCH 05/18] formats aliases --- src/NodeRSA.js | 4 ++++ test/tests.js | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/NodeRSA.js b/src/NodeRSA.js index 7c342ac..e509254 100644 --- a/src/NodeRSA.js +++ b/src/NodeRSA.js @@ -168,6 +168,10 @@ module.exports = (function () { throw Error("Empty key given"); } + if (format) { + format = EXPORT_FORMAT_ALIASES[format] || format; + } + if(!formats.detectAndImport(this.keyPair, keyData, format) && format === undefined) { throw Error("Key format must be specified"); } diff --git a/test/tests.js b/test/tests.js index e5eb8cf..8cc9589 100644 --- a/test/tests.js +++ b/test/tests.js @@ -232,7 +232,10 @@ describe("NodeRSA", function(){ 'pkcs1-public-der': {public: true, der: true, file: 'public_pkcs1.der'}, 'pkcs1-public-pem': {public: true, der: false, file: 'public_pkcs1.pem'}, 'pkcs8-public-der': {public: true, der: true, file: 'public_pkcs8.der'}, - 'pkcs8-public-pem': {public: true, der: false, file: 'public_pkcs8.pem'} + 'pkcs8-public-pem': {public: true, der: false, file: 'public_pkcs8.pem'}, + + 'private': {public: false, der: false, file: 'private_pkcs1.pem'}, + 'public': {public: true, der: false, file: 'public_pkcs8.pem'} }; describe("Good cases", function () { @@ -291,7 +294,7 @@ describe("NodeRSA", function(){ } }); - it("should export to " + format + " format", function () { + it("should export to \"" + format + "\" format", function () { var keyData = fs.readFileSync(keysFolder + options.file); var exported = sampleKey.exportKey(format); From 4d1aae232dd244dd559ece7dfb936d43bb932a13 Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 03:28:43 +0500 Subject: [PATCH 06/18] code style fix --- src/NodeRSA.js | 12 +++++++++--- src/formats/formats.js | 6 +++--- src/formats/pkcs1.js | 2 +- src/formats/pkcs8.js | 6 ++++-- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/NodeRSA.js b/src/NodeRSA.js index e509254..27c201a 100644 --- a/src/NodeRSA.js +++ b/src/NodeRSA.js @@ -15,8 +15,6 @@ var utils = require('./utils'); var schemes = require('./schemes/schemes.js'); var formats = require('./formats/formats.js'); -var PUBLIC_RSA_OID = '1.2.840.113549.1.1.1'; - module.exports = (function () { var SUPPORTED_HASH_ALGORITHMS = { node: ['md4', 'md5', 'ripemd160', 'sha', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512'], @@ -68,6 +66,7 @@ module.exports = (function () { } else if (_.isObject(key)) { this.generateKeyPair(key.b, key.e); } + this.setOptions(options); } @@ -110,6 +109,7 @@ module.exports = (function () { if (!schemes.isSignature(this.$options.signingScheme)) { throw Error('Unsupported signing scheme'); } + if (this.$options.signingSchemeOptions.hash && _.indexOf(SUPPORTED_HASH_ALGORITHMS[this.$options.environment], this.$options.signingSchemeOptions.hash) == -1) { throw Error('Unsupported hashing algorithm for ' + this.$options.environment + ' environment'); @@ -172,9 +172,10 @@ module.exports = (function () { format = EXPORT_FORMAT_ALIASES[format] || format; } - if(!formats.detectAndImport(this.keyPair, keyData, format) && format === undefined) { + if (!formats.detectAndImport(this.keyPair, keyData, format) && format === undefined) { throw Error("Key format must be specified"); } + this.$cache = {}; }; @@ -189,6 +190,7 @@ module.exports = (function () { if (!this.$cache[format]) { this.$cache[format] = formats.detectAndExport(this.keyPair, format); } + return this.$cache[format]; }; @@ -247,9 +249,11 @@ module.exports = (function () { try { buffer = _.isString(buffer) ? new Buffer(buffer, 'base64') : buffer; var res = this.keyPair.decrypt(buffer); + if (res === null) { throw Error('Key decrypt method returns null.'); } + return this.$getDecryptedData(res, encoding); } catch (e) { throw Error('Error during decryption (probably incorrect key). Original error: ' + e); @@ -268,11 +272,13 @@ module.exports = (function () { if (!this.isPrivate()) { throw Error("It is not private key"); } + var res = this.keyPair.sign(this.$getDataForEncrypt(buffer, source_encoding)); if (encoding && encoding != 'buffer') { res = res.toString(encoding); } + return res; }; diff --git a/src/formats/formats.js b/src/formats/formats.js index f38c648..6ef0bfa 100644 --- a/src/formats/formats.js +++ b/src/formats/formats.js @@ -31,7 +31,7 @@ module.exports = { var keyType = 'private'; var keyOpt = {type: 'default'}; - for(var i = 1; i < fmt.length; i++) { + for (var i = 1; i < fmt.length; i++) { if (fmt[i]) { switch (fmt[i]) { case 'public': @@ -64,13 +64,13 @@ module.exports = { return false; }, - detectAndExport: function(key, format) { + detectAndExport: function (key, format) { if (format) { var fmt = format.split('-'); var keyType = 'private'; var keyOpt = {type: 'default'}; - for(var i = 1; i < fmt.length; i++) { + for (var i = 1; i < fmt.length; i++) { if (fmt[i]) { switch (fmt[i]) { case 'public': diff --git a/src/formats/pkcs1.js b/src/formats/pkcs1.js index 91ffe8d..715e7c0 100644 --- a/src/formats/pkcs1.js +++ b/src/formats/pkcs1.js @@ -93,7 +93,7 @@ module.exports = { } }, - publicImport: function(key, data, options) { + publicImport: function (key, data, options) { options = options || {}; var buffer; diff --git a/src/formats/pkcs8.js b/src/formats/pkcs8.js index 0c4fe37..9647879 100644 --- a/src/formats/pkcs8.js +++ b/src/formats/pkcs8.js @@ -74,6 +74,7 @@ module.exports = { reader.readSequence(); reader.readInt(0); var header = new ber.Reader(reader.readString(0x30, true)); + if (header.readOID(0x06, true) !== PUBLIC_RSA_OID) { throw Error('Invalid Public key format'); } @@ -93,7 +94,7 @@ module.exports = { ); }, - publicExport: function(key, options) { + publicExport: function (key, options) { options = options || {}; var n = key.n.toBuffer(); @@ -122,7 +123,7 @@ module.exports = { } }, - publicImport: function(key, data, options) { + publicImport: function (key, data, options) { options = options || {}; var buffer; @@ -146,6 +147,7 @@ module.exports = { var reader = new ber.Reader(buffer); reader.readSequence(); var header = new ber.Reader(reader.readString(0x30, true)); + if (header.readOID(0x06, true) !== PUBLIC_RSA_OID) { throw Error('Invalid Public key format'); } From 93d1dde91c93017a0e090c5f7b430ba12b0cd20a Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 04:22:07 +0500 Subject: [PATCH 07/18] readme --- README.md | 64 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c0bfa20..9af467a 100644 --- a/README.md +++ b/README.md @@ -46,18 +46,19 @@ This library developed and tested primary for Node.js, but it still can work in ```javascript var NodeRSA = require('node-rsa'); -var key = new NodeRSA([key], [options]); +var key = new NodeRSA([keyData], [format], [options]); ``` -**key** - parameters of a generated key or the key in PEM format.
-**options** - additional settings +**keyData** — `{string|buffer|object}` — parameters of a generated key or the key in one of supported formats.
+**format** — `{string}` — format for importing key. See more details about formats in **Export/Import** section
+**options** — `{object}` — additional settings #### Options You can specify some options by second constructor argument, or over `key.setOptions()` method. -* **environment** - working environment, `'browser'` or `'node'`. Default autodetect. -* **encryptionScheme** - padding scheme for encrypt/decrypt. Can be `'pkcs1_oaep'` or `'pkcs1'`. Default `'pkcs1_oaep'`. -* **signingScheme** - scheme used for signing and verifying. Can be `'pkcs1'` or `'pss'` or 'scheme-hash' format string (eg `'pss-sha1'`). Default `'pkcs1-sha256'`, or, if chosen pss: `'pss-sha1'`. +* **environment** — working environment, `'browser'` or `'node'`. Default autodetect. +* **encryptionScheme** — padding scheme for encrypt/decrypt. Can be `'pkcs1_oaep'` or `'pkcs1'`. Default `'pkcs1_oaep'`. +* **signingScheme** — scheme used for signing and verifying. Can be `'pkcs1'` or `'pss'` or 'scheme-hash' format string (eg `'pss-sha1'`). Default `'pkcs1-sha256'`, or, if chosen pss: `'pss-sha1'`. **Advanced options:**
You also can specify advanced options for some schemes like this: @@ -78,7 +79,6 @@ options = { This lib supporting next hash algorithms: `'md5'`, `'ripemd160'`, `'sha1'`, `'sha256'`, `'sha512'` in browser and node environment and additional `'md4'`, `'sha'`, `'sha224'`, `'sha384'` in node only. - #### Creating "empty" key ```javascript var key = new NodeRSA(); @@ -107,16 +107,48 @@ Also you can use next methods: ```javascript key.generateKeyPair([bits], [exp]); -key.importKey(pem_string|buffer_contains_pem); ``` -**bits** - key size in bits. 2048 by default. -**exp** - public exponent. 65537 by default. +**bits** — `{int}` — key size in bits. 2048 by default. +**exp** — `{int}` — public exponent. 65537 by default. -### Export keys +### Import/Export keys ```javascript -key.exportPrivate(); -key.exportPublic(); +key.importKey(keyData, [format]); +key.exportKey([format]); +``` +**keyData** — `{string|buffer}` — key in PEM string **or** Buffer contains PEM string **or** Buffer contains DER encoded data. +**format** — `{string}` — format id for export/import. + +#### Format string syntax +Format string composed of several parts: `scheme-[key_type]-[output_type]` + + * **Scheme** — NodeRSA supports multiple format schemes for import/export keys: + * `'pkcs1'` — public key starts from `'-----BEGIN RSA PUBLIC KEY-----'` header and private key starts from `'-----BEGIN RSA PRIVATE KEY-----' header` + * `'pkcs8'` — public key starts from `'-----BEGIN PUBLIC KEY-----'` header and private key starts from `'-----BEGIN PRIVATE KEY-----' header` + * **Key type** — can be `'private'` or `'public'`. Default `'private'` + * **Output type** — can be: + * `'pem'` — Base64 encoded string with header and footer. Used by default. + * `'der'` — Binary encoded key data. + +Notice: If you provide **keyData** as DER you must specify it in format string. + + +**Shortcuts and examples** + * `'private'` or `'pkcs1'` or `'pkcs1-private'` — `'pkcs1-private-pem'` — private key encoded in pcks1 scheme as pem string. + * `'public'` or `'pkcs8-public'` — `'pkcs8-public-pem'` — public key encoded in pcks8 scheme as pem string. + * `'pkcs8'` or `'pkcs8-private'` — `'pkcs8-private-pem'` — private key encoded in pcks8 scheme as pem string. + * `'pkcs1-der'` — `'pkcs1-private-der'` — private key encoded in pcks1 scheme as binary buffer. + * `'pkcs8-public-der'` — public key encoded in pcks8 scheme as binary buffer. + +**Code example** + ``` +var keyData = '-----BEGIN PUBLIC KEY-----' + .... + '-----BEGIN PRIVATE KEY-----'; +key.importKey(keyData, 'pkcs8'); +var publicDer = key.exportKey('pkcs8-public-der'); +var privateDer = key.exportKey('pkcs1-der'); +``` + ### Properties @@ -125,7 +157,7 @@ key.exportPublic(); key.isPrivate(); key.isPublic([strict]); ``` -**strict** - if true method will return false if key pair have private exponent. Default `false`. +**strict** — `{boolean}` if true method will return false if key pair have private exponent. Default `false`. ```javascript key.isEmpty(); @@ -181,6 +213,10 @@ Questions, comments, bug reports, and pull requests are all welcome. ## Changelog +### 0.2.10 + * **Methods `.exportPrivate()` and `.exportPublic()` was replaced by `.exportKey([format])`. By default `.exportKey()` returns private key as `.exportPrivate()`, if you need public key from `.exportPublic()` you must specify format as `'public'` or `'pkcs8-public-pem'`.** + * Method `.importKey(key, [format])` now has second argument. + ### 0.2.0 * **`.getPublicPEM()` method was renamed to `.exportPublic()`** * **`.getPrivatePEM()` method was renamed to `.exportPrivate()`** From 4231f9334f1a09b539c8c922a0c252a43c654c86 Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 18:49:37 +0500 Subject: [PATCH 08/18] readme --- README.md | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 9af467a..95ad0da 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ var key = new NodeRSA([keyData], [format], [options]); ``` **keyData** — `{string|buffer|object}` — parameters of a generated key or the key in one of supported formats.
-**format** — `{string}` — format for importing key. See more details about formats in **Export/Import** section
+**format** — `{string}` — format for importing key. See more details about formats in [Export/Import](#importexport-keys) section
**options** — `{object}` — additional settings #### Options @@ -121,23 +121,21 @@ key.exportKey([format]); #### Format string syntax Format string composed of several parts: `scheme-[key_type]-[output_type]` +**Scheme** — NodeRSA supports multiple format schemes for import/export keys: + * `'pkcs1'` — public key starts from `'-----BEGIN RSA PUBLIC KEY-----'` header and private key starts from `'-----BEGIN RSA PRIVATE KEY-----' header` + * `'pkcs8'` — public key starts from `'-----BEGIN PUBLIC KEY-----'` header and private key starts from `'-----BEGIN PRIVATE KEY-----' header` +**Key type** — can be `'private'` or `'public'`. Default `'private'` +**Output type** — can be: + * `'pem'` — Base64 encoded string with header and footer. Used by default. + * `'der'` — Binary encoded key data. - * **Scheme** — NodeRSA supports multiple format schemes for import/export keys: - * `'pkcs1'` — public key starts from `'-----BEGIN RSA PUBLIC KEY-----'` header and private key starts from `'-----BEGIN RSA PRIVATE KEY-----' header` - * `'pkcs8'` — public key starts from `'-----BEGIN PUBLIC KEY-----'` header and private key starts from `'-----BEGIN PRIVATE KEY-----' header` - * **Key type** — can be `'private'` or `'public'`. Default `'private'` - * **Output type** — can be: - * `'pem'` — Base64 encoded string with header and footer. Used by default. - * `'der'` — Binary encoded key data. - -Notice: If you provide **keyData** as DER you must specify it in format string. - +**Notice:** For import, if *keyData* is pem string or buffer containing string, you can do not specify format, but if you provide *keyData* as DER you must specify it in format string. **Shortcuts and examples** - * `'private'` or `'pkcs1'` or `'pkcs1-private'` — `'pkcs1-private-pem'` — private key encoded in pcks1 scheme as pem string. - * `'public'` or `'pkcs8-public'` — `'pkcs8-public-pem'` — public key encoded in pcks8 scheme as pem string. - * `'pkcs8'` or `'pkcs8-private'` — `'pkcs8-private-pem'` — private key encoded in pcks8 scheme as pem string. - * `'pkcs1-der'` — `'pkcs1-private-der'` — private key encoded in pcks1 scheme as binary buffer. + * `'private'` or `'pkcs1'` or `'pkcs1-private'` == `'pkcs1-private-pem'` — private key encoded in pcks1 scheme as pem string. + * `'public'` or `'pkcs8-public'` == `'pkcs8-public-pem'` — public key encoded in pcks8 scheme as pem string. + * `'pkcs8'` or `'pkcs8-private'` == `'pkcs8-private-pem'` — private key encoded in pcks8 scheme as pem string. + * `'pkcs1-der'` == `'pkcs1-private-der'` — private key encoded in pcks1 scheme as binary buffer. * `'pkcs8-public-der'` — public key encoded in pcks8 scheme as binary buffer. **Code example** From e7abb552becceb8f9b1f8ba068e45684ec83bf37 Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 18:56:48 +0500 Subject: [PATCH 09/18] readme --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 95ad0da..90d5015 100644 --- a/README.md +++ b/README.md @@ -46,15 +46,15 @@ This library developed and tested primary for Node.js, but it still can work in ```javascript var NodeRSA = require('node-rsa'); -var key = new NodeRSA([keyData], [format], [options]); +var key = new NodeRSA([keyData, [format]], [options]); ``` -**keyData** — `{string|buffer|object}` — parameters of a generated key or the key in one of supported formats.
-**format** — `{string}` — format for importing key. See more details about formats in [Export/Import](#importexport-keys) section
-**options** — `{object}` — additional settings +* **keyData** — `{string|buffer|object}` — parameters for generating key or the key in one of supported formats.
+* **format** — `{string}` — format for importing key. See more details about formats in [Export/Import](#importexport-keys) section.
+* **options** — `{object}` — additional settings. #### Options -You can specify some options by second constructor argument, or over `key.setOptions()` method. +You can specify some options by second/third constructor argument, or over `key.setOptions()` method. * **environment** — working environment, `'browser'` or `'node'`. Default autodetect. * **encryptionScheme** — padding scheme for encrypt/decrypt. Can be `'pkcs1_oaep'` or `'pkcs1'`. Default `'pkcs1_oaep'`. @@ -89,6 +89,14 @@ var key = new NodeRSA(); var key = new NodeRSA({b: 512}); ``` +Also you can use next method: + +```javascript +key.generateKeyPair([bits], [exp]); +``` +**bits** — `{int}` — key size in bits. 2048 by default. +**exp** — `{int}` — public exponent. 65537 by default. + #### Load key from PEM string ```javascript @@ -103,14 +111,6 @@ var key = new NodeRSA('-----BEGIN RSA PRIVATE KEY-----\n'+ '-----END RSA PRIVATE KEY-----'); ``` -Also you can use next methods: - -```javascript -key.generateKeyPair([bits], [exp]); -``` -**bits** — `{int}` — key size in bits. 2048 by default. -**exp** — `{int}` — public exponent. 65537 by default. - ### Import/Export keys ```javascript key.importKey(keyData, [format]); From c90e841e1a63c299cbc019fa7180a9b10c56c667 Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 19:02:15 +0500 Subject: [PATCH 10/18] readme --- README.md | 11 +++++------ src/NodeRSA.js | 4 +++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 90d5015..558c781 100644 --- a/README.md +++ b/README.md @@ -94,8 +94,8 @@ Also you can use next method: ```javascript key.generateKeyPair([bits], [exp]); ``` -**bits** — `{int}` — key size in bits. 2048 by default. -**exp** — `{int}` — public exponent. 65537 by default. +* **bits** — `{int}` — key size in bits. 2048 by default. +* **exp** — `{int}` — public exponent. 65537 by default. #### Load key from PEM string @@ -116,8 +116,8 @@ var key = new NodeRSA('-----BEGIN RSA PRIVATE KEY-----\n'+ key.importKey(keyData, [format]); key.exportKey([format]); ``` -**keyData** — `{string|buffer}` — key in PEM string **or** Buffer contains PEM string **or** Buffer contains DER encoded data. -**format** — `{string}` — format id for export/import. +* **keyData** — `{string|buffer}` — key in PEM string **or** Buffer contains PEM string **or** Buffer contains DER encoded data. +* **format** — `{string}` — format id for export/import. #### Format string syntax Format string composed of several parts: `scheme-[key_type]-[output_type]` @@ -129,7 +129,7 @@ Format string composed of several parts: `scheme-[key_type]-[output_type]` * `'pem'` — Base64 encoded string with header and footer. Used by default. * `'der'` — Binary encoded key data. -**Notice:** For import, if *keyData* is pem string or buffer containing string, you can do not specify format, but if you provide *keyData* as DER you must specify it in format string. +**Notice:** For import, if *keyData* is PEM string or buffer containing string, you can do not specify format, but if you provide *keyData* as DER you must specify it in format string. **Shortcuts and examples** * `'private'` or `'pkcs1'` or `'pkcs1-private'` == `'pkcs1-private-pem'` — private key encoded in pcks1 scheme as pem string. @@ -147,7 +147,6 @@ var publicDer = key.exportKey('pkcs8-public-der'); var privateDer = key.exportKey('pkcs1-der'); ``` - ### Properties #### Key testing diff --git a/src/NodeRSA.js b/src/NodeRSA.js index 27c201a..572d11d 100644 --- a/src/NodeRSA.js +++ b/src/NodeRSA.js @@ -27,7 +27,9 @@ module.exports = (function () { var DEFAULT_EXPORT_FORMAT = 'private'; var EXPORT_FORMAT_ALIASES = { 'private': 'pkcs1-private-pem', - 'public': 'pkcs8-public-pem' + 'private-der': 'pkcs1-private-der', + 'public': 'pkcs8-public-pem', + 'public-der': 'pkcs8-public-der' }; /** From ec52a27b31c638e68e89bda0b177a0cb25c1caa9 Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 19:03:37 +0500 Subject: [PATCH 11/18] readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 558c781..cad3380 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ Also you can use next method: ```javascript key.generateKeyPair([bits], [exp]); ``` + * **bits** — `{int}` — key size in bits. 2048 by default. * **exp** — `{int}` — public exponent. 65537 by default. @@ -116,16 +117,20 @@ var key = new NodeRSA('-----BEGIN RSA PRIVATE KEY-----\n'+ key.importKey(keyData, [format]); key.exportKey([format]); ``` + * **keyData** — `{string|buffer}` — key in PEM string **or** Buffer contains PEM string **or** Buffer contains DER encoded data. * **format** — `{string}` — format id for export/import. #### Format string syntax Format string composed of several parts: `scheme-[key_type]-[output_type]` **Scheme** — NodeRSA supports multiple format schemes for import/export keys: + * `'pkcs1'` — public key starts from `'-----BEGIN RSA PUBLIC KEY-----'` header and private key starts from `'-----BEGIN RSA PRIVATE KEY-----' header` * `'pkcs8'` — public key starts from `'-----BEGIN PUBLIC KEY-----'` header and private key starts from `'-----BEGIN PRIVATE KEY-----' header` + **Key type** — can be `'private'` or `'public'`. Default `'private'` **Output type** — can be: + * `'pem'` — Base64 encoded string with header and footer. Used by default. * `'der'` — Binary encoded key data. From 65a73af580ee32c5400552adb2b1c5f2a73f2889 Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 19:03:47 +0500 Subject: [PATCH 12/18] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cad3380..d3f36d8 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ Format string composed of several parts: `scheme-[key_type]-[output_type]` * `'pkcs1'` — public key starts from `'-----BEGIN RSA PUBLIC KEY-----'` header and private key starts from `'-----BEGIN RSA PRIVATE KEY-----' header` * `'pkcs8'` — public key starts from `'-----BEGIN PUBLIC KEY-----'` header and private key starts from `'-----BEGIN PRIVATE KEY-----' header` -**Key type** — can be `'private'` or `'public'`. Default `'private'` +**Key type** — can be `'private'` or `'public'`. Default `'private'`
**Output type** — can be: * `'pem'` — Base64 encoded string with header and footer. Used by default. From 4474665682c47082e253f18bda83e4ed8675d386 Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 19:04:07 +0500 Subject: [PATCH 13/18] readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d3f36d8..c188be4 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,8 @@ key.exportKey([format]); * **format** — `{string}` — format id for export/import. #### Format string syntax -Format string composed of several parts: `scheme-[key_type]-[output_type]` +Format string composed of several parts: `scheme-[key_type]-[output_type]`
+ **Scheme** — NodeRSA supports multiple format schemes for import/export keys: * `'pkcs1'` — public key starts from `'-----BEGIN RSA PUBLIC KEY-----'` header and private key starts from `'-----BEGIN RSA PRIVATE KEY-----' header` From 507be4ab712052f6bcfa596e6bd3131701ca1500 Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 19:12:39 +0500 Subject: [PATCH 14/18] Update README.md --- README.md | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index c188be4..7ff5e35 100644 --- a/README.md +++ b/README.md @@ -49,16 +49,16 @@ var NodeRSA = require('node-rsa'); var key = new NodeRSA([keyData, [format]], [options]); ``` -* **keyData** — `{string|buffer|object}` — parameters for generating key or the key in one of supported formats.
-* **format** — `{string}` — format for importing key. See more details about formats in [Export/Import](#importexport-keys) section.
-* **options** — `{object}` — additional settings. +* keyData — `{string|buffer|object}` — parameters for generating key or the key in one of supported formats.
+* format — `{string}` — format for importing key. See more details about formats in [Export/Import](#importexport-keys) section.
+* options — `{object}` — additional settings. #### Options You can specify some options by second/third constructor argument, or over `key.setOptions()` method. -* **environment** — working environment, `'browser'` or `'node'`. Default autodetect. -* **encryptionScheme** — padding scheme for encrypt/decrypt. Can be `'pkcs1_oaep'` or `'pkcs1'`. Default `'pkcs1_oaep'`. -* **signingScheme** — scheme used for signing and verifying. Can be `'pkcs1'` or `'pss'` or 'scheme-hash' format string (eg `'pss-sha1'`). Default `'pkcs1-sha256'`, or, if chosen pss: `'pss-sha1'`. +* environment — working environment, `'browser'` or `'node'`. Default autodetect. +* encryptionScheme — padding scheme for encrypt/decrypt. Can be `'pkcs1_oaep'` or `'pkcs1'`. Default `'pkcs1_oaep'`. +* signingScheme — scheme used for signing and verifying. Can be `'pkcs1'` or `'pss'` or 'scheme-hash' format string (eg `'pss-sha1'`). Default `'pkcs1-sha256'`, or, if chosen pss: `'pss-sha1'`. **Advanced options:**
You also can specify advanced options for some schemes like this: @@ -95,8 +95,8 @@ Also you can use next method: key.generateKeyPair([bits], [exp]); ``` -* **bits** — `{int}` — key size in bits. 2048 by default. -* **exp** — `{int}` — public exponent. 65537 by default. +* bits — `{int}` — key size in bits. 2048 by default. +* exp — `{int}` — public exponent. 65537 by default. #### Load key from PEM string @@ -118,19 +118,19 @@ key.importKey(keyData, [format]); key.exportKey([format]); ``` -* **keyData** — `{string|buffer}` — key in PEM string **or** Buffer contains PEM string **or** Buffer contains DER encoded data. -* **format** — `{string}` — format id for export/import. +* keyData — `{string|buffer}` — key in PEM string **or** Buffer contains PEM string **or** Buffer contains DER encoded data. +* format — `{string}` — format id for export/import. #### Format string syntax Format string composed of several parts: `scheme-[key_type]-[output_type]`
-**Scheme** — NodeRSA supports multiple format schemes for import/export keys: +Scheme — NodeRSA supports multiple format schemes for import/export keys: * `'pkcs1'` — public key starts from `'-----BEGIN RSA PUBLIC KEY-----'` header and private key starts from `'-----BEGIN RSA PRIVATE KEY-----' header` * `'pkcs8'` — public key starts from `'-----BEGIN PUBLIC KEY-----'` header and private key starts from `'-----BEGIN PRIVATE KEY-----' header` -**Key type** — can be `'private'` or `'public'`. Default `'private'`
-**Output type** — can be: +Key type — can be `'private'` or `'public'`. Default `'private'`
+Output type — can be: * `'pem'` — Base64 encoded string with header and footer. Used by default. * `'der'` — Binary encoded key data. @@ -160,7 +160,7 @@ var privateDer = key.exportKey('pkcs1-der'); key.isPrivate(); key.isPublic([strict]); ``` -**strict** — `{boolean}` if true method will return false if key pair have private exponent. Default `false`. +strict — `{boolean}` — if true method will return false if key pair have private exponent. Default `false`. ```javascript key.isEmpty(); @@ -184,16 +184,18 @@ Return max data size for encrypt in bytes. key.encrypt(buffer, [encoding], [source_encoding]); ``` Return encrypted data.
-**buffer** - data for encrypting, may be string, Buffer, or any object/array. Arrays and objects will encoded to JSON string first.
-**encoding** - encoding for output result, may be `'buffer'`, `'binary'`, `'hex'` or `'base64'`. Default `'buffer'`.
-**source_encoding** - source encoding, works only with string buffer. Can take standard Node.js Buffer encodings (hex, utf8, base64, etc). `'utf8'` by default.
+ +* buffer — `{buffer}` — data for encrypting, may be string, Buffer, or any object/array. Arrays and objects will encoded to JSON string first.
+* encoding — `{string}` — encoding for output result, may be `'buffer'`, `'binary'`, `'hex'` or `'base64'`. Default `'buffer'`.
+* source_encoding — `{string}` — source encoding, works only with string buffer. Can take standard Node.js Buffer encodings (hex, utf8, base64, etc). `'utf8'` by default.
```javascript key.decrypt(buffer, [encoding]); ``` Return decrypted data.
-**buffer** - data for decrypting. Takes Buffer object or base64 encoded string.
-**encoding** - encoding for result string. Can also take `'buffer'` for raw Buffer object, or `'json'` for automatic JSON.parse result. Default `'buffer'`. + +* buffer — `{buffer}` — data for decrypting. Takes Buffer object or base64 encoded string.
+* encoding — `{string}` — encoding for result string. Can also take `'buffer'` for raw Buffer object, or `'json'` for automatic JSON.parse result. Default `'buffer'`. ### Signing/Verifying ```javascript @@ -205,10 +207,11 @@ Return signature for buffer. All the arguments are the same as for `encrypt` met key.verify(buffer, signature, [source_encoding], [signature_encoding]) ``` Return result of check, `true` or `false`.
-**buffer** - data for check, same as `encrypt` method.
-**signature** - signature for check, result of `sign` method.
-**source_encoding** - same as for `encrypt` method.
-**signature_encoding** - encoding of given signature. May be `'buffer'`, `'binary'`, `'hex'` or `'base64'`. Default `'buffer'`. + +* buffer — `{buffer}` — data for check, same as `encrypt` method.
+* signature — `{string}` — signature for check, result of `sign` method.
+* source_encoding — `{string}` — same as for `encrypt` method.
+* signature_encoding — `{string}` — encoding of given signature. May be `'buffer'`, `'binary'`, `'hex'` or `'base64'`. Default `'buffer'`. ## Contributing @@ -217,7 +220,8 @@ Questions, comments, bug reports, and pull requests are all welcome. ## Changelog ### 0.2.10 - * **Methods `.exportPrivate()` and `.exportPublic()` was replaced by `.exportKey([format])`. By default `.exportKey()` returns private key as `.exportPrivate()`, if you need public key from `.exportPublic()` you must specify format as `'public'` or `'pkcs8-public-pem'`.** + * **Methods `.exportPrivate()` and `.exportPublic()` was replaced by `.exportKey([format])`.** + * By default `.exportKey()` returns private key as `.exportPrivate()`, if you need public key from `.exportPublic()` you must specify format as `'public'` or `'pkcs8-public-pem'`. * Method `.importKey(key, [format])` now has second argument. ### 0.2.0 From 9e52aadd93fd13f796c3b02664b0877eeca841f4 Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 19:17:41 +0500 Subject: [PATCH 15/18] readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ff5e35..984c6d7 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ You can specify some options by second/third constructor argument, or over `key. **Advanced options:**
You also can specify advanced options for some schemes like this: -``` +```javascript options = { encryptionScheme: { scheme: 'pkcs1_oaep', //scheme @@ -146,7 +146,7 @@ Output type — can be: **Code example** -``` +```javascript var keyData = '-----BEGIN PUBLIC KEY-----' + .... + '-----BEGIN PRIVATE KEY-----'; key.importKey(keyData, 'pkcs8'); var publicDer = key.exportKey('pkcs8-public-der'); From b5b798614863718304d9e3f65233e5c480ac92fd Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 19:18:00 +0500 Subject: [PATCH 16/18] version bump --- package.json | 2 +- test/private_pkcs1.pem | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 test/private_pkcs1.pem diff --git a/package.json b/package.json index d3be58c..608ea37 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-rsa", - "version": "0.2.0", + "version": "0.2.10", "description": "Node.js RSA library", "main": "src/NodeRSA.js", "scripts": { diff --git a/test/private_pkcs1.pem b/test/private_pkcs1.pem new file mode 100644 index 0000000..2ea486c --- /dev/null +++ b/test/private_pkcs1.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCCdY+EpDC/vPa335l751SBM8d5Lf4z4QZX4bc+DqTY9zVY/rmP +GbTkCueKnIKApuOGMXJOaCwNH9wUftNt7T0foEwjl16uIC8m4hwSjjNL5TKqMVey +Syv04oBuidv76u5yNiLC4J85lbmW3WAyYkTCbm/VJZAXNJuqCm7AVWmQMQIDAQAB +AoGAEYR3oPfrE9PrzQTZNyn4zuCFCGCEobK1h1dno42T1Q5cu3Z4tB5fi79rF9Gs +NFo0cvBwyNZ0E88TXi0pdrlEW6mdPgQFd3CFxrOgKt9AGpOtI1zzVOb1Uddywq/m +WBPyETwEKzq7lC2nAcMUr0rlFrrDmUT2dafHeuWnFMZ/1YECQQDCtftsH9/prbgu +Q4F2lOWsLz96aix/jnI8FhBmukKmfLMXjCZYYv+Dsr8TIl/iriGqcSgGkBHHoGe1 +nmLUZ4EHAkEAq4YcB8T9DLIYUeaS+JRWwLOejU6/rYdgxBIaGn2m0Ldp/z7lLM7g +b0H5Al+7POajkAdnDclBDhyxqInHO4VvBwJBAJ25jNEpgNhqQKg5RsYoF2RDYchn ++WPan+7McLzGZPc4TFrmzKkMiK7GPMHjNokJRXwr7aBjVAPBjEEy7BvjPEECQFOJ +4rcKAzEewGeLREObg9Eg6nTqSMLMb52vL1V9ozR+UDrHuDilnXuyhwPX+kqEDl+E +q3V0cqHb6c8rI4TizRsCQANIyhoJ33ughNzbCIknkMPKtgvLOUARnbya/bkfRexL +icyYzXPNuqZDY8JZQHlshN8cCcZcYjGPYYscd2LKB6o= +-----END RSA PRIVATE KEY----- \ No newline at end of file From 9c7d62cb74ee05d79a85577523917f8b854fc4fd Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 20:04:07 +0500 Subject: [PATCH 17/18] formats refact --- src/formats/formats.js | 95 ++++++++++++++++++------------------------ test/tests.js | 13 +++++- 2 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/formats/formats.js b/src/formats/formats.js index 6ef0bfa..e975b2a 100644 --- a/src/formats/formats.js +++ b/src/formats/formats.js @@ -1,4 +1,32 @@ var _ = require('lodash'); + +function formatParse(format) { + format = format.split('-'); + var keyType = 'private'; + var keyOpt = {type: 'default'}; + + for (var i = 1; i < format.length; i++) { + if (format[i]) { + switch (format[i]) { + case 'public': + keyType = format[i]; + break; + case 'private': + keyType = format[i]; + break; + case 'pem': + keyOpt.type = format[i]; + break; + case 'der': + keyOpt.type = format[i]; + break; + } + } + } + + return {scheme: format[0], keyType: keyType, keyOpt: keyOpt}; +} + module.exports = { pkcs1: require('./pkcs1'), pkcs8: require('./pkcs8'), @@ -21,40 +49,18 @@ module.exports = { detectAndImport: function (key, data, format) { if (format === undefined) { - for (var format in module.exports) { - if (typeof module.exports[format].autoImport === 'function' && module.exports[format].autoImport(key, data)) { + for (var scheme in module.exports) { + if (typeof module.exports[scheme].autoImport === 'function' && module.exports[scheme].autoImport(key, data)) { return true; } } } else if (format) { - var fmt = format.split('-'); - var keyType = 'private'; - var keyOpt = {type: 'default'}; - - for (var i = 1; i < fmt.length; i++) { - if (fmt[i]) { - switch (fmt[i]) { - case 'public': - keyType = fmt[i]; - break; - case 'private': - keyType = fmt[i]; - break; - case 'pem': - keyOpt.type = fmt[i]; - break; - case 'der': - keyOpt.type = fmt[i]; - break; - } - } - } - - if (module.exports[fmt[0]]) { - if (keyType === 'private') { - module.exports[fmt[0]].privateImport(key, data, keyOpt); + var fmt = formatParse(format); + if (module.exports[fmt.scheme]) { + if (fmt.keyType === 'private') { + module.exports[fmt.scheme].privateImport(key, data, fmt.keyOpt); } else { - module.exports[fmt[0]].publicImport(key, data, keyOpt); + module.exports[fmt.scheme].publicImport(key, data, fmt.keyOpt); } } else { throw Error('Unsupported key format'); @@ -66,40 +72,19 @@ module.exports = { detectAndExport: function (key, format) { if (format) { - var fmt = format.split('-'); - var keyType = 'private'; - var keyOpt = {type: 'default'}; - - for (var i = 1; i < fmt.length; i++) { - if (fmt[i]) { - switch (fmt[i]) { - case 'public': - keyType = fmt[i]; - break; - case 'private': - keyType = fmt[i]; - break; - case 'pem': - keyOpt.type = fmt[i]; - break; - case 'der': - keyOpt.type = fmt[i]; - break; - } - } - } + var fmt = formatParse(format); - if (module.exports[fmt[0]]) { - if (keyType === 'private') { + if (module.exports[fmt.scheme]) { + if (fmt.keyType === 'private') { if (!key.isPrivate()) { throw Error("It is not private key"); } - return module.exports[fmt[0]].privateExport(key, keyOpt); + return module.exports[fmt.scheme].privateExport(key, fmt.keyOpt); } else { if (!key.isPublic()) { throw Error("It is not public key"); } - return module.exports[fmt[0]].publicExport(key, keyOpt); + return module.exports[fmt.scheme].publicExport(key, fmt.keyOpt); } } else { throw Error('Unsupported key format'); diff --git a/test/tests.js b/test/tests.js index 8cc9589..f6aea3a 100644 --- a/test/tests.js +++ b/test/tests.js @@ -235,7 +235,18 @@ describe("NodeRSA", function(){ 'pkcs8-public-pem': {public: true, der: false, file: 'public_pkcs8.pem'}, 'private': {public: false, der: false, file: 'private_pkcs1.pem'}, - 'public': {public: true, der: false, file: 'public_pkcs8.pem'} + 'public': {public: true, der: false, file: 'public_pkcs8.pem'}, + 'private-der': {public: false, der: true, file: 'private_pkcs1.der'}, + 'public-der': {public: true, der: true, file: 'public_pkcs8.der'}, + + 'pkcs1': {public: false, der: false, file: 'private_pkcs1.pem'}, + 'pkcs1-private': {public: false, der: false, file: 'private_pkcs1.pem'}, + 'pkcs1-der': {public: false, der: true, file: 'private_pkcs1.der'}, + 'pkcs8': {public: false, der: false, file: 'private_pkcs8.pem'}, + 'pkcs8-private': {public: false, der: false, file: 'private_pkcs8.pem'}, + 'pkcs8-der': {public: false, der: true, file: 'private_pkcs8.der'}, + 'pkcs1-public': {public: true, der: false, file: 'public_pkcs1.pem'}, + 'pkcs8-public': {public: true, der: false, file: 'public_pkcs8.pem'} }; describe("Good cases", function () { From c2800e3fe6b08fbfa06b33853f756aaec944df6f Mon Sep 17 00:00:00 2001 From: rzcoder Date: Sat, 29 Nov 2014 20:25:33 +0500 Subject: [PATCH 18/18] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 984c6d7..a40b62a 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ Output type — can be: **Code example** ```javascript -var keyData = '-----BEGIN PUBLIC KEY-----' + .... + '-----BEGIN PRIVATE KEY-----'; +var keyData = '-----BEGIN PUBLIC KEY----- ... -----BEGIN PRIVATE KEY-----'; key.importKey(keyData, 'pkcs8'); var publicDer = key.exportKey('pkcs8-public-der'); var privateDer = key.exportKey('pkcs1-der');