Skip to content

Commit

Permalink
Add lab8
Browse files Browse the repository at this point in the history
  • Loading branch information
vis4rd committed Nov 27, 2023
1 parent 6285ef0 commit b6eaa95
Show file tree
Hide file tree
Showing 5 changed files with 316 additions and 0 deletions.
28 changes: 28 additions & 0 deletions lab8/zad1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Aleksander Kluczka

import numpy as np

def zad1():
def h(x) -> str:
x = np.array([int(i) for i in f"{x:07b}"])
A = np.array([[1, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 1, 0],
[1, 1, 1, 1],
[0, 1, 1, 1],
[0, 0, 1, 1],
[0, 0, 0, 1]]).transpose()
retval = np.dot(A, x) % 2
return ''.join(retval.astype(str))

for i in range(0b1111111+1):
result = h(i)
if result == "0101":
print(f"{i:03d} - {i:07b} - 0101")


def main():
zad1()

if __name__ == '__main__':
main()
28 changes: 28 additions & 0 deletions lab8/zad2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Aleksander Kluczka

import numpy as np

def zad2():
M = 365
Q = [i for i in range(15, 31)]

def eps(M, Q):
mult = 1.0
for i in range(1, Q):
mult *= float((M - i) / M)
return 1 - mult

def eps_approx(M, Q):
return 1 - np.exp((-Q * (Q - 1)) / (2 * M))

print(f" Q | eps | eps_approx")
print(f"----+---------+-----------")
for q in Q:
print(f"{q:3d} | {eps(M, q):.5f} | {eps_approx(M, q):.5f}")


def main():
zad2()

if __name__ == '__main__':
main()
33 changes: 33 additions & 0 deletions lab8/zad3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Aleksander Kluczka

from Crypto.Hash import MD4, MD5, SHA1, SHA224, SHA256, SHA384, SHA512

def zad3():
texts = [
"The quick brown fox jumps over the lazy dog",
"The quick brown fox jumps over the lazy cog",
"",
]

def print_results(texts, func, name):
print(f"Function: {name}")
for text in texts:
h = func.new()
h.update(text.encode('utf-8'))
print(f"'{text}' -> {h.hexdigest()}")
print()

print_results(texts, MD4, "md4")
print_results(texts, MD5, "md5")
print_results(texts, SHA1, "sha1")
print_results(texts, SHA224, "sha224")
print_results(texts, SHA256, "sha256")
print_results(texts, SHA384, "sha384")
print_results(texts, SHA512, "sha512")


def main():
zad3()

if __name__ == '__main__':
main()
43 changes: 43 additions & 0 deletions lab8/zad4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Aleksander Kluczka

# from Crypto.Hash import MD4
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.hashes import Hash
from cryptography.hazmat.backends import default_backend

default_backend()

class MD4(hashes.HashAlgorithm):
name = "md4"
digest_size = 16
block_size = 64

def zad4():
a = [b"839c7a4d7a92cb5678a5d5b9eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edd45e51fe39708bf9427e9c3e8b9",
b"839c7a4d7a92cbd678a5d529eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edc45e51fe39708bf9427e9c3e8b9"]
b = [b"a6af943ce36f0cf4adcb12bef7f0dc1f526dd914bd3da3cafde14467ab129e640b4c41819915cb43db752155ae4b895fc71b9b0d384d06ef3118bbc643ae6384",
b"a6af943ce36f0c74adcb122ef7f0dc1f526dd914bd3da3cafde14467ab129e640b4c41819915cb43db752155ae4b895fc71b9a0d384d06ef3118bbc643ae6384"]
c = [b"76931fac9dab2b36c248b87d6ae33f9a62d7183a5d5789e4b2d6b441e2411dc709e111c7e1e7acb6f8cac0bb2fc4c8bc2ae3baaab9165cc458e199cb89f51b13",
b"76931fac9dab2b36d248b87d6af33f9a62d7183a5d5789e4b2d6b441e2411dc709e111c7e1e7acb6f8cac0bb2fc4c8bc2ae3baaab9265cc458e199cb89f51b13"]

def check_collision(hashes: list[str]):
one = Hash(MD4())
two = Hash(MD4())
one.update(hashes[0])
two.update(hashes[1])
one = one.finalize()
two = two.finalize()

print(f"{one=}\n{two=}")

return one == two

print(f"attempt a: {check_collision(a)}")
print(f"attempt b: {check_collision(b)}")
print(f"attempt c: {check_collision(c)}")

def main():
zad4()

if __name__ == '__main__':
main()
184 changes: 184 additions & 0 deletions lab8/zad5.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# Aleksander Kluczka

from Crypto.Hash import SHA1


def chunker(sequence, chunk_size: int):
return (
sequence[pos : pos + chunk_size] for pos in range(0, len(sequence), chunk_size)
)


def b2x_str(bit_str: str) -> str:
hex_str = ""
for c in chunker(bit_str, 8):
hex_str += f"{int(c, 2):02X} "
return hex_str


def sha1(message: str, print_debugs: bool = False):
def left_rotate(number: int, rotation_count: int, number_of_bits: int = 32) -> int:
def ensure_correct_1_bit_count() -> None:
assert (lft := f"{number:0{number_of_bits}b}".count("1")) == (
rgt := f"{result:0{number_of_bits}b}".count("1")
), f"Incorrect number of bits: {lft=} != {rgt=}"

