---
# System prepended metadata

title: Homework 6 (FCS)

---

# Homework 6 (FCS)






## Exercise 1

```python=
# hw6 SHA

import os
import sys
import hashlib

import random
import timeit

import random
import binascii

import numpy as np

def ex1():
	btxt1 = b'51.505-Foundations-of-Cybersecurity-MSSD'
	btxt2 = b'51.505-Foundations-of-Cybersecurity-MSSd'

	sha_btxt1 = hashlib.sha1(btxt1)
	sha_btxt2 = hashlib.sha1(btxt2)

	return sha_btxt1.hexdigest(), sha_btxt2.hexdigest()

```

<sha1 HASH object @ 0x000002653F669FB0>
<sha1 HASH object @ 0x000002653F79B210>

sha_btxt1.hexdigest() => `d2d2b25b4ee22957a08c41bfcb12e3b16e810699`

sha_btxt2.hexdigest() => `da7e687280aca8cd68a50ca5c1445f82da9783f7`


## Exercise 2

```python=

import os
import sys
import hashlib

import random
import timeit

import random
import binascii

import numpy as np

def ex2():
	

	n = [8, 16]

	mean_time = {n[0] : [], n[1] : []}

	# n = 8  => hashed.append(...).hexdigest()[0:2]
	# n = 16 => hashed.append(...).hexdigest()[0:4]


	for x in range(30):

		for k in n:
			rd512 = [hex(random.getrandbits(512))]
			collision_found = False
			start = timeit.default_timer()

			bites = int(k/4)

			hashed = [hashlib.sha512(binascii.unhexlify(rd512[0][2:].zfill(128))).hexdigest()[0:bites]]

			while not collision_found:
				# generate a new random message
				temp = hex(random.getrandbits(512))
				rd512.append(temp)

				hashed.append(hashlib.sha512(binascii.unhexlify(temp[2:].zfill(128))).hexdigest()[0:bites])

				for i in range(0, len(rd512)):	# sequentially pick each message/hash from the list
					for j in range(i+1, len(rd512)):	# and compare it with every other one
						if hashed[i] == hashed[j]:
							collision_found = True
							end = timeit.default_timer()
							
							print("\nMessage 1: ", rd512[i])
							print("Corresponding Hash: ", hashed[i])

							print("\nMessage 2: ", rd512[j])
							print("Corresponding Hash: ", hashed[j])

							time_taken = end - start
							break
					if collision_found:
						break

			print(f'For n = {k} A total of {len(rd512)} messages generated.')
			print(f'For n = {k} A total of {len(hashed)} hashes computed.')

			mean_time[k].append(time_taken)

	for key, val in mean_time.items():
		print(f'\nn = {key} on average takes {np.mean(val)} s')
```


Results:

