python实现sm4算法加解密及图形化界面

SM4密码算法是一个分组算法。数据分组长度为128比特,密钥长度为128比特。加密算法与密钥扩展算法都采用32轮迭代结构。SM4密码算法是以字节(8位)和字(32位)为单位进行数据处理。SM4密码算法是对合运算,因此加解密算法相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。

1.基本算法

SM4密码算法使用模2加和循环移位作为基本运算。

  1. 模2加:⨁,32位异或运算。
  2. 循环移位:<<<i,把32位字循环左移i位。
#两个8位16进制数,即32位2进制的异或运算
def yihuo_32(a0,a1):
    A = []
    ten_a0 = int(a0,16)#16进制转换为10进制
    ten_a1 = int(a1, 16)
    ten_bin_a0 = '{:032b}'.format(ten_a0)#10进制转换为32进制
    ten_bin_a1 = '{:032b}'.format(ten_a1)
    list_a0 = list(ten_bin_a0)
    list_a1 = list(ten_bin_a1)
    for i in range(32):#按位异或
        a = int(list_a0[i])^int(list_a1[i])
        A.append(a)
    c_1 = [str(i) for i in A]#整数转换为字符串
    c = ''.join(c_1)
    c = int(c, 2)#二进制转换为10进制
    c = '{:08x}'.format(c)#10进制转换为8位16进制,一定要规范位数
    return c

2.基本密码部件

(1)S盒

SM4 的S盒是一种以字节为单位的非线性代替变换,其密码学的作用是起混淆作用。S盒的输入和输出都是8位的字节。它本质是8位的非线性置换。设输入字节为a,输出字节为b,则S盒的运算可以可表示为 b = S_box(a)
在这里插入图片描述

(2)非线性变换τ

SM4的非线性变换τ是一种以字为单位的非线性代替变换。它由四个S盒并置构成。本质上它是S盒的一种并行应用。
设输入字为 A=(a0,a1,a2,a3),输出字为 B=(b0,b1,b2,b3),则
B = τ(A) = (S_box(a0),S_box(a1),S_box(a2),S_box(a3))
代码实现:

#s盒变换,一次处理一个字,共用4个S盒
#输入一个8位16进制的字符串,如'abcd1234'
def S_box(S_Input):
    #将8位字符串分成4组
    A = list(S_Input)
    a = [0,0,0,0]
    Out=[0,0,0,0]
    a[0] = [A[0],A[1]]#a0=['a','b']
    a[1] = [A[2],A[3]]
    a[2] = [A[4],A[5]]
    a[3] = [A[6],A[7]]
    #高位的16进制转换成10进制*16+低位的16进制转换成10进制
    for j in range(4):
        for i in range(2):
            a[j][i] = int(a[j][i],16)
        b = int(a[j][0]*16+a[j][1])
        Out[j] = SboxTable[b]
    for i in range(4):
        Out[i]='{:02x}'.format(Out[i])
    S_out = ''.join(Out)
    return S_out

(3)线性变换部件L

线性变换部件L是以字为处理单位的线性变换部件,其输入输出都是32位的字。其密码学的作用是起扩散作用的。设L的输入为字B,输出为字C,则
C=L(B) = B ⨁ (B<<<2) ⨁ (B<<<10) ⨁ (B<<<18) ⨁ (B<<<24)
代码实现

def xianxing_L(S_out,flag):#flag为1则处理轮函数,为0则是密钥扩展
    B = list(S_out) #字符串转换为列表
    for i in range(8):
        B[i]=int(B[i],16)	#16进制转换为10进制
        B[i]='{:04b}'.format(B[i]) #10进制转换为4位2进制
    B = B[0]+B[1]+B[2]+B[3]+B[4]+B[5]+B[6]+B[7] #最终转换为32位二进制字符串
    B_2 = B[2:] + B[:2] #循环左移
    B_10 = B[10:] + B[:10]
    B_18 = B[18:] + B[:18]
    B_24 = B[24:] + B[:24]
    B_13 = B[13:] + B[:13]
    B_23 = B[23:] + B[:23]
    B = list(B)
    if flag==1:	#轮函数的线性变换L
        for i in range(32):
            B[i] = int(B[i])^int(B_2[i])^int(B_10[i])^int(B_18[i])^int(B_24[i])
    else:	#密钥扩展的线性变换L'
        for i in range(32):
            B[i] = int(B[i]) ^ int(B_13[i]) ^ int(B_23[i])
    A = ['','','','','','','','']
    for i in range(8):
        for j in range(4):
            a = str(B[4*i+j])
            A[i] = A[i] + a
        A[i] = int(A[i],2)
        A[i] = '{:01x}'.format(A[i])	#转换为16进制
    L_out = ''.join(A)	#最终转换为8位16进制字符串
    return L_out

