Consolidation: CryptoPyThy


General     Shi muska di scensand dravenka oblomov Engleska Solzhenitzhin.
SUBTITLE: ‘FORGIVE ME IF I CONTINUE IN ENGLISH IN ORDER TO SAVE TIME’

So far we have learned about:

outputting information via the print statement (implicitly, there wasn’t a specific tutorial on it)

getting information from the user (raw_input)

the difference between strings and numbers, and how to manipulate them a little

how to loop over a range of numbers

conditionals – the if statement

how to get a list of numbers from 0 up to a specified number (range) and the remainder operator %

conditional looping – the while statement

a bit about variables and how they can be used to store information

Some of the reasons why we’re learning Python and not some other language

The List type, and how they can be used to store similar sorts of information

Functions and how they can be used to transform the arguments that you pass to them

How to use other people’s functions through the import statement we imported a module someone else wrote called random and made a guessing game with it; and, finally

We learned a little more about the string type and some ways of cutting them up and putting them back together again

Enter CryptoPyThy

In retrospect, this is probably a bit too much to cover without a breather.  However, we’ve now got a good slice of the basic concepts down and are able to write a program which will  make use of them.  I’m calling it CryptoPyThy (‘crypt-oh-pih-thee‘) and we can use it to make secret messages that no one else can read.  What we will do is write some code which:

* asks for a message to encrypt (or decrypt);

* takes that message and passes it to an encryption function;

* the encryption function breaks it down to each character in the message;

* it passes each character to another function which encrypts the characters; and

* after it has been encrypted, prints the encrypted message on the screen (then translates it back to show).

Or, at least that’s what I wanted it to do, but there’s some glitch in my system which is replacing some of the code by ?? So, in this tutorial, you’re going to have to work out what should go wherever  ?? appears and replace the ??.

To start, I’m going to introduce you to a builtin function – on that you have automatically without having to import it (like range()).  It’s called chr().  The argument you pass to chr() needs to be a number (an integer in fact).  Then, chr() takes that number and returns a letter (which can then be printed). Examples:

>>> chr(65)
'A'
>>> chr(104)+chr(105)+chr(32)+chr(116)+chr(104)+chr(101)+chr(114)+chr(101)+chr(33)
'hi there!'

If you want to see a list of characters try this:

>>> for i in range(32,127):
...     print chr(i),

While I’m here, I want to note that: we’ve got two numbers (ie arguments) in the range function (the first number is now where it starts from), but earlier we only saw one.  Also, we’ve put a comma at the end of the print statement.  This tells Python to keep printing from the same place next time it prints (normally it will start a new line).

There is a reverse function to chr(), and which takes a character and returns a number is called ord().

>>> ord('A')
65

So, chr(65) gave ‘A’ and ord(‘A’) gave 65.  You can test it by doing these:

>>> chr(ord('A'))
'A'  <- ord converted 'A' to 65,
        then chr converted 65 back to A
>>> ord(chr(65))
65   <- as above, but reversed.

We’re going to define our encryption function as follows:

>>> def encryptChar(character=None):
...    if character is None:
...      return ''
...    something = ??
...    spam = ord(character) + something
...    if spam > 127:
...      spam = spam - (128-32)
...    return chr(spam)

Put a number in where the question marks are.  It needs to be that number which, when doubled and then added to 32, equals 128.

Exercise: work out what the number should be and replace ‘??’ by that number in the something = ?? line in the function’s definition.   Hint: you can use Python to do the calculations for you and work backwards from 128 (actually, that’s two hints).

Explanation of the code:

