Cryptography Fun

Thread Solved

Join Date: Jun 2005
Posts: 146
Reputation: G-Do is an unknown quantity at this point 
Solved Threads: 28
G-Do's Avatar
G-Do G-Do is offline Offline
Junior Poster

Cryptography Fun

 
0
  #1
Aug 25th, 2005
Here's a cute little encipher/decipher program with a Tkinter GUI I wrote a while back. It's an implementation of a derivative of the Vigenere algorithm; the algorithm is taken from Laurence Smith's Cryptography: The Science of Secret Writing, Amazon link here. It's a dated book (and the technique itself is very old), so don't expect any serious security from this - just something fun to think about.
  1. # vigenere.py, a modification of the Vigenere ciphering program
  2. # Uses Tkinter
  3. import sys, string, tkMessageBox
  4. from Tkinter import *
  5. # -- The application class
  6. class Vigenere:
  7. # Initialize new instances of Vigenere
  8. def __init__(self, root):
  9. self.root = root
  10. self.makeStringVars()
  11. self.makeWidgets()
  12. # Initialize all widget-bound StringVars
  13. def makeStringVars(self):
  14. self.sv_message = StringVar(); self.sv_message.set("")
  15. self.sv_keyword = StringVar(); self.sv_keyword.set("")
  16. self.sv_alphakey = StringVar(); self.sv_alphakey.set("")
  17. # Initialize all Tkinter widgets
  18. def makeWidgets(self):
  19. # Set the application window's title and make it unresizable
  20. self.root.title("Vigenere")
  21. self.root.resizable(0, 0)
  22. # Make the main Frame for all widgets
  23. fr_main = Frame(self.root); fr_main.pack()
  24. # Make the Frame for the message widgets
  25. fr_message = Frame(fr_main); fr_message.pack()
  26. # Make the Frames for all keyword and alphakey widgets
  27. fr_keys = Frame(fr_main); fr_keys.pack(pady=10)
  28. fr_labels = Frame(fr_keys); fr_labels.pack(side=LEFT)
  29. fr_entries = Frame(fr_keys); fr_entries.pack(side=LEFT)
  30. # Make the Frame for the 'Encipher' and 'Decipher' Buttons
  31. fr_buttons = Frame(fr_main); fr_buttons.pack(pady=10)
  32. # Make the message Label and Entry
  33. lb_text = Label(fr_message, text="Text or Ciphertext")
  34. lb_text.pack()
  35. self.en_message = Entry(fr_message, width=60,
  36. textvariable=self.sv_message)
  37. self.en_message.pack()
  38. self.en_message.focus_set()
  39. # Make the keyword and alphakey Labels and Entries
  40. lb_keyword = Label(fr_labels, text="Keyword:")
  41. lb_alphakey = Label(fr_labels, text="Alphabet Key:")
  42. lb_keyword.pack(anchor="e"); lb_alphakey.pack(anchor="e")
  43. en_keyword = Entry(fr_entries, width=40,
  44. textvariable=self.sv_keyword)
  45. en_alphakey = Entry(fr_entries, width=40,
  46. textvariable=self.sv_alphakey)
  47. en_keyword.pack(); en_alphakey.pack()
  48. # Make the 'Encipher' and 'Decipher' Buttons
  49. bt_encipher = Button(fr_buttons, text="Encipher",
  50. command=self.encipher)
  51. bt_decipher = Button(fr_buttons, text="Decipher",
  52. command=self.decipher)
  53. bt_encipher.pack(side=LEFT); bt_decipher.pack(side=LEFT)
  54. # Callback which wraps the encipher function
  55. def encipher(self):
  56. # Grab the message, the keyword, and the alphakey
  57. message = self.sv_message.get()
  58. keyword = self.sv_keyword.get()
  59. alphakey = self.sv_alphakey.get()
  60. # If anything is missing, popup an error dialog
  61. # Otherwise, replace the current message with the
  62. # enciphered message
  63. if len(message) == 0 or len(keyword) == 0 or len(alphakey) == 0:
  64. self.popError(message, keyword, alphakey)
  65. else:
  66. self.en_message.delete(0, END)
  67. self.en_message.insert(END,
  68. encipher(message, keyword, alphakey))
  69. # Callback which wraps the decipher function
  70. def decipher(self):
  71. # Grab the message, the keyword, and the alphakey
  72. message = self.sv_message.get()
  73. keyword = self.sv_keyword.get()
  74. alphakey = self.sv_alphakey.get()
  75. # If anything is missing, popup an error dialog
  76. # Otherwise, replace the current message with the
  77. # deciphered message
  78. if len(message) == 0 or len(keyword) == 0 or len(alphakey) == 0:
  79. self.popError(message, keyword, alphakey)
  80. else:
  81. self.en_message.delete(0, END)
  82. self.en_message.insert(END,
  83. decipher(message, keyword, alphakey))
  84. # Popup a dialog which informs the user not to leave fields blank
  85. def popError(self, message, keyword, alphakey):
  86. error = "These boxes can't be left blank:\n"
  87. if len(message) == 0: error = error+"Text or Ciphertext, "
  88. if len(keyword) == 0: error = error+"Keyword, "
  89. if len(alphakey) == 0: error = error+"Alphakey, "
  90. error = error[0:len(error)-2]
  91. tkMessageBox.showerror(title="Error", message=error)
  92. # -- Module functions
  93. # -- Encipher a text using keyword and alphakey
  94. def encipher(text, keyword, alphakey):
  95. # Clean up the text, keyword, and alphakey
  96. text, keyword, alphakey = clean(text, keyword, alphakey)
  97. # Build the major alphabet and the cipher alphabets
  98. major = makeMajor(keyword)
  99. ciphers = makeCiphers(major, alphakey)
  100. # For each character in text, add the substitution character to
  101. # the ciphertext
  102. ciphertext = ""
  103. for i in range(len(text)):
  104. cipher = ciphers[i%len(alphakey)]
  105. substitute = cipher[string.find(major, text[i])]
  106. ciphertext = ciphertext+substitute
  107. return ciphertext
  108. # -- Decipher a text using keyword and alphakey
  109. def decipher(ciphertext, keyword, alphakey):
  110. # Clean up the text, keyword, and alphakey
  111. ciphertext, keyword, alphakey = clean(ciphertext, keyword,
  112. alphakey)
  113. # Build the major alphabet and the cipher alphabets
  114. major = makeMajor(keyword)
  115. ciphers = makeCiphers(major, alphakey)
  116. # For each character in ciphertext, add the correct character to
  117. # the text
  118. text = ""
  119. for i in range(len(ciphertext)):
  120. cipher = ciphers[i%len(alphakey)]
  121. correct = major[string.find(cipher, ciphertext[i])]
  122. text = text+correct
  123. return text
  124. # -- Clean up the text, keyword, and alphakey
  125. def clean(text, keyword, alphakey):
  126. # Get rid of quotes
  127. text = text.replace("\"", "").replace("\'", "")
  128. keyword = keyword.replace("\"", "").replace("\'", "")
  129. alphakey = alphakey.replace("\"", "").replace("\'", "")
  130. # Remove redunant characters from the keyword and alphakey
  131. keyword, alphakey = collapse(keyword), collapse(alphakey)
  132. # Return all three strings
  133. return text, keyword, alphakey
  134. # -- Remove all duplicate letters from keys
  135. def collapse(key):
  136. ret = ""
  137. for i in range(len(key)):
  138. letter = key[i]
  139. duplicate = False
  140. for j in range(i+1, len(key)):
  141. if letter == key[j]: duplicate = True
  142. if not duplicate: ret = ret+letter
  143. return ret
  144. # -- Build the major cipher alphabet around the input keyword
  145. def makeMajor(keyword):
  146. ret = keyword
  147. alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"+ \
  148. ":.;,?!@#$%&()+=-*/_<> []{}`~^"+ \
  149. "abcdefghijklmnopqrstuvwxyz"
  150. for i in range(len(alphabet)):
  151. if not alphabet[i] in ret: ret = ret+alphabet[i]
  152. return ret
  153. # -- Build the cipher alphabets using the major alphabet and alphakey
  154. def makeCiphers(major, alphakey):
  155. ret = []
  156. for i in range(len(alphakey)):
  157. index = string.index(major, alphakey[i])
  158. ret.append(major[index:]+major[:index])
  159. return ret
  160. # -- Main function
  161. def main(args):
  162. root = Tk()
  163. v = Vigenere(root)
  164. root.mainloop()
  165. # -- The following code executes upon command-line invocation
  166. if __name__ == "__main__": main(sys.argv)
