keyvenant
Version:
Keyvenant is a JavaScript tool to generate and export CovenantSQL keys to facilitate key management locally and in web extensions.
138 lines • 9.23 kB
JavaScript
import coinstring from 'coinstring';
import { string2Buffer } from './utils';
import THash from './utils/THash';
import * as keygen from './keygen';
import * as secretkey from './secretkey';
import * as symmetric from './symmetric';
/**
* create CovenantSQL keystore
* @param password master password user typed-in
* @param salt kdf salt
* @param addrVersion address version
* @param privateKeyVersion private key encode version
* @return keystore object
*/
export function createKeystore(password, salt, addrVersion, privateKeyVersion) {
// generate new key pair
let prvKey = keygen.createPrivateKey();
let pubKey = keygen.privateKeyToPublicKey(prvKey);
console.log('Print out private key for test', prvKey);
// covert to address
let address = keygen.publicKeyToAddress(pubKey, addrVersion);
// get derived key from password
let secretKey = secretkey.derive(password, salt);
// prepare iv for symmetric encryption
let iv = symmetric.generateIv();
let ciphertext = symmetric.encrypt(prvKey, secretKey, iv);
let mac = constructMac(secretKey, ciphertext);
let keystore = marshal(address, salt, mac, ciphertext, iv, privateKeyVersion);
return keystore;
}
/**
* recover private key from keystore and password
* @param password
* @param keystore
* @return private key string in hex
*/
export function recoverFromKeystore(password, salt, keystore) {
// get derived key from password
let secretKey = secretkey.derive(password, salt);
// prepare iv for symmetric encryption
let iv = keystore.crypto.iv;
let ciphertext = keystore.crypto.ciphertext;
// check mac
let macToVerify = constructMac(secretKey, ciphertext);
if (macToVerify !== keystore.mac) {
throw new Error('Input password is not valid for the keystore or version not compatible');
}
// decrypt private key
let prvKey = symmetric.decrypt(ciphertext, secretKey, iv);
return prvKey;
}
/**
* construct keystore json
* @param address wallet address
* @param salt kdf salt
* @param mac mac value
* @param ciphertext encrypted text
* @param iv symmetric iv
* @param privateKeyVersion version hex
* @return keystore object
*/
function marshal(address, salt, mac, ciphertext, iv, privateKeyVersion) {
let encrypted = constructEncrypted(privateKeyVersion, iv, ciphertext);
let keystore = {
address,
encrypted,
mac,
crypto: {
cipher: 'aes-256',
ciphertext,
iv
},
derivation: {
kdf: 'sha256x2',
salt
},
version: privateKeyVersion,
};
return keystore;
}
/**
* construct Mac for password pre-check
* secretKey + ciphertext as mac input
* then THash convert to Mac hex string and return
* @param secretKey derived key hex string
* @param ciphertext encrypted hex string
* @return mac as hex string
*/
function constructMac(secretKey, ciphertext) {
let secretKeyBuf = string2Buffer(secretKey);
let ciphertextBuf = string2Buffer(ciphertext);
// concat buffer & THash
let concated = Buffer.concat([secretKeyBuf, ciphertextBuf]);
let hashedMac = THash(concated);
return hashedMac.toString('hex');
}
/**
* construct base58 encoded string for CovenantSQL chain recover
* privateKeyVersion(1B) + iv(16B) + ciphertext(48B) as concated hex
* then base58 encoded the concated and return
* @param privateKeyVersion 1 btye version
* @param iv generated iv
* @param ciphertext encrypted ciphertext
* @return base58Encoded concated
*/
function constructEncrypted(privateKeyVersion, iv, ciphertext) {
let versionBuf = Buffer.from([privateKeyVersion]);
let ivBuf = string2Buffer(iv);
let ciphertextBuf = string2Buffer(ciphertext);
// concat buffer & base58 encode
let concated = Buffer.concat([versionBuf, ivBuf, ciphertextBuf]);
let base58Encoded = coinstring.encode(concated);
return base58Encoded;
}
/**
* deconstruct base58 encoded string for CovenantSQL chain recover
* @param encrypted base58Encoded concated
* @return {
* privateKeyVersion 1 btye version
* iv generated iv
* ciphertext encrypted ciphertext
* }
*/
export function deconstructEncrypted(encrypted) {
let encBuf = coinstring.decode(encrypted);
// 1st byte as privateKeyVersion
let versionBuf = encBuf.slice(0, 1);
// next 16 bytes as iv
let ivBuf = encBuf.slice(1, 17);
// next 48 bytes as cipher
let ciphertextBuf = encBuf.slice(17, 65);
return {
privateKeyVersion: versionBuf.toString('hex'),
iv: ivBuf.toString('hex'),
ciphertext: ciphertextBuf.toString('hex')
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5c3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL2tleXN0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sVUFBVSxNQUFNLFlBQVksQ0FBQTtBQUNuQyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQ3ZDLE9BQU8sS0FBSyxNQUFNLGVBQWUsQ0FBQTtBQUVqQyxPQUFPLEtBQUssTUFBTSxNQUFNLFVBQVUsQ0FBQTtBQUNsQyxPQUFPLEtBQUssU0FBUyxNQUFNLGFBQWEsQ0FBQTtBQUN4QyxPQUFPLEtBQUssU0FBUyxNQUFNLGFBQWEsQ0FBQTtBQUV4Qzs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FDNUIsUUFBZ0IsRUFDaEIsSUFBWSxFQUNaLFdBQW1CLEVBQ25CLGlCQUF5QjtJQUV6Qix3QkFBd0I7SUFDeEIsSUFBSSxNQUFNLEdBQVcsTUFBTSxDQUFDLGdCQUFnQixFQUFFLENBQUE7SUFDOUMsSUFBSSxNQUFNLEdBQVcsTUFBTSxDQUFDLHFCQUFxQixDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBQ3pELE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0NBQWdDLEVBQUcsTUFBTSxDQUFDLENBQUE7SUFFdEQsb0JBQW9CO0lBQ3BCLElBQUksT0FBTyxHQUFXLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsV0FBVyxDQUFDLENBQUE7SUFFcEUsZ0NBQWdDO0lBQ2hDLElBQUksU0FBUyxHQUFXLFNBQVMsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFBO0lBRXhELHNDQUFzQztJQUN0QyxJQUFJLEVBQUUsR0FBVyxTQUFTLENBQUMsVUFBVSxFQUFFLENBQUE7SUFDdkMsSUFBSSxVQUFVLEdBQVcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFBO0lBRWpFLElBQUksR0FBRyxHQUFXLFlB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