The function encryptChar() expects to receive a single character as an argument.  If no argument is passed in, the character defaults to None (not ‘None’ note quotes – Python actually has a value called None).  If the character is None, then return an empty string.  Otherwise, calculate the number representing the character and add something to it, so the number we now have represents another character.  Unfortunately, we’re limited to characters represented by the numbers 32 through 127 (this was decided many decades ago, don’t question it).  So if, after we’ve added something to it, we have a number bigger than 127, we need to get the number back in that range.   And, in particular, we want 128 to go to 32 (so what’s the number, which when added to 128 gives 32? [1]

Next we need a function which takes a message and splits it into characters.  We could do this by using the [:] operator we met earlier to extract each character one by one – eg message[0:1] etc.  However, we’d need to know how to work out the length of the message, so we’d know when to stop (answer = the len() function).  Rather, we’re going to rely on a neat thing about strings – they have their own implicit iterator. Let me explain by way of an example:

>>> for i in 'ABCDE':
...     print i
...
A
B
C
D
E

So, when Python encounters a statement like for i in someString: in the for loop it assigns to the variable i each of the characters in the string, one by one.  We will use this to split our message up:

>>> def encryptMsg(message= None):
...   if message is None:
...     return ''
...   encrypted = ''
...   for character in message:
...     encrypted += encryptChar(??)
...   return encrypted

As with the encryptChar() function, this function expects a message as its first argument, and defaults the message to None if none is provided.  Then it checks to see if the message is None, and if so, it returns an empty string -> .  As above you need to work out what goes in the place where the question marks are ‘??’.   The encryptChar function expects to receive a single character,  so the ?? need to be replaced by a variable which contains a single character.

Finally we need a way of inputting a message – make sure you replace ?? by  a function call that we’ve seen before for getting user input.

>>> def cryptoPyThy():
...   while True:
...     message = ??('Type your message for encryption: ')
...     encrypted = encryptMsg(message)
...     print 'Encrypted message = \n',encrypted
...     print 'Decrypted message = \n',encryptMsg(encrypted)
...     print
...     
...     if message == 'q':
...       break
...
>>> cryptoPyThy()
Type your message for encryption: This is a secret message
Encrypted message =
$89CP9CP1PC53B5DP=5CC175
Decrypted message =
This is a secret message

Note that this is a special encryption function – if you encrypt the encrypted message, then you get the original message (called the plain text)  back.  You can see that from the printout above.

Extra Points:

(hard): This code replaces one character by another in a consistent way.  Someone who was determined might be able to decrypt the messages if they see a lot of them – or if they see the plain text of the message. In fact, this is the correspondence:

>>> spam = ''
>>> for i in range(32,128):
...     spam +=chr(i)
...
>>>
>>> print spam+'\n'+encryptMsg(spam)
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO

(Easy):  explain what this bit of code did.

(Hard): Change the functions so that the amount of the offset (that is, the variable something) can be passed as an argument to the encryptChar() function.   That way you could encrypt each message slightly differently – but you’d need to tell the recipient the offset so they could decrypt the message (how could you use encryptChar to decrypt one of these messages? – hint: think of negative numbers).

Notes:

[1] Answer ->

128+x = 32

=> 128+x-128 = 32-128

=>  128-128 on the left hand side is zero, so

x = 32-128,

but if we want to subtract x, we add its negative

=> -x = -(32-128)

=> -x = 128-32

9 Responses to Consolidation: CryptoPyThy

  1. Pingback: Links 18/8/2010: PC-BSD 8.1 Reviewed, Vim 7.3 Released | Techrights

  2. Pingback: Python4Kids New Tutorial: Consolidation and CryptoPyThy Aug 18, 2010, 00 :04 UTC (0 Talkback[s]) (796 reads) | Linux News.co

  3. Pingback: Zasoby o Pythonie | Wiadomości o technologiach IT

  4. moskva1300 says:

    What means “encrypted += encryptChar(??)”,I dont understand
    the +=?

    • brendanscott says:

      c = a + b means take the current values of a and b, add them and store the result in c
      a += b means take the current values of a and b, add them and store the result in a

      a = 1
      b = 2
      c = 1+2
      gives a = 1, b = 2, c = 3
      a=1
      b=2
      a += b
      gives a = 3, b = 2

      In this case it says add the encrypted characters one at a time to the end of the string we’ve got so far.

      • DaniC says:

        THXXX !!

        No matter age you are u can always learn something new in life!!
        I enjoy your site a lot – u got me into python now :))

  5. moskva1300 says:

    In first part why I need “something” variable when it wil be subtracted?I’m confused.

  6. moskva1300 says:

    What function would I have to use to translate string to binary?

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.