密码工程ublock分组密码复现

ublock是全国密码算法设计竞赛中的一个作品

第二轮分组算法 

算法代码

import numpy as np
import binascii
# 定义S盒和逆S盒
S = ['7','4','9','c','b','a','d','8','f','e','1','6','0','3','2','5']
S_Inv = ['c','a','e','d','1','f','b','0','7','2','5','4','3','6','9','8']

#定义置换和逆置换
PL = [1,3,4,6,0,2,7,5]
PR = [2,7,5,0,1,6,4,3]
PL_Inv = [4,0,5,1,2,7,3,6]
PR_Inv = [3,4,0,7,6,2,5,1]

#定义PK置换
PK = [6,0,8,13,1,15,5,10,4,9,12,2,11,3,7,14]

#定义RC常数
RC = np.array([0x988cc9dd,0xf0e4a1b5,0x21357064,0x8397d2c6,
               0xc7d39682,0x4f5b1e0a,0x5e4a0f1b,0x7c682d39,
               0x392d687c,0xb3a7e2f6,0xa7b3f6e2,0x8e9adfcb,
               0xdcc88d99,0x786c293d,0x30246175,0xa1b5f0e4,
               ])

#定义轮密钥
subkey = np.array([0]*136).reshape(17,8)

#四比特的T操作
def multiply_by_2_in_GF_2_4(value):
    # 不可约多项式 x^4 + x + 1 的二进制表示为 10011,但我们只需要后四位进行异或操作,所以用0b0011
    irreducible_polynomial = 0b10011
    # 将输入值左移一位
    result = value << 1
    # 检查结果是否超过4位(即是否大于15)
    if result > 0b1111:
        # 如果是,那么与不可约多项式进行异或操作以保持结果在GF(2^4)内
        result ^= irreducible_polynomial       
    return result

def rotate_left(value, shift):      #移位操作
    value = hex(value)[2:].zfill(16)
    x1 = value[:8]
    x2 = value[8:]
    x1 = (x1[shift:] + x1[:shift])
    x2 = (x2[shift:] + x2[:shift])
    return int(x1+x2,16)


#生成轮密钥
def KeySchedule(key):   #输入为32位16进制的int型
    subkey[0][0] = int(key[:4],16)
    subkey[0][1] = int(key[4:8],16)
    subkey[0][2] = int(key[8:12],16)
    subkey[0][3] = int(key[12:16],16)
    subkey[0][4] = int(key[16:20],16)
    subkey[0][5] = int(key[20:24],16)
    subkey[0][6] = int(key[24:28],16)
    subkey[0][7] = int(key[28:],16)
    for round in range(16):
        state1 = []         #state1储存分块后的密钥
        for i in range(4):
            state1.append(key[i*8:i*8+8])
        
        state2 = state1[0] + state1[1]  #state2储存异或后的结果
        newstate2 = ''
        for i in range(16):      #对state2进行PK置换
            newstate2 += state2[PK[i]]
        state1[0] = newstate2[:8]
        state1[1] = newstate2[8:]

        state3 = hex(int(state1[0],16)^RC[round])[2:].zfill(8)   #将K0与RC[round]异或
        newstate3 = ''
        for i in range(8):          #进行S盒
            newstate3 += S[int(state3[i],16)]
        state1[2] = hex(int(newstate3,16) ^ int(state1[2],16))[2:].zfill(8)  #将S盒结果与K2异或
        
        state4 = ''
        for i in range(8):      #每4比特进行T操作
            state4 += hex(multiply_by_2_in_GF_2_4(int(state1[1][i],16)))[2:]
        state1[3] = hex(int(state4,16) ^ int(state1[3],16))[2:].zfill(8)  #将T操作结果与K3异或
        
        subkey[round+1][0] = eval('0x'+state1[2][:4])
        subkey[round+1][1] = eval('0x'+state1[2][4:])
        subkey[round+1][2] = eval('0x'+state1[3][:4])
        subkey[round+1][3] = eval('0x'+state1[3][4:])
        subkey[round+1][4] = eval('0x'+state1[1][:4])
        subkey[round+1][5] = eval('0x'+state1[1][4:])
        subkey[round+1][6] = eval('0x'+state1[0][:4])
        subkey[round+1][7] = eval('0x'+state1[0][4:])
        key = state1[2] + state1[3] + state1[1] + state1[0]
    return subkey

