Bitcoin Forum
November 23, 2017, 04:33:53 AM *
News: Latest stable version of Bitcoin Core: 0.15.1  [Torrent].
 
   Home   Help Search Donate Login Register  
Pages: [1]
  Print  
Author Topic: How to recover your wallet.dat encryption password (Brute force)  (Read 16870 times)
NEICH
Newbie
*
Offline Offline

Activity: 13


View Profile
April 08, 2013, 07:37:58 PM
 #1

Dear bitcoiners,

I forgot my pass for my encrypted wallet.dat. At the beginning I was not really worry, as I only had a few bitcoins... but currently, due to the high value of the coin I made big efforts for  recovering my password. Finally I was able to find the password by means of some scripts I built.
I hope they are useful for you also.

First, I installed an Ubuntu system in a VMware virtual machine. I then installed bitcoind, and ruby.

Then I figured out some rules for the developing of a passwords builder, obtaining a few personal dictionaries. This way I would run some dictionaries at home, and others in the office.
In my case I usually use passwords with a specific syntax... for example
1. Something like _bitcoin001$$$... the syntax will be:  [from zero to two characters]  + [word1] + [from 0 to a few numbers] + [a few characters]
2. Something like _coin13bitcoin001$$.... the syntax will be:  [from zero to two characters]  + [word1] + [a few numbers] + [word2] + [a few characters]
3....

I then assumed some general rules. In my case for example, I use to repeat the same character at the end... Normally I don't use digits above value 3, etc...
In your case you have to figure out your own rules and tune up my code.

I provide two scripts:

Build.rub will build your dictionaries according to the rules you have defined. This script will create a text file that will be used for searching for your lost password.
It is important to have this information in a file, as it will be mandatory for resuming from the last tested password in case you switch off the PC or you have a hard reset.

In the dictionaries building it is important to minimize the characters in the list (think about the common characters you use and discard those not used in your password, also do the same for the numbers you use). In addition, I looked for 6 unknown characters.... note that this leads to a searching of one month.... maybe your case is easier, and only forgot two or three characters..... I hope that !!. It is very useful to find rules that reduces the number of possibilities. For example in my case I normally repeat the same symbol several times instead of using different symbols consecutively.

Code:
#!/usr/bin/ruby -w build.rub

arrayNumSymbols = "\#$%&*+-=@_0123".chars.to_a
arraySymbols = "\#$%&*+-=@_".chars.to_a
arrayNumbers= "0123".chars.to_a

counter = 0
NumDiccionario = 1

#--------------------------------------------------------------------------------

min_left = 0  
max_left = 1  

min_center = 0
max_center = 2

min_right =  0
max_right =  4              #  This is not including an extra character that can be added at the end
max_Right_Symbol=3     # within right characters, this constant define the number of consecutive symbols
extra_symbol=1            # value 0 or 1. It defines if an extra character shall be added at the end

#-----------------------------------------------------------------
def storeWord(file,left,center,right,counter)
  
     case NumDiccionario
        when 1  then file.puts left + "word1" + right + "\n"                                 #_$word1$$$000+          -> LCR=2-0-6
        when 2  then file.puts left + "WORD1" + right + "\n"                               #_$WORD1$$$000+        -> LCR=2-0-6
        when 3  then file.puts left + "Word1" + right + "\n"                                 #_$Word1$$$000+         -> LCR=2-0-6
        when 4  then file.puts left + "word1" + center + "word2" + right + "\n"       #_word100word2$$$0+   -> LCR=1-2-4
        when 5  then file.puts left + "WORD1" + center + "WORD2" + right + "\n"    #_WORD100WORD2$$$0+   -> LCR=1-2-4
        when 6  then file.puts left + "Word1" + center + "Word2" + right + "\n"       #_Word100Word2$$$0+        -> LCR=1-2-4
     end
     counter = counter + 1
     return counter
end
#-----------------------------------------------------------------
left = ""
center = ""
right = ""

print "Building dictionary" + NumDiccionario.to_s + " .\n"
print "Wait...\n"

# --- This code defines the number of characters in the left, center and right of the generated password
case NumDiccionario
    when 1   then max_left = 2; max_center = 0; max_right = 6;
    when 2   then max_left = 1; max_center = 2; max_right = 4;
    when 3   then max_left = 1; max_center = 2; max_right = 4;
    when 4   then max_left = 2; max_center = 0; max_right = 5;
end

nameFile = "diccionario" + NumDiccionario.to_s + ".txt"
File.open(nameFile, 'w') do |file|

# ------- Calculation of left characters  ------------  
(min_left..max_left).each do |length_left|
  arraySymbols.repeated_permutation(length_left) do |str_left|
      left = str_left.join
      # ------- Calculation of center characters -------------
      (min_center..max_center).each do |length_center|
          arrayNumSymbols.repeated_permutation(length_center) do |str_center|
             center = str_center.join
             # ------- Calculation of right characters -------------
             (min_right..max_right).each do |length_right|
        max_symbols = [length_right, max_Right_Symbol].min
                 (0..max_symbols).each do |num_symbols|
        if (num_symbols == 0)
                         arrayNumbers.repeated_permutation(length_right) do |str_numeros|  
                              right = str_numeros.join
                              counter = storeWord file,left,center,right,counter
                              if extra_symbol==1
                                arraySymbols.each do |extra_caracter|
                                   right = str_numeros.join + extra_caracter
                                   #---- Store this word in the dictionary  ----------    
                                   counter = storeWord file,left,center,right,counter
                                end  
                              end
                         end
                      else
                         arraySymbols.each do |symbol|
                         str_symbols = symbol * num_symbols
                         max_numeros= length_right-num_symbols
                         arrayNumbers.repeated_permutation(max_numeros) do |str_numeros|
      right = str_numeros.join + str_symbols
                               counter = storeWord file,left,center,right,counter                    
                right = str_symbols + str_numeros.join
                               counter = storeWord file,left,center,right,counter
                               if extra_symbol==1
                                   arraySymbols.each do |extra_caracter|
      right = str_symbols + str_numeros.join + extra_caracter
                                       counter = storeWord file,left,center,right,counter
                                   end        
                               end
                             end
                         end
                      end
                  end
             end
      end
      end  
  end
end
end
print "Words counter: #{counter}. Maximum estimated time for password recovery #{counter/36000} hours. #{counter/864000} days \n"
      
File.open('lastLine.txt', 'w') do |file2|
    file2.puts "0"
end  

Note that by changing the constant "dicctionario" and running this script you can generate all dictionaries you define in the code (following your own rules)
run the scrip by using "ruby -w build.rub"

After you have generated the password files, you can use the following script for searching for the password:

- First of all, run the bitcoind in daemon mode:  bitcoind -daemon

- Then, run this script ruby -w search.rub

Sarch.rub

Code:
#!/usr/bin/ruby -w search.rub

num_line = 0

NumDiccionario = 1

#--------------------------------------------------------------------------------

#-----------------------------------------------------------------
def checkPassword (pass)
  print pass, "\t"
  system("bitcoind", "walletpassphrase", pass, "20")
  case $?.exitstatus
  when 0
    puts "You found it!  #{pass}"
    File.open('password.txt', 'w') do |file|
       file.puts phrase + "\n"
    end
    exit 0
end
#-----------------------------------------------------------------

str_num_line = "0"

File.open('lastLine.txt', 'r') do |file2|
           str_num_line = file2.gets
end  

if (str_num_line.to_i > 0 )
   print "Last searching stopped at line " + str_num_line + "\n"
   STDOUT.flush
   print "Continue from here? y/n:"
   resp = gets.chomp
   if (resp == "y")
       num_line =str_num_line.to_i
   end
end
  

print "Starting at line " + num_line.to_s + "... Good luck!!\n"

fileName = "Dictionary" + NumDiccionario.to_s + ".txt"
File.open(fileName, 'r') do |file|

print "Shifting index..."
(0..num_line).each do |i|
   line = file.gets
end

print "Searching..."

while line = file.gets
    print "Checking line:" + num_line.to_s + ": " + line
    str = line.chomp
    checkPassword  str
    num_line = num_line + 1
    if (num_line % 100)
       File.open('lastLine.txt', 'w') do |file2|
           file2.puts num_line.to_s + "\n"
       end    
    end
end
end


If you prepare the testing system in a virtual machine, you can run several instances, one per dictionary.... I was running up to 6 at the same time with an i7 and 3GB or RAM.
If you need help, and need support, feel free to contact with me.

Good finding!


BTCTC Address for Donations:  12PxVhcqdP2ZJLmeGnR33xfpBKA6nHsE2K
1511411633
Hero Member
*
Offline Offline

Posts: 1511411633

View Profile Personal Message (Offline)

Ignore
1511411633
Reply with quote  #2

1511411633
Report to moderator
1511411633
Hero Member
*
Offline Offline

Posts: 1511411633

View Profile Personal Message (Offline)

Ignore
1511411633
Reply with quote  #2

1511411633
Report to moderator
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction. Advertise here.
1511411633
Hero Member
*
Offline Offline

Posts: 1511411633

View Profile Personal Message (Offline)

Ignore
1511411633
Reply with quote  #2

1511411633
Report to moderator
1511411633
Hero Member
*
Offline Offline

Posts: 1511411633

View Profile Personal Message (Offline)

Ignore
1511411633
Reply with quote  #2

1511411633
Report to moderator
kicker049
Newbie
*
Offline Offline

Activity: 8



View Profile
April 11, 2013, 11:44:06 AM
 #2

Nice work Necih!
I hope this will help to increase the Bitcoin security.
Never use passwords less than 12 characters!

The greatest good you can do for another is not just to share your riches but to reveal to him his own (Benjamin Disraeli).
As everyone puts, tips are welcome. ฿: 17RvyqF1jAgc5Xzy8Uv8XniFiwHckucyny
Sharky444
Hero Member
*****
Offline Offline

Activity: 727


View Profile
June 10, 2013, 06:21:35 AM
 #3

I would be interested how long does it take to bruteforce a password with 12 chars. How much chars do you need to be reasonably secure if the bruteforce is done by say 1000 computers.

Radix - just imagine
NEICH
Newbie
*
Offline Offline

Activity: 13


View Profile
June 17, 2013, 08:13:06 PM
 #4

Dear Sharky444,

It depends on how you can delimit your calculation...

Two cases:

(A) Let's imagine you know some of the characters you used... Or someone knows you usually use numbers and certain symbols.... a very short list would include 20 characters ...
But let's imagine you are very sure that with only 12 chars it would be enough..... With 12 chars you will reach an amount of 20^12 = 4096*10^12 combinations.
The current brute force has a bitcoin client passphrase limitation: It can only check about 10 phrases per second due to security reasons.
This means that one PC, will take 13.168.724 years.

Now lets imagine you can run up to 6 virtual machines in your PC, in each of them you run the brute force script against the bitcoin a copy of the wallet client.... then the pc will need 1.316.874 years.... Now lets imagine you are really rich or an awesome hacker and you can have 100.000 computers working for the wallet password.....  Then you will spend 13 years for obtaining the password...... In addition, you would need the wallet.dat file.... that in fact is not very easy to be obtained.

