This is an old revision of the document!
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!
The goal of this exercise is to implement the meet-in-the-middle attack on double DES. For this, you are given a starter code (see below), implemented using the pycrypto library.
Perform the following tasks:
Starting from the starter code (see below), write methods to encrypt and decrypt using double-DES (2DES), defined as follows: 2DES( (k1,k2), m) = DES(k1, DES(k2, m))
You are given the ciphertexts
c1 = 'cda98e4b247612e5b088a803b4277710f106beccf3d020ffcc577ddd889e2f32'
c2 = '54826ea0937a2c34d47f4595f3844445520c0995331e5d492f55abcf9d8dfadf'
Decrypt them using the following keys:
k1 = 'Smerenie'
k2 = 'Dragoste'
The plaintext corresponding to c1 is m1='Fericiti cei saraci cu duhul, ca'. Find the plaintext m2 corresponding to c2.
Note also that for this exercises, we shall be using the default values when initialising the DES cipher (i.e. ECB mode and no IV).
Decrypt the entire ciphertext (c1 || c2) with k1 and k2 using 2DES and check it matches the messages m1||m2 above.
In this last but most important task, you are given the following ciphertext/plaintext pairs for 2DES with unknown keys:
m1 = 'Pocainta' (in byte string, i.e. can be used directly with pycrypto DES)
c1 = '9f98dbd6fe5f785d' (in hex string, you need to hex-decode)
m2 = 'Iertarea'
c2 = '6e266642ef3069c2'
You also know the last 6-bytes of each key (note we now have a different key than for the previous tasks): k1 (last 6 bytes) = 'oIkvH5' k2 (last 6 bytes) = 'GK4EoU'
Your task is now to find the full keys k1 and k2 by applying the meet-in-the-middle attack over 2DES.
To build a table, we recommend using a list of tuples, where you add new (key,enc) pairs as follows:
tb = [] tb.append(('keyval', 'encval'))
To sort the table, you can do this:
tbs = sorted(tb, key=itemgetter(1))
To search with binary search, first select just the second column (to search the encryptions):
tenc = [value for _,value in tbs]
then use the bisect library (e.g. bisect.bisect_left) https://docs.python.org/2/library/bisect.html
The starter code is this:
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()