1 | "use strict";
|
2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3 | if (k2 === undefined) k2 = k;
|
4 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
5 | }) : (function(o, m, k, k2) {
|
6 | if (k2 === undefined) k2 = k;
|
7 | o[k2] = m[k];
|
8 | }));
|
9 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
10 | Object.defineProperty(o, "default", { enumerable: true, value: v });
|
11 | }) : function(o, v) {
|
12 | o["default"] = v;
|
13 | });
|
14 | var __importStar = (this && this.__importStar) || function (mod) {
|
15 | if (mod && mod.__esModule) return mod;
|
16 | var result = {};
|
17 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
18 | __setModuleDefault(result, mod);
|
19 | return result;
|
20 | };
|
21 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
22 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
23 | };
|
24 | Object.defineProperty(exports, "__esModule", { value: true });
|
25 | exports.fromQuorumWallet = exports.fromKryptoKit = exports.fromEtherCamp = exports.fromEtherWallet = void 0;
|
26 | const crypto = __importStar(require("crypto"));
|
27 | const ethereumjs_util_1 = require("ethereumjs-util");
|
28 | const scrypt_js_1 = require("scrypt-js");
|
29 | const index_1 = __importDefault(require("./index"));
|
30 | const utf8 = require('utf8');
|
31 | const aesjs = require('aes-js');
|
32 | function runCipherBuffer(cipher, data) {
|
33 | return Buffer.concat([cipher.update(data), cipher.final()]);
|
34 | }
|
35 | const evpKdfDefaults = {
|
36 | count: 1,
|
37 | keysize: 16,
|
38 | ivsize: 16,
|
39 | digest: 'md5',
|
40 | };
|
41 | function mergeEvpKdfOptsWithDefaults(opts) {
|
42 | if (!opts) {
|
43 | return evpKdfDefaults;
|
44 | }
|
45 | return {
|
46 | count: opts.count || evpKdfDefaults.count,
|
47 | keysize: opts.keysize || evpKdfDefaults.keysize,
|
48 | ivsize: opts.ivsize || evpKdfDefaults.ivsize,
|
49 | digest: opts.digest || evpKdfDefaults.digest,
|
50 | };
|
51 | }
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 | function evp_kdf(data, salt, opts) {
|
64 | const params = mergeEvpKdfOptsWithDefaults(opts);
|
65 |
|
66 | function iter(block) {
|
67 | let hash = crypto.createHash(params.digest);
|
68 | hash.update(block);
|
69 | hash.update(data);
|
70 | hash.update(salt);
|
71 | block = hash.digest();
|
72 | for (let i = 1, len = params.count; i < len; i++) {
|
73 | hash = crypto.createHash(params.digest);
|
74 | hash.update(block);
|
75 | block = hash.digest();
|
76 | }
|
77 | return block;
|
78 | }
|
79 | const ret = [];
|
80 | let i = 0;
|
81 | while (Buffer.concat(ret).length < params.keysize + params.ivsize) {
|
82 | ret[i] = iter(i === 0 ? Buffer.alloc(0) : ret[i - 1]);
|
83 | i++;
|
84 | }
|
85 | const tmp = Buffer.concat(ret);
|
86 | return {
|
87 | key: tmp.slice(0, params.keysize),
|
88 | iv: tmp.slice(params.keysize, params.keysize + params.ivsize),
|
89 | };
|
90 | }
|
91 |
|
92 | function decodeCryptojsSalt(input) {
|
93 | const ciphertext = Buffer.from(input, 'base64');
|
94 | if (ciphertext.slice(0, 8).toString() === 'Salted__') {
|
95 | return {
|
96 | salt: ciphertext.slice(8, 16),
|
97 | ciphertext: ciphertext.slice(16),
|
98 | };
|
99 | }
|
100 | return { ciphertext };
|
101 | }
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 | function fromEtherWallet(input, password) {
|
108 | const json = typeof input === 'object' ? input : JSON.parse(input);
|
109 | let privateKey;
|
110 | if (!json.locked) {
|
111 | if (json.private.length !== 64) {
|
112 | throw new Error('Invalid private key length');
|
113 | }
|
114 | privateKey = Buffer.from(json.private, 'hex');
|
115 | }
|
116 | else {
|
117 | if (typeof password !== 'string') {
|
118 | throw new Error('Password required');
|
119 | }
|
120 | if (password.length < 7) {
|
121 | throw new Error('Password must be at least 7 characters');
|
122 | }
|
123 |
|
124 |
|
125 | const hash = json.encrypted ? json.private.slice(0, 128) : json.private;
|
126 |
|
127 | const cipher = decodeCryptojsSalt(hash);
|
128 | if (!cipher.salt) {
|
129 | throw new Error('Unsupported EtherWallet key format');
|
130 | }
|
131 |
|
132 | const evp = evp_kdf(Buffer.from(password), cipher.salt, { keysize: 32, ivsize: 16 });
|
133 | const decipher = crypto.createDecipheriv('aes-256-cbc', evp.key, evp.iv);
|
134 | privateKey = runCipherBuffer(decipher, Buffer.from(cipher.ciphertext));
|
135 |
|
136 | privateKey = Buffer.from(utf8.decode(privateKey.toString()), 'hex');
|
137 | }
|
138 | const wallet = new index_1.default(privateKey);
|
139 | if (wallet.getAddressString() !== json.address) {
|
140 | throw new Error('Invalid private key or address');
|
141 | }
|
142 | return wallet;
|
143 | }
|
144 | exports.fromEtherWallet = fromEtherWallet;
|
145 |
|
146 |
|
147 |
|
148 | function fromEtherCamp(passphrase) {
|
149 | return new index_1.default((0, ethereumjs_util_1.keccak256)(Buffer.from(passphrase)));
|
150 | }
|
151 | exports.fromEtherCamp = fromEtherCamp;
|
152 |
|
153 |
|
154 |
|
155 | async function fromKryptoKit(entropy, password) {
|
156 | function kryptoKitBrokenScryptSeed(buf) {
|
157 |
|
158 |
|
159 |
|
160 |
|
161 | function decodeUtf8Char(str) {
|
162 | try {
|
163 | return decodeURIComponent(str);
|
164 | }
|
165 | catch (err) {
|
166 | return String.fromCharCode(0xfffd);
|
167 | }
|
168 | }
|
169 | let res = '', tmp = '';
|
170 | for (let i = 0; i < buf.length; i++) {
|
171 | if (buf[i] <= 0x7f) {
|
172 | res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i]);
|
173 | tmp = '';
|
174 | }
|
175 | else {
|
176 | tmp += '%' + buf[i].toString(16);
|
177 | }
|
178 | }
|
179 | return Buffer.from(res + decodeUtf8Char(tmp));
|
180 | }
|
181 | if (entropy[0] === '#') {
|
182 | entropy = entropy.slice(1);
|
183 | }
|
184 | const type = entropy[0];
|
185 | entropy = entropy.slice(1);
|
186 | let privateKey;
|
187 | if (type === 'd') {
|
188 | privateKey = (0, ethereumjs_util_1.sha256)((0, ethereumjs_util_1.toBuffer)(entropy));
|
189 | }
|
190 | else if (type === 'q') {
|
191 | if (typeof password !== 'string') {
|
192 | throw new Error('Password required');
|
193 | }
|
194 | const encryptedSeed = (0, ethereumjs_util_1.sha256)(Buffer.from(entropy.slice(0, 30)));
|
195 | const checksum = entropy.slice(30, 46);
|
196 | const salt = kryptoKitBrokenScryptSeed(encryptedSeed);
|
197 | const aesKey = await (0, scrypt_js_1.scrypt)(Buffer.from(password, 'utf8'), salt, 16384, 8, 1, 32);
|
198 | |
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 | const decipher = new aesjs.ModeOfOperation.ecb(aesKey);
|
210 |
|
211 | privateKey = Buffer.concat([
|
212 | Buffer.from(decipher.decrypt(encryptedSeed.slice(0, 16))),
|
213 | Buffer.from(decipher.decrypt(encryptedSeed.slice(16, 32))),
|
214 | ]);
|
215 | if (checksum.length > 0) {
|
216 | if (checksum !== (0, ethereumjs_util_1.sha256)((0, ethereumjs_util_1.sha256)(privateKey)).slice(0, 8).toString('hex')) {
|
217 | throw new Error('Failed to decrypt input - possibly invalid passphrase');
|
218 | }
|
219 | }
|
220 | }
|
221 | else {
|
222 | throw new Error('Unsupported or invalid entropy type');
|
223 | }
|
224 | return new index_1.default(privateKey);
|
225 | }
|
226 | exports.fromKryptoKit = fromKryptoKit;
|
227 |
|
228 |
|
229 |
|
230 | function fromQuorumWallet(passphrase, userid) {
|
231 | if (passphrase.length < 10) {
|
232 | throw new Error('Passphrase must be at least 10 characters');
|
233 | }
|
234 | if (userid.length < 10) {
|
235 | throw new Error('User id must be at least 10 characters');
|
236 | }
|
237 | const merged = passphrase + userid;
|
238 | const seed = crypto.pbkdf2Sync(merged, merged, 2000, 32, 'sha256');
|
239 | return new index_1.default(seed);
|
240 | }
|
241 | exports.fromQuorumWallet = fromQuorumWallet;
|
242 | const Thirdparty = {
|
243 | fromEtherWallet,
|
244 | fromEtherCamp,
|
245 | fromKryptoKit,
|
246 | fromQuorumWallet,
|
247 | };
|
248 | exports.default = Thirdparty;
|
249 |
|
\ | No newline at end of file |