Lab 4-3: Cracking the Caesar Cipher¶
Note: Part of this lab came from Al Sweigart’s great book, Hacking Secret Ciphers with Python: A beginner’s Guide to cryptography and computer programming with Python, available online here at Invent With Python, among his other works. Feel free to check them out if they interest you!
Tutorial - Importing Custom Modules¶
Note to readers: This Tutorial section will be placed in its own page later in the curriculum building process, before this lab. Students will already know all this by the time they reach this lab.
Let’s start with a simple example. Create a file called sample_module.py
and another called import_functions.py
. It is super important that these two files be in the same directory.
Copy and paste the following code into sample_module.py
, then save the file.
1 2 3 4 5 6 7 8 | def say_hello():
print("Hello World!")
def add(a,b):
return a + b
def print_mult(a,b,c):
print(a * b * c)
|
Then start editing import_functions.py
. The goal here is to be able to access the python functions found in sample_module.py
.
Importing Entire Modules¶
Normally, if we wanted to access the random
or getpass
module, we would use import random
or import getpass
.
We can do the same with our own python file, sample_module.py
by using the code import sample_module
. This gives us access to the say_hello
, add
, and print_mult
functions from sample_module.py
.
Try running the following code in your python IDE:
1 2 3 4 5 | import sample_module
sample_module.say_hello()
print(sample_module.add(1,2))
sample_module.print_mult(2,3,2)
|
It should work as if those functions were defined in this file! Right now you are importing functions from a module that you created!
Importing Modules with an Alias¶
Then try running the following code in your python IDE:
1 2 3 4 5 | import sample_module as sm
sm.say_hello()
print(sm.add(1,2))
sm.print_mult(2,3,2)
|
Using as sm
after the import
statement means that we are giving the module another custom name, or an alias, from which we can access its functions - in this case, that custom name is sm
. You can see in the code function calls, we now call upon sm
instead of sample_module
. Note that the naming rules for aliases are the same as variables in python.
Importing Specific Functions from a Module¶
Then try running the following code in your python IDE:
1 2 3 | from sample_module import say_hello
say_hello()
|
You’ll notice that this time, we used a new keyword, from
. We import the say_hello
function from sample_module.py
. Unlike the previous examples, we are no longer importing ALL functions from the module - only the say_hello
function. If we wanted to import multiple functions from a module, we would just use a comma to separate them. For example: from sample_module import say_hello, add
.
Also note that when we call the function, we don’t need to reference its module.
Importing Specific Functions with an Alias¶
Lastly, we can combine everything we’ve learned to import a specific function from a module AND give it an alias! See the following short example:
1 2 3 | from sample_module import say_hello as sh
sh()
|
In this case, we are importing the say_hello
function from the sample_module.py
module, and giving it an alias of sh
, allowing us to perform the function call sh()
instead of say_hello()
. No other functions from sample_module.py
are imported with this statement. Note that using a single from
/import
/as
is limited to only importing a single function at a time.
Lab Requirements and Specifications¶
The Caesar cipher can be cracked by hand with only a little bit of time and perhaps some luck. However, the Caesar cipher can be cracked even faster by the computer, and that is what you are going to create in this lab.
You will be cracking the Caesar cipher using a method called “brute forcing” - trying every possible key/combination until you get the right one. Since the Caesar cipher only has 26 keys, this is a very trivial problem for a computer.
In order to do this lab, you need to have completed Lab 4-2 - Encrypting and Decrypting the Caesar Cipher.
You should name your file FILN_brute_caesar.py
, where FILN is your first initial and last name, no space. In addition, your file should be saved in the same directory as your Caesar Cipher python program. For the purposes of this lab, if I reference a file or module named caesar.py
or caesar
, it should be the same as your personal caesar file.
Previously, you learned how to import functions you’ve created in other .py
files. In your caesar.py
file, you should have created three functions - encrypt()
, decrypt()
, and main()
. In this lab, we will only be using the decrypt()
function.
Your first step should be to import the decrypt
function from your caesar.py
module. Feel free to give it an alias if desired.
Your main goal is to, given an encrypted string, use the imported decrypt
function to print out every possible decryption of that string. This can be done without defining any new functions in brute_caesar.py
. In fact, then entire program to brute force a message using an imported function can be as small as 5 lines!
Testing Your Program¶
You can attempt to bruteforce any encrypted message - and you can encrypt any message using your caesar.py
file!
For fun, you can also try decrypting this message through bruteforcing:
PMTTW NZWU BPM XIAB! BPMZM QA VWBPQVO BW AMM PMZM. EMTKWUM BW BPM EWZTL WN KZGXBWOZIXPG. BWBITTG NCV ABCNN!
Here is a sample output of what a brute force attempt might look like for the message:
YRJ REPFEV IVRCCP SVVE WRI RJ UVTZUVU KF LJV VMVE XF NREK KF UF CFFB DFIV CZBV
:
Key 0: YRJ REPFEV IVRCCP SVVE WRI RJ UVTZUVU KF LJV VMVE XF NREK KF UF CFFB DFIV CZBV
Key 1: XQI QDOEDU HUQBBO RUUD VQH QI TUSYTUT JE KIU ULUD WE MQDJ JE TE BEEA CEHU BYAU
Key 2: WPH PCNDCT GTPAAN QTTC UPG PH STRXSTS ID JHT TKTC VD LPCI ID SD ADDZ BDGT AXZT
Key 3: VOG OBMCBS FSOZZM PSSB TOF OG RSQWRSR HC IGS SJSB UC KOBH HC RC ZCCY ACFS ZWYS
Key 4: UNF NALBAR ERNYYL ORRA SNE NF QRPVQRQ GB HFR RIRA TB JNAG GB QB YBBX ZBER YVXR
Key 5: TME MZKAZQ DQMXXK NQQZ RMD ME PQOUPQP FA GEQ QHQZ SA IMZF FA PA XAAW YADQ XUWQ
Key 6: SLD LYJZYP CPLWWJ MPPY QLC LD OPNTOPO EZ FDP PGPY RZ HLYE EZ OZ WZZV XZCP WTVP
Key 7: RKC KXIYXO BOKVVI LOOX PKB KC NOMSNON DY ECO OFOX QY GKXD DY NY VYYU WYBO VSUO
Key 8: QJB JWHXWN ANJUUH KNNW OJA JB MNLRMNM CX DBN NENW PX FJWC CX MX UXXT VXAN URTN
Key 9: PIA IVGWVM ZMITTG JMMV NIZ IA LMKQLML BW CAM MDMV OW EIVB BW LW TWWS UWZM TQSM
Key 10: OHZ HUFVUL YLHSSF ILLU MHY HZ KLJPKLK AV BZL LCLU NV DHUA AV KV SVVR TVYL SPRL
Key 11: NGY GTEUTK XKGRRE HKKT LGX GY JKIOJKJ ZU AYK KBKT MU CGTZ ZU JU RUUQ SUXK ROQK
Key 12: MFX FSDTSJ WJFQQD GJJS KFW FX IJHNIJI YT ZXJ JAJS LT BFSY YT IT QTTP RTWJ QNPJ
Key 13: LEW ERCSRI VIEPPC FIIR JEV EW HIGMHIH XS YWI IZIR KS AERX XS HS PSSO QSVI PMOI
Key 14: KDV DQBRQH UHDOOB EHHQ IDU DV GHFLGHG WR XVH HYHQ JR ZDQW WR GR ORRN PRUH OLNH
Key 15: JCU CPAQPG TGCNNA DGGP HCT CU FGEKFGF VQ WUG GXGP IQ YCPV VQ FQ NQQM OQTG NKMG
Key 16: IBT BOZPOF SFBMMZ CFFO GBS BT EFDJEFE UP VTF FWFO HP XBOU UP EP MPPL NPSF MJLF
Key 17: HAS ANYONE REALLY BEEN FAR AS DECIDED TO USE EVEN GO WANT TO DO LOOK MORE LIKE
Key 18: GZR ZMXNMD QDZKKX ADDM EZQ ZR CDBHCDC SN TRD DUDM FN VZMS SN CN KNNJ LNQD KHJD
Key 19: FYQ YLWMLC PCYJJW ZCCL DYP YQ BCAGBCB RM SQC CTCL EM UYLR RM BM JMMI KMPC JGIC
Key 20: EXP XKVLKB OBXIIV YBBK CXO XP ABZFABA QL RPB BSBK DL TXKQ QL AL ILLH JLOB IFHB
Key 21: DWO WJUKJA NAWHHU XAAJ BWN WO ZAYEZAZ PK QOA ARAJ CK SWJP PK ZK HKKG IKNA HEGA
Key 22: CVN VITJIZ MZVGGT WZZI AVM VN YZXDYZY OJ PNZ ZQZI BJ RVIO OJ YJ GJJF HJMZ GDFZ
Key 23: BUM UHSIHY LYUFFS VYYH ZUL UM XYWCXYX NI OMY YPYH AI QUHN NI XI FIIE GILY FCEY
Key 24: ATL TGRHGX KXTEER UXXG YTK TL WXVBWXW MH NLX XOXG ZH PTGM MH WH EHHD FHKX EBDX
Key 25: ZSK SFQGFW JWSDDQ TWWF XSJ SK VWUAVWV LG MKW WNWF YG OSFL LG VG DGGC EGJW DACW
We can see clearly that the only one that makes sense is key 17
.
The following space is provided in case you want to test code out or write it in the browser:
Taking it Further¶
We wrote a program to brute force the Caesar Cipher, but it still involves a human to read its results and select the actual solution from a list of mostly gibberish. It saves us time, but can still be improved. As an extension to this project, I want you to consider possible ways we can have the computer detect whether a given decryption is actually English or not. If we can effectively build an English detector, we can remove the human element from our program. We’ll be able to run the program for an encrypted message and one correct decryption will be shown on the screen.
To reiterate, do not try to code it yourself (unless you’re sure of your idea) - I just want you to brainstorm.