(4)合成变换T

合成变换T由非线性变换τ和线性变换L复合而成,数据处理的单位是字。设输入为字X,则先对X进行非线性变换τ,再进行线性L变换。记为T(X)=L(τ(X))
由于合成变换T是非线性变换τ和线性变换L的复合,所以它综合起混淆和扩散的作用,从而可提高密码的安全性。
代码实现

def T(A,flag):#为1则论函数,为0则扩展密钥
    S_out = S_box(A)
    T_out = xianxing_L(S_out,flag)
    return T_out

3.轮函数

SM4密码算法采用对基本轮函数进行迭代的结构。利用上述基本密码部件,便可构成轮函数。SM4密码算法是一种以字为处理单位的密码函数。
设轮函数F的输入为(X0,X1,X2,X3),4个32位字,共128位。轮密钥为rk,rk也是一个32位的字。轮函数F的输出也是一个32位的字。轮函数F的运算式:
F(X0,X1,X2,X3,rk) =X0⨁T(X1⨁X2⨁X3⨁rk) =X0⨁L(τ(X1⨁X2⨁X3⨁rk))
简记B=(X1⨁X2⨁X3⨁rk),则
F(X0,X1,X2,X3,rk)=X0⨁[S_box(B)]⨁[S_box(B)<<<2]⨁[S_box(B)<<<10]⨁[S_box(B)<<<18]⨁[S_box(B)<<<24]
在这里插入图片描述
代码实现

#参数应该都为8位16进制字符串
def lun_func(X0,X1,X2,X3,rk,flag):#为1则轮函数,为0则扩展密钥
    x1 = yihuo_32(X1,X2)
    x2 = yihuo_32(x1,X3)
    x3 = yihuo_32(x2,rk)
    T_out = T(x3,flag)
    F_out = yihuo_32(T_out,X0)
    return F_out

4.加密算法

SM4密码算法是一个分组密码。数据分组长度为128比特,密钥长度为128比特。加密算法采用32轮迭代结构,每轮使用一个轮密钥。
设输入明文为(X0,X1,X2,X3),四个字,共128位。输入轮密钥为rki,i=0,1,…31,共32个字。输出密文为(Y0,Y1,Y2,Y3),四个字,128位。加密算法:
Xi+4= F(Xi,Xi+1,Xi+2,Xi+3,rki) = Xi⨁T(Xi+1⨁Xi+2⨁Xi+3⨁rki),i=0,1,2,…31

为了与解密算法需要的顺序一致,同时也与人们的习惯顺序一致,在加密算法之后还需要一个反序R:
R(Y0,Y1,Y2,Y3) = (X35,X34,X33,X32)
在这里插入图片描述
SM4一次处理四个字,产生一个字的中间密文,这个中间密文与前三个字拼接在一起供下一次加密处理,共迭代加密处理32轮,最终产生四个字的密文。整个加密处理过程像一个宽度为四个字的窗口在滑动,加密处理一轮,窗口滑动一个字,窗口滑动32次,加密迭代结束。

5.解密算法

SM4密码算法是对合运算,因此解密算法与加密算法相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。
设输入密文为(Y0,Y1,Y2,Y3),输入轮密钥为rki,i=31,30,…1,0,输出明文为
(M0,M1,M2,M3),(Y0,Y1,Y2,Y3)=(X35,X34,X33,X32)
为了便于对照,解密算法中仍然采用Xi表示密文。解密算法:
Xi= F(Xi+4,Xi+3,Xi+2,Xi+1,rki) = Xi+4⨁T(Xi+3⨁Xi+2⨁Xi+1⨁rki),i=31,30,…1,0
反序处理:
R(M0,M1,M2,M3) = (X3,X2,X1,X0)

