2

My school assignment is to make a new cipher based on a rotation 13 cipher, which uses the ord() function to get a character's ASCII value, adds 13, then uses chr() to convert that ASCII value to text. The problem is that it is purely alphabetical, so punctuation will not work. My solution is to create a dictionary of the the ASCII values and their text counterparts and make the input refer to the dictionary, add 13, and then use chr() to convert the value back to text. I do the same with decrypting it, but it subtracts 13. This works fine until I use a character that's value + 13 is out of range. When this happens, the character does not encrypt, thus being blank. With alphabetical characters however, since I use the upper() function, are subtracted by their uppercase counterparts, which are not out of range, so they're subtracted 13 from those characters, not becoming the right character. I.E., lowercase t-z are converted to uppercase, and encrypted become uppercase a-g. If I decrypt them, they become 4,5,6,7,8,9,and : since they're not in the same position as the lowercase values. I've tried making an if than statement changing the decrypted characters into T-Z if it is decrypted into 4-:. Am I over complicating an easy solution? I not, how can I fix these errors?

Encryption Code:

ascii_cipher = {
 ' ' : '32',
 '!' : '33',
 '"' : '34',
 '#' : '35',
 '$' : '36',
 '%' : '37',
 '&' : '38',
 "'" : '39',
 '(' : '40',
 ')' : '41',
 '*' : '42',
 '+' : '43',
 ',' : '44',
 '-' : '45',
 '.' : '46',
 '/' : '47',
 '0' : '48',
 '1' : '49',
 '2' : '50',
 '3' : '51',
 '4' : '52',
 '' : '53',
 '6' : '54',
 '7' : '55',
 '8' : '56',
 '9' : '57',
 ':' : '58',
 ';' : '59',
 '<' : '60',
 '=' : '61',
 '>' : '62',
 '?' : '63',
 '@' : '64',
 'A' : '65',
 'B' : '66',
 'C' : '67',
 'D' : '68',
 'E' : '69',
 'F' : '70',
 'G' : '71',
 'H' : '72',
 'I' : '73',
 'J' : '74',
 'K' : '75',
 'L' : '76',
 'M' : '77',
 'N' : '78',
 'O' : '79',
 'P' : '80',
 'Q' : '81',
 'R' : '82',
 'S' : '83',
 'T' : '84',
 'U' : '85',
 'V' : '86',
 'W' : '87',
 'X' : '88',
 'Y' : '89',
 'Z' : '90',
 '[' : '91',
 '\\' : '92' ,
 ']' : '93',
 '^' : '94',
 '_' : '95',
 '`' : '96',
 'a' : '97',
 'b' : '98',
 'c' : '99',
 'd' : '100',
 'e' : '101',
 'f' : '102',
 'g' : '103',
 'h' : '104',
 'i' : '105',
 'j' : '106',
 'k' : '107',
 'l' : '108',
 'm' : '109',
 'n' : '110',
 'o' : '111',
 'p' : '112',
 'q' : '113',
 'r' : '114',
 's' : '115',
 't' : '116',
 'u' : '117',
 'v' : '118',
 'w' : '119',
 'x' : '120',
 'y' : '121',
 'z' : '122',
 '{' : '123',
 '|' : '124',
 '}' : '125',}
 reverse_ascii_cipher = {v: k for k, v in ascii_cipher.items()}
 def encrypt_extended_rot13(s, direction):
        s = s.upper()
        output = ""
        for ch in s:
          if direction == "encrypt":
           output = output + chr(int(Crypto.ascii_cipher[ch])+13)
          elif direction == "decrypt":
            output = output + chr(int(Crypto.ascii_cipher[ch])-13)

        return output

GUI Code:

from tkinter import *
from tkinter.scrolledtext import*
from Crypto import *
k = 185
root = Tk()
c = Canvas(root,width=800,height=600)
textbox_plain=ScrolledText(root,width=30,height=10,
                           bg="#DDFFDD")
textbox_encrypted=ScrolledText(root,width=30,height=10,
                               bg="#DDDDFF")
textbox_plain.grid(row=1,column=0,padx=10,pady=10)
textbox_encrypted.grid(row=1,column=3,padx=10,pady=10)

