This shows you the differences between two versions of the page.
ii:labs:02:tasks:03 [2021/11/07 17:11] radu.mantu |
ii:labs:02:tasks:03 [2024/11/01 10:59] (current) radu.mantu [03. [50p] Solving a substitution cipher] |
||
---|---|---|---|
Line 1: | Line 1: | ||
==== 03. [50p] Solving a substitution cipher ==== | ==== 03. [50p] Solving a substitution cipher ==== | ||
+ | |||
+ | [[https://ocw.cs.pub.ro/courses/_media/ii/labs/02/tasks/crack_ciphertext.png|{{ :ii:labs:02:tasks:crack_ciphertext.png?700 |}}]] | ||
Time to get your hands dirty! Below, you have a [[https://en.wikipedia.org/wiki/Ciphertext|ciphertext]]. Specifically, this output is the result of a [[https://en.wikipedia.org/wiki/Substitution_cipher|substitution cipher]], meaning that every letter in the English alphabet has been assigned a random, unique correspondent. As you may have noticed, digits and special characters remain unchanged. | Time to get your hands dirty! Below, you have a [[https://en.wikipedia.org/wiki/Ciphertext|ciphertext]]. Specifically, this output is the result of a [[https://en.wikipedia.org/wiki/Substitution_cipher|substitution cipher]], meaning that every letter in the English alphabet has been assigned a random, unique correspondent. As you may have noticed, digits and special characters remain unchanged. | ||
- | |||
- | Your task is to write a //Python// script that will help you break the cipher and decode the original text. | ||
- | * [[https://www.pythontutorial.net/python-basics/python-read-text-file/|read]] the ciphertext from a file specified as a command line argument | ||
- | * use a __dictionary__ to map each encoded character back to it's original value | ||
- | * populate this dictionary as you progress in your attempt | ||
- | * whenever you run the script, it should print the text to the screen, with a few minor changes: | ||
- | * any character that exists as a key in the dictionary should be replaced with what you think the correspondent is. | ||
- | * any replaced character should be highlighted in __bold red__. | ||
<spoiler> | <spoiler> | ||
Line 39: | Line 33: | ||
QTLOUJOISO JOTLSHFLVB LK BLTWFUJOUT I JUTZLS RIJ TUIB, OFU WFXTWF GUVVJ TXSH, | QTLOUJOISO JOTLSHFLVB LK BLTWFUJOUT I JUTZLS RIJ TUIB, OFU WFXTWF GUVVJ TXSH, | ||
ISB GLSKPTUJ ISB KPTURLTNJ VPO. | ISB GLSKPTUJ ISB KPTURLTNJ VPO. | ||
- | |||
</code> | </code> | ||
</spoiler> | </spoiler> | ||
+ | |||
+ | Your task is to write a //Python// script that will help you break the cipher and decode the original text: | ||
+ | * [[https://www.pythontutorial.net/python-basics/python-read-text-file/|read]] the ciphertext from a file specified as a command line argument | ||
+ | * use a __dictionary__ to map each encoded character back to it's original value | ||
+ | * __manually__ populate this dictionary as you progress in your attempt and reveal new characters | ||
+ | * whenever you run the script, it should print the text to the screen, with a few minor changes: | ||
+ | * any character that exists as a key in the dictionary should be replaced with what you think the correspondent is. | ||
+ | * any replaced character should be highlighted in __bold red__. | ||
<note tip> | <note tip> | ||
Line 47: | Line 48: | ||
Remember ANSI codes? | Remember ANSI codes? | ||
<code bash> | <code bash> | ||
- | $ echo "\033[1;34m I'm blue... aba di... aba die... aba di aba die...\033[0m" | + | $ echo -e "\033[1;34m I'm blue, da ba dee, dabba daa-ee, dabba dee-a dabba da \033[0m" |
</code> | </code> | ||
---- | ---- | ||
- | In breaking a short substitution cipher like this while also knowing the original language, you need to look at bigrams and trigrams. Small group of letters that have a limited amount of possible values that make sense: //"to"//, //"and"//, //"the"//, etc. | + | In breaking a short substitution cipher like this while also knowing the original language, you need to look at bigrams and trigrams. Small groups of letters that have a limited amount of possible values that make sense: //"to"//, //"and"//, //"the"//, etc. As you reveal more and more of the original text, words will begin to form, making everything progressively easier. |
If you need an extra hint: | If you need an extra hint: | ||
<spoiler> | <spoiler> | ||
- | //"5 SLEUZGUT 1607"// looks like a date. Hmm... | + | //"5 SLEUZGUT"// looks like a date. Hmm... //**"SLEUZGUT"**//... |
</spoiler> | </spoiler> | ||
</note> | </note> | ||
+ | |||
+ | <note> | ||
+ | Already done? Try [[https://ctflearn.com/challenge/238|this challenge]] as well. | ||
+ | |||
+ | ---- | ||
+ | |||
+ | Alternatively, if you want to keep learning python, take a look at [[https://ocw.cs.pub.ro/courses/ep/labs/05|these labs]] for an introduction into //NumPy// (a fundamental module for numeric computation) and //matplotlib// (a module for plotting). | ||
+ | </note> | ||
+ | |||
+ | <solution -hidden> | ||
+ | <file python cracker.py> | ||
+ | #!/usr/bin/python3 | ||
+ | |||
+ | import sys | ||
+ | |||
+ | inv = { | ||
+ | # 'A' : '', | ||
+ | 'B' : 'D', | ||
+ | # 'C' : '', | ||
+ | 'D' : 'X', | ||
+ | 'E' : 'V', | ||
+ | 'F' : 'H', | ||
+ | 'G' : 'B', | ||
+ | 'H' : 'G', | ||
+ | 'I' : 'A', | ||
+ | 'J' : 'S', | ||
+ | 'K' : 'F', | ||
+ | 'L' : 'O', | ||
+ | 'M' : 'J', | ||
+ | 'N' : 'K', | ||
+ | 'O' : 'T', | ||
+ | 'P' : 'I', | ||
+ | 'Q' : 'P', | ||
+ | 'R' : 'W', | ||
+ | 'S' : 'N', | ||
+ | 'T' : 'R', | ||
+ | 'U' : 'E', | ||
+ | 'V' : 'L', | ||
+ | 'W' : 'C', | ||
+ | 'X' : 'U', | ||
+ | 'Y' : 'Y', | ||
+ | 'Z' : 'M', | ||
+ | } | ||
+ | |||
+ | def main(): | ||
+ | # cli arguments check | ||
+ | if len(sys.argv) != 2: | ||
+ | print("Usage ./cracker.py <input_file>") | ||
+ | |||
+ | # read contents of file | ||
+ | with open(sys.argv[1]) as f: | ||
+ | enc = f.read() | ||
+ | |||
+ | # make sure text is uppercase | ||
+ | enc = enc.upper() | ||
+ | |||
+ | # create (partially) translated text | ||
+ | dec = [ it if it not in inv else '\033[1;31m%s\033[0m' % inv[it] \ | ||
+ | for it in enc ] | ||
+ | dec = ''.join(dec) | ||
+ | |||
+ | # print translated text | ||
+ | print(dec) | ||
+ | | ||
+ | # program entry point | ||
+ | if __name__ == '__main__': | ||
+ | main() | ||
+ | </file> | ||
+ | </solution> |