ZUC密码算法 - Python实现

        这段时间一直在做密码学实验,写了三个算法:SMS4、ZUC、SM3。这些算法效率不高,也没有经过安全审计,可能有很多潜在的BUG,不过算法的总体思路还算清晰,写完实验报告就删掉的话,自己感觉也挺可惜的,所以就发到CSDN上来,初学者可以在学习的时候拿来做个参考。

         此实现参照国密局的ZUC标准文档编写,标准文档在百度文库可以找到。

算法整体流程图:

init()函数的流程图:

        源码包含在两个文件里。第一个文件:ConstParameters.py,定义了一些常量;第二个文件Functions.py是算法用到的功能模块,运行环境为Windowns 10 - 1809,Python 3.7.1

# -*- coding: utf-8 -*-
"""
Created on Fri Nov  2 15:29:33 2018

@author: wang
"""
D = ['100010011010111', '010011010111100', '110001001101011',\
     '001001101011110', '101011110001001', '011010111100010',\
     '111000100110101', '000100110101111', '100110101111000',\
     '010111100010011', '110101111000100', '001101011110001',\
     '101111000100110', '011110001001101', '111100010011010',\
     '100011110101100']
S1 = [[0x3E, 0x72, 0x5B, 0x47, 0xCA, 0xE0, 0x00, 0x33, 0x04, 0xD1, 0x54, 0x98, 0x09, 0xB9, 0x6D, 0xCB, ],
[0x7B, 0x1B, 0xF9, 0x32, 0xAF, 0x9D, 0x6A, 0xA5, 0xB8, 0x2D, 0xFC, 0x1D, 0x08, 0x53, 0x03, 0x90, ],
[0x4D, 0x4E, 0x84, 0x99, 0xE4, 0xCE, 0xD9, 0x91, 0xDD, 0xB6, 0x85, 0x48, 0x8B, 0x29, 0x6E, 0xAC, ],
[0xCD, 0xC1, 0xF8, 0x1E, 0x73, 0x43, 0x69, 0xC6, 0xB5, 0xBD, 0xFD, 0x39, 0x63, 0x20, 0xD4, 0x38, ],
[0x76, 0x7D, 0xB2, 0xA7, 0xCF, 0xED, 0x57, 0xC5, 0xF3, 0x2C, 0xBB, 0x14, 0x21, 0x06, 0x55, 0x9B, ],
[0xE3, 0xEF, 0x5E, 0x31, 0x4F, 0x7F, 0x5A, 0xA4, 0x0D, 0x82, 0x51, 0x49, 0x5F, 0xBA, 0x58, 0x1C, ],
[0x4A, 0x16, 0xD5, 0x17, 0xA8, 0x92, 0x24, 0x1F, 0x8C, 0xFF, 0xD8, 0xAE, 0x2E, 0x01, 0xD3, 0xAD, ],
[0x3B, 0x4B, 0xDA, 0x46, 0xEB, 0xC9, 0xDE, 0x9A, 0x8F, 0x87, 0xD7, 0x3A, 0x80, 0x6F, 0x2F, 0xC8, ],
[0xB1, 0xB4, 0x37, 0xF7, 0x0A, 0x22, 0x13, 0x28, 0x7C, 0xCC, 0x3C, 0x89, 0xC7, 0xC3, 0x96, 0x56, ],
[0x07, 0xBF, 0x7E, 0xF0, 0x0B, 0x2B, 0x97, 0x52, 0x35, 0x41, 0x79, 0x61, 0xA6, 0x4C, 0x10, 0xFE, ],
[0xBC, 0x26, 0x95, 0x88, 0x8A, 0xB0, 0xA3, 0xFB, 0xC0, 0x18, 0x94, 0xF2, 0xE1, 0xE5, 0xE9, 0x5D, ],
[0xD0, 0xDC, 0x11, 0x66, 0x64, 0x5C, 0xEC, 0x59, 0x42, 0x75, 0x12, 0xF5, 0x74, 0x9C, 0xAA, 0x23, ],
[0x0E, 0x86, 0xAB, 0xBE, 0x2A, 0x02, 0xE7, 0x67, 0xE6, 0x44, 0xA2, 0x6C, 0xC2, 0x93, 0x9F, 0xF1, ],
[0xF6, 0xFA, 0x36, 0xD2, 0x50, 0x68, 0x9E, 0x62, 0x71, 0x15, 0x3D, 0xD6, 0x40, 0xC4, 0xE2, 0x0F, ],
[0x8E, 0x83, 0x77, 0x6B, 0x25, 0x05, 0x3F, 0x0C, 0x30, 0xEA, 0x70, 0xB7, 0xA1, 0xE8, 0xA9, 0x65, ],
[0x8D, 0x27, 0x1A, 0xDB, 0x81, 0xB3, 0xA0, 0xF4, 0x45, 0x7A, 0x19, 0xDF, 0xEE, 0x78, 0x34, 0x60, ],]

