7
\$\begingroup\$

As an exercise, I wrote a program to decrypt a PDF file. The only thing that is known about the encryption password is that it is a single English word (all capital or lowercase).

The program uses a dictionary file containing over 45000 words to unlock the file. It looks like this:

dictionary.txt

AARHUS
AARON
ABABA
ABACK
ABAFT
ABANDON
ABANDONED
ABANDONING
ABANDONMENT
ABANDONS
ABASE
ABASED
ABASEMENT
ABASEMENTS
ABASES
ABASH
ABASHED
ABASHES
⋮
ZEROTH
ZEST
ZEUS
ZIEGFELD
ZIEGFELDS
ZIEGLER
ZIGGY
ZIGZAG
ZILLIONS
ZIMMERMAN
ZINC
ZION
ZIONISM
ZIONIST
ZIONISTS
ZIONS
ZODIAC
ZOE
ZOMBA
ZONAL
ZONALLY
ZONE
ZONED
ZONES
ZONING
ZOO
ZOOLOGICAL
ZOOLOGICALLY
ZOOM
ZOOMS
ZOOS
ZORN
ZOROASTER
ZOROASTRIAN
ZULU
ZULUS
ZURICH

pdf_password_breaker

"""
Brute force password breaker using a dictionary containing
English words.
"""
import sys
import PyPDF2
from pathlib import Path
def get_filename_from_user() -> Path:
 """Asks for a path from the User"""
 while True:
 filename: str = input("Enter filename in folder of script:")
 path: Path = Path(sys.path[0], filename)
 if path.is_file():
 return path.as_posix()
 print("File doesn't exist\n")
def decrypt(pdf_filename: Path, password: str) -> bool:
 """
 Try to decrypt a file. If not successful a false is returned.
 If the file passed is not encrypted also a false is passed
 """
 with open(pdf_filename, 'rb') as pdf_file:
 pdf_reader = PyPDF2.PdfFileReader(pdf_file)
 pdf_reader.decrypt(password)
 pdf_writer = PyPDF2.PdfFileWriter()
 try:
 for page_number in range(pdf_reader.numPages):
 pdf_writer.addPage(pdf_reader.getPage(page_number))
 except PyPDF2.utils.PdfReadError:
 return False
 new_name: str = pdf_filename.stem + "_decrypted.pdf"
 filename_decrypted = pdf_filename.parent / new_name
 with open(filename_decrypted, 'wb') as pdf_file_decrypted:
 pdf_writer.write(pdf_file_decrypted)
 return True
def break_encryption(pdf_filename: Path, dictionary_filename: str) -> bool:
 """Try's out words from a dictionary to break encryption"""
 with open(dictionary_filename, 'r') as dictionary_file:
 keyword: str = dictionary_file.readline().strip()
 if decrypt(pdf_filename, keyword):
 return keyword
 if decrypt(pdf_filename, keyword.lower()):
 return keyword.lower()
 while keyword:
 keyword = dictionary_file.readline().strip()
 if decrypt(pdf_filename, keyword):
 return keyword
 if decrypt(pdf_filename, keyword.lower()):
 return keyword.lower()
 return None
def pdf_password_breaker():
 """main loop"""
 filename: Path = get_filename_from_user()
 password: str = break_encryption(filename, "dictionary.txt")
 if password:
 print("File unlocked. Password was:" + password)
 return
 print("File could not be unlocked")
if __name__ == "__main__":
 pdf_password_breaker()

I tried a file with a simple password like "hello". It works but it takes a lot of time until it reaches the "hello" in the file.

I wonder if theres a way to improve the speed, or any other aspect of the code.

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Jan 16, 2019 at 17:25
\$\endgroup\$
0

1 Answer 1

14
\$\begingroup\$

Looking at the documentation of PdfFileReader.decrypt It states that it return 0 if the file fails or 1 if it succeeds.

You can also use isEncrypted to check if the file was encrypted in the first place.

So you can turn the loop around. First open the pdf file see if it was encrypted at all and if so try to call decrypt with every password in your dictionary.

answered Jan 16, 2019 at 17:31
\$\endgroup\$
2
  • 1
    \$\begingroup\$ And in doing that, only open the PDF file once - opening it twice for every password is a huge slow down. \$\endgroup\$ Commented Jan 16, 2019 at 23:38
  • \$\begingroup\$ i tryed that approach. it got quite a bit faster. but to crack hello it still takes quite some time \$\endgroup\$ Commented Jan 17, 2019 at 17:00

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.