19、将一个一维数组转化为二进制表示矩阵。例如 [1,2,3] 转化为 [[0,0,1], [0,1,0], [0,1,1]]

本文介绍了一种使用Python NumPy库将整数转换为二进制表示的方法,并将其存储在一个二维数组中。通过双重循环实现,先遍历外部数组,再通过内部循环将每个元素转换成二进制形式。
num = 4
n19 = np.arange(num)
n191 = np.zeros(shape=(num,num),dtype='int')
for i in range(num):
    n = n19[i]
    for j in range(num-1,-1,-1):
        n191[i][j] = n%2
        n = n//2
n191    
import re #导入模块 import base64 #导入模块 # IP置换表,用于初始置换 IP_table = [58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7] # IP逆置换表,用于最终置换 IP_re_table = [40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25] # E盒置换表 E = [32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1] # P盒置换表 P = [16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25] # S盒,共8个,每个S盒是一个4x16的矩阵 S = [ [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13], [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9], [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12], [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14], [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3], [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13], [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12], [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11], ] # PC-1置换表,用于密钥的初始置换 PC_1tab = [57, 49, 41, 33, 25, 17, 9, # 选择置换11, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4] # PC-2置换表,用于生成子密钥 PC_2tab = [14, 17, 11, 24, 1, 5, # 选择置换2表 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32] # 密钥左移的位数,共16轮,每轮左移的位数不同 SHIFT = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1] # 将明文转化为二进制 def str2bin(message): # 定义一个空字符串res,用于存储转换后的二进制结果 res = '' # 遍历输入的消息字符串message中的每一个字符 for i in message: # 使用ord()函数将字符转换为对应的ASCII码,然后使用bin()函数将ASCII码转换为二进制字符串 # bin()函数返回的字符串以'0b'开头,表示二进制,所以使用[2:]切片去掉前两个字符 tmp = bin(ord(i))[2:] # 将每个字符转化成二进制 # 计算当前字符的二进制表示的长度,如果不足8位,则在前面补充0,使其长度为8 # 使用字符串乘法生成足够数量的'0',然后与tmp拼接 tmp = str('0' * (8 - len(tmp))) + tmp # 补齐8位 # 将处理后的二进制字符串tmp追加到结果字符串res中 res += tmp # 计算res的长度除以64的余数,用于判断是否需要补充0以达到64的倍数 if len(res) % 64 != 0: # 如果余数不为0,计算需要补充的0的数量,即64减去余数 count = 64 - len(res) % 64 # 不够64位补充0 else: # 如果余数为0,说明已经是64的倍数,不需要补充0 count = 0 # 根据count的值,在res后面补充相应数量的'0' res += '0' * count # 返回最终的二进制字符串结果 return res # 将密钥转化为二进制,全部秘钥以补0的方式实现长度不满足64位的情况 def key2bin(key): # 初始化一个空字符串res,用于存储转换后的二进制结果 res = '' # 遍历输入的密钥字符串key中的每一个字符 for i in key: # 使用ord()函数将字符转换为对应的ASCII码,然后使用bin()函数将ASCII码转换为二进制字符串 # bin()函数返回的字符串以'0b'开头,表示二进制,所以使用[2:]切片去掉前两个字符 tmp = bin(ord(i))[2:] # 将每个字符转化成二进制 # 计算当前字符的二进制表示的长度,如果不足8位,则在前面补充0,使其长度为8 # 使用字符串乘法生成足够数量的'0',然后与tmp拼接 tmp = str('0' * (8 - len(tmp))) + tmp # 补齐8位 # 将处理后的二进制字符串tmp追加到结果字符串res中 res += tmp # 判断res的长度是否小于64 if len(res) < 64: # 如果小于64,计算需要补充的0的数量,注意这里应该是64减去res的长度(而不是res长度对64取余) # 原代码中的逻辑有误,因为当res长度小于64时,我们直接需要64-len(res)个0来补齐 count = 64 - len(res) # 不够64位补充0,原代码逻辑错误已修正 res += '0' * count else: # 如果res长度大于或等于64,只取前64位(原代码逻辑有误,因为else分支下应该是截取而不是赋值) # 但根据函数描述和常见需求,这里可能应该直接返回前64位,而不是重新赋值给res(这会导致后续代码无法看到修改) # 但由于我们只是在注释,所以按照原代码逻辑进行说明,并指出潜在问题 # 正确的做法可能是直接返回res[:64],但这里我们保持原代码结构进行注释 res = res[:64] # 实际上,这里应该直接返回res[:64]或者修改函数逻辑以避免重新赋值 # 返回最终的二进制字符串结果(注意:原代码在else分支下重新赋值了res,这可能导致逻辑错误) return res # IP盒处理 def ip_change(str_bin): # 初始化一个空字符串res,用于存储置换后的结果 res = '' # 遍历IP_table中的每一个元素(假设这些元素是索引,用于从str_bin中取值) for i in IP_table: # 根据IP_table中的索引i,从str_bin中取出对应的字符,并追加到结果字符串res中 # 注意:这里假设IP_table中的索引是有效的,即不会超出str_bin的长度 res += str_bin[i - 1] # 由于Python索引从0开始,而IP_table可能从1开始编号,所以这里需要i-1 # 返回置换后的结果字符串 return res # 定义一个名为zhihuan的置换函数 def zhihuan(s, tab): # 参数s为待置换的字符串,tab为置换表 # 获取置换表tab的长度 strlen = len(tab) # 初始化一个空列表list1,用于存放置换后的字符 list1 = [] # 遍历置换表tab中的每一个元素 for i in range(0, strlen): # 从tab中获取当前索引i对应的置换位置j(注意:这里假设tab中的索引是从1开始的) j = tab[i] # 将s中索引为j-1的字符转换为字符串(若s中的字符已经是字符串,则此转换是多余的) # 并将其添加到list1列表中(使用extend方法是因为如果s[j-1]是多个字符组成的字符串, # extend会将其拆分为单个字符并添加到列表中。但在此上下文中,我们假设s中的每个字符都是单独的) # 注意:如果tab中的索引直接对应s中的索引,则不需要j-1;但在这里我们按照j-1来处理 list1.extend(str(s[j - 1])) # 将list1中的所有元素合并为一个字符串s1 s1 = "".join(list1) # 返回置换后的字符串s1 return s1 # 定义一个名为zuoyi的函数,用于实现字符串s的循环左移n位 def zuoyi(s, n): # 获取字符串s的长度 strlen = len(s) # 对n取模strlen,确保n不大于字符串s的长度,实现循环的效果 n = n % strlen # 将字符串s转换为列表list1,因为字符串在Python中是不可变的,而列表是可变的 list1 = list(s) # 遍历字符串s的每个字符(实际上是遍历列表list1的每个元素) for i in range(0, strlen): # 如果当前索引i小于n,表示还需要继续左移 if i < n: # 在列表list1的末尾添加首元素(即list1[0]) # 这一步模拟了左移操作的一部分,但单独这一步并不能完成左移 list1.extend(list1[0:1]) # 注意:为了保持逻辑清晰,这里使用list1[0:1]来明确添加一个元素的切片 # 删除列表list1的首元素 # 这一步与上一步一起模拟了将首元素移动到列表末尾的操作 del list1[0] # 然而,由于上面的操作是在循环中进行的,且每次只移动一个元素, # 因此这个循环应该执行n次才能正确完成左移n位的操作 # 但原代码中使用了break语句,导致循环在第一次迭代后就终止了 else: # 当索引i达到或超过n时,跳出循环 # 这在原函数的逻辑中是不正确的,因为它阻止了左移操作的完成 break # 这行代码应该被移除或修改,以实现正确的循环左移 # 将修改后的列表list1重新转换为字符串s1 s1 = "".join(list1) # 返回循环左移后的字符串s1 # 但由于原函数中的逻辑错误,返回的s1并不是正确左移n位的结果 return s1 # 定义一个名为gen_key的函数,用于生成子密钥列表 def gen_key(key): Kkid = [] # 初始化一个空列表Kkid,用于存放生成的子密钥 # 调用zhihuan函数对输入的key进行置换选择1,PC_1tab是置换表1(注意:PC_1tab应该在函数外部定义) Kzhihuan1 = zhihuan(key, PC_1tab) # 将置换后的结果分为两部分:C和D # C是前半部分(索引0到27,共28个字符) C = Kzhihuan1[0:28] # D是后半部分(索引28到55,共28个字符) D = Kzhihuan1[28:56] # 循环16次,每次生成一个子密钥 for Kkidi in range(0, 16): # 对C和D分别进行左移操作,SHIFT[Kkidi]表示第Kkidi次循环需要左移的位数(注意:SHIFT应该在函数外部定义) C = zuoyi(C, SHIFT[Kkidi]) D = zuoyi(D, SHIFT[Kkidi]) # 将左移后的C和D拼接起来,然后调用zhihuan函数进行置换选择2,PC_2tab是置换表2(注意:PC_2tab应该在函数外部定义) # 置换选择2的结果是一个子密钥 Kkid.append(zhihuan(C + D, PC_2tab)) # 将生成的子密钥添加到Kkid列表中 # 返回生成的子密钥列表Kkid return Kkid # 定义一个名为e_change的函数,用于执行E盒置换 # 参数str_left表示要进行置换的输入字符串(通常是从左半部分S盒输出得到的48位字符串) def e_change(str_left): # 初始化一个空字符串res,用于存放置换后的结果 res = "" # 遍历E盒置换表E(注意:E应该在函数外部定义为一个包含置换位置的列表或数组) for i in E: # 根据E盒置换表E中的位置i,从输入字符串str_left中取出相应的字符 # 注意:由于Python的索引是从0开始的,而E盒置换表中的位置可能是从1开始的 # 因此需要使用i - 1作为索引(假设E盒置换表中的位置确实是从1开始编号的) res += str_left[i - 1] # 返回置换后的结果字符串 return res # 定义一个名为xor_change的函数,用于执行两个字符串的异或运算 # 参数str1和str2表示要进行异或运算的两个输入字符串(它们应该是长度相同的二进制字符串) def xor_change(str1, str2): # 初始化一个空字符串res,用于存放异或运算后的结果 res = "" # 遍历输入字符串str1的每个字符(由于str1和str2长度相同,因此也可以遍历str2) for i in range(0, len(str1)): # 将当前字符转换为整数(假设输入字符串中的字符都是有效的二进制数字'0'或'1') # 注意:int函数第二个参数10表示将字符按十进制数解析,但在这里实际上是将字符按字面值解析为整数('0'->0, '1'->1) # 因此,这里的10参数实际上是多余的,可以省略(但为了保持与原代码一致,这里保留了它) xor_res = int(str1[i], 10) ^ int(str2[i], 10) # 执行异或运算 # 根据异或运算的结果,将相应的字符添加到结果字符串res中 if xor_res == 1: res += '1' if xor_res == 0: res += '0' # 注意:这里可以使用更简洁的写法,即直接使用str(xor_res)来将结果转换为字符串并添加到res中 # 但为了保持与原代码逻辑一致,这里使用了条件判断来分别添加'0'或'1' # 返回异或运算后的结果字符串 return res # 定义一个名为s_change的函数,用于执行S盒置换 # 参数my_str表示要进行S盒置换的输入字符串(通常是从E盒置换后得到的48位二进制字符串) def s_change(my_str): res = "" # 初始化一个空字符串res,用于存放置换后的结果 c = 0 # 初始化计数器c,用于跟踪当前处理到第几个S盒 # 以6位为一组遍历输入字符串my_str for i in range(0, len(my_str), 6): now_str = my_str[i:i + 6] # 取出当前6位的分组 # 根据前一位和后一位确定行号(注意:这里假设输入是有效的二进制字符串) # 行号由第1位和第6位二进制数拼接而成,然后转换为十进制数 row = int(now_str[0] + now_str[5], 2) # 根据中间4位确定列号 # 列号由第2位到第5位二进制数拼接而成,然后转换为十进制数 col = int(now_str[1:5], 2) # 根据行号和列号从S盒中查找对应的输出值 # 注意:S应该在函数外部定义为一个包含8个S盒的列表,每个S盒是一个4x16的二维列表 # 这里假设S[c]表示当前处理的S盒(c从0到7) # row * 16 + col用于计算当前行和列在S盒中的索引位置 num = bin(S[c][row * 16 + col])[2:] # 从S盒中获取对应的输出值,并转换为二进制字符串 # 注意:bin函数输出的二进制字符串可能不足4位,因此需要进行补全 # 下面这个循环用于在num前面补0,直到num的长度为4 for gz in range(0, 4 - len(num)): num = '0' + num # 将当前S盒的输出值添加到结果字符串res中 res += num # 更新计数器c,准备处理下一个S盒 c += 1 # 返回S盒置换后的结果字符串 return res #P置换 def p_change(bin_str): res = "" for i in P: res += bin_str[i - 1] return res # E扩展置换 def f(str_left, key): e_change_output = e_change(str_left) xor_output = xor_change(e_change_output, key) # 将48位结果与子密钥Ki进行异或(xor) s_change_output = s_change(xor_output) res = p_change(s_change_output) return res # IP逆盒处理 def ip_re_change(bin_str): res = "" for i in IP_re_table: res += bin_str[i - 1] return res #主要加密函数 def encrypt(): bin_str = str2bin(input('请输入明文:')) bin_key = key2bin(input('请输入密钥:')) print('------------16个子密钥------------') tmp = re.findall(r'.{64}', bin_str) #每64位一组 a = gen_key(bin_key) re_L = [] re_R = [] for i in range(16) : print("k" + str(i + 1) + "=" + a[i]) print('------------左半部分------------') result = '' for i in tmp: str_bin = ip_change(i) # IP置换 key_lst = gen_key(bin_key) # 生成16个子密钥 str_left = str_bin[:32] str_right = str_bin[32:] for j in range(15): # 先循环15次 因为最后一次不需要不用换位 f_res = f(str_right, key_lst[j]) str_left = xor_change(f_res, str_left) str_left, str_right = str_right, str_left re_L.append(str_left) re_R.append(str_right) f_res = f(str_right, key_lst[15]) # 第16次 str_left = xor_change(str_left, f_res) fin_str = ip_re_change(str_left + str_right) # ip的逆 result += fin_str last = hex(int(result,2))[2:] #十六进制输出密文 for q in range(len(re_L)) : print('L' + str(q+1) + '=' + re_L[q]) print('L16=' + re_R[14]) print('------------右半部分------------') for p in range(len(re_R)) : print('R' + str(p+1) + '=' + re_R[p]) print('R16=' + str_left) print('------------密文------------') #print('\n十六进制密文为:', last) print("\nbase64密文为 :" + str(base64.b64encode(last.encode('utf-8')))[2:-1]) if __name__ == '__main__': encrypt() 这段代码里有使用现存的密码学代码库吗?
最新发布
09-20
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值