### option 1 - definition from PDF, but it's not a correct bit rotation???
### (ASSERT FAILS)
# print(f"org_number: {number:0{number_of_bits}b}")
# print(
# f"first_part: {(number << rotation_count) & 0xFFFFFFFF:0{number_of_bits}b}"
# )
# print(f"secnd_part: {(number >> number_of_bits):0{number_of_bits}b}")
# print(
# f"lft_rotate: {((number << rotation_count) | (number >> number_of_bits)) & 0xFFFFFFFF:032b}\n"
# )
# result: int = (
# ((number << rotation_count) & 0xFFFFFFFF) | (number >> number_of_bits)
# ) & 0xFFFFFFFF

### option 2 - technically correct definition from PDF - actual rotation
### (same result as option 3)
result: int = (
((number << rotation_count) & 0xFFFFFFFF)
| (number >> (number_of_bits - rotation_count))
) & 0xFFFFFFFF

### option 3 - "the pythonic way"
# number_str = f"{number:0{number_of_bits}b}"
# result: int = int(number_str[rotation_count:] + number_str[:rotation_count], 2)

# assert that the number of '1' is the same after rotation
ensure_correct_1_bit_count()
return result

# initial variables
h0 = 0x67452301
h1 = 0xEFCDAB89
h2 = 0x98BADCFE
h3 = 0x10325476
h4 = 0xC3D2E1F0

# convert message to bits
bit_msg = ""
for c in message:
bit_msg += f"{ord(c):08b}"
# bit_msg += f"{int(c, 16):08b}"

if print_debugs:
print(f"msg converted to binary (in hex) = {b2x_str(bit_msg)}")

bit_msg_length_before_fill: int = len(bit_msg)

# start with appending '1' to the message
bit_msg += "1"

# append k '0' bits, where 0 <= k < 512, so that the resulting message length is congruent to
# 448 modulo 512
k = -1
while True:
k += 1
if ((bit_msg_length_before_fill + 1 + k) % 512) == 448:
break

if print_debugs:
print(f"{k=}")

bit_msg += "0" * k
if print_debugs:
print(f"msg with filled 0 bits = {b2x_str(bit_msg)}")
assert len(bit_msg) % 512 == 448

# append length of the message as 64-bit big-endian integer
bit_msg += f"{bit_msg_length_before_fill:064b}"
if print_debugs:
print(f"msg with appended length = {b2x_str(bit_msg)}")
assert len(bit_msg) % 512 == 0

# loop over the message in 512-bit chunks
for chunk in chunker(bit_msg, 512):
assert len(chunk) == 512

# split the chunk into 16 32-bit words
w: dict[int, str] = {}
for i, word in enumerate(chunker(chunk, 32)):
assert 0 <= i <= 15
assert len(word) == 32
w[i] = int(word, 2)
assert 0 <= w[i] < 2**32

# extend the first 16 words into 80 32-bit words
for i in range(16, 80):
w[i] = left_rotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1)
assert 0 <= w[i] < 2**32

a, b, c, d, e = h0, h1, h2, h3, h4

# funny little loop
for i in range(80):
if 0 <= i <= 19:
f = (b & c) | ((~b) & d)
k = 0x5A827999
elif 20 <= i <= 39:
f = b ^ c ^ d
k = 0x6ED9EBA1
elif 40 <= i <= 59:
f = (b & c) | (b & d) | (c & d)
k = 0x8F1BBCDC
elif 60 <= i <= 79:
f = b ^ c ^ d
k = 0xCA62C1D6

# some swap shenanigans
temp = (left_rotate(a, 5) + f + e + k + w[i]) % (2**32)
e = d
d = c
c = left_rotate(b, 30)
b = a
a = temp

assert 0 <= a < (2**32)
assert 0 <= b < (2**32)
assert 0 <= c < (2**32)
assert 0 <= d < (2**32)
assert 0 <= e < (2**32)

assert 0 <= h0 < (2**32)
assert 0 <= h1 < (2**32)
assert 0 <= h2 < (2**32)
assert 0 <= h3 < (2**32)
assert 0 <= h4 < (2**32)

# rotate add 32-bit temp words
h0 = (h0 + a) % (2**32)
h1 = (h1 + b) % (2**32)
h2 = (h2 + c) % (2**32)
h3 = (h3 + d) % (2**32)
h4 = (h4 + e) % (2**32)

result = f"{h0:032b}{h1:032b}{h2:032b}{h3:032b}{h4:032b}"
assert len(result) == (32 * 5)
print(f"final result = {b2x_str(result)}")


def zad3(text: str):
h = SHA1.new()
h.update(text.encode("utf-8"))
result = f"{int(h.hexdigest(), 16):0b}"
print(f"Crypto.SHA1 = {b2x_str(result)}")


def zad5():
message = ""
print(f"message = '{message}'")

sha1(message, print_debugs=False)
zad3(message)


def main():
zad5()


if __name__ == "__main__":
main()

0 comments on commit b6eaa95

Please sign in to comment.