def Encode(message,subkey):
    left = int(message[:16],16)         #分块,10进制int
    right = int(message[16:],16)
    for round in range(16):
        keyleft = int(hex(subkey[round][0])[2:].zfill(4) + hex(subkey[round][1])[2:].zfill(4) + hex(subkey[round][2])[2:].zfill(4) + hex(subkey[round][3])[2:].zfill(4),16)   #密钥分块
        keyright = int(hex(subkey[round][4])[2:].zfill(4) + hex(subkey[round][5])[2:].zfill(4) + hex(subkey[round][6])[2:].zfill(4) + hex(subkey[round][7])[2:].zfill(4),16)
        left = hex(left ^ keyleft)[2:].zfill(16)    #16进制字符串
        right = hex(right ^ keyright)[2:].zfill(16)
        newleft=''
        newright=''
        for i in range(16):
            newleft += S[int(left[i],16)]
            newright += S[int(right[i],16)]
        left = int(newleft,16)  #10进制int
        right = int(newright,16)
        
        right = right ^ left
        left = left ^ rotate_left(right,1)

        right = right ^ rotate_left(left,2)
        left = left ^ rotate_left(right,2)

        right = right ^ rotate_left(left,5)
        left = left ^ right

        newleft = ''
        newright = ''
        left = hex(left)[2:].zfill(16)
        right = hex(right)[2:].zfill(16)
        for i in range(8):
            newleft += left[2*PL[i]:2*PL[i]+2]
            newright += right[2*PR[i]:2*PR[i]+2]
        left = int(newleft,16)
        right = int(newright,16)
        
    lr = int(hex(left)[2:].zfill(16) + hex(right)[2:].zfill(16),16)
    key = ''
    for i in range(8):
        key += hex(subkey[16][i])[2:].zfill(4)
    key = int(key,16)
    cypher = hex(lr ^ key)[2:].zfill(32)
    return cypher

def Decode(cypher,subkey):
    left = int(cypher[:16],16)
    right = int(cypher[16:],16)
    for round in range(16,0,-1):
        keyleft = int(hex(subkey[round][0])[2:].zfill(4) + hex(subkey[round][1])[2:].zfill(4) + hex(subkey[round][2])[2:].zfill(4) + hex(subkey[round][3])[2:].zfill(4),16)   #密钥分块
        keyright = int(hex(subkey[round][4])[2:].zfill(4) + hex(subkey[round][5])[2:].zfill(4) + hex(subkey[round][6])[2:].zfill(4) + hex(subkey[round][7])[2:].zfill(4),16)
        left = left ^ keyleft
        right = right ^ keyright
        newleft = ''
        newright = ''
        left = hex(left)[2:].zfill(16)
        right = hex(right)[2:].zfill(16)
        for i in range(8):
            newleft += left[2*PL_Inv[i]:2*PL_Inv[i]+2]
            newright += right[2*PR_Inv[i]:2*PR_Inv[i]+2]
        left = int(newleft,16)
        right = int(newright,16)
        
        left = left ^ right
        right = right ^ rotate_left(left,5)

        left = left ^ rotate_left(right,2)
        right = right ^ rotate_left(left,2)

        left = left ^ rotate_left(right,1)
        right = right ^ left
        left = hex(left)[2:].zfill(16)
        right = hex(right)[2:].zfill(16)
        newleft = ''
        newright = ''
        for i in range(16):
            newleft += S_Inv[int(left[i],16)]
            newright += S_Inv[int(right[i],16)]
            
        left = int(newleft,16)
        right = int(newright,16)
        
    cypher = int(hex(left)[2:].zfill(16) + hex(right)[2:].zfill(16),16)
    key = ''
    for i in range(8):
        key += hex(subkey[0][i])[2:].zfill(4)
    key = int(key,16)
    message = hex(cypher ^ key)[2:].zfill(32)
    return message

