Skip to content
This repository was archived by the owner on Oct 30, 2024. It is now read-only.

Commit 80f7584

Browse files
committed
Support encrypted KryptoKit seed
1 parent eacd3c0 commit 80f7584

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

index.js

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ var crypto = require('crypto')
33
var scryptsy = require('scrypt.js')
44
var uuid = require('uuid')
55
var utf8 = require('utf8')
6+
var aesjs = require('aes-js')
67

78
function assert (val, msg) {
89
if (!val) {
@@ -334,7 +335,36 @@ Wallet.fromEtherCamp = function (passphrase) {
334335
return new Wallet(ethUtil.sha3(new Buffer(passphrase)))
335336
}
336337

337-
Wallet.fromKryptoKit = function (entropy) {
338+
Wallet.fromKryptoKit = function (entropy, password) {
339+
function kryptoKitBrokenScryptSeed (buf) {
340+
// js-scrypt calls `new Buffer(String(salt), 'utf8')` on the seed even though it is a buffer
341+
//
342+
// The `buffer`` implementation used does the below transformation (doesn't matches the current version):
343+
// https://github.com/feross/buffer/blob/67c61181b938b17d10dbfc0a545f713b8bd59de8/index.js
344+
345+
function decodeUtf8Char (str) {
346+
try {
347+
return decodeURIComponent(str)
348+
} catch (err) {
349+
return String.fromCharCode(0xFFFD) // UTF 8 invalid char
350+
}
351+
}
352+
353+
var res = ''
354+
var tmp = ''
355+
356+
for (var i = 0; i < buf.length; i++) {
357+
if (buf[i] <= 0x7F) {
358+
res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
359+
tmp = ''
360+
} else {
361+
tmp += '%' + buf[i].toString(16)
362+
}
363+
}
364+
365+
return new Buffer(res + decodeUtf8Char(tmp))
366+
}
367+
338368
if (entropy[0] === '#') {
339369
entropy = entropy.slice(1)
340370
}
@@ -345,6 +375,42 @@ Wallet.fromKryptoKit = function (entropy) {
345375
var privKey
346376
if (type === 'd') {
347377
privKey = ethUtil.sha256(entropy)
378+
} else if (type === 'q') {
379+
if (typeof password !== 'string') {
380+
throw new Error('Password required')
381+
}
382+
383+
var encryptedSeed = ethUtil.sha256(new Buffer(entropy.slice(0, 30)))
384+
var checksum = entropy.slice(30, 46)
385+
386+
var salt = kryptoKitBrokenScryptSeed(encryptedSeed)
387+
var aesKey = scryptsy(new Buffer(password, 'utf8'), salt, 16384, 8, 1, 32)
388+
389+
/* FIXME: try to use `crypto` instead of `aesjs`
390+
391+
// NOTE: ECB doesn't use the IV, so it can be anything
392+
var decipher = crypto.createDecipheriv("aes-256-ecb", aesKey, new Buffer(0))
393+
394+
// FIXME: this is a clear abuse, but seems to match how ECB in aesjs works
395+
privKey = Buffer.concat([
396+
decipher.update(encryptedSeed).slice(0, 16),
397+
decipher.update(encryptedSeed).slice(0, 16),
398+
])
399+
*/
400+
401+
/* eslint-disable new-cap */
402+
var decipher = new aesjs.ModeOfOperation.ecb(aesKey)
403+
/* eslint-enable new-cap */
404+
privKey = Buffer.concat([
405+
decipher.decrypt(encryptedSeed.slice(0, 16)),
406+
decipher.decrypt(encryptedSeed.slice(16, 32))
407+
])
408+
409+
if (checksum.length > 0) {
410+
if (checksum !== ethUtil.sha256(ethUtil.sha256(privKey)).slice(0, 8).toString('hex')) {
411+
throw new Error('Failed to decrypt input - possibly invalid passphrase')
412+
}
413+
}
348414
} else {
349415
throw new Error('Unsupported or invalid entropy type')
350416
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
},
2525
"homepage": "https://github.com/axic/ethereumjs-wallet",
2626
"dependencies": {
27+
"aes-js": "^0.2.3",
2728
"ethereumjs-util": "^4.1.0",
2829
"scrypt.js": "^0.1.0",
2930
"uuid": "^2.0.1",

test/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,8 @@ describe('.fromKryptoKit()', function () {
143143
var wallet = Wallet.fromKryptoKit('dBWfH8QZSGbg1sAYHLBhqE5R8VGAoM7')
144144
assert.equal(wallet.getAddressString(), '0x3611981ad2d6fc1d7579d6ce4c6bc37e272c369c')
145145
})
146+
it('should work with encrypted input (q-type)', function () {
147+
var wallet = Wallet.fromKryptoKit('qhah1VeT0RgTvff1UKrUrxtFViiQuki16dd353d59888c25', 'testtest')
148+
assert.equal(wallet.getAddressString(), '0x3c753e27834db67329d1ec1fab67970ec1e27112')
149+
})
146150
})

0 commit comments

Comments
 (0)