S2 = [[0x55, 0xC2, 0x63, 0x71, 0x3B, 0xC8, 0x47, 0x86, 0x9F, 0x3C, 0xDA, 0x5B, 0x29, 0xAA, 0xFD, 0x77, ],
[0x8C, 0xC5, 0x94, 0x0C, 0xA6, 0x1A, 0x13, 0x00, 0xE3, 0xA8, 0x16, 0x72, 0x40, 0xF9, 0xF8, 0x42, ],
[0x44, 0x26, 0x68, 0x96, 0x81, 0xD9, 0x45, 0x3E, 0x10, 0x76, 0xC6, 0xA7, 0x8B, 0x39, 0x43, 0xE1, ],
[0x3A, 0xB5, 0x56, 0x2A, 0xC0, 0x6D, 0xB3, 0x05, 0x22, 0x66, 0xBF, 0xDC, 0x0B, 0xFA, 0x62, 0x48, ],
[0xDD, 0x20, 0x11, 0x06, 0x36, 0xC9, 0xC1, 0xCF, 0xF6, 0x27, 0x52, 0xBB, 0x69, 0xF5, 0xD4, 0x87, ],
[0x7F, 0x84, 0x4C, 0xD2, 0x9C, 0x57, 0xA4, 0xBC, 0x4F, 0x9A, 0xDF, 0xFE, 0xD6, 0x8D, 0x7A, 0xEB, ],
[0x2B, 0x53, 0xD8, 0x5C, 0xA1, 0x14, 0x17, 0xFB, 0x23, 0xD5, 0x7D, 0x30, 0x67, 0x73, 0x08, 0x09, ],
[0xEE, 0xB7, 0x70, 0x3F, 0x61, 0xB2, 0x19, 0x8E, 0x4E, 0xE5, 0x4B, 0x93, 0x8F, 0x5D, 0xDB, 0xA9, ],
[0xAD, 0xF1, 0xAE, 0x2E, 0xCB, 0x0D, 0xFC, 0xF4, 0x2D, 0x46, 0x6E, 0x1D, 0x97, 0xE8, 0xD1, 0xE9, ],
[0x4D, 0x37, 0xA5, 0x75, 0x5E, 0x83, 0x9E, 0xAB, 0x82, 0x9D, 0xB9, 0x1C, 0xE0, 0xCD, 0x49, 0x89, ],
[0x01, 0xB6, 0xBD, 0x58, 0x24, 0xA2, 0x5F, 0x38, 0x78, 0x99, 0x15, 0x90, 0x50, 0xB8, 0x95, 0xE4, ],
[0xD0, 0x91, 0xC7, 0xCE, 0xED, 0x0F, 0xB4, 0x6F, 0xA0, 0xCC, 0xF0, 0x02, 0x4A, 0x79, 0xC3, 0xDE, ],
[0xA3, 0xEF, 0xEA, 0x51, 0xE6, 0x6B, 0x18, 0xEC, 0x1B, 0x2C, 0x80, 0xF7, 0x74, 0xE7, 0xFF, 0x21, ],
[0x5A, 0x6A, 0x54, 0x1E, 0x41, 0x31, 0x92, 0x35, 0xC4, 0x33, 0x07, 0x0A, 0xBA, 0x7E, 0x0E, 0x34, ],
[0x88, 0xB1, 0x98, 0x7C, 0xF3, 0x3D, 0x60, 0x6C, 0x7B, 0xCA, 0xD3, 0x1F, 0x32, 0x65, 0x04, 0x28, ],
[0x64, 0xBE, 0x85, 0x9B, 0x2F, 0x59, 0x8A, 0xD7, 0xB0, 0x25, 0xAC, 0xAF, 0x12, 0x03, 0xE2, 0xF2, ],]
# -*- coding: utf-8 -*-
"""
Created on Fri Nov  2 15:53:40 2018

@author: wang
"""
import ConstParameters as cp
#convert int to k-bit binary number
#input:a-int; k-int;
#output:string
def Int2Bin(a, k):
    res = list(bin(a)[2:])
    for i in range(k-len(res)):
        res.insert(0, '0')
    return ''.join(res)

#loop left shift function
#input:a-int; k-int, the bits that should be shift;
#output-int
def LoopLeftShift(a, k):
    res = list(Int2Bin(a, 32))
    for i in range(k):
        temp = res.pop(0)
        res.append(temp)
    return int(''.join(res), 2)

#key loading alg
#input:Key-int; iv-int 
#output:a list contain[S15...S0]
#test:0x3d4c4be96a82fdaeb58f641db17b455b,0x84319aa8de6915ca1f6bda6bfbd8c766
def KeyLoading(Key, iv):
    Key_Str = Int2Bin(Key, 128)
    iv_Str = Int2Bin(iv, 128)
    res = []
    for i in range(16):
        temp = Key_Str[i*8:(i+1)*8]
        temp += cp.D[i]
        temp += iv_Str[i*8:(i+1)*8]
        res.append(int(temp, 2))
    
    return res

