Compare commits

...

3 Commits

Author SHA1 Message Date
Kgothatso
385a4cedbb Getting rid of all the uneeded logging 2019-11-26 22:43:24 +02:00
Kgothatso
4d16737b23 Verifying service produced challenge 2019-11-26 22:42:57 +02:00
Kgothatso
0a17e78fdc Improved encryption implementation 2019-11-26 22:42:26 +02:00
7 changed files with 96 additions and 60 deletions

View File

@ -28,48 +28,59 @@ module.exports.handler = (argv) => {
persistence().LoadDB()
.then(db => {
// TODO validate lock definition has all the parameters we need
// TODO: Verify challenge comes from a service we know...
return db.ExtendedPublicKey.findOne({
where: {
xpub: challenge.xpub
},
include: [
{
association: db.ExtendedPublicKey.Key // TODO: update this to wallet
// TODO: validate serviceExtendedPublicKey
const verification = cryptoUtil.verifyChallenge(
registerationMessage.serviceExtendedPublicKey,
challenge
);
if(verification) {
return db.ExtendedPublicKey.findOne({
where: {
xpub: challenge.xpub
},
include: [
{
association: db.ExtendedPublicKey.Key // TODO: update this to wallet
}
]
}).then(extendedPublicKey => {
if (extendedPublicKey) {
const encryptedKey = extendedPublicKey.key.encryptedPrivateKey;
const iv = extendedPublicKey.key.iv;
const password = "vanished";
const walletXpriv = cryptoUtil.decrypt(encryptedKey, password, iv);
var challengeDerivationPath = `${extendedPublicKey.derivationPath}/${challenge.derivationPath.split("c/")[1]}`;
const signature = cryptoUtil.signMessage(walletXpriv, challengeDerivationPath, challenge.message)
// TODO: save lock
return db.Lock.create({
userIdentifier: registerationMessage.userIdentifier,
url: registerationMessage.url,
serviceExtendedPublicKey: registerationMessage.serviceExtendedPublicKey,
signature: signature.toString('hex'),
message: challenge.message,
extendedPublicKeyId: extendedPublicKey.id
})
} else {
console.error("Sorry we can't create a lock with xpub: ", challenge.xpub);
return null;
}
}).then(lock => {
if(lock) {
console.log("Lock: ", lock.id);
console.log("Signature: ", lock.signature);
} else {
console.error("Failed to create the lock.");
}
]
}).then(extendedPublicKey => {
if (extendedPublicKey) {
const encryptedKey = extendedPublicKey.key.encryptedPrivateKey;
const password = "vanished";
const walletXpriv = cryptoUtil.decrypt(encryptedKey, password);
var challengeDerivationPath = `${extendedPublicKey.derivationPath}/${challenge.derivationPath.split("c/")[1]}`;
const signature = cryptoUtil.signMessage(walletXpriv, challengeDerivationPath, challenge.message)
// TODO: save lock
return db.Lock.create({
userIdentifier: registerationMessage.userIdentifier,
url: registerationMessage.url,
signature: signature.toString('hex'),
message: challenge.message,
extendedPublicKeyId: extendedPublicKey.id
})
} else {
console.error("Sorry we can't create a lock with xpub: ", challenge.xpub);
return null;
}
}).then(lock => {
if(lock) {
console.log("Lock: ", lock.id);
console.log("Signature: ", lock.signature);
} else {
console.error("Failed to create the lock.");
}
})
})
} else {
console.error("Challenge not signed by service");
}
})
}

View File

@ -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]}`;

View File

@ -19,20 +19,17 @@ module.exports.handler = (argv) => {
// TODO: validate user backed up mnemonic
const seed = bip39.mnemonicToSeedSync(mnemonic);
console.log("Seed: ", seed.toString('hex'))
const node = bip32.fromSeed(seed);
console.log("xpriv: ", node.toBase58());
// TODO: Get user key password
const password = "vanished";
// TODO: Encrypt text securely...
const encryptedPrivateKey = cryptoUtil.encrypt(node.toBase58(), password);
console.log("Encrypted Private Key: ", encryptedPrivateKey);
// Check if a key exist...
db.Key.create({
encryptedPrivateKey: encryptedPrivateKey,
encryptedPrivateKey: encryptedPrivateKey.cipherText,
iv: encryptedPrivateKey.iv,
name: "FirstKey"
}).then(key => {
console.log("Successfully created: ", key.name)

View File

@ -22,19 +22,14 @@ module.exports.handler = (argv) => {
// TODO: Load password from config...
if(key) {
const password = "vanished";
console.log("Encrypted: ", key.encryptedPrivateKey);
const decryptedPrivateKey = cryptoUtil.decrypt(key.encryptedPrivateKey, password);
console.log("Decrypted: ", decryptedPrivateKey);
const masterNode = bip32.fromBase58(decryptedPrivateKey);
const iv = key.iv;
console.log("Node: ", masterNode.toBase58());
const decryptedPrivateKey = cryptoUtil.decrypt(key.encryptedPrivateKey, password, iv);
const masterNode = bip32.fromBase58(decryptedPrivateKey);
const derivationPath = `m/${cryptoUtil.randomDerivationPath(true)}`
const xpubNode = masterNode.derivePath(derivationPath);
console.log("Xpub: ", xpubNode.neutered().toBase58());
// TODO save xpub and derivation path in db...
return db.ExtendedPublicKey.create({

View File

@ -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);
}
}

View File

@ -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

View File

@ -16,6 +16,10 @@ module.exports = function (sequelize, DataTypes, options) {
type: DataTypes.STRING,
allowNull: false
},
serviceExtendedPublicKey: {
type: DataTypes.STRING,
allowNull: false
},
signature: {
// Derivation from the master key...
// TODO: Add validation...