Do you see how it works? Ignore the Tkinter stuff - do you see what the enciphering and deciphering algorithms are doing?

To encipher text, first you must:
Strip the text, keyword, and alphakey of quotes (I couldn't get quotes to work), then remove redundant characters from the keyword and the alphakey. Create a major cipher alphabet by pulling the characters of the keyword out of the alphabet and sticking the keyword in front. In other words, if your alphabet looks like:

ABCDEFGHIJKLMNOPQRSTUVWXYZ

- and your keyword is PANTS, your major cipher alphabet will look like:

PANTSBCDEFGHIJKLMOQRUVWXYZ

Then, create a list of cipher alphabets based on your alphabet key (alphakey). Basically, for every character in alphabet key, "rotate" the alphabet so that character is in front. In other words, if your major cipher alphabet is the one we just saw, and your alphabet key is OMG, your list of cipher alphabets will be:

OQRUVWXYZPANTSBCDEFGHIJKLM
MOQRUVWXYZPANTSBCDEFGHIJKL
GHIJKLMOQRUVWXYZPANTSBCDEF

And that's just the groundwork - we haven't even started enciphering yet!

Now, here's where it gets complicated. This is a substitution cipher, which means that it works by exchanging characters for other characters. The central weakness of substitution ciphers is that they are easily broken by letter-frequency analyses - in other words, a smart cryptanalyst would look through the enciphered text for the frequencies of certain characters, and based on these frequencies, make guesses about which characters they represent in normal English. Our approach throws them off (a little) because there isn't a one-to-one map between our plain text characters and our enciphered text characters - we employ letter positions and multiple alphabets to do the substitution, as we shall see.

The enciphering algorithm is:
For each character in your plain text message, look at the character's string index. Divide this number by the length of the alphabet key and take the remainder. The remainder will be the list index of the cipher alphabet you are going to use. Then, find the index of the character in the major cipher alphabet. Find the character at the same index in the cipher alphabet you have just chosen. This is the character you will substitute.

So, if our message is MESSAGE, and we're on the first character (M):
The string index is 0. The length of the alphabet key (OMG) is three. The reminder of 0/3 is 0. This means we are going to use the first cipher alphabet, OQRUVWXYZPANTSBCDEFGHIJKLM, because it is the alphabet at index 0 in our alphabets list. Next, we try to find the index of M in the major cipher alphabet. We see that M is the seventeenth character, so the string index is 16. We take the character at the same position in our cipher alphabet: D. This is the character we will substitute for M.

Understanding the deciphering algorithm is left as an exercise to the reader.
Vi veri veniversum vivus vici
Reply With Quote Quick reply to this message  
Join Date: Oct 2004
Posts: 3,983
Reputation: vegaseat is just really nice vegaseat is just really nice vegaseat is just really nice vegaseat is just really nice vegaseat is just really nice 
Solved Threads: 926
Moderator
vegaseat's Avatar
vegaseat vegaseat is offline Offline
DaniWeb's Hypocrite

Re: Cryptography Fun

 
0
  #2
Aug 26th, 2005
G-Do very nice indeed! This would make a good contribution to the Python Code Snippets on DaniWeb. Right now there is mostly my stuff there, new blood and new ideas are always welcome! Just a thought.
May 'the Google' be with you!
Reply With Quote Quick reply to this message  
Join Date: Jun 2005
Posts: 146
Reputation: G-Do is an unknown quantity at this point 
Solved Threads: 28
G-Do's Avatar
G-Do G-Do is offline Offline
Junior Poster

Re: Cryptography Fun

 
0
  #3
Aug 26th, 2005
Whoa, I didn't even know that existed! Great, I have some other stuff I'd like to upload, too. :cheesy:
Vi veri veniversum vivus vici
Reply With Quote Quick reply to this message  
Reply

This thread has been marked solved.
Perhaps start a new thread instead?
Message:



Similar Threads
Other Threads in the Python Forum
Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC