UNPKG

@ethereumjs/wallet

Version:
149 lines 5.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Thirdparty = exports.fromQuorumWallet = exports.fromEtherCamp = exports.fromEtherWallet = void 0; const util_1 = require("@ethereumjs/util"); const base_1 = require("@scure/base"); const aes_js_1 = require("ethereum-cryptography/aes.js"); const keccak_js_1 = require("ethereum-cryptography/keccak.js"); const pbkdf2_js_1 = require("ethereum-cryptography/pbkdf2.js"); const js_md5_1 = require("js-md5"); const wallet_js_1 = require("./wallet.js"); const evpKdfDefaults = { count: 1, keysize: 16, ivsize: 16, digest: 'md5', }; function mergeEvpKdfOptsWithDefaults(opts) { if (!opts) { return evpKdfDefaults; } return { count: opts.count ?? evpKdfDefaults.count, keysize: opts.keysize ?? evpKdfDefaults.keysize, ivsize: opts.ivsize ?? evpKdfDefaults.ivsize, digest: opts.digest ?? evpKdfDefaults.digest, }; } /* * opts: * - digest - digest algorithm, defaults to md5 * - count - hash iterations * - keysize - desired key size * - ivsize - desired IV size * * Algorithm form https://www.openssl.org/docs/manmaster/crypto/EVP_BytesToKey.html * * FIXME: not optimised at all */ function evp_kdf(data, salt, opts) { const params = mergeEvpKdfOptsWithDefaults(opts); // A single EVP iteration, returns `D_i`, where block equlas to `D_(i-1)` function iter(block) { if (params.digest !== 'md5') throw new Error('Only md5 is supported in evp_kdf'); let hash = js_md5_1.md5.create(); hash.update(block); hash.update(data); hash.update(salt); block = Uint8Array.from(hash.array()); for (let i = 1, len = params.count; i < len; i++) { hash = js_md5_1.md5.create(); hash.update(block); block = new Uint8Array(hash.arrayBuffer()); } return block; } const ret = []; let i = 0; while ((0, util_1.concatBytes)(...ret).length < params.keysize + params.ivsize) { ret[i] = iter(i === 0 ? new Uint8Array() : ret[i - 1]); i++; } const tmp = (0, util_1.concatBytes)(...ret); return { key: tmp.subarray(0, params.keysize), iv: tmp.subarray(params.keysize, params.keysize + params.ivsize), }; } // http://stackoverflow.com/questions/25288311/cryptojs-aes-pattern-always-ends-with function decodeCryptojsSalt(input) { const ciphertext = base_1.base64.decode(input); if ((0, util_1.bytesToUtf8)(ciphertext.subarray(0, 8)) === 'Salted__') { return { salt: ciphertext.subarray(8, 16), ciphertext: ciphertext.subarray(16), }; } return { ciphertext }; } /* * Third Party API: Import a wallet generated by EtherWallet * This wallet format is created by https://github.com/SilentCicero/ethereumjs-accounts * and used on https://www.myetherwallet.com/ */ async function fromEtherWallet(input, password) { const json = typeof input === 'object' ? input : JSON.parse(input); let privateKey; if (!json.locked) { if (json.private.length !== 64) { throw new Error('Invalid private key length'); } privateKey = (0, util_1.unprefixedHexToBytes)(json.private); } else { if (typeof password !== 'string') { throw new Error('Password required'); } if (password.length < 7) { throw new Error('Password must be at least 7 characters'); } // the "encrypted" version has the low 4 bytes // of the hash of the address appended const hash = json.encrypted ? json.private.slice(0, 128) : json.private; // decode openssl ciphertext + salt encoding const cipher = decodeCryptojsSalt(hash); if (!cipher.salt) { throw new Error('Unsupported EtherWallet key format'); } // derive key/iv using OpenSSL EVP as implemented in CryptoJS const evp = evp_kdf((0, util_1.utf8ToBytes)(password), cipher.salt, { keysize: 32, ivsize: 16 }); const pr = await (0, aes_js_1.decrypt)(cipher.ciphertext, evp.key, evp.iv, 'aes-256-cbc'); // NOTE: yes, they've run it through UTF8 privateKey = (0, util_1.unprefixedHexToBytes)((0, util_1.bytesToUtf8)(pr)); } const wallet = new wallet_js_1.Wallet(privateKey); if (wallet.getAddressString() !== json.address) { throw new Error('Invalid private key or address'); } return wallet; } exports.fromEtherWallet = fromEtherWallet; /** * Third Party API: Import a brain wallet used by Ether.Camp */ function fromEtherCamp(passphrase) { return new wallet_js_1.Wallet((0, keccak_js_1.keccak256)((0, util_1.utf8ToBytes)(passphrase))); } exports.fromEtherCamp = fromEtherCamp; /** * Third Party API: Import a brain wallet used by Quorum Wallet */ function fromQuorumWallet(passphrase, userid) { if (passphrase.length < 10) { throw new Error('Passphrase must be at least 10 characters'); } if (userid.length < 10) { throw new Error('User id must be at least 10 characters'); } const merged = (0, util_1.utf8ToBytes)(passphrase + userid); const seed = (0, pbkdf2_js_1.pbkdf2Sync)(merged, merged, 2000, 32, 'sha256'); return new wallet_js_1.Wallet(seed); } exports.fromQuorumWallet = fromQuorumWallet; exports.Thirdparty = { fromEtherWallet, fromEtherCamp, fromQuorumWallet, }; //# sourceMappingURL=thirdparty.js.map