85 lines
2.7 KiB
JavaScript
85 lines
2.7 KiB
JavaScript
const crypto = require('crypto');
|
|
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
|
|
|
|
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: cipherText,
|
|
iv: iv
|
|
};
|
|
}
|
|
|
|
module.exports.decrypt = (cipherText, password, iv) => {
|
|
const key = crypto.createHash('sha256').update(password, 'utf8').digest();
|
|
const decipher = crypto.createDecipheriv(algorithm, key, iv);
|
|
|
|
var plainText = decipher.update(cipherText, 'hex', 'utf8');
|
|
plainText += decipher.final('utf8');
|
|
|
|
return plainText;
|
|
}
|
|
|
|
module.exports.randomDerivationPath = function(hardenedDerivation) {
|
|
// TODO harden derivation path
|
|
var randomNumbers = [];
|
|
|
|
for(var i = 0; i < 3; i++) {
|
|
randomNumbers.push(parseInt(crypto.randomBytes(3).toString('hex'), 16))
|
|
}
|
|
|
|
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];
|
|
}
|
|
|
|
if(derivationPath.startsWith("c/")) {
|
|
derivationPath = derivationPath.split("c/")[1];
|
|
}
|
|
|
|
const verificationNode = bip32.fromBase58(base58Key).derivePath(derivationPath);
|
|
const hash = crypto.createHash('sha256').update(message, 'utf8').digest();
|
|
|
|
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);
|
|
}
|
|
|