This shows you the differences between two versions of the page.
|
sasc:laboratoare:01 [2015/02/24 23:28] 127.0.0.1 external edit |
sasc:laboratoare:01 [2017/02/21 11:28] (current) dan.dragan |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ===== Laboratorul 01. ===== | + | ===== Lab 01 - Introduction ===== |
| + | ==== Python Crash Course ==== | ||
| + | === Python Interactive Mode === | ||
| + | |||
| + | 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: | ||
| + | * by writing a source file and running it (eventually, with some command line arguments) | ||
| + | * by entering commands in interactive mode | ||
| + | |||
| + | To start interactive mode, simply open a terminal window and run ''python'': | ||
| + | |||
| + | <code> | ||
| + | linux$ python | ||
| + | </code> | ||
| + | |||
| + | You can now write Python code just as you would in an actual program: | ||
| + | |||
| + | <code> | ||
| + | >>> print "Hello, SASC" | ||
| + | </code> | ||
| + | |||
| + | To quit interactive mode either press ''Ctrl+D'' or use: | ||
| + | |||
| + | <code> | ||
| + | >>> quit() | ||
| + | </code> | ||
| + | |||
| + | 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. | ||
| + | |||
| + | |||
| + | === Python Recipe #1 - Hail, Caesar! === | ||
| + | |||
| + | In Python, indentation is important; it is used to organize code in blocks. For example, the following C code: | ||
| + | |||
| + | <code C> | ||
| + | int foo(int a, int b) { | ||
| + | int x; | ||
| + | if (a > b) { | ||
| + | x = a; | ||
| + | } else { | ||
| + | x = b; | ||
| + | } | ||
| + | return x | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | is (approximately) the same as the following in Python: | ||
| + | |||
| + | <code Python> | ||
| + | def foo(a, b): | ||
| + | if a > b: | ||
| + | x = a | ||
| + | else: | ||
| + | x = b | ||
| + | return x | ||
| + | </code> | ||
| + | |||
| + | In this first recipe we'll see how to encrypt a single letter using Caesar's cipher. | ||
| + | |||
| + | <code Python> | ||
| + | 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)] | ||
| + | </code> | ||
| + | |||
| + | Create a new file named caesar.py containing the code above. To test the code, open the interpreter and try the following: | ||
| + | |||
| + | <code python> | ||
| + | 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') | ||
| + | </code> | ||
| + | |||
| + | === Python Exercise #1 - Decrypting a letter === | ||
| + | Add a ''caesar_dec'' function to ''caesar.py'', which decrypts a single letter encrypted using Caesar's cipher. | ||
| + | |||
| + | === Python Recipe #2 - Encrypting a string === | ||
| + | |||
| + | We'll now expand our function to take string as input. First, a little intro to Python ''for'' loops. Some examples: | ||
| + | |||
| + | <code python> | ||
| + | for i in [1, 2, 3]: | ||
| + | print i | ||
| + | </code> | ||
| + | |||
| + | In this first example, ''i'' iterates through the values in list ''[1, 2, 3]''. The code is similar to the classical **C** code: | ||
| + | |||
| + | <code C> | ||
| + | for (int i = 1; i <= 3; i++) { | ||
| + | printf("%d\n", i); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | To create lists of integers use the ''range'' function: | ||
| + | |||
| + | <code python> | ||
| + | for i in range(3): | ||
| + | print i | ||
| + | </code> | ||
| + | |||
| + | 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: | ||
| + | |||
| + | <code python> | ||
| + | for letter in 'ABCD': | ||
| + | print letter | ||
| + | </code> | ||
| + | |||
| + | We will now use the ''for'' instruction to expand our ''caesar_enc'' function: | ||
| + | |||
| + | <code Python> | ||
| + | alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ' | ||
| + | def caesar_enc_string(plaintext): | ||
| + | ciphertext = '' | ||
| + | for letter in plaintext: | ||
| + | ciphertext = ciphertext + caesar_enc(letter) | ||
| + | return ciphertext | ||
| + | | ||
| + | </code> | ||
| + | |||
| + | 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: | ||
| + | |||
| + | <code Python> | ||
| + | linux$ python -i caesar.py | ||
| + | >>> test = 'HELLO' | ||
| + | >>> test + 'WORLD' | ||
| + | >>> caesar_enc_string(test) | ||
| + | </code> | ||
| + | |||
| + | 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: | ||
| + | |||
| + | <code Python 'test_caesar.py'> | ||
| + | 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() | ||
| + | </code> | ||
| + | |||
| + | Then you can simply run the program, or type the following in a terminal: | ||
| + | <code Python> | ||
| + | python test_caesar.py | ||
| + | </code> | ||
| + | |||
| + | |||
| + | === Python Exercise #2 - Decrypting a string === | ||
| + | |||
| + | Add the corresponding ''caesar_dec_string'' function. | ||
| + | |||
| + | === Python Recipe #3 - Shift ciphers === | ||
| + | |||
| + | Python allows passing default values to parameters: | ||
| + | |||
| + | <code Python> | ||
| + | def foo(a, b = 3): | ||
| + | print a, b | ||
| + | </code> | ||
| + | <code Python> | ||
| + | >>> foo(1) | ||
| + | >>> foo(1, 2) | ||
| + | </code> | ||
| + | |||
| + | 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. | ||
| + | |||
| + | <code Python> | ||
| + | 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 | ||
| + | </code> | ||
| + | |||
| + | To test the new functions, try the below: | ||
| + | <code Python> | ||
| + | linux$ python -i caesar.py | ||
| + | >>> caesar_enc_string('HELLO') | ||
| + | >>> caesar_enc_string('HELLO', 0) | ||
| + | >>> caesar_enc_string('HELLO', 1) | ||
| + | </code> | ||
| + | |||
| + | |||
| + | === Python Exercise #3 - Shift ciphers === | ||
| + | |||
| + | Using default parameters, expand your shift cipher decryption functions to support arbitrary keys. | ||
| + | |||
| + | === Python Recipe #4 - Format conversions === | ||
| + | |||
| + | <code Python> | ||
| + | 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) | ||
| + | </code> | ||
| + | |||
| + | === Python Exercise #4 - Format conversions === | ||
| + | |||
| + | 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". | ||
| + | |||
| + | <code> | ||
| + | C1 = "000100010001000000001100000000110001011100000111000010100000100100011101000001010001100100000101" | ||
| + | |||
| + | C2 = "02030F07100A061C060B1909" | ||
| + | </code> | ||
| + | |||
| + | |||
| + | <hidden> | ||
| + | The solution is {{:ic:laboratoare:lab1_sol.zip|here}}. | ||
| + | </hidden> | ||