From 0a17e78fdcab1e737422f581ff8cacd0e70263cd Mon Sep 17 00:00:00 2001 From: Kgothatso Date: Tue, 26 Nov 2019 22:42:26 +0200 Subject: [PATCH] Improved encryption implementation --- lib/commands/authenticate-challenge.js | 3 ++- lib/core/cryptoUtil.js | 36 +++++++++++++++++++++----- lib/core/persistence/models/key.js | 4 +++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/lib/commands/authenticate-challenge.js b/lib/commands/authenticate-challenge.js index 2d08392..2d128e8 100644 --- a/lib/commands/authenticate-challenge.js +++ b/lib/commands/authenticate-challenge.js @@ -58,8 +58,9 @@ module.exports.handler = (argv) => { if(lock) { // Sign the message with the key that corresponds with this lock... const encryptedKey = lock.extendedPublicKey.key.encryptedPrivateKey; + const iv = lock.extendedPublicKey.key.iv; const password = "vanished"; - const walletXpriv = cryptoUtil.decrypt(encryptedKey, password); + const walletXpriv = cryptoUtil.decrypt(encryptedKey, password, iv); var challengeDerivationPath = `${lock.extendedPublicKey.derivationPath}/${challenge.derivationPath.split("c/")[1]}`; diff --git a/lib/core/cryptoUtil.js b/lib/core/cryptoUtil.js index 5859b47..5516a71 100644 --- a/lib/core/cryptoUtil.js +++ b/lib/core/cryptoUtil.js @@ -1,21 +1,24 @@ const crypto = require('crypto'); -const algorithm = 'aes-256-ecb'; +const algorithm = 'aes256'; const bip32 = require('bip32'); // NOTE I'm not a cryptographer... so don't be reusing any code from below as I don't have no idea what I'm doing -const iv = null; // If I knew what I was doing I would have a value assigned here... - module.exports.encrypt = (plainText, password) => { + const iv = crypto.randomBytes(16).toString('hex').slice(0, 16); // TODO figure out this iv stuff... + const key = crypto.createHash('sha256').update(password, 'utf8').digest(); const cipher = crypto.createCipheriv(algorithm, key, iv); var cipherText = cipher.update(plainText, 'utf8', 'hex'); cipherText += cipher.final('hex'); - return cipherText; + return { + cipherText: cipherText, + iv: iv + }; } -module.exports.decrypt = (cipherText, password) => { +module.exports.decrypt = (cipherText, password, iv) => { const key = crypto.createHash('sha256').update(password, 'utf8').digest(); const decipher = crypto.createDecipheriv(algorithm, key, iv); @@ -36,6 +39,17 @@ module.exports.randomDerivationPath = function(hardenedDerivation) { return randomNumbers.join('/') } +module.exports.verifyChallenge = function(serviceXpub, challenge) { + const requestSignature = challenge.request.signature; + const requestDerivationPath = challenge.request.signatureDerivationPath; + return this.verifyMessage( + serviceXpub, + requestDerivationPath, + JSON.stringify(this.unsignedChallenge(challenge)), + requestSignature + ); +} + module.exports.verifyMessage = function(base58Key, derivationPath, message, signature) { if(derivationPath.startsWith("a/")) { derivationPath = derivationPath.split("a/")[1]; @@ -51,10 +65,20 @@ module.exports.verifyMessage = function(base58Key, derivationPath, message, sign return verificationNode.verify(hash, Buffer.from(signature, 'hex')); } +module.exports.unsignedChallenge = function(challenge) { + return { + // keys must be alphabetically ordered + derivationPath: challenge.derivationPath, + message: challenge.message, + xpub: challenge.xpub + } +} + module.exports.signMessage = function(base58Key, derivationPath, message) { let signingNode = bip32.fromBase58(base58Key).derivePath(derivationPath); var hash = crypto.createHash('sha256').update(message, 'utf8').digest(); return signingNode.sign(hash); -} \ No newline at end of file +} + diff --git a/lib/core/persistence/models/key.js b/lib/core/persistence/models/key.js index 34984ea..54a312a 100644 --- a/lib/core/persistence/models/key.js +++ b/lib/core/persistence/models/key.js @@ -12,6 +12,10 @@ module.exports = function (sequelize, DataTypes, options) { type: DataTypes.STRING, allowNull: false }, + iv: { + type: DataTypes.STRING, + allowNull: false + }, name: { type: DataTypes.STRING, unique: true