```
Message 1:  0x59ac8f8e3fe67e93974f276fd88f97149d3f6fe3483b0246306bdf32571de9261731e150d365ab36a3929a05e5820d344468c24349ab09b490f8e304453d23c5
Corresponding Hash:  81

Message 2:  0x29f373b96e481c2707d91d15527e8dde55054009a4d207f2ab1f028cbf66beabcd5a9256f9058e8fc8138649fd2bfbc4c31118ea8216c083f16bdc8827fae0ae
Colliding Hash:  81
For n = 8 A total of 17 messages generated.
For n = 8 A total of 17 hashes computed.

Message 1:  0xd37693ac2c2c9cca567cf8f744be1f551d42359b5581e6b1cf52ddcde6fa51cc7456649dc5edb344cfd2c9991e0b1b78b2e0daaf980e78356f50c6d1db2a2410
Corresponding Hash:  0ca7

Message 2:  0x176aad7b3001d39e7e75ffa846a938f624186f28515c5c5f63055d0e9f667b5b3ce8fc22cbfb607d9a40263e3602c2cda8ea6a8d1f455d7f26704a504e16490d
Colliding Hash:  0ca7
For n = 16 A total of 250 messages generated.
For n = 16 A total of 250 hashes computed.

Message 1:  0x16c912771ba9acbd9552903eda53abf635584472191521b2ab85dcc5662dd2afc146d6cb16b696e2c1a0799ed0b6e7c2a68daeb9555432558f8afa9ea20d6d42
Corresponding Hash:  2a

Message 2:  0x73526f1bbd730438c7b8a07889a6d26f45a9a466e18c7469d48ca51fb87abe6bd5925e0b8fa0512741ae30f87c76aeb390444ea7831a1d6d4f83f4a6bd1c344b
Colliding Hash:  2a
For n = 8 A total of 16 messages generated.
For n = 8 A total of 16 hashes computed.

Message 1:  0x2defbf9a4297728d03efceedfbe6ca986fdfe042bbb2edba31557d47e1e9f6052b55425cb52b62509ddd9615b3ea4b49fb7261cbac5ea3235171353b9e54c1e7
Corresponding Hash:  116d

Message 2:  0x4e7622a81b772b58c2e1d075ec9b7437be672cde784ccd710e3d09c239d98fa1f4c4222f838e31902c433ec9fb62139821db156c6d6dff708ea1462fd67fb31
Colliding Hash:  116d
For n = 16 A total of 346 messages generated.
For n = 16 A total of 346 hashes computed.

Message 1:  0x9abec72a7de5363f76761c1a9c38ea703737d62ebe8e6512dcbb73e3b1c9258692611ccd9017e33e8131c6c845da2abe869a601cc3b001910a4fff52b646af3f
Corresponding Hash:  dc

Message 2:  0xc29bc570014bb95f22fb03799f59cccf66a8e0d29d053a436b270fa22ca5bbec5588471538225fa93da50416172a521161fb14d41862c84d6dfdec8e63a1e71a
Colliding Hash:  dc
For n = 8 A total of 17 messages generated.
For n = 8 A total of 17 hashes computed.

Message 1:  0x14b951d006bd2d3838839b68ebe675c131dd59c3f67a0552f769e33ea2c6fb31c098114778b16ec1a2ef5c0c496a63cf0a1bd76dcbc5c7301c63c7287c9321fa
Corresponding Hash:  9bc3

Message 2:  0x5fec090b49f34d6c945e4cf053b47df7d187b818c814586b26bf76841d662613db92b6542afe2f128e00edf165fdf1a885806189f37cd2b98760a68218312a4e
Colliding Hash:  9bc3
For n = 16 A total of 236 messages generated.
For n = 16 A total of 236 hashes computed.

Message 1:  0xf04fce383d0fe008fcf0d2c008bf992c890e4c1f013a3de9baa461031251b5c1c841d27766363f9af3d4667e9a405fb0e5e6ecee09af76d3b9cfb16d3090d434
Corresponding Hash:  1b

Message 2:  0x37d531773032d6a5f9c517d22cb7524a6254ac38392cc4ec8b3c74ba71020d5a10d4423107793bf44fc299cad348f2268cf79beb086141adfc7bbb888a0f8dc5
Colliding Hash:  1b
For n = 8 A total of 14 messages generated.
For n = 8 A total of 14 hashes computed.

Message 1:  0x13c02723ac2c882aa9933d70321a079be86074bcbe1d415ff2037f7fed2e0aa22382867e9a851e2dfaf18bf00365481785513e792e0cad71bc963514379e968b
Corresponding Hash:  7ccc

Message 2:  0xf313470f43b411ac68bba09d67717a95faa39a64215f2b1582f3d311fa4374c7d3d4178fca747e2b0307d3772a707711f3536d25911bebc3c4f990ac4cde3111
Colliding Hash:  7ccc
For n = 16 A total of 435 messages generated.
For n = 16 A total of 435 hashes computed.

Message 1:  0x6319d8ce028486d648bfc09fcf7f44a94174f4d74bf2a938d0223af30e60fad95554ec14f58bbb942d947359f04635ceead5dfccb0a5fa7b3b60ab5dde4be340
Corresponding Hash:  10

Message 2:  0xbaa9ed932e48973db7acb5314ecee2522689cd5ada2c5437102eda3c6efb9699b4854499a84535098260ce2c812a5e4290bbf8ce3d172f433d077ba83d7ff5c7
Colliding Hash:  10
For n = 8 A total of 14 messages generated.
For n = 8 A total of 14 hashes computed.

Message 1:  0xafa9dc40788ecb96114a230281a83fd8aa68c92268be832934f655159e47bf110f9d741d6f2f8383e2c9c60b8140b1a400e0f5f9789611c9573db7ecbd53108e
Corresponding Hash:  c74f

Message 2:  0xdf72f9a87de1be4ee53de28145f95f78fc9703315d463fa354cc1f331679357e940744438eb4e92715368390c2bad30b342df9a0e510ead9b741309c01d3a463
Colliding Hash:  c74f
For n = 16 A total of 41 messages generated.
For n = 16 A total of 41 hashes computed.

n = 8 on average takes 0.00015161999999998565 s

n = 16 on average takes 0.32491243999999997 s

n = 8 on average the number of messages are 15.6

n = 16 on average the number of messages are 261.6
```

The colliding hashes can be seen in the snippets of the results.


On average (for 30 iterations) H8 takes 0.00015161999999998565 s
On average (for 30 iterations) H16 takes 0.32491243999999997 s



## Exercise 3

```python=
def ex3():
	ns = [8,16]

	for n in ns:
		counter = 0
		preimage_found = False
		start = timeit.default_timer()

		bites = int(n/4)

		while not preimage_found:
			counter += 1
			# generate a random message
			rd512 = hex(random.getrandbits(512))

			hashed = hashlib.sha512(binascii.unhexlify(rd512[2:].zfill(128))).hexdigest()[0:bites]



			if hashed == "0"*bites:
				preimage_found = True
				end = timeit.default_timer()
				break

		print("Took", end - start, "seconds to find preimage.")
		print("The preimage found is ", rd512, " after generating ", counter, "messages.")
		print("The full SHA512 hash is ", hashlib.sha512(binascii.unhexlify(rd512[2:].zfill(128))).hexdigest())
```

Results
```
For H8 It took 0.00039320000000042654 seconds to find preimage.
The preimage found is  0x491b73a0d246dd6ab9336c26715fc36230a4aae62155f1d520fe2f917ff05b8535c2a1ce2c8c7dcd1b04a01c9ba80a9e53ac91e63ad1dbafc3b61c198995fce3  after generating  140 messages.
The full SHA512 hash is  000b14f3f660a7414ccf27befac3de7fc6b81d77cef09b89affc62a1621a778dd99dce163766e205be2b028ed01b0f4a301c228843b0ecd7f54a72adf4ea73b7
For H16 It took 0.15512569999999926 seconds to find preimage.
The preimage found is  0xe92a0859fcb5de01ff3c4327f1002be5503e689cad0d75a22d0ee763a11e1fda4a955b87be4d1875521be5091e01218724b2831f82aa218ae1140fd50d6a717f  after generating  69533 messages.
The full SHA512 hash is  00006126ec80341585798d7c415d9520fd3e2990af3b6069355bc654da5641174234d5d8cc6a485133adc80637080ba6ae87ab676867a36a56834dde77b8e37a
```



## Exercise 4


