// Copyright 2011-2012 16Systems, LLC. All rights reserved.
// TCHead is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// TCHead is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with TCHead. If not, see .
// Email: TCHead@16s.us
// 16 Systems, LLC
// P.O. Box 356
// Blacksburg, VA
// 24063
// Local Includes
#include "tchead.hpp"
int main( int argc, char * argv[] )
{
Botan::LibraryInitializer init;
boost::program_options::options_description d("\nAllowed options for TCHead");
d.add_options()
("debug,d", "Enable debugging.")
("file,f", boost::program_options::value(), "The TrueCrypt file or disk image to decrypt.")
("help,h", "Show this help message and exit.")
("hidden,H", "Decrypt the hidden volume header.")
("Passwords,P", boost::program_options::value(), "Path to text file of possible passwords or the string 'stdin' to read from std::cin rather than from a file.")
("system,s", "Specify system header.")
("version,v", "Print version and exit.")
;
boost::program_options::variables_map m;
try
{
boost::program_options::store( boost::program_options::parse_command_line( argc, argv, d ), m );
boost::program_options::notify(m);
}
catch ( boost::program_options::unknown_option )
{
std::cout << d << std::endl;
return 1;
}
if ( m.count("help") or argc == 1 )
{
version();
std::cout << d << std::endl;
return 0;
}
if ( m.count("version") )
{
version();
return 0;
}
std::string WORD;
if ( m.count("hidden") )
{
hidden = true;
}
if ( m.count("debug") )
{
debug = true;
}
if ( m.count("system") )
{
system_volume = true;
}
if ( m.count("file") )
{
volume_name = m["file"].as();
}
if ( m.count("Passwords") )
{
WORD_FILE = m["Passwords"].as();
if ( boost::iequals( WORD_FILE, "stdin" ) )
{
STDIN = true;
}
else
{
STDIN = false;
std::ifstream fin ( WORD_FILE.c_str() );
if ( !fin.is_open() )
{
std::cout << WORD_FILE << " cannot be opened.\n";
return 1;
}
fin.close();
}
}
char full_header[full_header_size];
std::ifstream src ( volume_name.c_str(), std::ios::binary );
if ( !src.is_open() )
{
std::cout << "Cannot open " << volume_name << std::endl;
return 1;
}
if ( system_volume )
{
if ( !hidden )
{
src.seekg( 31744 );
}
else
{
std::cerr << "--hidden may not be used with --system\n";
return 1;
}
}
if ( hidden )
{
if ( !system_volume )
{
src.seekg( 65536 );
}
else
{
std::cerr << "--hidden may not be used with --system\n";
return 1;
}
}
src.read( full_header, full_header_size );
src.close();
const std::string full_header_string( full_header, full_header_size );
const std::string salt = get_salt( full_header_string );
const std::string header = get_header( full_header_string );
std::map hashes = hash_map();
std::map::const_iterator hit;
std::map ciphers = load_ciphers();
const Botan::OctetString iv( get_iv() );
if ( STDIN )
{
while ( !std::cin.eof() )
{
getline( std::cin, WORD );
if ( !WORD.empty() )
{
std::cout << WORD << "\n";
// redundant code
for ( hit = hashes.begin(); hit != hashes.end(); ++hit )
{
Botan::PBKDF* pbkdf = Botan::get_pbkdf( hit->first );
const Botan::OctetString key = pbkdf->derive_key( 192, WORD, (Botan::byte*)salt.c_str(), salt.size(), hit->second );
delete pbkdf;
const std::string k1( key.as_string(), 0, 128 );
const std::string k2( key.as_string(), 128, 128 );
const std::string k3( key.as_string(), 256, 128 );
Botan::Pipe pipe( new Botan::Hex_Encoder );
pipe.process_msg( full_header_string );
pipe.process_msg( header );
pipe.process_msg( salt );
const std::string hex_full_header = pipe.read_all_as_string(0);
const std::string hex_header = pipe.read_all_as_string(1);
const std::string hex_salt = pipe.read_all_as_string(2);
const Botan::OctetString key_1 = k1;
const Botan::OctetString key_2 = k2;
const Botan::OctetString key_3 = k3;
if ( debug == true )
{
std::cout << "key: " << key.as_string() << std::endl;
std::cout << "key_1: " << key_1.as_string() << std::endl;
std::cout << "key_2: " << key_2.as_string() << std::endl;
std::cout << "key_3: " << key_3.as_string() << std::endl;
std::cout << "key_1_hex_size: " << key_1.as_string().size() << std::endl;
std::cout << "key_2_hex_size: " << key_2.as_string().size() << std::endl;
std::cout << "key_3_hex_size: " << key_3.as_string().size() << std::endl;
std::cout << "full_header_size: " << sizeof(full_header) << std::endl;
std::cout << "full_header_string_size: " << full_header_string.size() << std::endl;
std::cout << "hex_full_header_size: " << hex_full_header.size() << std::endl;
std::cout << "hex_full_header: " << hex_full_header << std::endl;
std::cout << "header_size: " << header.size() << std::endl;
std::cout << "hex_header_size: " << hex_header.size() << std::endl;
std::cout << "hex_header: " << hex_header << std::endl;
std::cout << "salt_size: " << salt.size() << std::endl;
std::cout << "hex_salt_size: " << hex_salt.size() << std::endl;
std::cout << "hex_salt: " << hex_salt << std::endl;
std::cout << "iterations: " << hit->second << std::endl;
}
std::map::const_iterator cit;
for ( cit = ciphers.begin(); cit != ciphers.end(); ++cit )
{
// Decrypt Individual Ciphers
if ( cit->second == 1 )
{
const std::string header_results( decrypt_header( cit->first, hex_header, key_1, iv ) );
const std::string test( header_results, 0, 8 ); // 64 4
if ( test == magic )
{
Botan::Pipe decode( new Botan::Hex_Decoder );
decode.process_msg( header_results );
const std::string decrypted_header = decode.read_all_as_string(0);
const std::string vol_header_ver( header_results, 8, 4 ); // 68 2
const std::string min_ver( header_results, 12, 4 ); // 70 2
const std::string hidden_size( header_results, 56, 16 ); // 92 8
const std::string volume_size( header_results, 72, 16 ); // 100 8
if ( verify( decrypted_header ) )
{
std::cout << "password: " << WORD << std::endl;
std::cout << "volume: " << volume_name << std::endl;
std::cout << "cipher: " << cit->first << std::endl;
std::cout << "hash: " << hit->first << std::endl;
std::cout << "decrypted_header: " << header_results << std::endl;
std::cout << "volume_header_format_version: " << vol_header_ver << std::endl;
std::cout << "minimum_truecrypt_version_required: " << min_ver << std::endl;
std::cout << std::endl;
return 0;
}
}
}
// Decrypt Two Cascading Ciphers
if ( cit->second == 2 )
{
;
}
// Decrypt Three Cascading Ciphers
if ( cit->second == 3 )
{
;
}
}
}
// end redundant code
}
}
}
else
{
std::ifstream fp ( WORD_FILE.c_str() );
while ( !fp.eof() )
{
getline( fp, WORD );
if ( (WORD[0] == '#') or WORD[0] == ' ' )
{
continue;
}
if ( !WORD.empty() )
{
std::cout << WORD << "\n";
// redundant code
for ( hit = hashes.begin(); hit != hashes.end(); ++hit )
{
Botan::PBKDF* pbkdf = Botan::get_pbkdf( hit->first );
const Botan::OctetString key = pbkdf->derive_key( 192, WORD, (Botan::byte*)salt.c_str(), salt.size(), hit->second );
delete pbkdf;
const std::string k1( key.as_string(), 0, 128 );
const std::string k2( key.as_string(), 128, 128 );
const std::string k3( key.as_string(), 256, 128 );
Botan::Pipe pipe( new Botan::Hex_Encoder );
pipe.process_msg( full_header_string );
pipe.process_msg( header );
pipe.process_msg( salt );
const std::string hex_full_header = pipe.read_all_as_string(0);
const std::string hex_header = pipe.read_all_as_string(1);
const std::string hex_salt = pipe.read_all_as_string(2);
const Botan::OctetString key_1 = k1;
const Botan::OctetString key_2 = k2;
const Botan::OctetString key_3 = k3;
if ( debug == true )
{
std::cout << "key: " << key.as_string() << std::endl;
std::cout << "key_1: " << key_1.as_string() << std::endl;
std::cout << "key_2: " << key_2.as_string() << std::endl;
std::cout << "key_3: " << key_3.as_string() << std::endl;
std::cout << "key_1_hex_size: " << key_1.as_string().size() << std::endl;
std::cout << "key_2_hex_size: " << key_2.as_string().size() << std::endl;
std::cout << "key_3_hex_size: " << key_3.as_string().size() << std::endl;
std::cout << "full_header_size: " << sizeof(full_header) << std::endl;
std::cout << "full_header_string_size: " << full_header_string.size() << std::endl;
std::cout << "hex_full_header_size: " << hex_full_header.size() << std::endl;
std::cout << "hex_full_header: " << hex_full_header << std::endl;
std::cout << "header_size: " << header.size() << std::endl;
std::cout << "hex_header_size: " << hex_header.size() << std::endl;
std::cout << "hex_header: " << hex_header << std::endl;
std::cout << "salt_size: " << salt.size() << std::endl;
std::cout << "hex_salt_size: " << hex_salt.size() << std::endl;
std::cout << "hex_salt: " << hex_salt << std::endl;
std::cout << "iterations: " << hit->second << std::endl;
}
std::map::const_iterator cit;
for ( cit = ciphers.begin(); cit != ciphers.end(); ++cit )
{
// Decrypt Individual Ciphers
if ( cit->second == 1 )
{
const std::string header_results( decrypt_header( cit->first, hex_header, key_1, iv ) );
const std::string test( header_results, 0, 8 ); // 64 4
if ( test == magic )
{
Botan::Pipe decode( new Botan::Hex_Decoder );
decode.process_msg( header_results );
const std::string decrypted_header = decode.read_all_as_string(0);
const std::string vol_header_ver( header_results, 8, 4 ); // 68 2
const std::string min_ver( header_results, 12, 4 ); // 70 2
const std::string hidden_size( header_results, 56, 16 ); // 92 8
const std::string volume_size( header_results, 72, 16 ); // 100 8
if ( verify( decrypted_header ) )
{
std::cout << "password: " << WORD << std::endl;
std::cout << "volume: " << volume_name << std::endl;
std::cout << "cipher: " << cit->first << std::endl;
std::cout << "hash: " << hit->first << std::endl;
std::cout << "decrypted_header: " << header_results << std::endl;
std::cout << "volume_header_format_version: " << vol_header_ver << std::endl;
std::cout << "minimum_truecrypt_version_required: " << min_ver << std::endl;
std::cout << std::endl;
return 0;
}
}
}
// Decrypt Two Cascading Ciphers
if ( cit->second == 2 )
{
;
}
// Decrypt Three Cascading Ciphers
if ( cit->second == 3 )
{
;
}
}
}
// end redundant code
}
}
fp.close();
}
}