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('加密完成')