```python=

def ex4():
	# Generate Key
	key = "1".zfill(32)
	print("Key: ", key)
	key = binascii.unhexlify(key)


	# Generate Random Tag
	_tag = hex(random.getrandbits(128))[2:].zfill(32)
	print("Tag: ", _tag)
	tag = binascii.unhexlify(_tag)

	# Decrypt single blk to find tag.
	cipher = AES.new(key, AES.MODE_CBC, IV = binascii.unhexlify('0'.zfill(32)))	# use AES CBC
	singleblk = int.from_bytes(cipher.decrypt(tag), byteorder='big')


	# consider two-block message "blk1 || blk2", where we have a choice of blk2
	blk2 = 1


	'''
	Assume as if tag was MAC(blk1 || blk2) = MAC((MAC(blk1) xor blk2)
	i.e. MAC(blk1) = blk2 xor singleblk
	'''
	_tagprev = hex(singleblk ^ blk2)[2:].zfill(32)
	print("Previous tag: ", _tagprev)
	tagprev = binascii.unhexlify(_tagprev)


	cipher = AES.new(key, AES.MODE_CBC, IV = binascii.unhexlify('0'.zfill(32)))	# use AES CBC
	blk1 = (cipher.decrypt(tagprev)).hex().zfill(32)


	print("Single Block Message: ", hex(singleblk)[2:].zfill(32))
	print("Block 1 of two-block Message: ", blk1)
	print("Block 2 of two-block Message: ", hex(blk2)[2:].zfill(32))

	ex4_verify(blk1, hex(blk2)[2:].zfill(32), _tag, _tagprev, hex(singleblk)[2:].zfill(32))





def ex4_verify(check_blk1, check_blk2, check_tag, check_tagprev, check_singleblk):
	key = key = "00000000000000000000000000000001".zfill(32)
	tag = check_tag.zfill(32)
	tagprev = check_tagprev.zfill(32)
	singleblk = check_singleblk.zfill(32)
	blk1 = check_blk1.zfill(32)
	blk2 = check_blk2

	key = binascii.unhexlify(key)
	tag = binascii.unhexlify(tag)
	tagprev = binascii.unhexlify(tagprev)
	singleblk = binascii.unhexlify(singleblk)
	blk1_blk2 = binascii.unhexlify(blk1 + blk2)

	cipher = AES.new(key, AES.MODE_CBC, IV = binascii.unhexlify('0'.zfill(32)))	# use AES CBC
	check1 = cipher.encrypt(singleblk).hex()
	cipher = AES.new(key, AES.MODE_CBC, IV = binascii.unhexlify('0'.zfill(32)))	# use AES CBC
	check2 = cipher.encrypt(blk1_blk2).hex()

	if check1 == check2[32:]:
		print("Tag is the same for ", singleblk.hex(), " and ", blk1_blk2.hex(), ".")
		print("Tag: ", tag.hex())
```


Results
```
Key:  00000000000000000000000000000001
Tag:  11fa92774478f2d8fc78756eaa0a1fb5
Previous tag:  0f87e3b053400b58a55239384065d87a
Single Block Message:  0f87e3b053400b58a55239384065d87b
Block 1 of two-block Message:  5f3e639ffb8736012b19a1a525246609
Block 2 of two-block Message:  00000000000000000000000000000001
Tag is the same for  0f87e3b053400b58a55239384065d87b  and  5f3e639ffb8736012b19a1a52524660900000000000000000000000000000001 .
Tag:  11fa92774478f2d8fc78756eaa0a1fb5
```

## Exercise 5

Let MAC(.) be the function using CBC=MAC that generates the tag for a message, such that $MAC(a) = t$

The two-block message would be $a || (a ⨁ MAC(a))$.

$MAC(a || (a ⨁ MAC(a)))$ =

= $MAC(MAC(a)  ⨁ (a ⨁ MAC(a)))$
= $MAC(MAC(a)  ⨁ MAC(a) ⨁ a)$
= $MAC(a)$
= $t$


In other words, by concatenating a with a ⨁ MAC(a), the corresponding tag is still t. The attacker can therefore choose the two-block message as a || (a ⨁ MAC(a)) and forge the tag as t.
In fact, we could continue concatenating more of a ⨁ MAC(a) and apply CBC-MAC and still arrive a tag t. In each XOR operation, the MAC(a) component of the newly concatenated block cancels out t from the previous MAC(.) output. This leaves the final MAC(.) with input a effectively, creating an output equal to t (that the attacked had earlier received).
