Last active
July 31, 2025 08:45
-
-
Save imneonizer/a403fa5f3fe897df756807819024aae1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# usage: python crack_pdf_password.py --pdf EAadhaar.pdf --age 70 | |
import itertools | |
import multiprocessing | |
from multiprocessing import Manager, Pool | |
from tqdm import tqdm | |
from PyPDF2 import PdfReader | |
import time | |
import threading | |
import argparse | |
from datetime import datetime | |
class PDFPasswordCracker: | |
def __init__(self, pdf_path, approx_age=65, num_workers=4): | |
self.pdf_path = pdf_path | |
self.num_workers = num_workers | |
self.letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
self.approx_age = approx_age | |
self.chunk_size = 100 # number of prefixes per task | |
current_year = datetime.now().year | |
start_year = current_year - (approx_age + 35) | |
end_year = current_year - (approx_age - 5) | |
self.years = [str(y) for y in range(start_year, end_year + 1)] | |
self.total_attempts = 26**4 * len(self.years) | |
def _attempt_passwords(self, args): | |
chunk, password_found_event, shared_dict, counter, lock = args | |
with open(self.pdf_path, "rb") as f: | |
reader = PdfReader(f) | |
for prefix_tuple in chunk: | |
if password_found_event.is_set(): | |
break | |
prefix = "".join(prefix_tuple) | |
for year in self.years: | |
if password_found_event.is_set(): | |
break | |
password = prefix + year | |
try: | |
if reader.decrypt(password): | |
with lock: | |
shared_dict["password"] = password | |
password_found_event.set() | |
return | |
except Exception: | |
pass | |
with lock: | |
counter["value"] += 1 | |
def _chunk_prefixes(self, iterable, chunk_size): | |
it = iter(iterable) | |
while True: | |
chunk = list(itertools.islice(it, chunk_size)) | |
if not chunk: | |
break | |
yield chunk | |
def crack(self): | |
manager = Manager() | |
password_found_event = manager.Event() | |
shared_dict = manager.dict() | |
counter = manager.dict() | |
counter["value"] = 0 | |
lock = manager.Lock() | |
# Create chunks of work | |
prefix_gen = itertools.product(self.letters, repeat=4) | |
chunked_prefixes = list(self._chunk_prefixes(prefix_gen, self.chunk_size)) | |
args = [ | |
(chunk, password_found_event, shared_dict, counter, lock) | |
for chunk in chunked_prefixes | |
] | |
# Progress bar thread | |
def progress_updater(total, counter_dict, stop_event): | |
with tqdm(total=total, desc="Brute-forcing", unit="attempt") as pbar: | |
last = 0 | |
while not stop_event.is_set(): | |
with lock: | |
current = counter_dict["value"] | |
pbar.update(current - last) | |
last = current | |
time.sleep(0.1) | |
stop_event = threading.Event() | |
progress_thread = threading.Thread( | |
target=progress_updater, args=(self.total_attempts, counter, stop_event) | |
) | |
progress_thread.start() | |
with Pool(processes=self.num_workers) as pool: | |
pool.map(self._attempt_passwords, args) | |
stop_event.set() | |
progress_thread.join() | |
if "password" in shared_dict: | |
print(f"\n[✓] Password found: {shared_dict['password']}") | |
return shared_dict["password"] | |
else: | |
print("\n[-] Password not found.") | |
return None | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser(description="Brute-force Aadhaar PDF password") | |
parser.add_argument("--pdf", help="Path to Aadhaar PDF") | |
parser.add_argument( | |
"--age", | |
type=int, | |
default=100, | |
help="Approximate age of the person (default: 100)", | |
) | |
parser.add_argument( | |
"--workers", | |
type=int, | |
default=multiprocessing.cpu_count(), | |
help="Number of parallel workers (default: CPU cores)", | |
) | |
args = parser.parse_args() | |
cracker = PDFPasswordCracker( | |
args.pdf, approx_age=args.age, num_workers=args.workers | |
) | |
cracker.crack() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Use this if first 4 letter of name is already known | |
import PyPDF2 | |
pdf_path = "EAadhaar.pdf" | |
prefix = "GENI" | |
# Load the PDF | |
with open(pdf_path, "rb") as file: | |
reader = PyPDF2.PdfReader(file) | |
for year in range(1925, 2026): | |
password = f"{prefix}{year}" | |
try: | |
if reader.decrypt(password): | |
print(f"Password found: {password}") | |
break | |
except Exception as e: | |
continue | |
else: | |
print("Password not found in given range.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment