├── .gitignore ├── LICENSE ├── README.md ├── setup.py └── tckfc ├── __init__.py └── tckfc.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Octosec 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tckfc 2 | ===== 3 | 4 | [![Latest Version](https://img.shields.io/pypi/v/tckfc.svg)](https://pypi.python.org/pypi/tckfc/) 5 | [![Downloads](https://img.shields.io/pypi/dm/tckfc.svg)](https://pypi.python.org/pypi/tckfc/) 6 | [![Download format](https://img.shields.io/pypi/format/tckfc.svg)](https://pypi.python.org/pypi/tckfc/) 7 | [![Supported Python versions](https://img.shields.io/pypi/pyversions/tckfc.svg)](https://pypi.python.org/pypi/tckfc/) 8 | [![License](https://img.shields.io/pypi/l/tckfc.svg)](https://pypi.python.org/pypi/tckfc/) 9 | 10 | This tool seeks asynchronously TrueCrypt key file using combinations of provided key files with provided password. 11 | 12 | Installation 13 | ============ 14 | pip install tckfc 15 | 16 | Usage 17 | ===== 18 | 19 | ``tckfc [-h] [-c [COMBINATION]] keyfiles tcfile password`` 20 | 21 | * **keyfiles:** Possible key files directory 22 | * **tcfile:** TrueCrypt encrypted file 23 | * **password:** Password for TrueCrypt file 24 | 25 | Example 26 | ======= 27 | 28 | cp a.pdf keys/ 29 | cp b.doc keys/ 30 | cp c.txt keys/ 31 | cp d.jpg keys/ 32 | cp e.gif keys/ 33 | python tckfc.py keys/ encrypted.img 123456 34 | 35 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/Octosec/tckfc/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 36 | 37 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | try: 2 | from setuptools import setup 3 | except ImportError: 4 | from distutils.core import setup 5 | 6 | config = dict(description='Asynchronously TrueCrypt key file brute force tool', 7 | long_description=open('README.md').read(), 8 | author='Halit Alptekin', 9 | url='https://github.com/Octosec/tckfc', 10 | author_email='info@halitalptekin.com', 11 | license='MIT', 12 | keywords='truecrypt, password, crack, security, tool', 13 | version='0.3.3', 14 | packages=['tckfc'], 15 | scripts=[], 16 | name='tckfc', 17 | entry_points={'console_scripts': ['tckfc = tckfc.tckfc:main', ]}) 18 | 19 | setup(**config) 20 | -------------------------------------------------------------------------------- /tckfc/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.3.3" -------------------------------------------------------------------------------- /tckfc/tckfc.py: -------------------------------------------------------------------------------- 1 | """ 2 | TrueCrypt key file cracker 3 | """ 4 | import argparse 5 | import os 6 | import logging 7 | import sys 8 | import commands 9 | import itertools 10 | import multiprocessing 11 | import functools 12 | import signal 13 | import time 14 | import tempfile 15 | import shutil 16 | 17 | __version__ = "0.2.0" 18 | 19 | # TCKFC log handler file 20 | TCKFC_LOG_FILE = ".tckfc.log" 21 | 22 | # Error messages tuple 23 | ERROR_MESSAGES = ("TrueCrypt File does not exist", "Mount directory does not exist", 24 | "Already mounted", "Key files folder does not exist", 25 | "Combination value should be minimum from number of key files", 26 | "TrueCrypt not installed.") 27 | 28 | 29 | class TCKFCError(Exception): 30 | """ 31 | TrueCrypt Key File Cracker 32 | Base Exception Class 33 | """ 34 | def __init__(self, name): 35 | """ 36 | Constructor method 37 | @name: str 38 | """ 39 | self.name = name 40 | self.logger = logging.getLogger(__name__) 41 | self.logger.warning(name) 42 | 43 | def __repr__(self): 44 | """ 45 | Representation dunder method 46 | """ 47 | return "".format(self.name) 48 | 49 | def __str__(self): 50 | """ 51 | Str dunder method 52 | """ 53 | return "".format(self.name) 54 | 55 | def truecrypt_handler(kc, psw, tcf, mp): 56 | """ 57 | TrueCrypt Handler 58 | @psw: truecrypt file password 59 | @tcf: truecrypt encrypted file 60 | @mp: mount point of truecrypt file 61 | @kc: possible key files 62 | """ 63 | logger = logging.getLogger(__name__) 64 | key_files = ",".join(kc) 65 | logger.debug("Key files: {0}".format(key_files)) 66 | 67 | # Init command line string 68 | command = "truecrypt -t --non-interactive -p {0} -k {1} {2} {3} &> /dev/null" 69 | command = command.format(psw, key_files, tcf, mp) 70 | logger.debug("Command: '{0}'".format(command)) 71 | 72 | # Execute command 73 | result = commands.getstatusoutput(command) 74 | logger.debug("Command result status: '{0}'".format(result[0])) 75 | logger.debug("Command result: '{0}'".format(result[1])) 76 | 77 | # Check the result 78 | if not result[0] and not result[1]: 79 | logger.info("Successfully opened with: '{0}'".format(key_files)) 80 | commands.getstatusoutput("truecrypt -d {0}".format(tcf)) 81 | logger.info("Mount point removed") 82 | sys.exit(0) 83 | else: 84 | logger.info("Failed with: '{0}'".format(key_files)) 85 | 86 | 87 | class TCKFC(object): 88 | """ 89 | TrueCrypt key file cracker 90 | Main class for cracking 91 | """ 92 | def __init__(self, args): 93 | """ 94 | Constructor 95 | @args: argparse instance 96 | """ 97 | # Set the arguments 98 | self.key_files_dir = args.keyfiles 99 | self.tc_file = args.tcfile 100 | self.password = args.password 101 | self.mount_point = tempfile.mkdtemp() 102 | self.combination = args.combination 103 | self.pool = multiprocessing.Pool(multiprocessing.cpu_count(), self.__init_worker) 104 | 105 | # Init the logger 106 | self.logger = logging.getLogger(__name__) 107 | self.logger.debug("Argument parsing is completed") 108 | 109 | # Check args is valid 110 | self.__is_valid() 111 | 112 | # Find all of the possible key files 113 | self.key_files = self.__get_key_files() 114 | self.logger.debug("Key files: {0}".format(self.key_files)) 115 | 116 | def crack(self): 117 | """ 118 | Crack function 119 | """ 120 | # Check the combination number 121 | if len(self.key_files) < self.combination: 122 | raise TCKFCError(ERROR_MESSAGES[4]) 123 | self.logger.debug("Key file combinations {0}".format(self.combination)) 124 | 125 | # Create combinations 126 | combinations = itertools.combinations(self.key_files, self.combination) 127 | 128 | # Create partial crack function 129 | crack_function = functools.partial(truecrypt_handler, psw=self.password, tcf=self.tc_file, mp=self.mount_point) 130 | 131 | # Crack with multiple cores and wait 132 | self.pool.map_async(crack_function, combinations) 133 | 134 | # Handle ctrl-c 135 | try: 136 | time.sleep(10) 137 | except KeyboardInterrupt: 138 | self.pool.terminate() 139 | self.pool.join() 140 | shutil.rmtree(self.mount_point) 141 | else: 142 | self.pool.close() 143 | self.pool.join() 144 | shutil.rmtree(self.mount_point) 145 | 146 | def __get_key_files(self): 147 | """ 148 | Get the key files 149 | return: all possible key files in key_files_dir 150 | """ 151 | # Find the all files in key_files_dir 152 | files = [] 153 | for root, _, file_names in os.walk(self.key_files_dir): 154 | for file_name in file_names: 155 | files.append(os.path.join(os.path.abspath(root), file_name)) 156 | return files 157 | 158 | def __is_valid(self): 159 | """ 160 | Check directories and files are correct 161 | """ 162 | if not os.path.isfile(self.tc_file): 163 | raise TCKFCError(ERROR_MESSAGES[0]) 164 | if not os.path.isdir(self.mount_point): 165 | raise TCKFCError(ERROR_MESSAGES[1]) 166 | if os.path.ismount(self.mount_point): 167 | raise TCKFCError(ERROR_MESSAGES[2]) 168 | if not os.path.isdir(self.key_files_dir): 169 | raise TCKFCError(ERROR_MESSAGES[3]) 170 | if commands.getstatusoutput("which truecrypt")[0]: 171 | raise TCKFCError(ERROR_MESSAGES[4]) 172 | 173 | def __init_worker(self): 174 | signal.signal(signal.SIGINT, signal.SIG_IGN) 175 | 176 | 177 | def main(): 178 | """ 179 | Main function 180 | """ 181 | # Init the root logger with log format 182 | log_formatter = logging.Formatter("[%(asctime)s] [%(levelname)-7.7s] [%(message)s]") 183 | root_logger = logging.getLogger(__name__) 184 | root_logger.setLevel(logging.DEBUG) 185 | 186 | # Init the file handler for logging 187 | file_handler = logging.FileHandler(TCKFC_LOG_FILE) 188 | file_handler.setFormatter(log_formatter) 189 | file_handler.setLevel(logging.DEBUG) 190 | root_logger.addHandler(file_handler) 191 | 192 | # Init the standart error for logging 193 | console_handler = logging.StreamHandler() 194 | console_handler.setLevel(logging.INFO) 195 | console_handler.setFormatter(log_formatter) 196 | root_logger.addHandler(console_handler) 197 | 198 | # Init the argument parser 199 | parser = argparse.ArgumentParser() 200 | parser.add_argument("keyfiles", help="Key directory that contains possible key files", action="store") 201 | parser.add_argument("tcfile", help="TrueCrypt encrypted file", action="store") 202 | parser.add_argument("password", help="TrueCrypt decryption key", action="store") 203 | parser.add_argument("-c", "--combination", help="Keyfile combinations", default=1, nargs='?', type=int) 204 | 205 | # Start 206 | try: 207 | root_logger.debug("Cracking is started") 208 | tckfc = TCKFC(parser.parse_args()) 209 | tckfc.crack() 210 | except TCKFCError: 211 | sys.exit(1) 212 | else: 213 | root_logger.debug("Cracking is completed") 214 | 215 | if __name__ == "__main__": 216 | main() 217 | --------------------------------------------------------------------------------