UNPKG

@ckb-ccc/core

Version:

Core of CCC - CKBer's Codebase

111 lines (110 loc) 4.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.keystoreEncrypt = keystoreEncrypt; exports.keystoreDecrypt = keystoreDecrypt; const aes_1 = require("@noble/ciphers/aes"); const scrypt_1 = require("@noble/hashes/scrypt"); const sha3_1 = require("@noble/hashes/sha3"); const utils_1 = require("@noble/hashes/utils"); const index_js_1 = require("../bytes/index.js"); const index_js_2 = require("../hex/index.js"); // The parameter r ("blockSize") const DEFAULT_SCRYPT_PARAM_R = 8; // The parallelization parameter p const DEFAULT_SCRYPT_PARAM_P = 1; // The CPU/Memory cost parameter N const DEFAULT_SCRYPT_PARAM_N = 262144; function mac(derivedKey, cipherText) { return (0, index_js_2.hexFrom)((0, sha3_1.keccak_256)((0, index_js_1.bytesConcat)(derivedKey.slice(16, 32), cipherText))).slice(2); } /** * @public */ async function keystoreEncrypt(privateKeyLike, chainCodeLike, password) { const salt = (0, utils_1.randomBytes)(32); const iv = (0, utils_1.randomBytes)(16); const kdfparams = { dklen: 32, salt: (0, index_js_2.hexFrom)(salt).slice(2), n: DEFAULT_SCRYPT_PARAM_N, r: DEFAULT_SCRYPT_PARAM_R, p: DEFAULT_SCRYPT_PARAM_P, }; const derivedKey = await (0, scrypt_1.scryptAsync)((0, index_js_1.bytesFrom)(password, "utf8"), salt, { N: kdfparams.n, r: kdfparams.r, p: kdfparams.p, dkLen: kdfparams.dklen, }); const cipher = (0, aes_1.ctr)(derivedKey.slice(0, 16), iv.map((v) => v)); const ciphertext = cipher.encrypt((0, index_js_1.bytesConcat)((0, index_js_1.bytesFrom)(privateKeyLike), (0, index_js_1.bytesFrom)(chainCodeLike))); return { id: (0, index_js_2.hexFrom)((0, utils_1.randomBytes)(16)).slice(2), crypto: { ciphertext: (0, index_js_2.hexFrom)(ciphertext).slice(2), cipherparams: { iv: (0, index_js_2.hexFrom)(iv).slice(2), }, cipher: "aes-128-ctr", kdf: "scrypt", kdfparams, mac: mac(derivedKey, ciphertext), }, }; } /** * @public */ async function keystoreDecrypt(keystore, password) { if (typeof keystore !== "object" || keystore === null || !("crypto" in keystore)) { throw Error("Invalid keystore"); } const crypto = keystore.crypto; if (typeof crypto !== "object" || crypto === null || !("kdfparams" in crypto) || !("ciphertext" in crypto) || typeof crypto.ciphertext !== "string" || !("mac" in crypto) || typeof crypto.mac !== "string" || !("cipherparams" in crypto) || typeof crypto.cipherparams !== "object" || crypto.cipherparams === null || !("iv" in crypto.cipherparams) || typeof crypto.cipherparams.iv !== "string") { throw Error("Invalid crypto"); } const kdfparams = crypto.kdfparams; if (typeof kdfparams !== "object" || kdfparams === null || !("n" in kdfparams) || typeof kdfparams.n !== "number" || !("r" in kdfparams) || typeof kdfparams.r !== "number" || !("p" in kdfparams) || typeof kdfparams.p !== "number" || !("dklen" in kdfparams) || typeof kdfparams.dklen !== "number" || !("salt" in kdfparams) || typeof kdfparams.salt !== "string") { throw Error("Invalid kdfparams"); } const derivedKey = await (0, scrypt_1.scryptAsync)((0, index_js_1.bytesFrom)(password, "utf8"), (0, index_js_1.bytesFrom)(kdfparams.salt), { N: kdfparams.n, r: kdfparams.r, p: kdfparams.p, dkLen: kdfparams.dklen, }); const ciphertext = (0, index_js_1.bytesFrom)(crypto.ciphertext); if (mac(derivedKey, ciphertext) !== crypto.mac) { throw Error("Invalid password"); } const cipher = (0, aes_1.ctr)(derivedKey.slice(0, 16), (0, index_js_1.bytesFrom)(crypto.cipherparams.iv)); const result = cipher.decrypt(ciphertext); return { privateKey: result.slice(0, 32), chainCode: result.slice(32), }; }