Skip to content

Commit 5063a1e

Browse files
Add bitcoin core wallet file password recovery service
1 parent af6c425 commit 5063a1e

File tree

1 file changed

+207
-0
lines changed

1 file changed

+207
-0
lines changed
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
// The FinderOuter
2+
// Copyright (c) 2020 Coding Enthusiast
3+
// Distributed under the MIT software license, see the accompanying
4+
// file LICENCE or http://www.opensource.org/licenses/mit-license.php.
5+
6+
using Autarkysoft.Bitcoin;
7+
using FinderOuter.Backend.Hashing;
8+
using FinderOuter.Models;
9+
using FinderOuter.Services.SearchSpaces;
10+
using System;
11+
using System.Diagnostics;
12+
using System.Runtime.CompilerServices;
13+
using System.Security.Cryptography;
14+
using System.Threading.Tasks;
15+
16+
namespace FinderOuter.Services
17+
{
18+
public class CorePassService
19+
{
20+
public CorePassService(IReport rep)
21+
{
22+
report = rep;
23+
}
24+
25+
26+
private readonly IReport report;
27+
private CorePassSearchSpace searchSpace;
28+
29+
30+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
31+
private static unsafe bool MoveNext(PermutationVar* items, int len)
32+
{
33+
for (int i = len - 1; i >= 0; i--)
34+
{
35+
if (items[i].Increment())
36+
{
37+
return true;
38+
}
39+
}
40+
41+
return false;
42+
}
43+
44+
public unsafe void MainLoop(int firstItem, ParallelLoopState loopState)
45+
{
46+
// Compute SHA512(pass | salt) iteration times
47+
// AES key is first 32 bytes of hash state
48+
// AES IV is the next 16 bytes
49+
// If decrypted result ^ XOR == 16 the password was correct
50+
51+
using Aes aes = Aes.Create();
52+
aes.KeySize = 256;
53+
aes.Mode = CipherMode.ECB;
54+
aes.Padding = PaddingMode.None;
55+
56+
PermutationVar[] items = new PermutationVar[searchSpace.PasswordLength];
57+
58+
Debug.Assert(searchSpace.Salt != null);
59+
Debug.Assert(searchSpace.Salt.Length == 8);
60+
Span<byte> passBa = new byte[searchSpace.MaxPasswordSize + searchSpace.Salt.Length];
61+
62+
ulong* ptr = stackalloc ulong[Sha512Fo.UBufferSize];
63+
ulong* wPt = ptr + 8;
64+
65+
fixed (byte* passBaPt = &passBa[0], allVals = &searchSpace.AllValues[0], saltPt = &searchSpace.Salt[0])
66+
fixed (int* lens = &searchSpace.PermutationLengths[0], sizePt = &searchSpace.PermutationSizes[0])
67+
fixed (PermutationVar* itemsPt = &items[0])
68+
{
69+
byte* tvals = allVals;
70+
int* tlens = lens;
71+
for (int i = 0; i < items.Length; i++)
72+
{
73+
int size = searchSpace.PermutationCounts[i];
74+
items[i] = new PermutationVar(size, tvals, tlens);
75+
tvals += sizePt[i];
76+
tlens += size;
77+
}
78+
79+
for (int i = 0; i < firstItem; i++)
80+
{
81+
#if DEBUG
82+
bool b =
83+
#endif
84+
itemsPt[0].Increment();
85+
#if DEBUG
86+
Debug.Assert(b);
87+
#endif
88+
}
89+
90+
do
91+
{
92+
if (loopState.IsStopped)
93+
{
94+
return;
95+
}
96+
97+
passBa.Clear();
98+
int totalPassLen = 0;
99+
foreach (var item in items)
100+
{
101+
totalPassLen += item.WriteValue(passBaPt + totalPassLen, passBa.Length);
102+
}
103+
Debug.Assert(totalPassLen <= searchSpace.MaxPasswordSize - searchSpace.Salt.Length);
104+
Buffer.MemoryCopy(saltPt, passBaPt + totalPassLen, passBa.Length, searchSpace.Salt.Length);
105+
totalPassLen += searchSpace.Salt.Length;
106+
107+
Sha512Fo.Init(ptr);
108+
Sha512Fo.CompressData(passBaPt, totalPassLen, totalPassLen, ptr, wPt);
109+
110+
wPt[08] = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000UL; // 1 followed by 0 bits: pad1
111+
wPt[09] = 0;
112+
wPt[10] = 0;
113+
wPt[11] = 0;
114+
wPt[12] = 0;
115+
wPt[13] = 0;
116+
wPt[14] = 0;
117+
wPt[15] = 512; // Message length is 64 byte previous hash or 512 bits
118+
for (int i = 0; i < searchSpace.Iteration - 1; i++)
119+
{
120+
// Previous hash is now our working vector
121+
*(Block64*)wPt = *(Block64*)ptr;
122+
123+
// Now initialize hashState to compute next round
124+
Sha512Fo.Init(ptr);
125+
Sha512Fo.Compress64(ptr, wPt);
126+
}
127+
128+
aes.IV = new byte[16]
129+
{
130+
(byte)(ptr[4] >> 56), (byte)(ptr[4] >> 48), (byte)(ptr[4] >> 40), (byte)(ptr[4] >> 32),
131+
(byte)(ptr[4] >> 24), (byte)(ptr[4] >> 16), (byte)(ptr[4] >> 8), (byte)ptr[4],
132+
133+
(byte)(ptr[5] >> 56), (byte)(ptr[5] >> 48), (byte)(ptr[5] >> 40), (byte)(ptr[5] >> 32),
134+
(byte)(ptr[5] >> 24), (byte)(ptr[5] >> 16), (byte)(ptr[5] >> 8), (byte)ptr[5],
135+
};
136+
aes.Key = new byte[32]
137+
{
138+
(byte)(ptr[0] >> 56), (byte)(ptr[0] >> 48), (byte)(ptr[0] >> 40), (byte)(ptr[0] >> 32),
139+
(byte)(ptr[0] >> 24), (byte)(ptr[0] >> 16), (byte)(ptr[0] >> 8), (byte)ptr[0],
140+
141+
(byte)(ptr[1] >> 56), (byte)(ptr[1] >> 48), (byte)(ptr[1] >> 40), (byte)(ptr[1] >> 32),
142+
(byte)(ptr[1] >> 24), (byte)(ptr[1] >> 16), (byte)(ptr[1] >> 8), (byte)ptr[1],
143+
144+
(byte)(ptr[2] >> 56), (byte)(ptr[2] >> 48), (byte)(ptr[2] >> 40), (byte)(ptr[2] >> 32),
145+
(byte)(ptr[2] >> 24), (byte)(ptr[2] >> 16), (byte)(ptr[2] >> 8), (byte)ptr[2],
146+
147+
(byte)(ptr[3] >> 56), (byte)(ptr[3] >> 48), (byte)(ptr[3] >> 40), (byte)(ptr[3] >> 32),
148+
(byte)(ptr[3] >> 24), (byte)(ptr[3] >> 16), (byte)(ptr[3] >> 8), (byte)ptr[3]
149+
};
150+
151+
using ICryptoTransform decryptor = aes.CreateDecryptor();
152+
byte[] decryptedResult = new byte[16];
153+
decryptor.TransformBlock(searchSpace.Encrypted, 0, 16, decryptedResult, 0);
154+
155+
bool isCorrect = true;
156+
for (int i = 0; i < searchSpace.XOR.Length; i++)
157+
{
158+
if ((searchSpace.XOR[i] ^ decryptedResult[i]) != 16)
159+
{
160+
isCorrect = false;
161+
break;
162+
}
163+
}
164+
165+
if (isCorrect)
166+
{
167+
loopState.Stop();
168+
report.FoundAnyResult = true;
169+
170+
char[] temp = new char[totalPassLen];
171+
for (int i = 0; i < temp.Length; i++)
172+
{
173+
temp[i] = (char)passBaPt[i];
174+
}
175+
176+
report.AddMessageSafe($"Password is: {new string(temp)}");
177+
return;
178+
}
179+
180+
} while (MoveNext(itemsPt + 1, items.Length - 1));
181+
}
182+
}
183+
184+
185+
private void StartParallel()
186+
{
187+
int max = searchSpace.PermutationCounts[0];
188+
report.SetProgressStep(max);
189+
ParallelOptions opts = report.BuildParallelOptions();
190+
Parallel.For(0, max, opts, (firstItem, state) => MainLoop(firstItem, state));
191+
}
192+
193+
194+
public async void Find(CorePassSearchSpace ss)
195+
{
196+
report.Init();
197+
198+
searchSpace = ss;
199+
report.SetTotal(searchSpace.GetTotal());
200+
report.Timer.Start();
201+
202+
await Task.Run(StartParallel);
203+
204+
report.Finalize();
205+
}
206+
}
207+
}

0 commit comments

Comments
 (0)