6.密钥扩展算法

SM4 密码算法使用128位的加密密钥,并采用32轮迭代加密结构,每一轮加密使用一个32位的轮密钥,共使用32个轮密钥。因此需要使用密钥扩展算法,从加密密钥产生出32个轮密钥。

(1)常数FK

在密钥扩展中使用如下的常数:
FK0=(A3B1BAC6),FK1=(56AA3350),FK2=(677D9197),FK3=(B27022DC)

(2)固定参数CK

共使用32个固定参数Cki,Cki是一个字,其产生规则如下:
设cki为Cki的第j个字节(i=0,1,…31;j=0,1,2,3),即Cki=(cki,0,cki,1,cki,2,cki,3),则cki,j=(4i+j) * 7 (mod 256)
这32个固定参数如下:

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

(3)密钥扩展算法

设输入加密密钥为MK=(MK0,MK1,MK2,MK3),输出轮密钥为rki,i=0,1,2,…31,中间数据为Ki,i=0,1,…34,35。
密钥扩展算法:

  1. (K0,K1,K2,K3) = (MK0⨁FK0,MK1⨁FK1,MK2⨁FK2,MK3⨁FK3)
  2. For i =0,1,…30,31 Do
    rki=Ki+4=Ki⨁T’(Ki+1⨁Ki+12⨁Ki+3⨁CKi)

说明:其中的T ’ 变换与加密算法轮函数中的T基本相同,只将其中的线性变换L修改为以下L ’ :
L '(B)=B ⨁ (B<<<13) ⨁ (B<<<23)
代码实现

def extend_key(MK0,MK1,MK2,MK3):#'01234567','89abcdef','fedcba98','76543210'
    K0 = yihuo_32(MK0,FK[0])
    K1 = yihuo_32(MK1,FK[1])
    K2 = yihuo_32(MK2,FK[2])
    K3 = yihuo_32(MK3,FK[3])#'a292ffa1', 'df01febf', '99a12b0f', 'c42410cc'
    K = [K0,K1,K2,K3]#S_box:'e25d48f6','b0903951','93f64305','bb912b1f'
    rk = []#'8283cb69',S_box:'8ad24122'
    for i in range(32):
        a = lun_func(K[i],K[i+1],K[i+2],K[i+3],CK[i],flag=0)
        K.append(a)
        rk.append(a)
    return rk

源码sm4.py

# -*- coding: utf-8 -*-

SboxTable = [
    0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
    0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
    0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
    0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
    0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
    0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
    0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
    0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
    0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
    0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
    0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
    0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
    0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
    0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
    0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
    0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
]

FK = ['a3b1bac6', '56aa3350', '677d9197', 'b27022dc']

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'
]

#s盒变换,一次处理一个字,共用4个S盒
#输入一个8位16进制的字符串,如'abcd1234'
def S_box(S_Input):
    #将8位字符串分成4组
    A = list(S_Input)
    a = [0,0,0,0]
    Out=[0,0,0,0]
    a[0] = [A[0],A[1]]#a0=['a','b']
    a[1] = [A[2],A[3]]
    a[2] = [A[4],A[5]]
    a[3] = [A[6],A[7]]
    #高位的16进制转换成10进制*16+低位的16进制转换成10进制
    for j in range(4):
        for i in range(2):
            a[j][i] = int(a[j][i],16)
        b = int(a[j][0]*16+a[j][1])
        Out[j] = SboxTable[b]
    for i in range(4):
        Out[i]='{:02x}'.format(Out[i])
    S_out = ''.join(Out)
    return S_out

