DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Coding
  3. Languages
  4. Fun with Python and Silly Ciphers

Fun with Python and Silly Ciphers

Mike Driscoll user avatar by
Mike Driscoll
·
Apr. 27, 13 · Interview
Like (0)
Save
Tweet
Share
4.67K Views

Join the DZone community and get the full member experience.

Join For Free

when i was a kid, i was really into secret codes and ciphers. i thought they were all kinds of fun. my mom thought it would be fun to use some of the ciphers i was so enamored with in treasure hunts for special occasions, like birthdays. she would take something like a cryptograph wheel and create codes with it that my brother and i would have to decode with our own wheel to find a gift or another clue. we used stuff where numbers would represent letters (a=1, b=2, c=3) or we would use a sliding scale where you move the alphabet one letter over so a=b, c=d, d=e, etc. sometimes we’d create a code stick where you get a long string of paper and wrap it around a pencil and then write a message of the paper. it’s pretty much impossible to read when it’s unwrapped.

anyway, i decided to create a silly cipher program with wxpython where i could input a string and have it convert it to something else. i also wanted my program to decode it too. now you can’t really make a program that can use a cryptograph wheel or a code stick, but for number codes or slide scales, that’s extremely easy.

creating an encoding gui

cipher_trans

creating the actual gui is a piece of cake. it takes a little more work to code up the back end where you have to actually parse the string and change it into something else. for this exercise, i created 4 encoders and 3 decoders. the 5 encoders encode strings into numbers, ascii (which is a different set of numbers), l33t (just for fun), and hex. for the decoders, i decode everything except for l33t. let’s take a moment to study the code for the gui:

import controller
import wx
 
########################################################################
class cipherpanel(wx.panel):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self, parent):
        """constructor"""
        wx.panel.__init__(self, parent=parent)
        choices = ["", "alpha2num", "ascii", "l33t", "hex"]
        decode_choices = ["", "ascii", "hex", "num2alpha"]
        self.mainsizer = wx.boxsizer(wx.vertical)
 
        tolbl = wx.statictext(self, label="translate into:")
        self.tocbo = wx.combobox(self, value=choices[1], choices=choices)
        self.add2hsizer([tolbl, self.tocbo])
 
        fromlbl = wx.statictext(self, label="translate from:")
        self.fromcbo = wx.combobox(self, value="", choices=decode_choices)
        self.add2hsizer([fromlbl, self.fromcbo])
 
        txtlbl = wx.statictext(self, label="enter text to encode or decode:")
        self.originaltxt = wx.textctrl(self, style=wx.te_multiline)
 
        self.translatedtxt = wx.textctrl(self, style=wx.te_multiline)
 
        encodebtn = wx.button(self, label="encode")
        encodebtn.bind(wx.evt_button, self.onencode)
        decodebtn = wx.button(self, label="decode")
        decodebtn.bind(wx.evt_button, self.ondecode)
 
        # layout widgets
        self.mainsizer.add(txtlbl, 0, wx.all, 5)
        self.mainsizer.add(self.originaltxt, 1, wx.expand|wx.all, 5)
        self.mainsizer.add(self.translatedtxt, 1, wx.expand|wx.all, 5)
        self.add2hsizer([encodebtn, decodebtn])
 
        self.setsizer(self.mainsizer)
 
    #----------------------------------------------------------------------
    def add2hsizer(self, widgets):
        """
        add widgets to a horizontal sizer
        """
        sizer = wx.boxsizer(wx.horizontal)
        for widget in widgets:
            sizer.add(widget, 0, wx.all|wx.center, 5)
 
        if isinstance(widgets[0], wx.button):
            self.mainsizer.add(sizer, 0, wx.center)
        else:
            self.mainsizer.add(sizer)
 
    #----------------------------------------------------------------------
    def ondecode(self, event):
        """
        decodes what's in the original text box to the encoding 
        specified and puts the result in the bottom text box
        """
        from_value = self.fromcbo.getvalue()
        value_to_decode = self.originaltxt.getvalue()
        if from_value == "hex":
            new_value = value_to_decode.decode("hex")
        elif from_value == "ascii":
            value_to_decode = [int(i) for i in value_to_decode.split()]
            new_value = controller.convertfromascii(value_to_decode)
        elif from_value == "num2alpha":
            value_to_decode = value_to_decode.split()
            new_value = controller.convertfromnumbers(value_to_decode)
        else:
            return
 
        self.translatedtxt.setvalue(new_value)
 
    #----------------------------------------------------------------------
    def onencode(self, event):
        """
        encodes what's in the original text box to the encoding 
        specified and puts the result in the bottom text box
        """
        to_value = self.tocbo.getvalue()
        value_to_encode = self.originaltxt.getvalue()
        if to_value == "hex":
            new_value = value_to_encode.encode("hex")
        elif to_value == "ascii":
            new_value = controller.converttoascii(value_to_encode)
        elif to_value == "l33t":
            new_value = controller.converttoleet(value_to_encode)
        elif to_value == "alpha2num":
            new_value = controller.converttonumbers(value_to_encode)
 
        self.translatedtxt.setvalue(new_value)
 
