I found a post describing how to recover an Ethereum wallet keystore by guessing a single password, however, it uses node synchronous code, and I'm trying to convert it into asynchronous code so that I can use multithreading using worker_threads.
run.js (snippet)
for (let x = 0; x <= maxX*passesPerThread; x++) {
passes[x +1] = c.iterate(passes[x], chars)
}
for (let x = 0; x < maxX; x++) {
dcWorker[x] = new Worker('./worker.js', { workerData: { FILE: FILE, PASSWORD: passes[x*passesPerThread], workerNum: x, passesPerThread: passesPerThread, CHARS: chars}, })
dcWorker[x].on('message', (data) => {
if (data.status === 'done') {
console.log(" w" + x + "d")
}
})
}
crack.js (snippet)
function crack(PASSWORD, FILE) {
const data = fs.readFile(FILE, {encoding: "utf8"}, (err, data) => {
if (err) throw err
const content = data
attempt(data, PASSWORD, FILE)
})
}
function attempt(data, PASSWORD, FILE) {
const keythereum = require("keythereum")
const keyObject = JSON.parse(data)
keythereum.recover(PASSWORD, keyObject, privateKey => {
if (!privateKey.toString() === "message authentication code mismatch") {
console.log("\npossible password: " + PASSWORD + "\naddress: " + `0x${keyObject.address}` + "\npriv key: " + `0x${privateKey}`)
savePass(PASSWORD, FILE)
//process.exit()
}
})
}
worker.js (snippet)
passes = new Array()
passes[0] = pass
maxX = workerData.passesPerThread
const cProm =
new Promise((resolve, reject) => {
for (let x = 1; x < maxX; x++) {
passes[x] = c.iterate(passes[x -1], chars)
}
resolve('done')
})
.then(value => {
for (let x = 1; x < maxX; x++) {
process.stdout.write(" w" + workerData.workerNum + "a" + passes[x] + "T" + Date.now() + ", ")
c.crack(passes[x], FILE)
}
parentPort.postMessage({ status: value })
})
.catch(err => {
parentPort.postMessage({ status: err })
})
I don't understand why the stack is processing all output before actually attempting each crack attempt.
The following is output, then a long pause while it attempts to crack ONE password for each thread, instead of many passwords per thread like the output seems to indicate:
w1aeasyaspsi, w1d
w1aeasyaspsi,
w1aeasyaspyeT1641634988273, w1aeasyaspyaT1641634988274, w1aeasyaspysT1641634988274, w1aeasyaspyyT1641634988274, w1aeasyaspypT1641634988274, w1aeasyaspyiT1641634988274, w1aeasyasppeT1641634988274, w1aeasyasppaT1641634988274, w1aeasyasppsT1641634988274, w0aeasyaspaa, w3aeasyasiea, w0d
w3d
w0aeasyaspaa,
w0aeasyaspasT1641634988279, w0aeasyaspayT1641634988280, w0aeasyaspapT1641634988280, w0aeasyaspaiT1641634988280, w0aeasyaspseT1641634988280, w0aeasyaspsaT1641634988280, w0aeasyaspssT1641634988280, w0aeasyaspsyT1641634988280, w0aeasyaspspT1641634988280, w3aeasyasiea,
w3aeasyasiesT1641634988279, w3aeasyasieyT1641634988280, w3aeasyasiepT1641634988280, w3aeasyasieiT1641634988280, w3aeasyasiaeT1641634988280, w3aeasyasiaaT1641634988280, w3aeasyasiasT1641634988280, w3aeasyasiayT1641634988280, w3aeasyasiapT1641634988280, w2aeasyasppy, w2d
w2aeasyasppy,
w2aeasyaspppT1641634988296, w2aeasyasppiT1641634988297, w2aeasyaspieT1641634988297, w2aeasyaspiaT1641634988297, w2aeasyaspisT1641634988297, w2aeasyaspiyT1641634988297, w2aeasyaspipT1641634988297, w2aeasyaspiiT1641634988298, w2aeasyasieeT1641634988298,
after this is output almost instantaneously, it pauses while it attempts to crack 4 passwords, then the process drops out (without error).
I was expecting the output to pause after each comma ,
but it outputs everything before attempting anything.
The idea is to, for example, crack 10 passwords per thread, where there are 4 threads, then when the worker is terminated, a new worker in its place is started with the next 10 passwords, however, I'm just trying to run each worker_thread once to start until I can debug the rest of it.
So, my questions are:
i gave up trying to understand promises (but i understand some of it) so i reverted to synchronous code while still implementing true multithreading via nodejs
cluster
and it now runs much, much faster than single threaded
run.js
//(synchronous functions not displayed)
//...
workers = new Array()
if (cluster.isMaster) {
pass = ""
if(PROGRESS === "CONTINUE") {
if (checkFileExists(FILE + ".progress.txt")) {
console.log("progress file found: continuing")
try {
const data = fs.readFileSync(FILE + ".progress.txt", 'utf8')
pass = data
} catch (err) {
console.error(err)
}
if (!pass.length > 0) pass = chars.substring(0,1)
} else {
console.log("progress file not found: starting at beginning; this is ok if first time running")
pass = chars.substring(0,1)
}
} else pass = chars.substring(0,1)
let r = 0
let someLeft = true
let passes = new Array()
passes[0] = pass
for (let y = 1; y < cpuCount; y++) passes[y] = iterate(passes[y -1])
let passTried = new Array()
for (let y = 0; y < cpuCount; y++) passTried[y] = false
for (let x = 0; x < cpuCount; x++) {
workers[x] = cluster.fork()
passTried[x] = true
workers[x].send({ message: passes[x] })
workers[x].on('message', function(msg) {
if (msg.stat) {
for (sworker in workers) {
workers[sworker].process.kill()
}
process.exit()
}
if (msg.att) {
process.stdout.write("\rattempted: " + msg.att)
r++
if (r % 100 == 0) {
fs.writeFileSync(FILE + '.progress.txt', msg.att, function (err) {
if (err) throw err
})
r = 0
}
for (let i = 0; i < cpuCount; i++) {
if (!passTried[i]) {
passTried[i] = true
workers[x].send({ message: passes[i] })
break
}
}
someLeft = false
for (let i = 0; i < cpuCount; i++) {
if (!passTried[i]) {
someLeft = true
break
}
}
if (!someLeft) {
passes = getNewBlock(passes)
for (let y = 0; y < cpuCount; y++) passTried[y] = false
someLeft = true
}
}
})
}
} else {
process.on('message', function(pass) {
crack(pass.message)
process.send({ att: pass.message })
})
}
please note that this is a bit of an ugly hack-job and shouldn't be implemented in a server and definitely should not be implemented in production because it uses blocking code, but for my narrow purpose it does the job
thanks to everyone of whom tried to show me the way of using asynchronous code in the comments above