UNPKG

@hashgraph/cryptography

Version:

Cryptographic utilities and primitives for the Hiero SDK

137 lines (127 loc) 4.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createKeystore = createKeystore; exports.loadKeystore = loadKeystore; var _BadKeyError = _interopRequireDefault(require("../BadKeyError.cjs")); var crypto = _interopRequireWildcard(require("./aes.cjs")); var hex = _interopRequireWildcard(require("../encoding/hex.cjs")); var utf8 = _interopRequireWildcard(require("../encoding/utf8.cjs")); var hmac = _interopRequireWildcard(require("./hmac.cjs")); var pbkdf2 = _interopRequireWildcard(require("./pbkdf2.cjs")); var random = _interopRequireWildcard(require("./random.cjs")); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const HMAC_SHA256 = "hmac-sha256"; /** * @typedef {object} KeystoreKdfParams * @property {number} dkLen * @property {string} salt * @property {number} c * @property {string} prf */ /** * @typedef {object} KeystoreCipherParams * @property {string} iv */ /** * @typedef {object} KeystoreCrypto * @property {string} ciphertext * @property {KeystoreCipherParams} cipherparams * @property {string} cipher * @property {string} kdf * @property {KeystoreKdfParams} kdfparams * @property {string} mac */ /** * @typedef {object} Keystore * @property {number} version * @property {KeystoreCrypto} crypto */ /** * @param {Uint8Array} privateKey * @param {string} passphrase * @returns {Promise<Uint8Array>} */ async function createKeystore(privateKey, passphrase) { // all values taken from https://github.com/ethereumjs/ethereumjs-wallet/blob/de3a92e752673ada1d78f95cf80bc56ae1f59775/src/index.ts#L25 const dkLen = 32; const c = 262144; const saltLen = 32; const salt = await random.bytesAsync(saltLen); const key = await pbkdf2.deriveKey(hmac.HashAlgorithm.Sha256, passphrase, salt, c, dkLen); const iv = await random.bytesAsync(16); // AES-128-CTR with the first half of the derived key and a random IV const cipherText = await crypto.createCipheriv(crypto.CipherAlgorithm.Aes128Ctr, key.slice(0, 16), iv, privateKey); const mac = await hmac.hash(hmac.HashAlgorithm.Sha384, key.slice(16), cipherText); /** * @type {Keystore} */ const keystore = { version: 1, crypto: { ciphertext: hex.encode(cipherText), cipherparams: { iv: hex.encode(iv) }, cipher: crypto.CipherAlgorithm.Aes128Ctr, kdf: "pbkdf2", kdfparams: { dkLen, salt: hex.encode(salt), c, prf: HMAC_SHA256 }, mac: hex.encode(mac) } }; return utf8.encode(JSON.stringify(keystore)); } /** * @param {Uint8Array} keystoreBytes * @param {string} passphrase * @returns {Promise<Uint8Array>} */ async function loadKeystore(keystoreBytes, passphrase) { /** * @type {Keystore} */ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const keystore = JSON.parse(utf8.decode(keystoreBytes)); if (keystore.version !== 1) { throw new _BadKeyError.default(`unsupported keystore version: ${keystore.version}`); } const { ciphertext, cipherparams: { iv }, cipher, kdf, kdfparams: { dkLen, salt, c, prf }, mac } = keystore.crypto; if (kdf !== "pbkdf2") { throw new _BadKeyError.default(`unsupported key derivation function:" + ${kdf}`); } if (prf !== HMAC_SHA256) { throw new _BadKeyError.default(`unsupported key derivation hash function: ${prf}`); } const saltBytes = hex.decode(salt); const ivBytes = hex.decode(iv); const cipherBytes = hex.decode(ciphertext); const key = await pbkdf2.deriveKey(hmac.HashAlgorithm.Sha256, passphrase, saltBytes, c, dkLen); const macHex = hex.decode(mac); const verifyHmac = await hmac.hash(hmac.HashAlgorithm.Sha384, key.slice(16), cipherBytes); // compare that these two Uint8Arrays are equivalent if (!macHex.every((b, i) => b === verifyHmac[i])) { throw new _BadKeyError.default("HMAC mismatch; passphrase is incorrect"); } return crypto.createDecipheriv(cipher, key.slice(0, 16), ivBytes, cipherBytes); }