########################################################################
class cipherframe(wx.frame):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self):
        """constructor"""
        title = "cipher creator / translator"
        size = (800,600)
        wx.frame.__init__(self, none, title=title, size=size)
        panel = cipherpanel(self)
        self.show()
 
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.app(false)
    frame = cipherframe()
    app.mainloop()

we should probably take a couple moments and break this down. as you probably noticed in the screenshot earlier, this gui has a couple of comboboxes, a couple multiline textctrls and two buttons. the comboboxes control what we’re encoding or decoding to. we have imported a mysterious module called “controller” which houses all the code that does the encoding. we’ll look at that in a minute. first, we need to look at a couple of the functions in this piece. in the onencode method, we should how to grab the value we’re going to encode and pass it to the appropriate controller function. for the ondecode method, we sometimes have to do a little pre-processing before we pass the data on to the controller. you can see an example in the ascii portion of the conditional where we have to create a list of integers or in the num2alpha section where we need to create a list of numbers. once you understand what’s going on here, feel free to continue to the next piece of code below.

#----------------------------------------------------------------------
def converttoascii(string):
    """"""
    output = []
    for letter in string:
        output.append( ord(letter) )
 
    return " ".join([str(i) for i in output])
 
#----------------------------------------------------------------------
def converttoceasar(string):
    """




http://www.wikihow.com/create-secret-codes-and-ciphers




    shifts the alphabet 3 places such that a becomes x,
    b becomes y, etc
    """
    ceasar_dict = {"a": "x", 
                   "b": "y",
                   "c": "z",
                   "d": "a",
                   "e": "b",
                   "f": "c",
                   "g": "d",
                   "h": "e",
                   "i": "f",
                   "j": "g",
                   "k": "h",
                   "l": "i",
                   "m": "j",
                   "n": "k",
                   "o": "l",
                   "p": "m",
                   "q": "n",
                   "r": "o",
                   "s": "p",
                   "t": "q",
                   "u": "r",
                   "v": "s",
                   "w": "t",
                   "x": "u",
                   "y": "v",
                   "z": "w"}
    new_string = ""
    for char in string:
        if char == ' ':
            new_string += ' '
        else:
            new_string += ceasar_dict[char.lower()]
    return new_string
 
#----------------------------------------------------------------------
def converttoleet(string):
    """"""
    leet_dict = {"a":"4", "b":"8", "e":"3", "l":"1",
                 "o":"0", "s":"5", "t":"7"}
    new_string = ""
    for letter in string:
        if letter.lower() in leet_dict:
            letter = leet_dict[letter.lower()]
        new_string += letter
    return new_string
 