Now, go to a more realistic situation:
(B) You have no idea about the used password characters.... you may have upper-cases, lower-cases, numbers, symbols.... You should include a lot of characters for your combinations calculation... Then you may consider 85 characters...  {a...z, A...Z, 0..9, !"·$$%&/()=?¿^<>@#~|[]{}€*¨Ç;:_/*......... etc)

Same calculation will lead to a brute force time of 762.183.626 years
In this case, if you want to get the password in a reasonable time (about 1 month) you would need 762.183.626.000.000 computers.

From my point of view, 12 characters is a long and very safe password... maybe too long for our minds.
I think it is safe enough to use passwords of 10 characters, where you alternate text, upper/lower-cases, numbers, and rare symbols.... Considering that some brute-force dictionaries may not be treating very rare symbols for reducing the combinations number... if you are using rare symbols you will increase a lot your password safety:  "¬ ~| % ` [ ] } etc..."

biggie
Member
**
Offline Offline

Activity: 85


View Profile
July 11, 2013, 02:03:30 AM
 #5

Dear Sharky444,

It depends on how you can delimit your calculation...

Two cases:

(A) Let's imagine you know some of the characters you used... Or someone knows you usually use numbers and certain symbols.... a very short list would include 20 characters ...
But let's imagine you are very sure that with only 12 chars it would be enough..... With 12 chars you will reach an amount of 20^12 = 4096*10^12 combinations.
The current brute force has a bitcoin client passphrase limitation: It can only check about 10 phrases per second due to security reasons.
This means that one PC, will take 13.168.724 years.

Now lets imagine you can run up to 6 virtual machines in your PC, in each of them you run the brute force script against the bitcoin a copy of the wallet client.... then the pc will need 1.316.874 years.... Now lets imagine you are really rich or an awesome hacker and you can have 100.000 computers working for the wallet password.....  Then you will spend 13 years for obtaining the password...... In addition, you would need the wallet.dat file.... that in fact is not very easy to be obtained.

Now, go to a more realistic situation:
(B) You have no idea about the used password characters.... you may have upper-cases, lower-cases, numbers, symbols.... You should include a lot of characters for your combinations calculation... Then you may consider 85 characters...  {a...z, A...Z, 0..9, !"·$$%&/()=?¿^<>@#~|[]{}€*¨Ç;:_/*......... etc)

Same calculation will lead to a brute force time of 762.183.626 years
In this case, if you want to get the password in a reasonable time (about 1 month) you would need 762.183.626.000.000 computers.

From my point of view, 12 characters is a long and very safe password... maybe too long for our minds.
I think it is safe enough to use passwords of 10 characters, where you alternate text, upper/lower-cases, numbers, and rare symbols.... Considering that some brute-force dictionaries may not be treating very rare symbols for reducing the combinations number... if you are using rare symbols you will increase a lot your password safety:  "¬ ~| % ` [ ] } etc..."




Thank you for the info !

Only one thing, the limitation of 10 per second is just coded in the client software right ? So a programmer can change that and recompile the client and this allows you to use all you got in computing power.
TradeFortress
VIP
Legendary
*
Offline Offline

Activity: 910


View Profile
July 11, 2013, 06:42:32 AM
 #6

It's not coded in the client, when you create a passphrase it appends a random salt at the end for it so that it will take on average 0.1 seconds to try and decrypt.

Example: your password is password.

Your computer can do 20,000 decryptions per second.

So your real password would be between password000 to password999. (So on average 0.1 seconds, because on average you're going to decrypt it halfway through).

When you decrypt, bitcoind tries all the keyspace which on average will take 0.1 seconds.
biggie
Member
**
Offline Offline

Activity: 85


View Profile
July 11, 2013, 03:20:28 PM
 #7

It's not coded in the client, when you create a passphrase it appends a random salt at the end for it so that it will take on average 0.1 seconds to try and decrypt.

Example: your password is password.

Your computer can do 20,000 decryptions per second.

So your real password would be between password000 to password999. (So on average 0.1 seconds, because on average you're going to decrypt it halfway through).

When you decrypt, bitcoind tries all the keyspace which on average will take 0.1 seconds.

Ah ok, i thought you'd simply adjust the bitcoind code responsible for decryption to remove such delay Smiley
lophie
Hero Member
*****
Offline Offline

Activity: 924


Unlimited Free Crypto


View Profile
August 13, 2013, 01:05:17 PM
 #8

ruby -w Build.rub
ruby: invalid option -b

Never used ruby, can anyone help me here :S.

grue
Global Moderator
Legendary
*
Offline Offline

Activity: 2044



View Profile
August 13, 2013, 01:47:34 PM
 #9

ruby -w Build.rub
ruby: invalid option -b

Never used ruby, can anyone help me here :S.
try

ruby -w "build.rub"

It is pitch black. You are likely to be eaten by a grue.

Tired of annoying signature ads? Ad block for signatures
lophie
Hero Member
*****
Offline Offline

Activity: 924


Unlimited Free Crypto


View Profile
August 13, 2013, 02:23:18 PM
 #10

ruby -w Build.rub
ruby: invalid option -b

Never used ruby, can anyone help me here :S.
try

ruby -w "build.rub"

I actually got it when tried to rationale the code. First line, there is no "build.rub", it should be deleted. Thanks anyway.

Pages: [1]
  Print  
 
Jump to:  

Sponsored by , a Bitcoin-accepting VPN.
Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!