Open 3rdIteration opened 2 years ago
FWIW here is the decryptor code in js:
function getSHA256(t) {
var md = forge.md.sha256.create();
md.update(t);
return md.digest().toHex();
}
function decryptWallet(payload, password, salt, iterations, aes_cipher) {
// decrypts the wallet
// payload, salt are in Base64
// payload contains the IV (first 16 or 12 bytes)
var encryption_key = forge.util.bytesToHex(forge.pkcs5.pbkdf2(forge.util.encode64(forge.util.hexToBytes(getSHA256(password))), forge.util.decode64(salt), iterations, 32, "sha256"));
var iv_hex = null;
var payload_hex = null;
var aes_auth_tag = null;
var payload_bytes = forge.util.decode64(payload);
if (aes_cipher === "AES-CBC") {
iv_hex = forge.util.bytesToHex(payload_bytes.slice(0,16));
payload_hex = forge.util.bytesToHex(payload_bytes.slice(16));
} else if (aes_cipher === "AES-GCM") {
iv_hex = forge.util.bytesToHex(payload_bytes.slice(0,12));
aes_auth_tag = forge.util.bytesToHex(payload_bytes.slice(12, 12+16));
payload_hex = forge.util.bytesToHex(payload_bytes.slice(12+16));
} else {
throw("Unrecognized cipher");
}
// decrypt the wallet
var decipher = forge.cipher.createDecipher(aes_cipher, forge.util.hexToBytes(encryption_key));
if (aes_cipher === "AES-CBC") {
decipher.start({iv: forge.util.hexToBytes(iv_hex)});
} else if (aes_cipher === "AES-GCM") {
decipher.start({iv: forge.util.hexToBytes(iv_hex), tag: forge.util.hexToBytes(aes_auth_tag), additionalData: forge.util.hexToBytes(""), tagLength: 128});
} else {
throw("Unrecognized cipher");
}
decipher.update(forge.util.createBuffer(forge.util.hexToBytes(payload_hex)));
var output_data = null;
if (decipher.finish()) {
// decryption succeeded, but need to check output
try {
output_data = JSON.parse(decipher.output.data);
} catch (err) {
output_data = null;
}
}
return output_data; // the decrypted wallet, or null if failed
}
function encryptWallet(payload, password, iterations, aes_cipher) {
// encrypts the payload
// payload is in JSON
// prepends IV (16 bytes) to payload
// returns Base64 iv+payload, and salt
var salt_bytes = forge.random.getBytesSync(16);
var key_bytes = forge.pkcs5.pbkdf2(forge.util.encode64(forge.util.hexToBytes(getSHA256(password))), salt_bytes, iterations, 32, "sha256");
var iv_bytes = null;
if (aes_cipher === "AES-CBC") {
iv_bytes = forge.random.getBytesSync(16);
} else if (aes_cipher === "AES-GCM") {
iv_bytes = forge.random.getBytesSync(12);
} else {
throw("Unrecognized cipher");
}
var cipher = forge.cipher.createCipher(aes_cipher, key_bytes);
if (aes_cipher === "AES-CBC") {
cipher.start({iv: iv_bytes});
} else if (aes_cipher === "AES-GCM") {
cipher.start({iv: iv_bytes, additionalData: forge.util.hexToBytes(""), tagLength: 128});
} else {
throw("Unrecognized cipher");
}
cipher.update(forge.util.createBuffer(JSON.stringify(payload)));
cipher.finish();
var encrypted_payload = null;
if (aes_cipher === "AES-CBC") {
encrypted_payload = iv_bytes + cipher.output.data;
} else if (aes_cipher === "AES-GCM") {
encrypted_payload = iv_bytes + cipher.mode.tag.data + cipher.output.data;
} else {
throw("Unrecognized cipher");
}
var response = {
salt: forge.util.encode64(salt_bytes),
payload: forge.util.encode64(encrypted_payload),
cipher: aes_cipher
};
var decrypted_payload = decryptWallet(response.payload, password, response.salt, iterations, aes_cipher);
if (decrypted_payload === null || JSON.stringify(decrypted_payload) !== JSON.stringify(payload)) {
throw("Unable to decrypt encrypted payload.");
}
return response;
}
function testBrowserEncryption(){
var result = false;
try {
encryptWallet({a:1}, forge.util.bytesToHex(forge.random.getBytesSync(12)), 1000, "AES-CBC");
encryptWallet({a:1}, forge.util.bytesToHex(forge.random.getBytesSync(12)), 1000, "AES-GCM");
result = true; // if we got here, we're fine
} catch (err) {
result = false;
}
try {
var s_special = "`1234567890-=~!@#$%^&*()_+abcdпароль";
var s_normal = "`1234567890-=~!@#$%^&*()_+abcdefghABCDEFG";
result = (result &&
(s_special !== forge.util.encodeUtf8(s_special)) &&
(s_normal === forge.util.encodeUtf8(s_normal)) &&
(getSHA256(s_special) === "33bc2af5524c1b8512b4d2b06d8f7b5efa30aca50f4f9801a3f0ba01240964e6") &&
(getSHA256(forge.util.encodeUtf8(s_special)) === "4b21f9780a8ce6fec928c0754b0e55ddb7298308a72f21a8f0120019819c6644") &&
(getSHA256(s_normal) === "5962ca3e3114351e42762683bd861eaa735e8c8ca07378c63330fcaccc504a56") &&
(getSHA256(forge.util.encodeUtf8(s_normal)) === "5962ca3e3114351e42762683bd861eaa735e8c8ca07378c63330fcaccc504a56"));
} catch (err) {
result = false;
}
return result;
}
However with mandatory 2FA it seems, offline recovery is probably not an option anymore.
Once you have the wallet file it would be fine, so if you want to fix it up and bring a PR then please do.
Basically dogechain support has come through two abandoned sponsored features (so the person sponsoring didn't end up paying on delivery of working code) so I'm not inclined to expand any time on this wallet type beyond approving a PR.
I can certainly do that, but I'm not sure how much utility the feature would have. My old dogechain wallet, which did not have 2FA enabled, had it forced upon it at some point in the last few months and since it's linked to my old school email that I no longer have access to, I'm effectively locked out. I have it backed up, but if I remember correctly the most obvious way to back up one's account is the plaintext pdf. Any new account I open have the same problem - 2FA enforced logins. Is this specific feature one that is frequently asked about beyond the two abandoned sponsors? Because it feels particularly niche, all things considered.
I maintain a library for opening legacy format wallets and while a different use case, I'd be happy to integrate/solve problems that actual long time crypto users have ran into, like figuring out what coin is in a particular wallet.dat file as in #80 - and the feature would also do the same for passworded but not encrypted wallet files - and bitcoinj-based wallets and keyfiles as well. If you think that's within the scope of this repo I'd be happy to add that set of features instead, as almost inevitably I find myself referring those who ask questions about my library to this repo.
@jimtje I am currently trying to regain acces to an old wallet of mine from 2017. I had given up hope on this wallet but recently discovering this btcrecover program I would like to give it another try. So it is very unfortunate that the one wallet type I am trying to recover has broken due to this recent update.
I have acces to my 2FA so I have been able to download the wallet file(looks the same as the example above from 3rdItteration), but now I need to decrypt it so the btcrecover program can use it again. I have taken a look at your wallet decryptor javascript code but I am unsure how to run it with the wallet. I would very much appreciate it if you could help with this matter.
@jimtje I am currently trying to regain acces to an old wallet of mine from 2017. I had given up hope on this wallet but recently discovering this btcrecover program I would like to give it another try. So it is very unfortunate that the one wallet type I am trying to recover has broken due to this recent update.
I have acces to my 2FA so I have been able to download the wallet file(looks the same as the example above from 3rdItteration), but now I need to decrypt it so the btcrecover program can use it again. I have taken a look at your wallet decryptor javascript code but I am unsure how to run it with the wallet. I would very much appreciate it if you could help with this matter.
Support could be fixed if you want to sponsor it.
@3rdIteration What would this sponsorship entail (specifics)?
It's already half done, so would basically just be $250 USD. Once the sponsorship payment was recieved then the feature would be completed and merged within two weeks.
@3rdIteration It is good to hear that it is almost finished. Unfortunately I do not have that kind of money right now.
Can you please fix the issue. I have 30k dogecoin in dogechain wallet. I will donate to the creator if i am able to recover it
I'm happy to look at it as a trusted recovery if you like.
I'm happy to look at it as a trusted recovery if you like. Hello, dogechain.info will stop functioning on June 1st, could you help us decipher the code? What good will the code be if it is of no use to anyone? I think everyone who can restore access to their dogecoins will thank you financially
If you want a trusted recovery then you can request one here: https://cryptoguide.tips/recovery-services-consultations/
These wallets are also incorrectly detected as a blockchain.com wallet, either way it's broken.
Sample of updated wallet files is here: https://github.com/3rdIteration/btcrecover/blob/6ba24508d4a752bc06a1dd29d52c55c23f1f0795/btcrecover/test/test-wallets/dogechain.wallet.aes.json.2022-01
The correct password is the standard test password, "btcr-test-password".