#----------------------------------------------------------------------
def converttonumbers(string):
    """
    convert a string to numbers where a=1, b=2, c=3, etc
    """
    keys = "abcdefghijklmnopqrstuvwxyz"
    values = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11',
              '12', '13', '14', '15', '16', '17', '18', '19', '20', 
              '21', '22', '23', '24', '25', '26']
    num_dict = dict(zip(keys,values))
    new_string = ""
    for letter in string:
        if letter.lower() in num_dict:
            new_string += num_dict[letter.lower()] + " "
    return new_string
 
#----------------------------------------------------------------------
def convertfromascii(data):
    """
    convert from ascii
    """
    s = ""
    if isinstance(data, str):
        for item in data.split():
            s += chr(int(item))
    else:
        # can also convert a list of integers
        for item in data:
            s += chr(item)
    return s
 
#----------------------------------------------------------------------
def convertfromceasar(string):
    """
    converts string from ceasar to normal
    """
    unceasar_dict = {"x": "a",
                     "y": "b",
                     "z": "c",
                     "a": "d",
                     "b": "e",
                     "c": "f",
                     "d": "g",
                     "e": "h",
                     "f": "i",
                     "g": "j",
                     "h": "k",
                     "i": "l",
                     "j": "m",
                     "k": "n",
                     "l": "o",
                     "m": "p",
                     "n": "q",
                     "o": "r",
                     "p": "s",
                     "q": "t",
                     "r": "u",
                     "s": "v",
                     "t": "w",
                     "u": "x",
                     "v": "y",
                     "w": "z"}
    new_string = ""
    for char in string:
        if char == ' ':
            new_string += ' '
        else:
            new_string += unceasar_dict[char.lower()]
    return new_string
 
#----------------------------------------------------------------------
def convertfromnumbers(data):
    """
    convert a list of numbers to letters where 1=a, 2=b, 3=c, etc
    """
    keys = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11',
            '12', '13', '14', '15', '16', '17', '18', '19', '20', 
            '21', '22', '23', '24', '25', '26']
    values = "abcdefghijklmnopqrstuvwxyz"
    num_dict = dict(zip(keys,values))
 
    new_string = ""
    for char in data:
        val = num_dict[char]
        new_string += val
    return new_string
 
#----------------------------------------------------------------------
if __name__ == "__main__":
    x = converttoascii("i love you")
    y = converttoleet("i love you")
    print x
    new_x = [int(i) for i in x.split()]
    print convertfromascii(new_x)
    print convertfromascii(x)
 
    x = converttoceasar("meeting tomorrow at station")
    print "meeting tomorrow at station =>", x
    print "%s =>" % x, convertfromceasar(x)
 
    t = converttonumbers("python rules")
    print "python rules => " + t
    print "%s => " % t, convertfromnumbers(t.split())

you may notice that i have included other examples in the controller that aren’t currently hooked into the gui. for example, i have a converter function in there to convert strings to ceasar, which is a popular cipher where the alphabet is shifted 3 places in one direction or the other. anyway, one of the nicest bits about this code is that we didn’t need to import anything. it all works with just normal python! to convert to ascii, we use python’s builtin ord . for most of the others, we use dictionaries to map the values. at the bottom of the script, we have a few test cases to check and make sure it is converting the strings as we expect it to. these should probably be made into real unit tests, but for a quick and dirty check, these work great!

wrapping up

there are several other codes i’d like to add to this at some point, such as morse code. i also like the codes where the message is hidden in the text, such as every first letter (or last) in a poem spells our something or where every letter at the beginning of a sentence spells something. those were always fun. i’ve included a few links at the end of this article so you can read about other fun codes and ciphers. have fun coding!

additional reading

  • secret codes for cubs and scouts
  • cryptology for kids
  • the pig pen cipher – this one is fun!
  • wikihow – how to create secret codes and ciphers

download the source!

  • ciphergui.zip
  • ciphergui.tar
Cipher Python (language)

Published at DZone with permission of Mike Driscoll, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Public Key and Private Key Pairs: Know the Technical Difference
  • How To Best Use Java Records as DTOs in Spring Boot 3
  • AWS CodeCommit and GitKraken Basics: Essential Skills for Every Developer
  • What Are the Different Types of API Testing?

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: