Python:SM4

SM4

即国家密码管理局发布的无线局域网产品使用的SMS4密码算法
SM4.0(原名SMS4.0)是中华人民共和国政府采用的一种分组密码标准

实现

程序运行说明

根据上方文档说明:

  • 该算法的分组长度为 128 比特,密钥长度为 128 比特。加密算法与密钥扩展算法都采用 32 轮非线性迭代结构。解密算法与加密算法的结构相同,只是轮密钥 rk 的使用顺序相反,解密轮密钥是加密轮密钥的逆序。
  • 最终调用函数 enc() 即可
  • 程序中注释仅用于验证算法的正确性,不影响最终结果

参数

  • 输入:十六进制表示的明文字符串(最大长度为128bit即字符串最大长度为16)和十六进制表示的加密密钥字符串mk(最大长度同样为128bit即字符串最大长度为16)
  • 输出:十六进制密文字符串
  • 其余函数及常量请参考上面的官方文档

代码

def sbox(a):
    s=['d690e9fecce13db716b614c228fb2c05',
       '2b679a762abe04c3aa44132649860699',
       '9c4250f491ef987a33540b43edcfac62',
       'e4b31ca9c908e89580df94fa758f3fa6',
       '4707a7fcf37317ba83593c19e6854fa8',
       '686b81b27164da8bf8eb0f4b70569d35',
       '1e240e5e6358d1a225227c3b01217887',
       'd40046579fd327524c3602e7a0c4c89e',
       'eabf8ad240c738b5a3f7f2cef96115a1',
       'e0ae5da49b341a55ad933230f58cb1e3',
       '1df6e22e8266ca60c02923ab0d534e6f',
       'd5db3745defd8e2f03ff6a726d6c5b51',
       '8d1baf92bbddbc7f11d95c411f105ad8',
       '0ac13188a5cd7bbd2d74d012b8e5b4b0',
       '8969974a0c96777e65b9f109c56ec684',
       '18f07dec3adc4d2079ee5f3ed7cb3948']
    b=''
    for i in range(4):
        r=int(a[2*i],16)
        c=int(a[2*i+1],16)
        b=b+s[r][c*2:(c+1)*2]
    return int(b,16)

def cl(x,i):#Cycle left
    x='{:032b}'.format(x)
    i=i%32
    x=x[i:]+x[:i]
    return int(x,2)

fk=[int('A3B1BAC6',16),int('56AA3350',16),int('677D9197',16),int('B27022DC',16)]
ck=[]
for i in range(32):
    cki=[]
    for j in range(4):
        cki.append('{:02x}'.format(((4*i+j)*7)%256))
    ck.append(int(''.join(cki),16))
'''
ck=['00070e15','1c232a31','383f464d','545b6269',
    '70777e85','8c939aa1','a8afb6bd','c4cbd2d9',
    'e0e7eef5','fc030a11','181f262d','343b4249',
    '50575e65','6c737a81','888f969d','a4abb2b9',
    'c0c7ced5','dce3eaf1','f8ff060d','141b2229',
    '30373e45','4c535a61','686f767d','848b9299',
    'a0a7aeb5','bcc3cad1','d8dfe6ed','f4fb0209',
    '10171e25','2c333a41','484f565d','646b7279']
'''
def f(x,rk,i):
    return x[i]^t(x[i+1]^x[i+2]^x[i+3]^rk)

def t(x):
    return l(tau(x))
def t_(x):#t'
    return l_(tau(x))

def tau(a):
    a='{:08x}'.format(a)
    b=sbox(a)
    return b

def l(b):
    c=b^cl(b, 2)^cl(b, 10)^cl(b, 18)^cl(b, 24)
    return c
def l_(b):#l'
    c=b^cl(b, 13)^cl(b, 23)
    return c

def enc(x,mk):
    if len(x)!=32:
        x=(32-len(x))*'0'+x
    p=[x[:8],x[8:16],x[16:24],x[24:]]
    x=p
    for i in range(len(x)):
        x[i]=int(x[i],16)
    rk=kea(mk, fk, ck)
    for i in range(32):
        #print('rk['+'{:02d}'.format(i)+'] = '+'{:08x}'.format(rk[i]),end='   ')
        x.append(f(x,rk[i],i))
        #print('x['+'{:02d}'.format(i)+'] = '+'{:08x}'.format(x[-1]))
    #print()
    y=x[32:][::-1]
    for i in range(len(y)):
        y[i]='{:08x}'.format(y[i])
    y=''.join(y)
    return y

def kea(mk,fk,ck):#Key extension algorithm
    if len(mk)!=32:
        mk=(32-len(mk))*'0'+mk
    p=[mk[:8],mk[8:16],mk[16:24],mk[24:]]
    mk=p
    for i in range(len(mk)):
        mk[i]=int(mk[i],16)
    k=[]
    for i in range(4):
        k.append(mk[i]^fk[i])
    for i in range(32):
        k.append(k[i]^t_(k[i+1]^k[i+2]^k[i+3]^ck[i]))
    rk=k[4:]
    return rk

if __name__=='__main__':
    p=input('Your plaintext(hex):')
    mk=input('Your encryption key(hex):')
    print()
    y=enc(p, mk)
    print('Ciphertext:',end=(' '))
    for i in range(4):
        print(y[i*8:(i+1)*8],end=' ')
    print()

运行效果

按照文档中的示例:
验证时将明文及加密密钥中的空格去掉
过程参数输出在注释

  • 示例一
    对一组明文用密钥加密一次
    明——文:01234567 89abcdef fedcba98 76543210
    加密密钥:01234567 89abcdef fedcba98 76543210
    并输出轮密钥 rk[i] 与每轮输出状态 x[i]
    Python:SM4_第1张图片
    最后得到密文:681edf34 d206965e 86b3e94f 536e4246
    过程相关参数以及结果均与文档一致

  • 示例二
    利用相同加密密钥对一组明文反复加密1000000次
    明——文:01234567 89abcdef fedcba98 76543210
    加密密钥:01234567 89abcdef fedcba98 76543210
    Python:SM4_第2张图片
    得到密文:595298c7 c6fd271f 0402f804 c33d3f66

你可能感兴趣的:(python)