Laboratorul 01 - Introduction

Python3 Crash Course

Check-out this tutorial: here.

Encoding vs Encryption

Encoding

  • Is used to transform data from one format to another.
  • Typically used in data transfer between different systems.
  • The information is NOT kept secret!!!
  • To decode the encoded data you only need to know the algorithm that was used.

Encryption

  • Transform data in order to keep it secret.
  • The algorithm is usually public, the key is secret.
  • Keywords: plaintext, ciphertext
  • Types: Private-Key Encryption vs Public-Key Encryption (upcoming)

During the labs, you will often need to convert data from one format to another. The most used data formats are the following:

  • ASCII (text)
  • Binary (01010101)
  • Hexadecimal [0-9a-fA-F]
  • Base64 [a-Az-Z0-9] with '+' and '/'. Base64 usually ends in '=' or '=='. Used A LOT in Web because HTTP is a text transfer protocol.

Finally, here you have some useful conversion functions and XOR operations for different data formats:

utils.py
import base64
 
# CONVERSION FUNCTIONS
 
def _chunks(string, chunk_size):
    for i in range(0, len(string), chunk_size):
        yield string[i:i+chunk_size]
 
def _hex(x):
    return format(x, '02x')
 
def hex_2_bin(data):
    return ''.join(f'{int(x, 16):08b}' for x in _chunks(data, 2))
 
def str_2_bin(data):
    return ''.join(f'{ord(c):08b}' for c in data)
 
def bin_2_hex(data):
    return ''.join(f'{int(b, 2):02x}' for b in _chunks(data, 8))
 
def str_2_hex(data):
    return ''.join(f'{ord(c):02x}' for c in data)
 
def bin_2_str(data):
    return ''.join(chr(int(b, 2)) for b in _chunks(data, 8))
 
def hex_2_str(data):
    return ''.join(chr(int(x, 16)) for x in _chunks(data, 2))
 
# XOR FUNCTIONS
 
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 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 hexxor(a, b):  # xor two hex-strings, trims the longer input
    return ''.join(_hex(int(x, 16) ^ int(y, 16)) for (x, y) in zip(_chunks(a, 2), _chunks(b, 2)))
 
# BASE64 FUNCTIONS
 
def b64decode(data):
    return bytes_to_string(base64.b64decode(string_to_bytes(data)))
 
def b64encode(data):
    return bytes_to_string(base64.b64encode(string_to_bytes(data)))
 
# PYTHON3 'BYTES' FUNCTIONS
 
def bytes_to_string(bytes_data):
    return bytes_data.decode()  # default utf-8
 
def string_to_bytes(string_data):
    return string_data.encode()  # default utf-8
Bytes in Python

Check out the following examples:

text1 = "Ana are mere"
text2 = b"Ana are mere"
type(text1) # <class 'str'>
type(text2) # <class 'bytes'>

Both texts store basically the same information. The difference is in how the data is internally 'encoded' into 2 different object types. During the labs, we will mostly work with str types, but some external libraries may require to transform the data from the string representation to a bytes object.

Exercise #1 - Encoding is nice

Decode the following strings:

C1 = "010101100110000101101100011010000110000101101100011011000110000100100001"
C2 = "526f636b2c2050617065722c2053636973736f727321"
C3 = "WW91IGRvbid0IG5lZWQgYSBrZXkgdG8gZW5jb2RlIGRhdGEu"

Exercise #2 - But XOR-ing is cool

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"

Hail, Caesar!

Encrypting a letter

Let's start with a simple one:

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:

shell$ python
>>> from caesar import *
>>> print(alphabet)
>>> alphabet[0]
>>> ord('A')
>>> len(alphabet)
>>> ord('D') - ord('A')
>>> 26 % 26
>>> 28 % 26
>>> -1 % 26
>>> caesar_enc('D')
>>> caesar_enc('Z')
>>> caesar_enc('B')

Exercise #3 - Decrypting a letter

Add a 'caesar_dec' function to 'caesar.py', which decrypts a single letter encrypted using Caesar's cipher.

Encrypting a string

We'll now expand our function to take strings as input.

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:

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:

test_caesar.py
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

Exercise #4 - Decrypting a string

Add the corresponding 'caesar_dec_string' function.

Shift ciphers

Python allows passing default values to parameters. 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:

shell$ python -i caesar.py
>>> caesar_enc_string('HELLO')
>>> caesar_enc_string('HELLO', 0)
>>> caesar_enc_string('HELLO', 1)

Exercise #5 - Shift Ciphers

Using default parameters, expand your shift cipher decryption functions to support arbitrary keys.

Bonus Exercise - Many-Time Pad

Decrypt the last ciphertext knowing that all the messages were encrypted with the same key using OTP.

