Laboratorul 05 - DES

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.

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 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

Exercitiul 1 (2p)

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.

Exercise 2 (3p)

De ce urmatoarele scheme nu aduc nicio imbunatatire fata de DES? Justificati!

  • a) c = k1 ⊕ DES(k2, m)
  • b) c = DES(k2, m ⊕ k1)

Puteti folosi mai multe perechi (mesaj, ciphertext).

Exercitiul 3 (5p)

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:

A. Instalati biblioteca pycrypto

B. Implementati 2DES

Pornind de la schelet, implementati metodele des2_enc si des2_dec folosind double-DES (2DES).

2DES( (k1,k2), m) = DES(k1, DES(k2, m))

C. Testati 2DES

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.

In biblioteca Pycrypto, DES primeste o cheie pe 8 octeti (64 biti) chiar daca ar trebui sa primeasca numai 7 octeti (56 biti). Ultimul bit din fiecare octet este considerat ca fiind un bit de paritate, dar este ignorat de biblioteca. Astfel cheia ce se foloseste va fi intr-adevar de dimensiunea 56 biti. Pentru simplitate insa, in acest exercitiu vom considera ca dimensiunea cheiei este de 64 biti. Astfel putem folosi cheile de 8 caractere de mai sus pentru DES.

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.

D. Implementati atacul meet-in-the-middle pentru 2DES

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:

desmitm.py
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()
ic/labs/05.txt · Last modified: 2021/11/01 15:51 by razvan.smadu
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