[python]SM4算法实现

# python实现SM4算法
# 不考虑工作模式和消息填充
ROUND = 32
TIME = 1000000


class SM4:

    def __init__(self):
        self.FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]
        self.CK = [0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
                   0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
                   0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
                   0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279]
        self.Sbox = [
            [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]]

    def linear0(self, x):
        y = x ^ (((x << 2) | (x >> 30)) & 0xffffffff) ^ (((x << 10) | (x >> 22)) & 0xffffffff) ^ \
            (((x << 18) | (x >> 14)) & 0xffffffff) ^ (((x << 24) | (x >> 8)) & 0xffffffff)
        return y

    def linear1(self, x):
        y = x ^ (((x << 13) | (x >> 19)) & 0xffffffff) ^ (((x << 23) | (x >> 9)) & 0xffffffff)
        return y

    def t(self, a, b, c, d, type):
        # 非线性变换--S盒
        e = '{:08x}'.format(a ^ b ^ c ^ d)
        a0 = self.Sbox[int(e[0], 16)][int(e[1], 16)]
        b0 = self.Sbox[int(e[2], 16)][int(e[3], 16)]
        c0 = self.Sbox[int(e[4], 16)][int(e[5], 16)]
        d0 = self.Sbox[int(e[6], 16)][int(e[7], 16)]
        X = int('{:02x}'.format(a0) + '{:02x}'.format(b0) + '{:02x}'.format(c0) + '{:02x}'.format(d0), 16)

        # 线性变换
        if type == 0:
            # 加密消息使用的线性变换
            Y = self.linear0(X)
        else:
            # 密钥扩展使用的线性变换
            Y = self.linear1(X)
        return Y

    # 密钥扩展函数
    def key_extend(self, mk):
        rk = []
        mk0 = int(mk[:8], 16)
        mk1 = int(mk[8:16], 16)
        mk2 = int(mk[16:24], 16)
        mk3 = int(mk[24:32], 16)
        k0 = mk0 ^ self.FK[0]
        k1 = mk1 ^ self.FK[1]
        k2 = mk2 ^ self.FK[2]
        k3 = mk3 ^ self.FK[3]

        for i in range(ROUND):
            rk.append(k0 ^ self.t(k1, k2, k3, self.CK[i], 1))
            k0 = k1
            k1 = k2
            k2 = k3
            k3 = rk[i]

        return rk

    # 加/解密函数
    def encryption(self, msg, mk, mode):
        # 计算轮密钥
        rk = self.key_extend(mk)
        if mode == 1:
            rk = rk[::-1]

        x0 = int(msg[:8], 16)
        x1 = int(msg[8:16], 16)
        x2 = int(msg[16:24], 16)
        x3 = int(msg[24:32], 16)
        # 32次迭代计算
        for i in range(ROUND):
            temp = x0 ^ self.t(x1, x2, x3, rk[i], 0)
            x0 = x1
            x1 = x2
            x2 = x3
            x3 = temp
        # 1次反序计算
        cipher = '{:08x}'.format(x3) + '{:08x}'.format(x2) + '{:08x}'.format(x1) + '{:08x}'.format(x0)

        return cipher.encode()


if __name__ == "__main__":
    # 测试SM4文算法档中的两个示例
    # SM4算法文档没有明确填充规则和加密模式,此处默认消息长度为16字节(=128比特)
    msg = b'0123456789abcdeffedcba9876543210'
    mk = b'0123456789abcdeffedcba9876543210'

    # 加密1次
    print('------------test1(加密1次)----------------')
    test1 = SM4()
    print('message:', msg.decode())
    # 加密
    if len(msg) % 32 == 0:
        cipher1 = test1.encryption(msg.decode(), mk.decode(), 0)
        print('cipher1:', cipher1)
    else:
        print('明文长度不是128比特的整数倍')
        exit(1)
    # 解密
    if len(cipher1) % 32 == 0:
        plain1 = test1.encryption(cipher1.decode(), mk.decode(), 1)
        print('plain1: ', plain1)
    else:
        print('密文长度不是128比特的整数倍')
        exit(1)

    # 加密1000000次,大约耗时10分钟
    test2 = SM4()
    print('------------test2(加密1000000次)----------------')
    print('message:', msg.decode())
    for i in range(TIME):
        if len(msg) % 32 == 0:
            cipher2 = test2.encryption(msg.decode(), mk.decode(), 0)
            msg = cipher2
        else:
            print('明文长度不是128比特的整数倍')
            exit(1)
    print('cipher2:', cipher2)

    for i in range(TIME):
        if len(cipher2) % 32 == 0:
            plain2 = test2.encryption(msg.decode(), mk.decode(), 1)
            msg = plain2
        else:
            print('密文长度不是128比特的整数倍')
            exit(1)
    print('plain2: ', plain2)

运行结果:
[python]SM4算法实现_第1张图片

你可能感兴趣的:(密码,安全,python)