In acest laborator vom face niste exercitii ce folosesc algoritmul DES si variatii ale acestuia discutate la curs. Prezentarea PowerPoint pentru acest laborator poate fi găsită aici.
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 byte_2_bin(bval): """ Transform a byte (8-bit) value into a bitstring """ return bin(bval)[2:].zfill(8) 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
DESX este definit sub forma DESX( (k1,k2,k3), m) = k1 ⊕ DES(k2, m ⊕ k3). Construiti un atac impotriva DESX care sa ruleze intr-un timp proportional cu 2120.
De ce urmatoarele scheme nu aduc nicio imbunatatire fata de DES? Justificati!
Scopul acestui exercitiu este de a implementa atacul meet-in-the-middle pe 2DES. Porniti de la scheletul de laborator (vezi mai jos) care se foloseste de biblioteca pycrypto.
Realizati urmatoarele sarcini:
Pornind de la schelet, implementati metodele des2_enc si des2_dec folosind double-DES (2DES).
2DES( (k1,k2), m) = DES(k1, DES(k2, m))
Folositi urmatoarele ciphertexts
c1 = 'cda98e4b247612e5b088a803b4277710f106beccf3d020ffcc577ddd889e2f32'
c2 = '54826ea0937a2c34d47f4595f3844445520c0995331e5d492f55abcf9d8dfadf'
Decriptati-le folosind cheile:
k1 = 'Smerenie'
k2 = 'Dragoste'
Primul plaintext corespunzator lui c1 este m1='Fericiti cei saraci cu duhul, ca'. Gasiti al doilea plaintext m2 ce ii corespunde lui c2.
Vom considera de asemenea ca initializam DES-ul cu valorile default (i.e. modul ECB si niciun IV).
Decriptati intregul ciphertext (c1 || c2) cu cheile k1 si k2 folosind 2DES si asigurati-va ca rezultatul dat este mesajul initial m1||m2.
In ultimul si cel mai important pas vi se dau niste perechi plaintext/ciphertext obtinute prin criptarea cu 2DES cu niste chei necunoscute:
m1 = 'Pocainta' (in byte string, i.e. poate fi dat direct ca parametru catre pycrypto DES)
c1 = '9f98dbd6fe5f785d' (in hex string, trebuie sa il decodificati mai intai)
m2 = 'Iertarea'
c2 = '6e266642ef3069c2'
Vi se mai dau si ultimii 6 bytes ale celor 2 chei (care sunt altele decat cele folosite la pasii anteriori):
k1 (last 6 bytes) = 'oIkvH5'
k2 (last 6 bytes) = 'GK4EoU'
Sarcina voastra este sa gasiti restul octetilor din k1 si k2 aplicand atacul meet-in-the-middle. Your task is now to find the full keys k1 and k2 by applying the meet-in-the-middle attack over 2DES.
Pentru a construi un tabel, recomandam sa folositi o lista de tupluri unde adaugati perechi de forma (cheie, encriptie) ca in urmatorul exemplu:
tb = [] tb.append(('keyval', 'encval'))
Pentru a sorta tabelul:
tbs = sorted(tb, key=itemgetter(1))
Pentru a realiza cautare binara in tabel, selectati mai intai a doua coloana (pentru a cauta dupa encriptie):
tenc = [value for _,value in tbs]
iar apoi folositi biblioteca bisect (e.g. bisect.bisect_left): https://docs.python.org/2/library/bisect.html
Scheletul de cod:
from utils import * from operator import itemgetter import bisect from Crypto.Cipher import DES def get_index(a, x): """Locate the leftmost value exactly equal to x in list a""" i = bisect.bisect_left(a, x) if i != len(a) and a[i] == x: return i else: return -1 def des_enc(k, m): """ Encrypt a message m with a key k using DES as follows: c = DES(k, m) Args: m should be a bytestring (i.e. a sequence of characters such as 'Hello' or '\x02\x04') k should be a bytestring of length exactly 8 bytes. Note that for DES the key is given as 8 bytes, where the last bit of each byte is just a parity bit, giving the actual key of 56 bits, as expected for DES. The parity bits are ignored. Return: The bytestring ciphertext c """ d = DES.new(k, DES.MODE_ECB) c = d.encrypt(m) return c def des_dec(k, c): """ Decrypt a message c with a key k using DES as follows: m = DES(k, c) Args: c should be a bytestring (i.e. a sequence of characters such as 'Hello' or '\x02\x04') k should be a bytestring of length exactly 8 bytes. Note that for DES the key is given as 8 bytes, where the last bit of each byte is just a parity bit, giving the actual key of 56 bits, as expected for DES. The parity bits are ignored. Return: The bytestring plaintext m """ d = DES.new(k, DES.MODE_ECB) m = d.decrypt(c) return m def main(): # Exercitiu pentru test des2_enc key1 = 'Smerenie' key2 = 'Dragoste' m1_given = 'Fericiti cei saraci cu duhul, ca' c1 = 'cda98e4b247612e5b088a803b4277710f106beccf3d020ffcc577ddd889e2f32' # TODO: implement des2_enc and des2_dec m1 = des2_dec(key1, key2, hex_2_str(c1)) print('ciphertext: ' + c1) print('plaintext: ' + m1) print('plaintext in hexa: ' + str_2_hex(m1)) # TODO: run meet-in-the-middle attack for the following plaintext/ciphertext m1 = 'Pocainta' c1 = '9f98dbd6fe5f785d' # in hex string m2 = 'Iertarea' c2 = '6e266642ef3069c2' # Note: you only need to search for the first 2 bytes of the each key: k1 = '??oIkvH5' k2 = '??GK4EoU' if __name__ == "__main__": main()