Hash及Hmac
Hash算法,主要用于获取摘要值,由于其不可逆向,从而保证明文的完整性。
Hmac在Hash的基础上引入了密钥,在Hmac的计算过程中通过两次异或,两次Hash得出消息认证码。目前SSL协议、IPsec协议、SSH协议等在通信过程中都使用了Hmac算法保护数据的完整性。
Hmac比Hash多了一层安全性,使用Hash算法时如明文与摘要同时被篡改,则无法确保其完整性。使用Hmac算法时,在无法获取密钥的情况下即使篡改了明文与摘要,接收方也能通过Hmac算法判断其完整性遭到了破坏。
Hash实现
1.填充
Hash算法对数据输入长度无要求,因为在接受到原始输入后,必须对其进行填充使其长度为L的倍数,在SM3算法中,L为64(Byte)。
SM3算法的填充方式为:
首先将明文按照512bit分组,下文中提到的64bit的L为分组前整体数据的长度。
长度小于448bit时。
在明文后填充一个“1”,在尾部填充明文的长度L(L填充在最尾部,如L小于64bit,在高位填充0),然后在填充的“1”和尾部64bit的L之间填充0,使数据整体长度达到512bit。
输入数据(16进制)“616263”
>>>"61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018"
长度大于或等于448bit,但小于512bit时
在明文后填充一个“1”,然后在尾部填充0,使长度达到512bit。然后填充一组512bit数据(448个0+64bit的L)
输入数据(16进制)“616263800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000”
>>>“6162638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200”
长度大于512bit时,判断最后一组数据的长度,然后按照上面的方式进行填充
输入数据(16进制)“616263800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000”
分组后的数据:
>>>['61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018', '61']
填充后的数据:
>>>['61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018', '61800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000208']
长度等于512bit或为512bit的倍数时
在尾部填充一个“1”,447个“0”,以及64bit的L。
输入数据(16进制)“6162638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001861626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018”
分组后的数据:
>>>['61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018', '61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018']
填充后的数据:
>>>['61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018', '61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018', '80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400']
代码实现
def group(list, n):##分组
for i in range(0, len(list), n):
yield list[i:i + n]
def sm3(data):
l = len(data)//2
byte = '{0:x}'.format(int(l*8))
data_list = []
[data_list.append(i) for i in group(data, 128)]
m = l%64
if m < 56 and m != 0:
data_list[-1] = (data_list[-1]+'80').ljust(112,'0')+str(byte).rjust(16,'0')
elif m >= 56:
data_list[-1] = (data_list[-1]+'80').ljust(128,'0')
data_list.append(112*'0'+str(byte).rjust(16,'0'))
elif m == 0:
data_list.append('80'+110*'0'+str(byte).rjust(16,'0'))
return data_list
2.迭代压缩
迭代压缩过程中主要使用异或、或、与、非运算以及32位循环左移,这里不再描述具体运算规则。
在迭代压缩过程中,为了方便,所有值都改为了10进制。
IV和TJ为GB-T32905给出的初始值与常量。
def xor(a,b):
a1 = int(a,16)
b1 = int(b,16)
A = '{:08x}'.format(int(a1^b1))
return A
def left_hex(list,n):
out1 = '{:032b}'.format(int(list,16))
out2 = out1[n:] + out1[:n]
out_list = '{:08x}'.format(int(out2,2))
return out_list
def left_int(list,n):
out1 = '{:032b}'.format(list)
out2 = out1[n:] + out1[:n]
out_list = int(out2,2)
return out_list
IV = [1937774191, 1226093241, 388252375, 3666478592,2842636476, 372324522, 3817729613, 2969243214,]
Tj =[
2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169,
2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169,
2043430169, 2043430169, 2043430169, 2043430169, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042
]
def FFj(X, Y, Z, j):
if 0 <= j and j < 16:
return X ^ Y ^ Z
elif 16 <= j and j < 64:
return (X & Y) | (X & Z) | (Y & Z)
def GGj(X, Y, Z, j):
if 0 <= j and j < 16:
return X ^ Y ^ Z
elif 16 <= j and j < 64:
return (X & Y) | ((~ X) & Z)
def P0(X):
return X ^ left_int(X,9) ^ left_int(X,17)
def P1(X):
return xor(xor(X ,left_hex(X,15)),left_hex(X,23))
def CF(V,data):
W = []
W1 = []
[W.append(data[i*8:(i+1)*8]) for i in range(16)]
for i in range(16,68):
w_in = xor(xor(P1(xor(xor(W[i-16],W[i-9]),left_hex(W[i-3],15))),left_hex(W[i-13],7)),W[i-6])
w_out = '{:08x}'.format(int(w_in,16))
W.append(w_out)
[W1.append(xor(W[i],W[i+4])) for i in range(64)]
A,B,C,D,E,F,G,H = V
for i in range(0,64):
ss1 = left_int((left_int(A,12)+E+left_int(Tj[i],i%32) & 0xffffffff),7)
ss2 = ss1^(left_int(A,12))
tt1 = (FFj(A,B,C,i) + D + ss2 + int(W1[i],16)) & 0xffffffff
tt2 = (GGj(E,F,G,i) + H + ss1 + int(W[i],16)) & 0xffffffff
D = C
C = left_int(B, 9)
B = A
A = tt1
H = G
G = left_int(F, 19)
F = E
E = P0(tt2)
outV = [A ^ V[0], B ^ V[1], C ^ V[2], D ^ V[3],E ^ V[4], F ^ V[5], G ^ V[6], H ^ V[7]]
return outV
Hmac实现
def sm3_hmac(data,key):
l = len(key)//2
if l >64:
key = sm3(key)
else:pass
key = key.ljust(128,'0')
opad = '5c'*64
ipad = '36'*64
ipadkey = '%x'%(int(key,16)^int(ipad,16))
M = sm3(ipadkey+data)
opadkey = '%x'%(int(key,16)^int(opad,16))
out_data = sm3(opadkey+M)
return out_data
完整代码
IV = [1937774191, 1226093241, 388252375, 3666478592,2842636476, 372324522, 3817729613, 2969243214,]
Tj =[
2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169,
2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169,
2043430169, 2043430169, 2043430169, 2043430169, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042,
2055708042, 2055708042, 2055708042, 2055708042
]
def group(list, n):##分组
for i in range(0, len(list), n):
yield list[i:i + n]
def xor(a,b):
a1 = int(a,16)
b1 = int(b,16)
A = '{:08x}'.format(int(a1^b1))
return A
def left_hex(list,n):
out1 = '{:032b}'.format(int(list,16))
out2 = out1[n:] + out1[:n]
out_list = '{:08x}'.format(int(out2,2))
return out_list
def left_int(list,n):
out1 = '{:032b}'.format(list)
out2 = out1[n:] + out1[:n]
out_list = int(out2,2)
return out_list
def FFj(X, Y, Z, j):
if 0 <= j and j < 16:
return X ^ Y ^ Z
elif 16 <= j and j < 64:
return (X & Y) | (X & Z) | (Y & Z)
def GGj(X, Y, Z, j):
if 0 <= j and j < 16:
return X ^ Y ^ Z
elif 16 <= j and j < 64:
return (X & Y) | ((~ X) & Z)
def P0(X):
return X ^ left_int(X,9) ^ left_int(X,17)
def P1(X):
return xor(xor(X ,left_hex(X,15)),left_hex(X,23))
def CF(V,data):
W = []
W1 = []
[W.append(data[i*8:(i+1)*8]) for i in range(16)]
for i in range(16,68):
w_in = xor(xor(P1(xor(xor(W[i-16],W[i-9]),left_hex(W[i-3],15))),left_hex(W[i-13],7)),W[i-6])
w_out = '{:08x}'.format(int(w_in,16))
W.append(w_out)
[W1.append(xor(W[i],W[i+4])) for i in range(64)]
A,B,C,D,E,F,G,H = V
for i in range(0,64):
ss1 = left_int((left_int(A,12)+E+left_int(Tj[i],i%32) & 0xffffffff),7)
ss2 = ss1^(left_int(A,12))
tt1 = (FFj(A,B,C,i) + D + ss2 + int(W1[i],16)) & 0xffffffff
tt2 = (GGj(E,F,G,i) + H + ss1 + int(W[i],16)) & 0xffffffff
D = C
C = left_int(B, 9)
B = A
A = tt1
H = G
G = left_int(F, 19)
F = E
E = P0(tt2)
outV = [A ^ V[0], B ^ V[1], C ^ V[2], D ^ V[3],E ^ V[4], F ^ V[5], G ^ V[6], H ^ V[7]]
return outV
def sm3(data):
l = len(data)//2
byte = '{0:x}'.format(int(l*8))
data_list = []
[data_list.append(i) for i in group(data, 128)]
m = l%64
if m < 56 and m != 0:
data_list[-1] = (data_list[-1]+'80').ljust(112,'0')+str(byte).rjust(16,'0')
elif m >= 56:
data_list[-1] = (data_list[-1]+'80').ljust(128,'0')
data_list.append(112*'0'+str(byte).rjust(16,'0'))
elif m == 0:
data_list.append('80'+110*'0'+str(byte).rjust(16,'0'))
V = IV
for i in range(0,len(data_list)):
V = CF(V,data_list[i])
for i in range(len(V)):
V[i] = '{:08x}'.format(V[i])
return ''.join(V)
def sm3_hmac(data,key):
l = len(key)//2
if l >64:
key = sm3(key)
else:pass
key = key.ljust(128,'0')
opad = '5c'*64
ipad = '36'*64
ipadkey = '%x'%(int(key,16)^int(ipad,16))
M = sm3(ipadkey+data)
opadkey = '%x'%(int(key,16)^int(opad,16))
out_data = sm3(opadkey+M)
return out_data
版权声明:本文为weixin_46491183原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。