1. DES- 60 points

Solved by: s0rc3r3r

In this challenge, we are given pairs of plaintext-ciphertext encrypted in DES-ECB using the same value of the key. The plaintext-ciphertext pairs are given in “known-plaintext.txt”. When we look closely at the values in the file, we can observe that for some pairs, the following characteristic exists:

E(E(m)) = m, where E() is the encryption function and m is the message

This peculiar vulnerability exists only in DES and exists only for a set of key values, that are known as weak keys. You can read about weak keys here: https://en.wikipedia.org/wiki/Weak_key#Weak_keys_in_DES

So the set of plaintexts are encrypted using a weak key. Now that number of weak keys is less, we can iterate over each weak key list and check if decryption of a ciphertext value in the file gives its corresponding plaintext.

Wrote the following script to implement it:

```from Crypto.Cipher import DES

obj1 = open("known_plaintexts.txt",'r')
pt_ct_list = [i.rstrip("\r").replace(" ","") for i in pt_ct_list]

# Weak key list
key = ["0101010101010101", "FEFEFEFEFEFEFEFE", "E0E0E0E0F1F1F1F1", "1F1F1F1F0E0E0E0E"]

for i in key:
key_obj = DES.new(i.decode("hex"), DES.MODE_ECB)
# Taking one ciphertext from file
ct = pt_ct_list[0][:16].decode("hex")
# Corresponding plaintext from file
pt = pt_ct_list[0][18:].decode("hex")
# Potential plaintext
pot_pt = key_obj.decrypt(ct)
if pot_pt == pt:
print "Key: ", i
```

Key: “E0E0E0E0F1F1F1F1”

We got the first blood for this challenge, pretty easy! >_<

2. OSS-Signature- 100 points

Solved by: s0rc3r3r

We are given m1, m2, x1, y1, x2, y2, k and n which satisfy the given equations:

$m1 = x1^2 + k*y1^2 \mod n$ –> Equation-1
$m2 = x2^2 + k*y2^2 \mod n$ –> Equation-2

The task is to express m1*m2 using a similar representation ie.
$m1*m2 = s1^2 + k*s2^2 \mod n$
and hence, we have to find the value of s1 and s2.

We can find s1 and s2 from the following:
1. Multiply Equation-1 and Equation-2, we will have:
$= (x1^2 + k*y1^2) * (x2^2 + k*y2^2)$
$= (x1^2*x2^2) + (k*x1^2*y2^2) + (k*x2^2*y1^2) + (k^2*y1^2*y2^2)$
We can make it a perfect square by adding and subtracting 2*x1*x2*k*y1*y2, we will then have:
$((x1^2*x2^2) + (k^2*y1^2*y2^2) + (2*x1*x2*k*y1*y2)) + (k*x1^2*y2^2) + (k*x2^2*y1^2) - (k*x1*x2*y1*y2)$
And hence,
$((x1*x2) + (k*y1*y2))^2 + k*((x1*y2) - (x2*y1))$
Where s1 = x1*x2 + k*y1*y2 and s2 = x2*y1 – x1*y2

Wrote the following code to implement it:

```
term1 = x1**2 + k*(y1**2)
term2 = x2**2 + k*(y2**2)
assert (term1*term2) % n == 5141
s1 = x1*x2 + k*y1*y2
s2 = x2*y1 - x1*y2
assert (s1**2 + k*(s2**2)) % n == 5141
# Modulo reduction
print "s1: ", s1 % n
print "s2: ", s2 % n
```

And we get the values of s1 and s2 that satisfy the conditions:

s1 = 3228192414578958851010842513154275809496752450843437198583166196901565071578144066800517210864829309956656172864622172889502523814134130877601254638400747755883616155295299435314390972047946113969350548381594633322779945307216665767237995638888452882989503186673207123359630734140939449837354851424900356484212983667331443801108560693455298625538140549843770730178132648956596007707374948190919655158210892858713252214782069457662864873988983041011930880072395421594443371267339482128681654521226571357238152202622389403367075320562466814355917951666554746996134626758309948472069549094989922908904448493268680406656

s2 = 24484535381781389323074470421911819639042225964435602473611268830778094454640680950247904607938498485547308794156596530048036709040042946833357706925382417888065011049859098805247309143606836121648675503265954564725192812735457023952534691595036622842908877779999269095789286247447026022826317754191340149168483076749534241533561701691035224125146103048048656077931512856242523043968028811895609749316745020908526817848861116370125504641363458061292626411114312230260298354677312266199167460831130312481867664446125836465876792580053773528992613465690017628197218948554388712333570191622746063799279773801301923351131

3. fHash – 200 points

Solved by: v4d3r and s0rc3r3r

Optimised Brute Force:

```import os
from hashlib import md5

def foo(h, m):
return md5(h.encode('utf-8') + m.encode('utf-8')).hexdigest()[:4]

def round(hl, m, hr):
#print foo(hl,m), foo(hr,m)
return foo(hl, m), foo(hr, m)

def fHash(hl, hr, M):
message = list(map(''.join, zip(*[iter(M)] * 4)))
for m in message:
#print "for message part :" + m
#print hl, hr
hl, hr = round(hl, m, hr)
return hl + hr

if __name__ == '__main__':
h = (fHash('7575', 'A8A8', '7368617269666374'))
print (fHash('7575', 'A8A8', '7368617269666374'))
#l=5958
#r=433b
print (fHash('5958', '433b', '7368617269666300'))

#the bruteforce goes here
#We assume the hash exist for message with last byte changed to \x00
print (fHash('7575', 'A8A9', '7368617269666300'))
left=""
right=""
#to get all ascii chars
a=""
for i in range(126):
a+=chr(i)
for i in a:
print "i passed :" + str(ord(i)*100/126) +"%"  # to get % completion
for j in a:
for k in a:
for l in a:
left=(i+j).encode("hex")
right=(k+l).encode("hex")
if (fHash(left, right, '7368617269666300'))==h:
print "found: Left is " + left + " and Right is " + right
break

```