100行代码手把手带你实现Feisitel加密算法

互联架构唠唠嗑 2024-08-01 01:20:34
简介

Feistel 加密算法,或者叫做 Feistel 网络,是一种块加密(block cipher)模型,很多常见的加密算法都具有 Feistel 结构,如 DES、blowfish 等。

Feistel 将明文分割成固定大小(block size)的块(如 32bit、64bit),然后对于每个块进行若干轮操作,每轮操作需要用到一个 key,因此总计需要循环轮数个 key。解密时需要用相同的 keys,因此这是一种对称加密算法。

加密步骤将明文转换为 8-bit 二进制形式根据块大小(block size)分割成若干个数据块,不足整数块时需要加 padding生成轮数(rounds)个 key 的 keys 数组对于每个数据块进行若干轮操作,具体如下:在每轮操作中都将数据块分成相等的左右两部分(L1, R1)将右半部分(R1)与keys[n]进行加密函数f运算,记为f1然后将f1与左半部分进行异或(XOR)操作的结果作为下一轮输入的左半部分(L2)将本轮左半部分(L1)作为下一轮输入的右半部分(R2)下一轮的输入为L2 + R2, 再进行下一轮操作在最后一轮结束后将左半部分(Ln)和右半部分(Rn)对调(这样可以使用同一个循环进行加密和解密)

解密步骤将密文使用相同的 keys 进行与加密过程相同的循环,不过 key 的顺序与加密时相反(加密时使用 key[1], key[2], ..., key[n], 解密时使用 key[n], key[n-1], ..., key[1])组合数据块并按照 8bit 进行分割根据 ASCII 码转换为明文

Python 实现

首先定义一些变量

plain_text = 'Hello world!'# 为了便于取整,选择8bitblock_size = 8rounds = 16keys = []

生成随机的 keys

def rand_key(n): res = '' for i in range(n): bit = random.randint(0, 1) res += str(bit) return res# length 是key的长度,可以根据需要调整def generate_keys(length, rounds): for i in range (rounds): keys.append(rand_key(length)) return res

定义每一轮循环的操作

def exor(a, b): n = len(a) res = '' for i in range(n): if a[i] == b[i]: res += '0' else: res += '1' return resdef round(str, key): n = len(str) // 2 L1 = str[0:n] R1 = str[n:] # 这里的f函数选择exor操作 # 可以替换为其他的加密函数 f1 = exor(R1, key) R2 = exor(f1, L1) L2 = R1 return L2 + R2

加密过程

def feistel_encode(s, rounds): res = '' # 将密文转为8bit二进制表示 str_ascii = [ord(x) for x in s] str_bin = [format(x, '08b') for x in str_ascii] str_bin = ''.join(str_bin) # 选择block size的一半最为key length是因为将f函数定义为xor操作 # 保证长度和block size的一半相等,在执行时就不需要补padding # 实际的key length会更长,一般不会少于128bit避免被快速爆破 key_length = block_size // 2 generate_keys(key_length, rounds) res_bin = '' for n in range(0, len(str_bin), block_size): temp = str_bin[n:n + block_size] for i in range(rounds): temp = round(temp, keys[i]) # 最后一轮循环后交换左右部分 temp = temp[key_length::] + temp[0:key_length] res_bin += temp # 将密文转为ASCII字符表示 for i in range(0, len(res_bin), 8): bin_data = res_bin[i: i + 8] decimal = int(bin_data, 2) res += chr(decimal) return res

解密过程

def feistel_decode(s): res = '' str_ascii = [ord(x) for x in s] str_bin = [format(x, '08b') for x in str_ascii] str_bin = ''.join(str_bin) res_bin = '' for n in range(0, len(str_bin), block_size): temp = str_bin[n:n + block_size] for key in reversed(keys): # 确保使用反向密钥 temp = round(temp, key) key_length = len(keys[0]) # 最后一轮循环后交换左右部分 temp = temp[key_length::] + temp[0:key_length] res_bin += temp # 转为ASCII字符 for i in range(0, len(res_bin), 8): bin_data = res_bin[i: i + 8] decimal = int(bin_data, 2) res += chr(decimal) return res

最后测试一下

def main(): print('plain_text: ', plain_text) # plain_text: Hello world! cipher_text = feistel_encode(plain_text, rounds) print('cipher_text: ', cipher_text) # cipher_text: yààÓlKÓàh} decode_text = feistel_decode(cipher_text) print('decode_text: ', decode_text) # decode_text: Hello world!if __name__ == "__main__": main()总结本文中为了方便演示将block size和key size设置较小,实际一般会更长,如果不满整个block则需要补padding(用0填充)加密和解密使用相同的循环,但是注意不要忘记需要在加/解密的最后一轮循环后交换左、右部分动手实现时可以将round设为1或2,单步观察每一轮循环的结果时间复杂度 O(n)额外空间 O(n)

作者:justMonika链接:https://juejin.cn/post/7395069382433456147

0 阅读:3

互联架构唠唠嗑

简介:感谢大家的关注