ciphers.ciphertexts
8841a58f876901c9e195d1e320e0c30a017bec11b0643d30533adcb0475e85a820d64e1a0869963453b490933b7005839f7d8a9571c8a890d75773bc2acc11d5cb3259f0610e95ad6ae1ec8445fc836b661b9c0554494c430210989e4a42ff7b4c19338945a68653c89d783e8460935c93896a3d73d9bc84a8e381951443ab8ada62c5d662d43c0da848c3602d
8e14e681d0651cd5fb99d1a87cee972b4436fe19b22c3d1e7a75c2a6155ac4fa06d74e07042889300ab490d226614c818574d99a38d8a899d45478f83cca04818a3549f061079bb139a5f78542eac63873499513460d48534345addf5f42b632475623d14fb49c16c1913d7fca019f59d09b253c3c98a480e1e3829c0942bec2da478bcc6bd42a00e953883a622497
e332a0cad0610ad6e691c6b967ad90634c73ec04fe216e586272dcb0474f98b336de5252042895310ab48c93277d4089d061968e76cbe194da0174f97dc512cd8e7b59bf351a8dad39acfdcb04edc62a275695045c4e405f4910bb9e4746f27915541fc653b5c81ec09f7f22ca2d945c9c916a2a7397bc8da4add1990945b7869c4a969a7a9c3f06a846882c6c28d6f9e6255ec96dd0b50e378054b2c89f6ee255312d330508e9cf4d43db
8812e8c6842612d5a895c3a87ca28230557fe717fe2b75117571d0ad475985ae3bd04550041d8e2744a5d5ca3c60058e9e6c96db379ceb90df427df9338850c7842948a6701dd0e853b4eb9f45ffc6386e56800c5001095d4544ad934e06f3385d1f25c243a9c653eed23b3983239a589ec23d206891e882a2e3869b1445bbc38907c2d461d42c0dfb57c7207e2adbfeaa2a4bc37ccceb5777cf36f58f8776a75b242a7d105babd2564d959b79b8bd
8008ac83d06f079cfbd0dba27aee89365262a904b62d740a3679dab01305cabb3ed30b0a4c2c92270aa581d227660586827dd99e2eddeb8cda5836e835c150d28a3648fe352698e878afe19f0df7882c2b1b9914125e09500c52b08b0b5db63a5e13348952af891d8f9f37229e609254868b26206698bc85a2ad82d3465cbccf9d4396c922d42d01e644cd6e7424ccb7b12c518d6d9faf166fc538bacc947fb149773f7c444ae7c95609959776b9e028502e45e0f6186c4fa51f4c80834f373d1f0b6130b770b6e1ce87
9603efdd952614d4e69ed4ed66af95260171e61cba687b0a797795a4154893fa33cc0b094125977b0a8f9ac673745782d074968c76d3e6d8d14e7af8628438c0833a45b1351b9bbd6daef69849be9f2e6653dc4042425b425810a99e474bb7325b0566c048e79c1bcad23f308725dd1db9c52769689ca480a4ad96d41f58a786974a8c942ebd7904e407db2b632f99eea9361fd976d2a25771c574ab81
8907a18f9d671a9bfa95c5a86aabcf634072fc50b1686f177778d4e3174583b433910b2e4820953415f6a5df3a7b44c7936dd9983383a8bbc34c36ff288413c4c77b4ea5350c9be86db3fd8910f7836a277a9101544c4411455ead9a474fa075153e27c006aa891a8f803d218f24941d93976a3b7398aa8deda29895481793c58f46c2d66bd43f1afd49cb2f606bc9f2e6255ad87cdeb4036bc138abcad76ead5b232e3d446ee2cf190c8d9b76a8b37b5e7c0bf6b71d7d42a50105c1964739224a1230
960ea9dbd04e169bec9fd0be2ea790635263fb00ac216e11787d9bed47618ffa35d65d1b57699a3b45a29dd62135428e966cd8db14c9fcd8c2497fef7dc319c79f7b44a3350b97ae7fa4ea8e0beac865274c9801410d6e5e4810be965d4fa07b5c0566e14faa9b16c3947671be28941db88d393d3cb1a181bea69d924654bdcb9f58c2ce61d43407e1498827636bcdffa3634cda76d6ab127d8068badd8363ec
b952fa8f836e1cccfbd0c0bd2ebd8c635925bb50bf3a78587c6fc6b74768b9991bf60b1d4c28893449a290c120355688d074908f33cee994da5836e835c150d29f2944be724f86fc2be1f19845f0893f27499117154f50454910bf90590ae17b461966c543b3cf008f95377188219256d083242d3c95a783a6e390804658a7d4da588adf62983d07ec42882f6a2ad0f9e8
a20cbb9f953f1083e283dfba3afbcf6e142fff1aa964304c606edffa574286f7608248121622916118e28580637348cb982dc9936581bd8edb0d31ff2ec2038cdf37168b385bceba2ab5fb9e48f9952c3c57833d120d6a6375608db07469871d4e3823df43b5bd00cabd16149e299c58a0a30e2672b4bd80b9aa8198037ab7d5894a85df7dd57f15
Hints

  • What happens when you XOR a character from [a-z] with the character ' ' (spacebar). Check also for [A-Z].
  • You can't write a perfect algorithm to solve the problem in one shot, you will mostly have to guess. Why?
  • The challenge is nice, but can get tedious. Luckily for us there is a cool open source implementation. Check it out!

How to run on Windows

  1. Activate WSL (Windows Linux Subsystem) here
    1. turn Windows features on/off
    2. activate “Containers” and “Windows Subsystem for Linux”
    3. restart and install Ubuntu from Windows Store
    4. open a terminal and type ubuntu
    5. wait for the installation to complete and don't forget to “sudo apt-get upgrade”, “sudo apt-get update”
  2. check that you have python3 installed and pip (python package manager)
  3. pip install urwid
  4. python mtp.py <ciphertexts filename>
ic/laboratoare/01.txt · Last modified: 2020/10/18 15:55 by acosmin.maria
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0