For example:
$ ./johnny.py truecrypt_container Bb Mm '5$Ss' Mm 'A@4a'
will try all possible L337-speak translations of the first letter of each word in the phrase "Bite My Shiny Metal Ass" for the truecrypt file container "truecrypt_container". I believe you can also use the script on a truecrypted hard drive partition, if applicable (by passing the path to the specific block device), though I haven't tested that using it in this way works.
Please note that I wrote it for Linux, and if any part of the keyspace contains metacharacters, you may need to use single-quotes in passing that part of it. Also, the account on your machine needs to be sudo-able (well of course; you're running TrueCrypt!)
#!/usr/bin/env python
import re,subprocess,sys
from os import path
from functools import reduce
def callTC(keyattempt):
global TCloc,volume
comm = ['sudo',TCloc,'--text','--non-interactive',"--password="+keyattempt,volume]
return subprocess.Popen(comm,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
def tryKey(position):
global keyspace,keylen,nptot,permutation,done,nperm,passphrase,volume
# If not at the bottom level of recursion yet, assemble the trial password
if(position < keylen):
for char in keyspace[position]:
permutation[position] = char
trial=tryKey(position+1)
if(trial):
return True
return False
# If at the bottom level, the permutation has been completed, so attempt to run the command
else:
nperm += 1 # one more permutation is being tried
passphrase=''.join(permutation)
trial = callTC(passphrase)[1]
if ( trial.decode('utf-8').rfind('already mounted') != -1) :
print ('(unmounting volume...)')
subprocess.call(['sudo','truecrypt','-d',volume])
nperm -= 1;
return tryKey(position)
if((done+1.0)/100.0 <= nperm*1.0/nptot):
done = int(100*float(nperm)/float(nptot))
print("%3d%% (%d of %d) total permutations tried; current guess = %s" % (done,nperm,nptot,passphrase))
return ( trial.decode('utf-8') == '' ) # stderr
def main():
global TCloc,volume,keyspace,keylen,nptot,permutation,passphrase,done,nperm
if(len(sys.argv) < 3):
print "Usage: johnny.py [path to TrueCrypt volume] [set of possible first characters] [set of possible second characters] ...\n"
print "Recover a TrueCrypt password based on a rememberd mnemonic. Pass johnny.py a space-delineated list of strings each"
print "representing the set of possible characters for each character in the password. If your passphrase contains a space, use quotes ;-)"
sys.exit(0)
TCloc = ((subprocess.Popen(['which','truecrypt'],stdout=subprocess.PIPE)).communicate())[0][0:-1]
volume=sys.argv[1]
keyspace = sys.argv[2:]
keylen = len(keyspace)
nptot = reduce(lambda x, y: x*y,[len(chars) for chars in keyspace])
permutation = ['' for x in keyspace]
done = 0
nperm = 0
if (not path.exists(path.dirname(volume))):
print('File ' + volume + ': no such file or directory.')
elif (not path.exists(volume)):
print('File ' + volume + ': not found in ' + path.dirname(volume))
else:
passfile = open('pass.txt','w')
print("Trying each of the %d possible keys..." % nptot)
if(tryKey(0)):
print('Successfully determined TrueCrypt password: ' + passphrase)
passfile.write(passphrase)
passfile.close()
else:
print('Did not succeed in finding TrueCrypt password in specified keyspace.')
if __name__ == '__main__':
main()
I know, this may be reinventing the wheel, but since I couldn't find something like this myself I decided to cobble it together so that I could use it myself, and only recently I remembered that I had it. I have neglected this blog for ages, and though I'm sharing it just in case it would be useful to someone who Googles for an answer in the future, it's really just the perfect excuse to start posting.
No comments:
Post a Comment