def ECBencode(message,subkey):      #ECB加密模式

    messagelen = len(message)       #填充
    block = int(np.ceil(messagelen/32))
    if len(message[(block-1)*32:]) < 32:
        message += '0'*(32-len(message[(block-1)*32:]))
    block +=1
    message = message + '0'*(32-len(str(messagelen))) + hex(messagelen)[2:] 

    cypher = ''                     #加密
    for i in range(block):    
        cypher += Encode(message[i*32:(i+1)*32],subkey)
    return cypher

def ECBdecode(cypher,subkey):
    block = int((len(cypher)/32))
    message = ''
    for i in range(block):
        message += Decode(cypher[i*32:(i+1)*32],subkey)
    return message

def CBCencode(message,subkey):      #CBC加密模式
    messagelen = len(message)
    block = int(np.ceil(messagelen/32))
    if len(message[(block-1)*32:]) < 32:
        message += '0'*(32-len(message[(block-1)*32:]))
    block +=1
    message = message + '0'*(32-len(str(messagelen))) + hex(messagelen)[2:] 
    cypher = ''
    IV = int('1234567890abcdeffedcba0987654321',16)
    cypher += Encode(hex(int(message[0:32],16) ^ IV)[2:].zfill(32),subkey)
    for i in range(1,block):
        cypher += Encode(hex(int(message[i*32:(i+1)*32],16) ^ int(cypher[(i-1)*32:(i)*32],16))[2:].zfill(32),subkey)
    return cypher

def CBCdecode(cypher,subkey):
    block = int((len(cypher)/32))
    message = ''
    IV = int('1234567890abcdeffedcba0987654321',16)
    message += hex(int(Decode(cypher[0:32],subkey),16) ^ IV)[2:].zfill(32)
    for i in range(1,block):
        txt = Decode(cypher[i*32:(i+1)*32],subkey)
        message += hex(int(txt,16) ^ int(cypher[(i-1)*32:(i)*32],16))[2:].zfill(32)
    return message



测试代码

from uBlock  import *
from PIL import Image
import io
import time

key = '0123456789abcdeffedcba9876543210'
print(f'密钥为{key}')
subkey = KeySchedule(key)

# 测试
message = '0123456789abcdeffedcb9876543210'
print(f"明文为{message}")
cipher = Encode(message,subkey)
print(f'密文为{cipher}')
mesg = Decode(cipher,subkey)
print(f'解密结果为{mesg}')

time1 = 0
for j in range (5):
    time_start = time.time()
    for i in range(10000):
        cipher = Encode(message,subkey)
        mesg = Decode(cipher,subkey)
    time_end = time.time()
    time1 = time1 + ((time_end - time_start)/10000)
print(f"平均加解密时间:{time1/5}")


image_path = 'pic.bmp'  # 替换为你的图片路径
header = b'BM\xc6\x0b(\x00\x00\x00\x00\x006\x00\x00\x00(\x00\x00\x008\x04\x00\x00*\x03\x00\x00\x01\x00\x18\x00\x00\x00\x00\x00\x90\x0b(\x00J,\x00\x00J,\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'


#CBC模式加密
print('开始对图片进行CBC模式加密')
with open(image_path, 'rb') as image_file:
    image_content = image_file.read()
    image_content = binascii.hexlify(image_content[54:])
    hex_string = image_content.decode('ascii')
    image_file.close()

hex_string = CBCencode(hex_string,subkey)
hex_string = binascii.unhexlify(hex_string)
data = header + hex_string
with open ('CBCout.bmp', 'wb') as f:
    f.write(data)
    f.close()
print('加密完成')


#ECB模式加密
print('开始对图片进行ECB模式加密')
with open(image_path, 'rb') as image_file:
    image_content = image_file.read()
    image_content = binascii.hexlify(image_content[54:])
    hex_string = image_content.decode('ascii')
    image_file.close()

hex_string = ECBencode(hex_string,subkey)
hex_string = binascii.unhexlify(hex_string)
data = header + hex_string
with open ('ECBout.bmp', 'wb') as f:
    f.write(data)
    f.close()
print('加密完成')



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值