Compare commits
3 Commits
de7bd68872
...
385a4cedbb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
385a4cedbb | ||
|
|
4d16737b23 | ||
|
|
0a17e78fdc |
@@ -28,48 +28,59 @@ module.exports.handler = (argv) => {
|
|||||||
persistence().LoadDB()
|
persistence().LoadDB()
|
||||||
.then(db => {
|
.then(db => {
|
||||||
// TODO validate lock definition has all the parameters we need
|
// TODO validate lock definition has all the parameters we need
|
||||||
// TODO: Verify challenge comes from a service we know...
|
// TODO: validate serviceExtendedPublicKey
|
||||||
return db.ExtendedPublicKey.findOne({
|
const verification = cryptoUtil.verifyChallenge(
|
||||||
where: {
|
registerationMessage.serviceExtendedPublicKey,
|
||||||
xpub: challenge.xpub
|
challenge
|
||||||
},
|
);
|
||||||
include: [
|
if(verification) {
|
||||||
{
|
return db.ExtendedPublicKey.findOne({
|
||||||
association: db.ExtendedPublicKey.Key // TODO: update this to wallet
|
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]}`;
|
})
|
||||||
|
} else {
|
||||||
|
console.error("Challenge not signed by service");
|
||||||
|
}
|
||||||
|
|
||||||
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.");
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -58,8 +58,9 @@ module.exports.handler = (argv) => {
|
|||||||
if(lock) {
|
if(lock) {
|
||||||
// Sign the message with the key that corresponds with this lock...
|
// Sign the message with the key that corresponds with this lock...
|
||||||
const encryptedKey = lock.extendedPublicKey.key.encryptedPrivateKey;
|
const encryptedKey = lock.extendedPublicKey.key.encryptedPrivateKey;
|
||||||
|
const iv = lock.extendedPublicKey.key.iv;
|
||||||
const password = "vanished";
|
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]}`;
|
var challengeDerivationPath = `${lock.extendedPublicKey.derivationPath}/${challenge.derivationPath.split("c/")[1]}`;
|
||||||
|
|
||||||
|
|||||||
@@ -19,20 +19,17 @@ module.exports.handler = (argv) => {
|
|||||||
|
|
||||||
// TODO: validate user backed up mnemonic
|
// TODO: validate user backed up mnemonic
|
||||||
const seed = bip39.mnemonicToSeedSync(mnemonic);
|
const seed = bip39.mnemonicToSeedSync(mnemonic);
|
||||||
console.log("Seed: ", seed.toString('hex'))
|
|
||||||
const node = bip32.fromSeed(seed);
|
const node = bip32.fromSeed(seed);
|
||||||
console.log("xpriv: ", node.toBase58());
|
|
||||||
|
|
||||||
// TODO: Get user key password
|
// TODO: Get user key password
|
||||||
const password = "vanished";
|
const password = "vanished";
|
||||||
// TODO: Encrypt text securely...
|
// TODO: Encrypt text securely...
|
||||||
const encryptedPrivateKey = cryptoUtil.encrypt(node.toBase58(), password);
|
const encryptedPrivateKey = cryptoUtil.encrypt(node.toBase58(), password);
|
||||||
|
|
||||||
console.log("Encrypted Private Key: ", encryptedPrivateKey);
|
|
||||||
|
|
||||||
// Check if a key exist...
|
// Check if a key exist...
|
||||||
db.Key.create({
|
db.Key.create({
|
||||||
encryptedPrivateKey: encryptedPrivateKey,
|
encryptedPrivateKey: encryptedPrivateKey.cipherText,
|
||||||
|
iv: encryptedPrivateKey.iv,
|
||||||
name: "FirstKey"
|
name: "FirstKey"
|
||||||
}).then(key => {
|
}).then(key => {
|
||||||
console.log("Successfully created: ", key.name)
|
console.log("Successfully created: ", key.name)
|
||||||
|
|||||||
@@ -22,19 +22,14 @@ module.exports.handler = (argv) => {
|
|||||||
// TODO: Load password from config...
|
// TODO: Load password from config...
|
||||||
if(key) {
|
if(key) {
|
||||||
const password = "vanished";
|
const password = "vanished";
|
||||||
|
const iv = key.iv;
|
||||||
|
|
||||||
console.log("Encrypted: ", key.encryptedPrivateKey);
|
const decryptedPrivateKey = cryptoUtil.decrypt(key.encryptedPrivateKey, password, iv);
|
||||||
|
|
||||||
const decryptedPrivateKey = cryptoUtil.decrypt(key.encryptedPrivateKey, password);
|
|
||||||
console.log("Decrypted: ", decryptedPrivateKey);
|
|
||||||
const masterNode = bip32.fromBase58(decryptedPrivateKey);
|
const masterNode = bip32.fromBase58(decryptedPrivateKey);
|
||||||
|
|
||||||
console.log("Node: ", masterNode.toBase58());
|
|
||||||
|
|
||||||
const derivationPath = `m/${cryptoUtil.randomDerivationPath(true)}`
|
const derivationPath = `m/${cryptoUtil.randomDerivationPath(true)}`
|
||||||
|
|
||||||
const xpubNode = masterNode.derivePath(derivationPath);
|
const xpubNode = masterNode.derivePath(derivationPath);
|
||||||
console.log("Xpub: ", xpubNode.neutered().toBase58());
|
|
||||||
|
|
||||||
// TODO save xpub and derivation path in db...
|
// TODO save xpub and derivation path in db...
|
||||||
return db.ExtendedPublicKey.create({
|
return db.ExtendedPublicKey.create({
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const algorithm = 'aes-256-ecb';
|
const algorithm = 'aes256';
|
||||||
const bip32 = require('bip32');
|
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
|
// 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) => {
|
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 key = crypto.createHash('sha256').update(password, 'utf8').digest();
|
||||||
const cipher = crypto.createCipheriv(algorithm, key, iv);
|
const cipher = crypto.createCipheriv(algorithm, key, iv);
|
||||||
|
|
||||||
var cipherText = cipher.update(plainText, 'utf8', 'hex');
|
var cipherText = cipher.update(plainText, 'utf8', 'hex');
|
||||||
cipherText += cipher.final('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 key = crypto.createHash('sha256').update(password, 'utf8').digest();
|
||||||
const decipher = crypto.createDecipheriv(algorithm, key, iv);
|
const decipher = crypto.createDecipheriv(algorithm, key, iv);
|
||||||
|
|
||||||
@@ -36,6 +39,17 @@ module.exports.randomDerivationPath = function(hardenedDerivation) {
|
|||||||
return randomNumbers.join('/')
|
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) {
|
module.exports.verifyMessage = function(base58Key, derivationPath, message, signature) {
|
||||||
if(derivationPath.startsWith("a/")) {
|
if(derivationPath.startsWith("a/")) {
|
||||||
derivationPath = derivationPath.split("a/")[1];
|
derivationPath = derivationPath.split("a/")[1];
|
||||||
@@ -51,6 +65,15 @@ module.exports.verifyMessage = function(base58Key, derivationPath, message, sign
|
|||||||
return verificationNode.verify(hash, Buffer.from(signature, 'hex'));
|
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) {
|
module.exports.signMessage = function(base58Key, derivationPath, message) {
|
||||||
let signingNode = bip32.fromBase58(base58Key).derivePath(derivationPath);
|
let signingNode = bip32.fromBase58(base58Key).derivePath(derivationPath);
|
||||||
|
|
||||||
@@ -58,3 +81,4 @@ module.exports.signMessage = function(base58Key, derivationPath, message) {
|
|||||||
|
|
||||||
return signingNode.sign(hash);
|
return signingNode.sign(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ module.exports = function (sequelize, DataTypes, options) {
|
|||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false
|
allowNull: false
|
||||||
},
|
},
|
||||||
|
iv: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
name: {
|
name: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
unique: true
|
unique: true
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ module.exports = function (sequelize, DataTypes, options) {
|
|||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false
|
allowNull: false
|
||||||
},
|
},
|
||||||
|
serviceExtendedPublicKey: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
signature: {
|
signature: {
|
||||||
// Derivation from the master key...
|
// Derivation from the master key...
|
||||||
// TODO: Add validation...
|
// TODO: Add validation...
|
||||||
|
|||||||
Reference in New Issue
Block a user