#bit reconstruct
#input-LFSR
#output-X, a list consisted by four integers
def BitRec(LFSR):
    X0 = Int2Bin(LFSR[15], 31)[:16]+Int2Bin(LFSR[14], 31)[15:]
    X1 = Int2Bin(LFSR[11], 31)[15:]+Int2Bin(LFSR[9], 31)[:16]
    X2 = Int2Bin(LFSR[7], 31)[15:]+Int2Bin(LFSR[5], 31)[:16]
    X3 = Int2Bin(LFSR[2], 31)[15:]+Int2Bin(LFSR[0], 31)[:16]
    return [int(X0, 2), int(X1, 2), int(X2, 2), int(X3, 2)]

#input:a-int
#output:32bits string consisted by 0/1
def S(a):
    a = Int2Bin(a, 32)
    index = []
    for i in range(8):
        index.append(int(a[4*i:4*(i+1)], 2))
    return SBox(index[0], index[1], 1)+SBox(index[2], index[3], 2)+\
            SBox(index[4], index[5], 1)+SBox(index[6], index[7], 2)    
def SBox(a1, a2, k):
    if k == 1:
        return Int2Bin(cp.S1[a1][a2], 8)
    else:
        return Int2Bin(cp.S2[a1][a2], 8)

#k = 1 - initialisationMode, 0-workMode
def LFSRMode(u, LFSR, k):
    s16 = 2**15*LFSR[15] + 2**17*LFSR[13] + 2**21*LFSR[10] + 2**20*LFSR[4] + \
    (1+2**8)*LFSR[0]
    if k == 1:
        s16 = (u+s16) % (2**31-1)
    else:
        s16 = s16 % (2**31-1)
    if s16 == 0:
        s16 = 2**31 - 1
    LFSR.pop(0)
    LFSR.append(s16)
    return LFSR


#nolinear function F
#input:X, a list consisted by four integers; R1\R2-int, memory unit variable.
#output:W, int
def F(X, R1, R2):
    modulus = 2**32
    W = ((X[0]^R1)+R2) % (modulus)
    W1 = (R1+X[1]) % (modulus)
    W2 = R2^X[2]
    temp1 = Int2Bin(W1, 32)[16:32] + Int2Bin(W2, 32)[:16]
    temp2 = Int2Bin(W2, 32)[16:32] + Int2Bin(W1, 32)[:16]
    temp1 = int(temp1, 2)
    temp2 = int(temp2, 2)
    temp1 = temp1^(LoopLeftShift(temp1, 2))^(LoopLeftShift(temp1, 10))^\
    (LoopLeftShift(temp1, 18))^(LoopLeftShift(temp1, 24))
    temp2 = temp2^(LoopLeftShift(temp2, 8))^(LoopLeftShift(temp2, 14))^\
    (LoopLeftShift(temp2, 22))^(LoopLeftShift(temp2, 30))
    R1 = S(temp1)
    R2 = S(temp2)
    return W, int(R1, 2), int(R2, 2)

#Key-int, iv-int
#LFSR-list, consisted by 16 integers 
def init(Key, iv):
    LFSR = KeyLoading(Key, iv)
    R1, R2 = 0, 0
    for i in range(32):
        X = BitRec(LFSR)
        W, R1, R2 = F(X, R1, R2)
        LFSR = LFSRMode(W>>1, LFSR, 1)  
    X = BitRec(LFSR)
    W, R1, R2 = F(X, R1, R2) 
    LFSR = LFSRMode(W>>1, LFSR, 2)
    return LFSR, R1, R2

#LFSR-list, consisted by 16 integers, R1 R2-int
#Z-int, z can be convert to 32 bits key stream
def work(LFSR, R1, R2):
    X = BitRec(LFSR)
    W, R1, R2 = F(X, R1, R2)
    Z = W^X[3]
    LFSR = LFSRMode(W>>1, LFSR, 2)
    return LFSR, R1, R2, Z

测试:

Int2Bin()

输入(5566,128),将5566转换为128位0-1字符串,转换成功。

LoopLeftShift()

将1234循环左移5位。注意,算法中的循环左移是对于32位二进制数来说的。数字不足32位,前边要先补零然后再做循环左移运算。

KeyLoading()

给定密钥和初始化向量,生成最初的LFSR。对比官方文档,LFSR正确,此模块功能正常。

BitRec()

比特重组。使用的参数LFSR就是上方刚刚生成的。对比官方文档,X正确,此模块功能正常。

S盒:

手动验算,S盒模块正常。

算法运行模块:init()work()

直接测试密钥流:

对比官方文档,密钥流正确。因此算法整体上是正确的。

  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值