From f71a6bbb0a044f6325bae3d1ea10b6b1ceda8c9f Mon Sep 17 00:00:00 2001 From: Vasco Santos Date: Thu, 14 Mar 2019 22:26:07 +0000 Subject: [PATCH] Revert "feat: adds support for ed25199 and secp256k1 (#31)" This reverts commit 9eb11f42452b4266db0c19de3310e809a0087669. --- README.md | 6 +- src/keychain.js | 128 +++++++++++++++++++--------------------- test/keychain.spec.js | 132 ++++++++++++------------------------------ 3 files changed, 98 insertions(+), 168 deletions(-) diff --git a/README.md b/README.md index 655ff03d..24bcf0d6 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,8 @@ Managing a key - `createKey (name, type, size, callback)` - `renameKey (oldName, newName, callback)` - `removeKey (name, callback)` -- `exportKey (name, password, callback)` // Omit _password_ for `ed25199` or `secp256k1` keys -- `importKey (name, encKey, password, callback)` // Omit _password_ for `ed25199` or `secp256k1` keys +- `exportKey (name, password, callback)` +- `importKey (name, pem, password, callback)` - `importPeer (name, peer, callback)` A naming service for a key @@ -67,7 +67,7 @@ A naming service for a key - `findKeyById (id, callback)` - `findKeyByName (name, callback)` -Cryptographically protected messages (Only supported with RSA keys) +Cryptographically protected messages - `cms.encrypt (name, plain, callback)` - `cms.decrypt (cmsData, callback)` diff --git a/src/keychain.js b/src/keychain.js index e236d8a8..cecc3207 100644 --- a/src/keychain.js +++ b/src/keychain.js @@ -20,7 +20,7 @@ const NIST = { } const defaultOptions = { - // See https://cryptosense.com/blog/parameter-choice-for-pbkdf2/ + // See https://cryptosense.com/parametesr-choice-for-pbkdf2/ dek: { keyLength: 512 / 8, iterationCount: 10000, @@ -197,8 +197,7 @@ class Keychain { if (err) return _error(callback, err) if (exists) return _error(callback, `Key '${name}' already exists`) - type = type.toLowerCase() - switch (type) { + switch (type.toLowerCase()) { case 'rsa': if (size < 2048) { return _error(callback, `Invalid RSA key size ${size}`) @@ -212,16 +211,21 @@ class Keychain { if (err) return _error(callback, err) keypair.id((err, kid) => { if (err) return _error(callback, err) - - if (type === 'ed25519' || type === 'secp256k1') { - const keypairMarshal = keypair.bytes - self._storeKey(name, kid, keypairMarshal, dsname, callback) - } else { - keypair.export(this._(), (err, pem) => { + keypair.export(this._(), (err, pem) => { + if (err) return _error(callback, err) + const keyInfo = { + name: name, + id: kid + } + const batch = self.store.batch() + batch.put(dsname, pem) + batch.put(DsInfoName(name), JSON.stringify(keyInfo)) + batch.commit((err) => { if (err) return _error(callback, err) - self._storeKey(name, kid, pem, dsname, callback) + + callback(null, keyInfo) }) - } + }) }) }) }) @@ -361,85 +365,76 @@ class Keychain { } /** - * Export an existing key. - * If it's as an RSA key, include a password to export as a PEM encrypted PKCS #8 string + * Export an existing key as a PEM encrypted PKCS #8 string * * @param {string} name - The local key name; must already exist. - * @param {string} password - The password, for RSA keys (optional) + * @param {string} password - The password * @param {function(Error, string)} callback * @returns {undefined} */ exportKey (name, password, callback) { - if (typeof password === 'function' && typeof callback === 'undefined') { - callback = password - password = undefined - } if (!validateKeyName(name)) { return _error(callback, `Invalid key name '${name}'`) } + if (!password) { + return _error(callback, 'Password is required') + } const dsname = DsName(name) this.store.get(dsname, (err, res) => { if (err) { return _error(callback, `Key '${name}' does not exist. ${err.message}`) } - if (password) { - const encKey = res.toString() - crypto.keys.import(encKey, this._(), (err, privateKey) => { - if (err) return _error(callback, err) - privateKey.export(password, callback) - }) - } else { - crypto.keys.unmarshalPrivateKey(res, callback) - } + const pem = res.toString() + crypto.keys.import(pem, this._(), (err, privateKey) => { + if (err) return _error(callback, err) + privateKey.export(password, callback) + }) }) } /** - * Import a new key - * If it's as an RSA key, include a password to import from a PEM encrypted PKCS #8 string + * Import a new key from a PEM encoded PKCS #8 string * * @param {string} name - The local key name; must not already exist. - * @param {string} encKey - The encoded key. If it's an RSA key, it needs to be a PEM encoded PKCS #8 string - * @param {string} password - The password for RSA keys. (optional) + * @param {string} pem - The PEM encoded PKCS #8 string + * @param {string} password - The password. * @param {function(Error, KeyInfo)} callback * @returns {undefined} */ - importKey (name, encKey, password, callback) { + importKey (name, pem, password, callback) { const self = this - if (typeof password === 'function' && typeof callback === 'undefined') { - callback = password - password = undefined - } if (!validateKeyName(name) || name === 'self') { return _error(callback, `Invalid key name '${name}'`) } - if (!encKey) { - return _error(callback, 'The encoded key is required') + if (!pem) { + return _error(callback, 'PEM encoded key is required') } - const dsname = DsName(name) self.store.has(dsname, (err, exists) => { if (err) return _error(callback, err) if (exists) return _error(callback, `Key '${name}' already exists`) - - if (password) { - crypto.keys.import(encKey, password, (err, privateKey) => { - if (err) return _error(callback, 'Cannot read the key, most likely the password is wrong') - privateKey.id((err, kid) => { + crypto.keys.import(pem, password, (err, privateKey) => { + if (err) return _error(callback, 'Cannot read the key, most likely the password is wrong') + privateKey.id((err, kid) => { + if (err) return _error(callback, err) + privateKey.export(this._(), (err, pem) => { if (err) return _error(callback, err) - privateKey.export(this._(), (err, pem) => { + const keyInfo = { + name: name, + id: kid + } + const batch = self.store.batch() + batch.put(dsname, pem) + batch.put(DsInfoName(name), JSON.stringify(keyInfo)) + batch.commit((err) => { if (err) return _error(callback, err) - self._storeKey(name, kid, pem, dsname, callback) + + callback(null, keyInfo) }) }) }) - } else { - encKey.id((err, kid) => { - if (err) return _error(callback, err) - self._storeKey(name, kid, encKey.bytes, dsname, callback) - }) - } + }) }) } @@ -462,28 +457,23 @@ class Keychain { if (err) return _error(callback, err) privateKey.export(this._(), (err, pem) => { if (err) return _error(callback, err) - self._storeKey(name, kid, pem, dsname, callback) + const keyInfo = { + name: name, + id: kid + } + const batch = self.store.batch() + batch.put(dsname, pem) + batch.put(DsInfoName(name), JSON.stringify(keyInfo)) + batch.commit((err) => { + if (err) return _error(callback, err) + + callback(null, keyInfo) + }) }) }) }) } - _storeKey (name, kid, encKey, dsname, callback) { - const self = this - const keyInfo = { - name: name, - id: kid - } - const batch = self.store.batch() - batch.put(dsname, encKey) - batch.put(DsInfoName(name), JSON.stringify(keyInfo)) - batch.commit((err) => { - if (err) return _error(callback, err) - - callback(null, keyInfo) - }) - } - /** * Gets the private key as PEM encoded PKCS #8 string. * diff --git a/test/keychain.spec.js b/test/keychain.spec.js index 9e3c6dc6..ed6f1a80 100644 --- a/test/keychain.spec.js +++ b/test/keychain.spec.js @@ -13,11 +13,9 @@ const PeerId = require('peer-id') module.exports = (datastore1, datastore2) => { describe('keychain', () => { const passPhrase = 'this is not a secure phrase' - const keyName = 'tajné jméno' - const renamedKeyName = 'ชื่อลับ' - let keyInfo - let ecKeyInfo - let secpKeyInfo + const rsaKeyName = 'tajné jméno' + const renamedRsaKeyName = 'ชื่อลับ' + let rsaKeyInfo let emptyKeystore let ks @@ -82,43 +80,23 @@ module.exports = (datastore1, datastore2) => { }) describe('key', () => { - it('can be an ed25519 key', function (done) { - this.timeout(50 * 1000) - ks.createKey(keyName + 'ed25519', 'ed25519', 2048, (err, info) => { - expect(err).to.not.exist() - expect(info).exist() - ecKeyInfo = info - done() - }) - }) - - it('can be an secp256k1 key', function (done) { - this.timeout(50 * 1000) - ks.createKey(keyName + 'secp256k1', 'secp256k1', 2048, (err, info) => { - expect(err).to.not.exist() - expect(info).exist() - secpKeyInfo = info - done() - }) - }) - it('can be an RSA key', function (done) { this.timeout(50 * 1000) - ks.createKey(keyName, 'rsa', 2048, (err, info) => { + ks.createKey(rsaKeyName, 'rsa', 2048, (err, info) => { expect(err).to.not.exist() expect(info).exist() - keyInfo = info + rsaKeyInfo = info done() }) }) it('has a name and id', () => { - expect(keyInfo).to.have.property('name', keyName) - expect(keyInfo).to.have.property('id') + expect(rsaKeyInfo).to.have.property('name', rsaKeyName) + expect(rsaKeyInfo).to.have.property('id') }) it('is encrypted PEM encoded PKCS #8', (done) => { - ks._getPrivateKey(keyName, (err, pem) => { + ks._getPrivateKey(rsaKeyName, (err, pem) => { expect(err).to.not.exist() expect(pem).to.startsWith('-----BEGIN ENCRYPTED PRIVATE KEY-----') done() @@ -126,7 +104,7 @@ module.exports = (datastore1, datastore2) => { }) it('does not overwrite existing key', (done) => { - ks.createKey(keyName, 'rsa', 2048, (err) => { + ks.createKey(rsaKeyName, 'rsa', 2048, (err) => { expect(err).to.exist() done() }) @@ -179,26 +157,26 @@ module.exports = (datastore1, datastore2) => { ks.listKeys((err, keys) => { expect(err).to.not.exist() expect(keys).to.exist() - const mykey = keys.find((k) => k.name.normalize() === keyName.normalize()) + const mykey = keys.find((k) => k.name.normalize() === rsaKeyName.normalize()) expect(mykey).to.exist() done() }) }) it('finds a key by name', (done) => { - ks.findKeyByName(keyName, (err, key) => { + ks.findKeyByName(rsaKeyName, (err, key) => { expect(err).to.not.exist() expect(key).to.exist() - expect(key).to.deep.equal(keyInfo) + expect(key).to.deep.equal(rsaKeyInfo) done() }) }) it('finds a key by id', (done) => { - ks.findKeyById(keyInfo.id, (err, key) => { + ks.findKeyById(rsaKeyInfo.id, (err, key) => { expect(err).to.not.exist() expect(key).to.exist() - expect(key).to.deep.equal(keyInfo) + expect(key).to.deep.equal(rsaKeyInfo) done() }) }) @@ -233,14 +211,14 @@ module.exports = (datastore1, datastore2) => { }) it('requires plain data as a Buffer', (done) => { - ks.cms.encrypt(keyName, 'plain data', (err, msg) => { + ks.cms.encrypt(rsaKeyName, 'plain data', (err, msg) => { expect(err).to.exist() done() }) }) it('encrypts', (done) => { - ks.cms.encrypt(keyName, plainData, (err, msg) => { + ks.cms.encrypt(rsaKeyName, plainData, (err, msg) => { expect(err).to.not.exist() expect(msg).to.exist() expect(msg).to.be.instanceOf(Buffer) @@ -267,7 +245,7 @@ module.exports = (datastore1, datastore2) => { emptyKeystore.cms.decrypt(cms, (err, plain) => { expect(err).to.exist() expect(err).to.have.property('missingKeys') - expect(err.missingKeys).to.eql([keyInfo.id]) + expect(err.missingKeys).to.eql([rsaKeyInfo.id]) done() }) }) @@ -284,11 +262,9 @@ module.exports = (datastore1, datastore2) => { describe('exported key', () => { let pemKey - let ed25519Key - let secp256k1Key it('is a PKCS #8 encrypted pem', (done) => { - ks.exportKey(keyName, 'password', (err, pem) => { + ks.exportKey(rsaKeyName, 'password', (err, pem) => { expect(err).to.not.exist() expect(pem).to.startsWith('-----BEGIN ENCRYPTED PRIVATE KEY-----') pemKey = pem @@ -300,49 +276,13 @@ module.exports = (datastore1, datastore2) => { ks.importKey('imported-key', pemKey, 'password', (err, key) => { expect(err).to.not.exist() expect(key.name).to.equal('imported-key') - expect(key.id).to.equal(keyInfo.id) - done() - }) - }) - - it('can export ed25519 key', (done) => { - ks.exportKey(keyName + 'ed25519', (err, key) => { - expect(err).to.not.exist() - ed25519Key = key - expect(key).to.exist() - done() - }) - }) - - it('ed25519 key can be imported', (done) => { - ks.importKey('imported-key-ed25199', ed25519Key, (err, key) => { - expect(err).to.not.exist() - expect(key.name).to.equal('imported-key-ed25199') - expect(key.id).to.equal(ecKeyInfo.id) - done() - }) - }) - - it('can export secp256k1 key', (done) => { - ks.exportKey(keyName + 'secp256k1', (err, key) => { - expect(err).to.not.exist() - secp256k1Key = key - expect(key).to.exist() - done() - }) - }) - - it('secp256k1 key can be imported', (done) => { - ks.importKey('imported-key-secp256k1', secp256k1Key, (err, key) => { - expect(err).to.not.exist() - expect(key.name).to.equal('imported-key-secp256k1') - expect(key.id).to.equal(secpKeyInfo.id) + expect(key.id).to.equal(rsaKeyInfo.id) done() }) }) it('cannot be imported as an existing key name', (done) => { - ks.importKey(keyName, pemKey, 'password', (err, key) => { + ks.importKey(rsaKeyName, pemKey, 'password', (err, key) => { expect(err).to.exist() done() }) @@ -402,40 +342,40 @@ module.exports = (datastore1, datastore2) => { describe('rename', () => { it('requires an existing key name', (done) => { - ks.renameKey('not-there', renamedKeyName, (err) => { + ks.renameKey('not-there', renamedRsaKeyName, (err) => { expect(err).to.exist() done() }) }) it('requires a valid new key name', (done) => { - ks.renameKey(keyName, '..\not-valid', (err) => { + ks.renameKey(rsaKeyName, '..\not-valid', (err) => { expect(err).to.exist() done() }) }) it('does not overwrite existing key', (done) => { - ks.renameKey(keyName, keyName, (err) => { + ks.renameKey(rsaKeyName, rsaKeyName, (err) => { expect(err).to.exist() done() }) }) it('cannot create the "self" key', (done) => { - ks.renameKey(keyName, 'self', (err) => { + ks.renameKey(rsaKeyName, 'self', (err) => { expect(err).to.exist() done() }) }) it('removes the existing key name', (done) => { - ks.renameKey(keyName, renamedKeyName, (err, key) => { + ks.renameKey(rsaKeyName, renamedRsaKeyName, (err, key) => { expect(err).to.not.exist() expect(key).to.exist() - expect(key).to.have.property('name', renamedKeyName) - expect(key).to.have.property('id', keyInfo.id) - ks.findKeyByName(keyName, (err, key) => { + expect(key).to.have.property('name', renamedRsaKeyName) + expect(key).to.have.property('id', rsaKeyInfo.id) + ks.findKeyByName(rsaKeyName, (err, key) => { expect(err).to.exist() done() }) @@ -443,20 +383,20 @@ module.exports = (datastore1, datastore2) => { }) it('creates the new key name', (done) => { - ks.findKeyByName(renamedKeyName, (err, key) => { + ks.findKeyByName(renamedRsaKeyName, (err, key) => { expect(err).to.not.exist() expect(key).to.exist() - expect(key).to.have.property('name', renamedKeyName) + expect(key).to.have.property('name', renamedRsaKeyName) done() }) }) it('does not change the key ID', (done) => { - ks.findKeyByName(renamedKeyName, (err, key) => { + ks.findKeyByName(renamedRsaKeyName, (err, key) => { expect(err).to.not.exist() expect(key).to.exist() - expect(key).to.have.property('name', renamedKeyName) - expect(key).to.have.property('id', keyInfo.id) + expect(key).to.have.property('name', renamedRsaKeyName) + expect(key).to.have.property('id', rsaKeyInfo.id) done() }) }) @@ -478,11 +418,11 @@ module.exports = (datastore1, datastore2) => { }) it('can remove a known key', (done) => { - ks.removeKey(renamedKeyName, (err, key) => { + ks.removeKey(renamedRsaKeyName, (err, key) => { expect(err).to.not.exist() expect(key).to.exist() - expect(key).to.have.property('name', renamedKeyName) - expect(key).to.have.property('id', keyInfo.id) + expect(key).to.have.property('name', renamedRsaKeyName) + expect(key).to.have.property('id', rsaKeyInfo.id) done() }) })