frame1 = Frame(root)
frame1.grid(row=1, column=1)
button_encrypt = Button(frame1, text="Encrypt >>")
button_decrypt = Button(frame1, text="<< Decrypt")
button_encrypt.grid(row=0, column=0, padx=10, pady=10)
button_decrypt.grid(row=1, column=0, padx=10, pady=10)
# Some basic labels
label_plain = Label(root, text="Plain Text")
label_encrypted = Label(root, text="Encrypted Text")
label_plain.grid(row=0, column=0, pady=(10,0))
label_encrypted.grid(row=0, column=3, pady=(10, 0))
# Create two ScrolledText objects
textbox_plain = ScrolledText(root, width=30,
height=10, bg="#DDFFDD")
textbox_encrypted = ScrolledText(root, width=30,    
height=10, bg="#DDDDFF")
textbox_plain.grid(row=1, column=0, padx=10, pady=10)
textbox_encrypted.grid(row=1, column=3, padx=10, pady=10)
def encrypt():
 plain = textbox_plain.get(1.0, "end-1c")
 encrypted = Crypto.encrypt_extended_rot13(plain,"encrypt")
 textbox_encrypted.delete(1.0, "end")
 textbox_encrypted.insert(1.0, encrypted)
 print(encrypted)
def decrypt():
 encrypted = textbox_encrypted.get(1.0, "end-1c")
 decrypted = Crypto.encrypt_extended_rot13(encrypted,"decrypt")
 textbox_plain.delete(1.0, "end")
 textbox_plain.insert(1.0, decrypted)
frame1 = Frame(root)
frame1.grid(row=1, column=1)
button_encrypt = Button(frame1, text="Encrypt >>",
 command=encrypt)
button_decrypt = Button(frame1, text="<< Decrypt",
 command=decrypt)
button_encrypt.grid(row=0, column=0, padx=10, pady=10)
button_decrypt.grid(row=1, column=0, padx=10, pady=10)
mainloop()
Mike Fleitz
  • 31
  • 1
  • 7

1 Answers1

1

Yes, you are over complicating the solution. The thing about the rot 13 (or any rotational cipher) is that if you are adding so you end up outside the given interval, you should start over at the lower end. Thus, whatever set of input characters you allow, you should generate output within the same set. So, assuming we limit the cipher to handle capital letters A-Z, then all encrypted characters should also be within this range.

Now, on to your solution; your ascii_cipher dict is not adding any value. chrworks perfectly fine on the same values, including punctuation. However, I would imagine that those characters should be excluded from the encrypted characters. Thus, assuming we want to encrypt a message of letters A-Z using rot13, then the encrypt function could look something like:

def encrypt_letter(ch, rot=13):
    if ch < 'A' or ch > 'Z':
        # This is outside the allowed range, just return the letter
        return ch
    else:
        # Normalise and modulus add rotation
        set_size = ord('Z') - ord('A') + 1
        return chr((ord(ch) - ord('A') + rot) % set_size + ord('A'))

def encrypt_msg(str, rot=13):
    return "".join([encrypt_letter(ch, rot) for ch in str])

And then we can derive the decrypt function by encrypting with a negative rotation:

def decrypt_msg(str, rot=13):
    return encrypt_msg(str, -rot)

Make an attempt to understand the code I have written as it contains some nice python constructs, such as list comprehension.

JohanL
  • 6,671
  • 1
  • 12
  • 26
  • what do you mean by "those characters should be excluded from the encrypted characters"? I am trying to include punctuation within this module, not exclude it. – Mike Fleitz Apr 27 '17 at 14:15
  • Sure, you _can_ do that, but that is typically not done for these type of ciphers. Instead, to make them "harder" to crack, the white spacing and the punctuation is normally removed altogether and the letters grouped into groups of e.g. 5. If you _still_ want to include small letters (which you do not seem to do in your original solution), punctuation, and spacing, you should increase the `set_size` and move the limits. I.e., replace all `'A'`:s with `' '` (space) and `'Z'`:s with `'}'`. – JohanL Apr 27 '17 at 18:16
  • I do not understand what you mean, my assigment is to create a rotation cipher that can encryt punctuation as well as letters.p – Mike Fleitz Apr 28 '17 at 14:13
  • OK, I don't like that assignment, but that's another question. ;-) Exactly what counts as punctuation. Which characters should be covered? Small letters? All ascii caracters including non-printable? – JohanL Apr 28 '17 at 14:19
  • Characters from "space to "}" in ascii. – Mike Fleitz May 01 '17 at 19:08
  • OK, then change as I wrote in the comment above `'A'` to `' '` and `'Z'` to `'}'` (in all places). – JohanL May 01 '17 at 19:10