This shows you the differences between two versions of the page.
ic:laboratoare:05 [2020/10/28 01:36] acosmin.maria |
ic:laboratoare:05 [2020/11/04 14:00] (current) philip.dumitru [Exercise 3 (5p)] |
||
---|---|---|---|
Line 1: | Line 1: | ||
===== Laboratorul 05 - DES ===== | ===== Laboratorul 05 - DES ===== | ||
- | |||
In this lab we'll do some exercises with DES and some of its variants, as we discussed in the last lecture [[https://drive.google.com/file/d/1Fjybv6k5QudRB1bkAi5shVUGlUyTO_0U/view|here]]. | In this lab we'll do some exercises with DES and some of its variants, as we discussed in the last lecture [[https://drive.google.com/file/d/1Fjybv6k5QudRB1bkAi5shVUGlUyTO_0U/view|here]]. | ||
+ | |||
+ | <file python 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): | ||
+ | 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 | ||
+ | | ||
+ | # THIS ONE IS NEW | ||
+ | def hex_2_bytes(hex_data): | ||
+ | return bytes.fromhex(hex_data) # default utf-8 | ||
+ | </file> | ||
==== Exercise 1 (2p) ==== | ==== Exercise 1 (2p) ==== | ||
Line 26: | Line 86: | ||
=== A. Install the pycrypto library === | === A. Install the pycrypto library === | ||
- | See https://pypi.python.org/pypi/pycrypto. | + | <hidden>this is outdated: https://pypi.python.org/pypi/pycrypto.</hidden> |
+ | See https://pypi.org/project/pycryptodome/ | ||
=== B. Implement 2DES === | === B. Implement 2DES === | ||
Line 75: | Line 137: | ||
Your task is now to find the full keys k1 and k2 by applying the meet-in-the-middle attack over 2DES. | 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, I recommend using a list of tuples, where you add new (key,enc) pairs as follows: | + | To build a table, we recommend using a list of tuples, where you add new (key,enc) pairs as follows: |
<code> | <code> | ||
tb = [] | tb = [] | ||
- | tb.append(('keyval', 'encva')) | + | tb.append(('keyval', 'encval')) |
</code> | </code> | ||
Line 96: | Line 158: | ||
<code python desmitm.py> | <code python desmitm.py> | ||
- | import sys | + | from utils import * |
- | import random | + | |
- | import string | + | |
from operator import itemgetter | from operator import itemgetter | ||
- | import time | ||
import bisect | import bisect | ||
from Crypto.Cipher import DES | from Crypto.Cipher import DES | ||
- | |||
- | 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 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 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 | ||
- | """ | ||
- | bv = int(bs,2) | ||
- | return int2hexstring(bv) | ||
- | |||
- | def byte2bin(bval): | ||
- | """ | ||
- | Transform a byte (8-bit) value into a bitstring | ||
- | """ | ||
- | return bin(bval)[2:].zfill(8) | ||
- | |||
- | 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 get_index(a, x): | def get_index(a, x): | ||
- | 'Locate the leftmost value exactly equal to x in list a' | + | """Locate the leftmost value exactly equal to x in list a""" |
- | i = bisect.bisect_left(a, x) | + | i = bisect.bisect_left(a, x) |
- | if i != len(a) and a[i] == x: | + | if i != len(a) and a[i] == x: |
- | return i | + | return i |
- | else: | + | else: |
- | return -1 | + | return -1 |
def des_enc(k, m): | def des_enc(k, m): | ||
- | """ | + | """ |
- | Encrypt a message m with a key k using DES as follows: | + | Encrypt a message m with a key k using DES as follows: |
- | c = DES(k, m) | + | c = DES(k, m) |
- | Args: | + | Args: |
- | m should be a bytestring (i.e. a sequence of characters such as 'Hello' or '\x02\x04') | + | 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. | + | 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 | + | 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. | + | each byte is just a parity bit, giving the actual key of 56 bits, as expected for DES. |
- | The parity bits are ignored. | + | The parity bits are ignored. |
- | Return: | + | Return: |
- | The bytestring ciphertext c | + | The bytestring ciphertext c |
- | """ | + | """ |
- | d = DES.new(k) | + | d = DES.new(k, DES.MODE_ECB) |
- | c = d.encrypt(m) | + | c = d.encrypt(m) |
- | + | return c | |
- | return c | + | |
def des_dec(k, c): | def des_dec(k, c): | ||
- | """ | + | """ |
- | Decrypt a message c with a key k using DES as follows: | + | Decrypt a message c with a key k using DES as follows: |
- | m = DES(k, c) | + | m = DES(k, c) |
- | Args: | + | Args: |
- | c should be a bytestring (i.e. a sequence of characters such as 'Hello' or '\x02\x04') | + | 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. | + | 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 | + | 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. | + | each byte is just a parity bit, giving the actual key of 56 bits, as expected for DES. |
- | The parity bits are ignored. | + | The parity bits are ignored. |
- | Return: | + | Return: |
- | The bytestring plaintext m | + | The bytestring plaintext m |
- | """ | + | """ |
- | d = DES.new(k) | + | d = DES.new(k, DES.MODE_ECB) |
- | m = d.decrypt(c) | + | m = d.decrypt(c) |
- | + | return m | |
- | return m | + | |
| | ||
def main(): | 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)) | ||
- | # Exercitiu pentru test des2_enc | + | print('ciphertext: ' + c1) |
- | key1 = 'Smerenie' | + | print('plaintext: ' + m1) |
- | key2 = 'Dragoste' | + | print('plaintext in hexa: ' + str_2_hex(m1)) |
- | m1_given = 'Fericiti cei saraci cu duhul, ca' | + | |
- | c1 = 'cda98e4b247612e5b088a803b4277710f106beccf3d020ffcc577ddd889e2f32' | + | # TODO: run meet-in-the-middle attack for the following plaintext/ciphertext |
- | # TODO: implement des2_enc and des2_dec | + | m1 = 'Pocainta' |
- | m1 = des2_dec(key1, key2, c1.decode('hex')) | + | c1 = '9f98dbd6fe5f785d' # in hex string |
- | + | m2 = 'Iertarea' | |
- | print 'ciphertext: ' + c1 | + | c2 = '6e266642ef3069c2' |
- | print 'plaintext: ' + m1 | + | |
- | print 'plaintext in hexa: ' + m1.encode('hex') | + | |
- | + | ||
- | # 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: | + | # Note: you only need to search for the first 2 bytes of the each key: |
- | k1 = '??oIkvH5' | + | k1 = '??oIkvH5' |
- | k2 = '??GK4EoU' | + | k2 = '??GK4EoU' |
- | + | ||
if __name__ == "__main__": | if __name__ == "__main__": | ||
- | main() | + | main() |
</code> | </code> | ||