235 lines
4.6 KiB
Python
235 lines
4.6 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
|
# md6hash for Python 2, 3
|
|
#
|
|
# Usage:
|
|
# md6 = md6hash();
|
|
# data = "md6 FTW";
|
|
# result = md6.hex(data);
|
|
# print(result)
|
|
#
|
|
|
|
import binascii
|
|
|
|
class md6hash():
|
|
def __to_word(self, i_byte):
|
|
length = len(i_byte)
|
|
o_word = []
|
|
|
|
for i in range(0, length, 8):
|
|
o_word.append(
|
|
((i_byte[i + 0] & 0xff) << 56) |
|
|
((i_byte[i + 1] & 0xff) << 48) |
|
|
((i_byte[i + 2] & 0xff) << 40) |
|
|
((i_byte[i + 3] & 0xff) << 32) |
|
|
((i_byte[i + 4] & 0xff) << 24) |
|
|
((i_byte[i + 5] & 0xff) << 16) |
|
|
((i_byte[i + 6] & 0xff) << 8) |
|
|
((i_byte[i + 7] & 0xff) << 0)
|
|
)
|
|
|
|
return o_word
|
|
|
|
def __from_word(self, i_word):
|
|
length = len(i_word)
|
|
o_byte = []
|
|
|
|
for i in range(length):
|
|
o_byte.append((i_word[i] >> 56) & 0xff)
|
|
o_byte.append((i_word[i] >> 48) & 0xff)
|
|
o_byte.append((i_word[i] >> 40) & 0xff)
|
|
o_byte.append((i_word[i] >> 32) & 0xff)
|
|
o_byte.append((i_word[i] >> 24) & 0xff)
|
|
o_byte.append((i_word[i] >> 16) & 0xff)
|
|
o_byte.append((i_word[i] >> 8) & 0xff)
|
|
o_byte.append((i_word[i] >> 0) & 0xff)
|
|
|
|
return o_byte
|
|
|
|
def __crop(self, size, data, right):
|
|
length = int((size + 7) / 8)
|
|
remain = size % 8
|
|
|
|
if right:
|
|
data = data[len(data) - length:]
|
|
else:
|
|
data = data[:length]
|
|
|
|
if remain > 0:
|
|
data[length - 1] &= (0xff << (8 - remain)) & 0xff
|
|
|
|
return data
|
|
|
|
def __hash(self, size, data, key, levels):
|
|
b = 512
|
|
c = 128
|
|
n = 89
|
|
d = size
|
|
M = data
|
|
|
|
K = key[:64]
|
|
k = len(K)
|
|
|
|
while len(K) < 64:
|
|
K.append(0x00)
|
|
|
|
K = self.__to_word(K)
|
|
|
|
r = max(80 if k else 0, 40 + int(d / 4))
|
|
|
|
L = levels
|
|
ell = 0
|
|
|
|
S0 = 0x0123456789abcdef
|
|
Sm = 0x7311c2812425cfa0
|
|
|
|
Q = [
|
|
0x7311c2812425cfa0, 0x6432286434aac8e7, 0xb60450e9ef68b7c1,
|
|
0xe8fb23908d9f06f1, 0xdd2e76cba691e5bf, 0x0cd0d63b2c30bc41,
|
|
0x1f8ccf6823058f8a, 0x54e5ed5b88e3775d, 0x4ad12aae0a6d6031,
|
|
0x3e7f16bb88222e0d, 0x8af8671d3fb50c2c, 0x995ad1178bd25c31,
|
|
0xc878c1dd04c4b633, 0x3b72066c7a1552ac, 0x0d6f3522631effcb
|
|
];
|
|
|
|
t = [17, 18, 21, 31, 67, 89]
|
|
rs = [10, 5, 13, 10, 11, 12, 2, 7, 14, 15, 7, 13, 11, 7, 6, 12]
|
|
ls = [11, 24, 9, 16, 15, 9, 27, 15, 6, 2, 29, 8, 15, 5, 31, 9]
|
|
|
|
def f(N):
|
|
S = S0
|
|
A = list(N)
|
|
|
|
j = 0
|
|
i = n
|
|
|
|
while j < r:
|
|
for s in range(16):
|
|
x = S
|
|
x ^= A[i + s - t[5]]
|
|
x ^= A[i + s - t[0]]
|
|
x ^= A[i + s - t[1]] & A[i + s - t[2]]
|
|
x ^= A[i + s - t[3]] & A[i + s - t[4]]
|
|
x ^= x >> rs[s]
|
|
|
|
if len(A) <= i + s:
|
|
while len(A) <= i + s:
|
|
A.append(0x00)
|
|
|
|
A[i + s] = x ^ ((x << ls[s]) & 0xffffffffffffffff)
|
|
|
|
S = (((S << 1) & 0xffffffffffffffff) ^ (S >> 63)) ^ (S & Sm)
|
|
|
|
j += 1
|
|
i += 16
|
|
|
|
return A[(len(A) - 16):]
|
|
|
|
def mid(B, C, i, p, z):
|
|
U = ((ell & 0xff) << 56) | i & 0xffffffffffffff
|
|
V = ((r & 0xfff) << 48) | ((L & 0xff) << 40) | ((z & 0xf) << 36) | ((p & 0xffff) << 20) | ((k & 0xff) << 12) | (d & 0xfff)
|
|
|
|
return f(Q + K + [U, V] + C + B)
|
|
|
|
def par(M):
|
|
P = 0
|
|
B = []
|
|
C = []
|
|
z = 0 if len(M) > b else 1
|
|
|
|
while len(M) < 1 or (len(M) % b) > 0:
|
|
M.append(0x00)
|
|
P += 8
|
|
|
|
M = self.__to_word(M)
|
|
|
|
while len(M) > 0:
|
|
B.append(M[:int(b / 8)])
|
|
M = M[int(b / 8):]
|
|
|
|
i = 0
|
|
p = 0
|
|
l = len(B)
|
|
|
|
while i < l:
|
|
p = P if i == (len(B) - 1) else 0
|
|
C += mid(B[i], [], i, p, z)
|
|
|
|
i += 1
|
|
p = 0
|
|
|
|
return self.__from_word(C)
|
|
|
|
def seq(M):
|
|
P = 0
|
|
B = []
|
|
C = [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
|
|
|
|
while len(M) < 1 or (len(M) % (b - c)) > 0:
|
|
M.append(0x00)
|
|
P += 8
|
|
|
|
M = self.__to_word(M)
|
|
|
|
while len(M) > 0:
|
|
B.append(M[:int((b - c) / 8)])
|
|
M = M[int((b - c) / 8):]
|
|
|
|
i = 0
|
|
p = 0
|
|
l = len(B)
|
|
|
|
while i < l:
|
|
p = P if i == (len(B) - 1) else 0
|
|
z = 1 if i == (len(B) - 1) else 0
|
|
C = mid(B[i], C, i, p, z)
|
|
|
|
i += 1
|
|
p = 0
|
|
|
|
return self.__from_word(C)
|
|
|
|
while True:
|
|
ell += 1
|
|
M = seq(M) if ell > L else par(M)
|
|
|
|
if len(M) == c:
|
|
break
|
|
|
|
return self.__crop(d, M, True)
|
|
|
|
def __bytes(self, i_str):
|
|
i_str = binascii.hexlify(i_str.encode("ascii"))
|
|
o_byte = [int(i_str[i:i+2], 16) for i in range(0, len(i_str), 2)]
|
|
|
|
return o_byte
|
|
|
|
def __prehash(self, data, size, key, levels):
|
|
data = self.__bytes(data)
|
|
key = self.__bytes(key)
|
|
|
|
if size <= 0:
|
|
size = 1
|
|
elif size > 512:
|
|
size = 512
|
|
|
|
return self.__hash(size, data, key, levels)
|
|
|
|
def hex(self, data="", size=256, key="", levels=64):
|
|
byte = self.__prehash(data, size, key, levels)
|
|
hexstr = ""
|
|
|
|
for i in byte:
|
|
hexstr += "%02x" % i
|
|
|
|
return hexstr
|
|
|
|
def raw(self, data="", size=256, key="", levels=64):
|
|
byte = self.__prehash(data, size, key, levels)
|
|
rawstr = ""
|
|
|
|
for i in byte:
|
|
rawstr += chr(i)
|
|
|
|
return rawstr |