def xianxing_L(S_out,flag):#flag为1则处理论函数,为0则是密钥扩展
    B = list(S_out)
    for i in range(8):
        B[i]=int(B[i],16)
        B[i]='{:04b}'.format(B[i])
    B = B[0]+B[1]+B[2]+B[3]+B[4]+B[5]+B[6]+B[7]
    B_2 = B[2:] + B[:2]
    B_10 = B[10:] + B[:10]
    B_18 = B[18:] + B[:18]
    B_24 = B[24:] + B[:24]
    B_13 = B[13:] + B[:13]
    B_23 = B[23:] + B[:23]
    B = list(B)
    if flag==1:
        for i in range(32):
            B[i] = int(B[i])^int(B_2[i])^int(B_10[i])^int(B_18[i])^int(B_24[i])
    else:
        for i in range(32):
            B[i] = int(B[i]) ^ int(B_13[i]) ^ int(B_23[i])
    A = ['','','','','','','','']
    for i in range(8):
        for j in range(4):
            a = str(B[4*i+j])
            A[i] = A[i] + a
        A[i] = int(A[i],2)
        A[i] = '{:01x}'.format(A[i])
    L_out = ''.join(A)
    return L_out

def T(A,flag):#为1则论函数,为0则扩展密钥
    S_out = S_box(A)
    T_out = xianxing_L(S_out,flag)
    return T_out

#参数应该都为8位16进制字符串
def lun_func(X0,X1,X2,X3,rk,flag):#为1则论函数,为0则扩展密钥
    x1 = yihuo_32(X1,X2)
    x2 = yihuo_32(x1,X3)
    x3 = yihuo_32(x2,rk)
    T_out = T(x3,flag)
    F_out = yihuo_32(T_out,X0)
    return F_out

#两个8位16进制数,即32位2进制的异或运算
def yihuo_32(a0,a1):
    A = []
    ten_a0 = int(a0,16)#16进制转换为10进制
    ten_a1 = int(a1, 16)
    ten_bin_a0 = '{:032b}'.format(ten_a0)#10进制转换为32进制
    ten_bin_a1 = '{:032b}'.format(ten_a1)
    list_a0 = list(ten_bin_a0)
    list_a1 = list(ten_bin_a1)
    for i in range(32):#按位异或
        a = int(list_a0[i])^int(list_a1[i])
        A.append(a)
    c_1 = [str(i) for i in A]
    c = ''.join(c_1)
    c = int(c, 2)#二进制转换为10进制
    c = '{:08x}'.format(c)#10进制转换为8位16进制,一定要规范位数
    return c

def extend_key(MK0,MK1,MK2,MK3):#'01234567','89abcdef','fedcba98','76543210'
    K0 = yihuo_32(MK0,FK[0])
    K1 = yihuo_32(MK1,FK[1])
    K2 = yihuo_32(MK2,FK[2])
    K3 = yihuo_32(MK3,FK[3])#'a292ffa1', 'df01febf', '99a12b0f', 'c42410cc'
    K = [K0,K1,K2,K3]#S_box:'e25d48f6','b0903951','93f64305','bb912b1f'
    rk = []#'8283cb69',S_box:'8ad24122'
    for i in range(32):
        a = lun_func(K[i],K[i+1],K[i+2],K[i+3],CK[i],flag=0)
        K.append(a)
        rk.append(a)
    return rk

def encrypt(MK0,MK1,MK2,MK3,X0,X1,X2,X3,en_de):#en_de为1则加密,X是明密文
    rk = extend_key(MK0,MK1,MK2,MK3)#生成扩展密钥
    X = [X0,X1,X2,X3]
    for i in range(32):
        if en_de==1:
            x = lun_func(X[i], X[i+1], X[i+2], X[i+3], rk[i], flag=1)
        else:
            x = lun_func(X[i], X[i + 1], X[i + 2], X[i + 3], rk[31-i], flag=1)
        X.append(x)
    Y = [0,0,0,0]
    for i in range(4):
        Y[i] = X[35-i]
    return Y
print(encrypt('01234567','89abcdef','fedcba98','76543210','01234567','89abcdef','fedcba98','76543210',1))
#密文['681edf34', 'd206965e', '86b3e94f', '536e4246']
#明文/密钥'01234567', '89abcdef', 'fedcba98', '76543210'

加密结果:
在这里插入图片描述
若要实现图形化界面,可参考前几篇博客的tkinter_.py
https://blog.csdn.net/qq_43710705/article/details/103810799
https://blog.csdn.net/qq_43710705/article/details/103818256

有错请指出,谢谢。

  • 10
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值