Skip to content

Instantly share code, notes, and snippets.

@hoehrmann
Created October 9, 2013 21:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hoehrmann/6908712 to your computer and use it in GitHub Desktop.
Save hoehrmann/6908712 to your computer and use it in GitHub Desktop.
Compute a TrueCrypt password from a TrueCrypt password and associated keyfiles.
#!perl -w
use Modern::Perl;
use String::CRC32;
use MIME::Base64;
use autodie;
#####################################################################
# Apply keyfiles to TrueCrypt passwords -- TrueCrypt allows users to
# specify one or more keyfiles that are applied to user passwords to
# make password recovery more difficult. Oddly, many of the popular
# TrueCrypt password recovery programs do not support keyfiles. This
# tool computes the derived password offline to close that gap. Note
# that derived passwords usually contain bytes outside the range of
# printable ASCII, and TrueCrypt does not really support passwords
# with non-ASCII characters in them, and password recovery tools are
# often unable to handle newlines in passwords. At least on Windows
# though, with the proper escaping applied the bytes pass through ok,
# see the code below. The derived password is printed out with a pre-
# fix `base64:` followed by the encoded bytes to be binary-safe.
#####################################################################
die "Usage: $0 password /path/to/keyfile1 ...\n" unless @ARGV > 1;
my ($p, @files) = @ARGV;
sub apply_keyfiles_to_password {
my ($p, @files) = @_;
my $P = $p;
my $kpl = 64;
my @KP = (0) x ($kpl);
if ($kpl > length($P)) {
$P .= ("\x00") x ($kpl - length($P));
}
for my $keyfile (@files) {
my $pool_pos = 0;
my $bytes = do {
open my $f, '<', $keyfile;
binmode $f;
# TrueCrypt will read no more than 1 MB of a keyfile
local $/ = \1048576;
<$f>;
};
my $crc = crc32('');
for my $byte (split //, $bytes) {
$crc = crc32($byte, $crc);
my @digest = split //, pack('N', ~$crc);
for my $crc_byte (@digest) {
$KP[ $pool_pos++ % $kpl ] += ord($crc_byte);
}
}
}
my $pwd = do {
my @P = map { ord } split //, $P;
for my $ix (0 .. $kpl - 1) {
$P[$ix] += $KP[$ix];
}
join '', map { chr($_ % (2**8)) } @P;
};
}
my $pwd = apply_keyfiles_to_password($p, @files);
print "base64:" . do { encode_base64($pwd) =~ s/\s+//r };
__END__
use Win32;
use Win32::Process;
use Win32::ShellQuote qw//;
my $quoted_pwd = Win32::ShellQuote::quote_native($pwd);
Win32::Process::Create(
my $ProcessObj,
"TrueCrypt.exe",
"/v example.truecrypt /p $quoted_pwd /s /q /l x:",
0,
NORMAL_PRIORITY_CLASS,
"."
) or die;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment