Hash Functions


from struct import *
from Crypto.Cipher import AES
from functools import reduce


def slicepad(x, bsize, flag=0):
    # Slice & pad string
    if flag > 0:
        t = len(x)
        X = (
            t.to_bytes(t.bit_length() + 1, byteorder="big")
        ) + x
    else:
        X = x
    u = len(X) % bsize
    if u > 0:
        X += b"0" * (bsize - u)
    return [
        X[bsize * i : bsize * (i + 1)]
        for i in range(0, int(len(X) / bsize))
    ]


def xorstr(x, y):
    return bytearray(x[i] ^ y[i] for i in range(0, len(x)))


def CBCMAC(enc, bsize):
    "Implementazione di CBCMAC su funzione enc"

    def chain(X, IV, k):
        H = IV
        for i in range(0, len(X)):
            print("Chain variable H:", H)
            print("TXT block X:", X[i])
            H = xorstr(H, X[i])
            print("Masked block:", H)
            H = enc(H, k)
        return H

    def actualCBC(x, k, IV):
        sl = slicepad(x, bsize)
        w = chain(sl, IV, k)
        return w
        # return unpack('B'*len(w),w)

    return actualCBC


def HMACgen(hash, B):
    "Costruzione HMAC"

    def HMAC(K, txt):
        ipad = b"\x36" * B
        opad = b"\x5c" * B
        if len(K) == B:
            K0 = K
        elif len(K) > B:
            K0 = hash(K)
            if len(K0) < B:
                K0 += b"\x00" * (B - len(L))
        elif len(K) < B:
            K0 = K + b"\x00" * (B - len(K))
        temp0 = xorstr(K0, ipad) + txt
        temp1 = xorstr(K0, opad)
        h1 = temp1 + hash(temp0)
        return hash(h1)

    return HMAC


def CallMDC(chain, bsize, flag):
    def ActualMDC(x, IV=b"\x00" * bsize):
        sl = slicepad(x, bsize, flag)
        w = chain(sl, IV)
        # return unpack('B'*len(w),w)
        return w

    return ActualMDC


def BasicMerkle(f, bsize, flag=0):
    "Costruzione di Merkle-Damgard (base)"

    def chain(sliced, IV):
        H = IV
        for i in range(0, len(sliced)):
            print("Chain variable:", H)
            print("Text:", sliced[i])
            H = f(H, sliced[i])
            print("-")
        return H

    return CallMDC(chain, bsize, flag)


def Construction3C(f, g, bsize, flag=0):
    def chain(sliced, IV):
        H = IV
        Z = b"\x00" * len(IV)
        for i in range(0, len(sliced)):
            print("Chain variable:", H)
            print("Text:", sliced[i])
            H = f(bytes(H), bytes(sliced[i]))
            print("Cascade value:", H)
            Z = xorstr(Z, H)
            print("Accumulation value", Z)
            print("-")
        return g(bytes(H), bytes(Z))

    return CallMDC(chain, bsize, flag)


def DavisMeyerConst(enc):
    def DoEnc(H, m):
        return xorstr(H, enc(H, m))

    return DoEnc


# SAMPLE HASHING
# enc=AES in modalita' ECB


def aesEnc(x, K):
    ECB = AES.new(K, AES.MODE_ECB)
    return ECB.encrypt(bytes(x))


enc = DavisMeyerConst(aesEnc)


hashCBC = CBCMAC(enc, 16)


# Chiave
key = "0123456789ABCDEF"
# Initial vector
IV = b"\x00" * 16
# Test text
TXT0 = b"The quick brown fox jumps over the lazy dog... Lorem ipsum"
TXT1 = b"Uhe quick brown fox jumps over the lazy dog... Lorem ipsum"
h1 = hashCBC(TXT0, key, IV)
h2 = hashCBC(TXT1, key, IV)

hashMDC1 = BasicMerkle(enc, 16)
h3 = hashMDC1(TXT0, IV)

hashMDC2 = BasicMerkle(enc, 16, 1)
h4 = hashMDC2(TXT0, IV)

hashMDC3 = Construction3C(enc, enc, 16)
h5 = hashMDC3(TXT0, IV)