UNPKG

ssv-keys

Version:

Tool for splitting a validator key into a predefined threshold of shares via Shamir-Secret-Sharing (SSS), and encrypt them with a set of operator keys.

144 lines 5.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const crypto_1 = tslib_1.__importDefault(require("crypto")); const scrypt_js_1 = require("scrypt-js"); const ethereumjs_wallet_1 = tslib_1.__importDefault(require("ethereumjs-wallet")); const ethereumjs_util_1 = require("ethereumjs-util"); const keystore_1 = require("../exceptions/keystore"); /** * Decrypt private key from key store data * Supports key store versions: v1, v3, v4 * * Example of usage (Node env): * * const keyStoreFilePath = path.join(process.cwd(), 'validator_keys', 'keystore.json'); * const keyStoreString: string = fs.readFileSync(keyStoreFilePath).toString(); * const keyStoreData = JSON.parse(keyStoreString); * const keyStore = new EthereumKeyStore(keyStoreData); * const password = 'testtest'; * console.log('Private Key:', await keyStore.getPrivateKey(password)); */ class EthereumKeyStore { /** * Receive key store data from string or parsed JSON * @param keyStoreData */ constructor(keyStoreData) { this.privateKey = ''; if (!keyStoreData) { throw new keystore_1.KeyStoreDataFormatError(keyStoreData, 'Key store data should be JSON or string'); } if (typeof keyStoreData === 'string') { this.keyStoreData = JSON.parse(keyStoreData); } else { this.keyStoreData = keyStoreData; } if (!this.keyStoreData.version) { throw new keystore_1.KeyStoreInvalidError(this.keyStoreData, 'Invalid keystore file'); } } getPublicKey() { var _a; if (this.keyStoreData) { switch ((_a = this.keyStoreData.version) !== null && _a !== void 0 ? _a : this.keyStoreData.Version) { case 1: return this.keyStoreData.Address; case 3: return this.keyStoreData.id; case 4: return this.keyStoreData.pubkey; } } return ''; } /** * Decrypt private key using user password * @param password */ async getPrivateKey(password = '') { // In case private key exist we return it if (this.privateKey) return this.privateKey; switch (this.keyStoreData.version) { case 1: this.wallet = await ethereumjs_wallet_1.default.fromV1(this.keyStoreData, password); break; case 3: this.wallet = await ethereumjs_wallet_1.default.fromV3(this.keyStoreData, password, true); break; case 4: this.wallet = await this.fromV4(this.keyStoreData, password); break; } if (this.wallet) { this.privateKey = this.wallet.getPrivateKey().toString('hex'); if (!this.privateKey) { throw new keystore_1.KeyStorePasswordError('Invalid password'); } } return this.privateKey; } /** * Import a wallet (Version 4 of the Ethereum wallet format). * * @param input A JSON serialized string, or an object representing V3 Keystore. * @param password The keystore password. */ async fromV4(input, password) { const json = typeof input === 'object' ? input : JSON.parse(input); if (json.version !== 4) { throw new keystore_1.EthereumWalletError('Not a V4 wallet'); } let derivedKey; let kdfParams; if (json.crypto.kdf.function === 'scrypt') { kdfParams = json.crypto.kdf.params; derivedKey = (0, scrypt_js_1.syncScrypt)(Buffer.from(password), Buffer.from(kdfParams.salt, 'hex'), kdfParams.n, kdfParams.r, kdfParams.p, kdfParams.dklen); } else if (json.crypto.kdf.function === 'pbkdf2') { kdfParams = json.crypto.kdf.params; if (kdfParams.prf !== 'hmac-sha256') { throw new keystore_1.EthereumWalletError('Unsupported parameters to PBKDF2'); } derivedKey = crypto_1.default.pbkdf2Sync(Buffer.from(password), Buffer.from(kdfParams.salt, 'hex'), kdfParams.c, kdfParams.dklen, 'sha256'); } else { throw new keystore_1.EthereumWalletError('Unsupported key derivation scheme'); } const ciphertext = Buffer.from(json.crypto.cipher.message, 'hex'); const checksumBuffer = Buffer.concat([Buffer.from(derivedKey.slice(16, 32)), ciphertext]); const hashFunctions = { keccak256: ethereumjs_util_1.keccak256, sha256: ethereumjs_util_1.sha256, }; const hashFunction = hashFunctions[json.crypto.checksum.function]; const mac = hashFunction(checksumBuffer); if (mac.toString('hex') !== json.crypto.checksum.message) { throw new keystore_1.EthereumWalletError('Invalid password'); } const decipher = crypto_1.default.createDecipheriv(json.crypto.cipher.function, derivedKey.slice(0, 16), Buffer.from(json.crypto.cipher.params.iv, 'hex')); const seed = this.runCipherBuffer(decipher, ciphertext); return new ethereumjs_wallet_1.default(seed); } /** * @param cipher * @param data */ runCipherBuffer(cipher, data) { return Buffer.concat([cipher.update(data), cipher.final()]); } /** * Convert byte array to string * @param byteArray */ static toHexString(byteArray) { return Array.from(byteArray, (byte) => { // eslint-disable-next-line no-bitwise return (`0${(byte & 0xFF).toString(16)}`).slice(-2); }).join(''); } } exports.default = EthereumKeyStore; //# sourceMappingURL=EthereumKeyStore.js.map