Python is an easy to learn interactive programming language. Throughout this lab, we'll be using Python 2.7.
You can run Python code in two ways:
To start interactive mode, simply open a terminal window and run python
:
linux$ python
You can now write Python code just as you would in an actual program:
>>> print "Hello, SASC"
To quit interactive mode either press Ctrl+D
or use:
>>> quit()
Interactive mode is useful when you want to quickly try something out (for example, testing decryption for a certain key) without going through the hassle of writing a new source file and running it.
In Python, indentation is important; it is used to organize code in blocks. For example, the following C code:
int foo(int a, int b) { int x; if (a > b) { x = a; } else { x = b; } return x }
is (approximately) the same as the following in Python:
def foo(a, b): if a > b: x = a else: x = b return x
In this first recipe we'll see how to encrypt a single letter using Caesar's cipher.
alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ' def caesar_enc(letter): if letter < 'A' or letter > 'Z': print 'Invalid letter' return else: return alphabet[(ord(letter) - ord('A') + 3) % len(alphabet)]
Create a new file named caesar.py containing the code above. To test the code, open the interpreter and try the following:
linux$ python >>> from caesar import * >>> print alphabet >>> alphabet[0] >>> ord('A') >>> len(alphabet) >>> ord('D') - ord('A') >>> 28 % 26 >>> -1 % 26 >>> caesar_enc('D') >>> caesar_enc('Z') >>> caesar_enc('B')
Add a caesar_dec
function to caesar.py
, which decrypts a single letter encrypted using Caesar's cipher.
We'll now expand our function to take string as input. First, a little intro to Python for
loops. Some examples:
for i in [1, 2, 3]: print i
In this first example, i
iterates through the values in list [1, 2, 3]
. The code is similar to the classical C code:
for (int i = 1; i <= 3; i++) { printf("%d\n", i); }
To create lists of integers use the range
function:
for i in range(3): print i
Execute the code above in the interpreter. Using the range function with two parameters, change the above to print integers 1 through 10.
In Python, for
can iterate through multiple types of objects, including strings. Try the below:
for letter in 'ABCD': print letter
We will now use the for
instruction to expand our caesar_enc
function:
alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ' def caesar_enc_string(plaintext): ciphertext = '' for letter in plaintext: ciphertext = ciphertext + caesar_enc(letter) return ciphertext
Test the above by starting a new interpreter; this time, we'll skip the from caesar import *
part by running the source file before starting interactive mode:
linux$ python -i caesar.py >>> test = 'HELLO' >>> test + 'WORLD' >>> caesar_enc_string(test)
Another way to run things, which can be very useful in general is to use a main() function and write your program script as follows:
import sys import random import string import operator alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ' def caesar_enc(letter): if letter < 'A' or letter > 'Z': print 'Invalid letter' return else: return alphabet[(ord(letter) - ord('A') + 3) % len(alphabet)] def caesar_enc_string(plaintext): ciphertext = '' for letter in plaintext: ciphertext = ciphertext + caesar_enc(letter) return ciphertext def main(): m = 'BINEATIVENIT' c = caesar_enc_string(m) print c if __name__ == "__main__": main()
Then you can simply run the program, or type the following in a terminal:
python test_caesar.py
Add the corresponding caesar_dec_string
function.
Python allows passing default values to parameters:
def foo(a, b = 3): print a, b
>>> foo(1) >>> foo(1, 2)
We can use default parameter values to expand our caesar_enc
function to take the key as an additional parameter, without breaking compatibility with our previous code.
def caesar_enc(letter, k = 3): if letter < 'A' or letter > 'Z': print 'Invalid letter' return None else: return alphabet[(ord(letter) - ord('A') + k) % len(alphabet)] def caesar_enc_string(plaintext, k = 3): ciphertext = '' for letter in plaintext: ciphertext = ciphertext + caesar_enc(letter, k) return ciphertext
To test the new functions, try the below:
linux$ python -i caesar.py >>> caesar_enc_string('HELLO') >>> caesar_enc_string('HELLO', 0) >>> caesar_enc_string('HELLO', 1)
Using default parameters, expand your shift cipher decryption functions to support arbitrary keys.
import binascii def strxor(a, b): # xor two strings (trims the longer input) return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)]) def hexxor(a, b): # xor two hex strings (trims the longer input) ha = a.decode('hex') hb = b.decode('hex') return "".join([chr(ord(x) ^ ord(y)).encode('hex') for (x, y) in zip(ha, hb)]) def bitxor(a, b): # xor two bit strings (trims the longer input) return "".join([str(int(x)^int(y)) for (x, y) in zip(a, b)]) def str2bin(ss): """ Transform a string (e.g. 'Hello') into a string of bits """ bs = '' for c in ss: bs = bs + bin(ord(c))[2:].zfill(8) return bs def hex2bin(hs): """ Transform a hex string (e.g. 'a2') into a string of bits (e.g.10100010) """ bs = '' for c in hs: bs = bs + bin(int(c,16))[2:].zfill(4) return bs def bin2hex(bs): """ Transform a bit string into a hex string """ return hex(int(bs,2))[2:-1] def byte2bin(bval): """ Transform a byte (8-bit) value into a bitstring """ return bin(bval)[2:].zfill(8) def str2int(ss): """ Transform a string (e.g. 'Hello') into a (long) integer by converting first to a bistream """ bs = str2bin(ss) li = int(bs, 2) return li def int2hexstring(bval): """ Transform an int value into a hexstring (even number of characters) """ hs = hex(bval)[2:] lh = len(hs) return hs.zfill(lh + lh%2) def bin2str(bs): """ Transform a binary srting into an ASCII string """ n = int(bs, 2) return binascii.unhexlify('%x' % n)
Find the plaintext messages for the following ciphertexts knowing that the cipher is the XOR operation (ciphertext = plaintext XOR key) and the key is “abcdefghijkl”.
C1 = "000100010001000000001100000000110001011100000111000010100000100100011101000001010001100100000101" C2 = "02030F07100A061C060B1909"