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

简介: Feistel 加密算法,或者叫做 Feistel 网络,是一种块加密(block cipher)模型,很多常见的加密算法都具有 Feistel 结构,如 DES、blowfish 等。Feistel 将明文分割成固定大小(block size)的块(如 32bit、64bit),然后对于每个块进行若干轮操作,每轮操作需要用到一个 key,因此总计需要循环轮数个 key。解密时需要用相同的 keys,因此这是一种对称加密算法。

简介

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


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

加密步骤

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

解密步骤

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

Python 实现

首先定义一些变量

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

生成随机的 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 res
def 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)
相关文章
|
异构计算
实验三 基于FPGA的数码管动态扫描电路设计 quartus/数码管/电路模块设计(上)
实验三 基于FPGA的数码管动态扫描电路设计 quartus/数码管/电路模块设计(上)
2044 0
实验三 基于FPGA的数码管动态扫描电路设计 quartus/数码管/电路模块设计(上)
|
计算机视觉
高频分量
高频分量
863 7
|
Docker 容器 应用服务中间件
Docker 客户端是如何拉取镜像的?
Docker客户端拉取镜像的过程遵循Docker Registry HTTP API V2规范,主要分为解析镜像名、鉴权、获取Manifest、拉取Layers及本地合并五个步骤。它与Docker Hub、Harbor等仓库通信,确保镜像正确下载和构建。
1756 59
|
存储 缓存 JSON
详解HTTP四种请求:POST、GET、DELETE、PUT
【4月更文挑战第3天】
77346 5
详解HTTP四种请求:POST、GET、DELETE、PUT
|
存储 SQL 缓存
Hadoop入门(一篇就够了)
Hadoop入门(一篇就够了)
42247 6
Hadoop入门(一篇就够了)
|
iOS开发
苹果手机请求程序报network error错误
苹果手机请求程序报network error错误
898 0
一次主账号AK-SK疑似泄露处理过程
缘起最近抽业余时间帮朋友看了一眼他的公司的一批阿里云账号,发现一个极为严重的隐患,那就是有主账号访问密钥对(AK - AccessKeyId,SK - AccessKeySecret,后面统一简称AK-SK),且这个AK-SK是明文写在公司App应用的配置文件中,App用它来上传下载客户的文件。
|
算法 芯片
基于MPPT最大功率跟踪算法的光伏并网发电系统simulink仿真
本项目采用Simulink仿真构建基于MPPT的最大功率跟踪光伏并网发电系统,自行建立PV模型而非使用内置模块。系统包含MPPT控制器、PI控制器、锁相环及逆变器等,实现光伏阵列在各种条件下高效运行于最大功率点。仿真结果显示光伏并网输出的电流(Ipv)、电压(Upv)及功率(Ppv)波形。通过闭环控制,系统持续调整以维持最佳功率输出,有效提升光伏系统的整体效能和环境适应性。

热门文章

最新文章