Skip to content

Add tqdm progress bar support #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 22 additions & 56 deletions compressedcrack/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,14 @@
import argparse
import time
import sys
from tqdm import tqdm

# Default Constants
LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
NUMBERS = "0123456789"
SPECIAL_CHARACTERS = "!@#$%^&*()-_+=~`[]{}|\\:;\"'<>,.?"


def test_archive_password(file_path, password, verbose):
"""
Attempts to extract the archive using the specified password.

Parameters:
- file_path: The path to the archive file.
- password: The password to attempt.
- verbose: If True, prints additional information during the process.

Returns:
- True if the password successfully extracts the archive, False otherwise.
"""

if verbose:
sys.stdout.flush()
try:
Expand All @@ -34,55 +22,42 @@ def test_archive_password(file_path, password, verbose):
except patoolib.util.PatoolError:
return False


def calculate_password_combinations(start_length, max_length, character_set):
return sum(len(character_set) ** i for i in range(start_length, max_length + 1))


def brute_force_password(file_path, start_length, max_length, character_set, verbose):
"""
Generates password combinations within specified length range and character set,
testing each against the provided archive.

Parameters:
- file_path: Path to the archive file to be cracked.
- start_length: Minimum length of passwords to generate.
- max_length: Maximum length of passwords to generate.
- character_set: Characters to use for generating passwords.
- verbose: If True, enables verbose output.

Returns:
- The correct password if found, otherwise None.
- Total number of passwords tried.
- Time taken to process the last subset of passwords.
"""

total_password_count = 0
for length in range(start_length, max_length + 1):
start_time = time.time()
password_count = 0
# if verbose, print total number of passwords will be generated
if verbose:
print("-" * 50)
print(
f"\nGenerating passwords with length {length}...")
print(
f"\nTotal passwords to be generated: {len(character_set) ** length}")
for password_tuple in product(character_set, repeat=length):

# Create tqdm progress bar for the current password length
total_combinations = len(character_set) ** length
progress_bar = tqdm(product(character_set, repeat=length),
total=total_combinations,
desc=f"Trying passwords of length {length}",
unit="password")

for password_tuple in progress_bar:
password = ''.join(password_tuple)
password_count += 1
total_password_count += 1

if test_archive_password(file_path, password, verbose):
progress_bar.close() # Close the progress bar
print(f"\nPassword is correct: {password}")
return password, total_password_count, time.time() - start_time

# Update the progress bar description with attempts count
progress_bar.set_postfix({"Attempts": password_count})

progress_bar.close()
end_time = time.time()
if verbose:
print(
f"\nNo password match found for {password_count} passwords generated with length {length}.")
print(
f"Total time for this subset: {end_time - start_time:.2f} seconds")
return None, total_password_count, 0
print(f"\nNo password match found for {password_count} passwords generated with length {length}.")
print(f"Total time for this subset: {end_time - start_time:.2f} seconds")

return None, total_password_count, 0

def customize_character_set(default_set, set_name):
custom_set = input(
Expand All @@ -92,11 +67,7 @@ def customize_character_set(default_set, set_name):
return custom_set
return default_set


def main():
"""
Main function to parse command line arguments and initiate the brute force process.
"""
parser = argparse.ArgumentParser(
description="Crack password-protected archives using brute force.")
parser.add_argument("file_path", help="Path to the compressed file.")
Expand All @@ -109,24 +80,20 @@ def main():

args = parser.parse_args()

# Interactive character set definition with customization option
character_set = ""
if input("Include letters? (y/n): ").lower().startswith('y'):
character_set += customize_character_set(LETTERS, "letters")
if input("Include numbers? (y/n): ").lower().startswith('y'):
character_set += customize_character_set(NUMBERS, "numbers")
if input("Include special characters? (y/n): ").lower().startswith('y'):
character_set += customize_character_set(
SPECIAL_CHARACTERS, "special characters")
character_set += customize_character_set(SPECIAL_CHARACTERS, "special characters")

if not character_set:
print("\nNo characters selected. Using default character set.")
character_set = LETTERS + NUMBERS + SPECIAL_CHARACTERS

# Print the character set to be used
print(f"\nCharacter set to be used: {character_set}")
print(
f"Total password combinations to be tried: {calculate_password_combinations(args.min_length, args.max_length, character_set)}")
print(f"Total password combinations to be tried: {calculate_password_combinations(args.min_length, args.max_length, character_set)}")

overall_start_time = time.time()
password, total_password_count, subset_time = brute_force_password(
Expand All @@ -141,6 +108,5 @@ def main():
print(f"Total passwords tried: {total_password_count}")
print(f"Total execution time: {overall_time:.2f} seconds")


if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
patool==2.2.0
tqdm