吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 845|回复: 12
收起左侧

[学习记录] 使用python及参考部分资料实现的rc4加密算法,如有错误欢迎指正。

[复制链接]
BlackPig1234 发表于 2026-3-17 19:09
# 1.初始化S表
s = list(range(256))

# 2.用种子密钥来填充k表
k = []
# 输入种子密钥,填充K表
seed = input("请输入连续数字的种子密钥:")
key_seed = [int(c) for c in seed]
length_ks = len(key_seed)

if length_ks >= 255:
    for i in range(0, 256):
        k.append(key_seed[i])
else:
    for i in range(0, 256):
        # 如果长度大于255
        if i < length_ks:
            k.append(key_seed[i])
        else:
            # 如果种子长度小于255,需要循环进行填充
            k.append(key_seed[i % length_ks])

# 用K表对S表进行置换
j = 0
for i in range(0, 256):
    j = (j + s[i] + k[i]) % 256
    # 交换S表中两个位置的变量
    s[i], s[j] = s[j], s[i]

# 密钥形成了,下一步形成流密钥
def ral_key(length):
    """
    用来形成最后真正的流密钥
    :param length: 需要加密的明文长度
    :return: rk[]需要异或的真正的流密码
    """
    global s  # 使用全局的S盒
    rk = []  # 记录真正的流密钥
    i = j = 0
    # 将s盒进行复制,防止操作修改全局S盒,因为python是引用传递
    s_copy = s.copy()
    for r in range(0, length):
        i = (i + 1) % 256
        j = (j + s_copy[i]) % 256
        # 交换i与j之间的s表值
        s_copy[i], s_copy[j] = s_copy[j], s_copy[i]
        t = (s_copy[i] + s_copy[j]) % 256
        rk.append(s_copy[t])
    return rk

def RC4(text):
    """
    加密函数,使用密钥流对明文进行异或
    :param text: 加密的明文字符串
    :return: 密文
    """
    # 明文转字节列表
    text_bytes = [ord(c) for c in text]

    # 生成等长流密钥
    rk = ral_key(len(text_bytes))

    # 异或加密
    mi_text = []
    for i in range(len(text_bytes)):
        mi_text.append(text_bytes[i] ^ rk[i])  # 修正:异或操作,用append

    return mi_text

def De_RC4(mi_text):
    """
    解密函数
    :param rk: 加密的流密钥
    :param mi_text: 密文
    :return: 明文
    """
    # 生成相同流密钥(需要相同的初始S盒,所以real_key会复制S盒)
    rk = ral_key(len(mi_text))

    # 异或解密(与加密相同操作)
    ming_text = []
    for i in range(len(mi_text)):
        ming_text.append(mi_text[i] ^ rk[i])

    # 字节转字符串
    return ''.join(chr(b) for b in ming_text)

if __name__ == "__main__":
    print("\n" + "="* 50)

    # 输入明文
    plaintext = input("请输入要加密的明文:")

    # 加密
    cipher = RC4(plaintext)
    print(f"\n加密完成!")
    print(f"密文长度:{len(cipher)} 字节")
    print(f"密文(hex):", ''.join(f'{b:02x}' for b in cipher))
    print(f"密文(数字):{cipher}")

    # 加密
    print("\n" + "-"*50)
    decryted = De_RC4(cipher)
    print(f"解密完成!")
    print(f"解密结果:{decryted}")

    # 验证
    if decryted == plaintext:
        print("\n√ 验证成功:解密结果与原文一致!")
    else:
        print("\n× 验证失败!")

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
Snxiolng + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hernnin 发表于 2026-3-17 21:14
不错,学到了
Candy123Y 发表于 2026-3-17 21:30
longoom313 发表于 2026-3-17 21:46
头像被屏蔽
zljxaoshuai 发表于 2026-3-17 21:48
提示: 作者被禁止或删除 内容自动屏蔽
lnzdl 发表于 2026-3-17 21:52
学习了,python
Kcode 发表于 2026-3-17 22:08
学到了,python
inKant 发表于 2026-3-17 23:17
有意思。一起学习吧。
WQ52pojie 发表于 2026-3-17 23:45
很详细的学习过程,感谢大佬分享
haoqwenie 发表于 2026-3-27 15:54
这真是一个非常棒的学习记录!你对 RC4 算法的核心逻辑(KSA 密钥调度算法、PRGA 伪随机生成算法以及异或操作)理解得很准确。特别值得表扬的是,你注意到了 **Python 中列表是引用传递** 这一细节,并使用了 `s.copy()` 来防止解密时 S 盒被污染,这是一个非常聪明且关键的处理!

不过,从工程实践和代码健壮性的角度来看,你的代码还有几个可以优化和修正的地方。以下是具体的分析和改进建议:

### 1. 种子密钥的处理方式(Bug/局限性)
**原代码:**
```python
seed = input("请输入连续数字的种子密钥:")
key_seed = [int(c) for c in seed]
```
**问题:** 这里强制要求用户输入“连续数字”,并将其强转为 `int`。在标准的 RC4 中,密钥可以是任何字符(字母、符号等),算法是通过字符的 ASCII/UTF-8 编码值(即字节)来计算的。如果用户输入字母,你的代码会报错。
**改进:** 直接将字符串转为字节序列,例如使用 `[ord(c) for c in seed]` 或更推荐的 `seed.encode('utf-8')`。

### 2. K表的生成过于繁琐(优化点)
**原代码:**
你使用了一个 `if-else` 和循环来预先生成一个长达 256 的 `k` 表。
**问题:** 这一步在数学上是正确的,但在代码上有些冗余。
**改进:** 可以直接在打乱 S 盒的循环中,使用取模运算 `key_seed[i % length_ks]` 来实现密钥的循环读取,从而完全省去构建 `k` 表的步骤。

### 3. 明文字符的编码问题(健壮性)
**原代码:**
```python
text_bytes = [ord(c) for c in text]
```
**问题:** `ord()` 对于英文字符(ASCII)没有问题,但如果你的明文包含中文,`ord("中")` 会返回一个大于 255 的数字(如 20013),这超出了一个字节(0-255)的范围,会导致后续基于字节的加密逻辑出现逻辑错误或无法完美还原。
**改进:** 使用标准的 `.encode('utf-8')` 将明文转为真正的字节流,解密后再用 `.decode('utf-8')` 还原。

### 4. 全局变量的使用(架构设计)
**原代码:** S 盒初始化和打乱的操作直接写在了全局作用域中。
**问题:** 这意味着这个脚本只要被运行或导入,就会立刻要求输入密钥。而且如果你想在同一个程序中用两个不同的密钥加密两段不同的文本,现在的结构很难实现。
**改进:** 将 S 盒的初始化(KSA)封装成一个函数。

---

### 优化后的参考代码

结合上述建议,我用更符合 Python 习惯(Pythonic)的方式重构了你的代码。你可以将这段代码与你的原版进行对比学习:

```python
def rc4_ksa(key_bytes):
    """
    密钥调度算法 (KSA): 初始化并打乱S盒
    :param key_bytes: 密钥的字节序列
    :return: 初始化好的S盒
    """
    s = list(range(256))
    j = 0
    key_length = len(key_bytes)
   
    for i in range(256):
        # 直接使用 i % key_length 实现密钥循环,无需预先构建长度为256的K表
        j = (j + s[i] + key_bytes[i % key_length]) % 256
        s[i], s[j] = s[j], s[i]
        
    return s

def rc4_prga(s, text_length):
    """
    伪随机生成算法 (PRGA): 生成密钥流
    :param s: 已经过KSA处理的S盒
    :param text_length: 需要生成的密钥流长度
    :return: 密钥流 (列表)
    """
    s_copy = s.copy()  # 复制S盒,避免污染原状态
    i = 0
    j = 0
    keystream = []
   
    for _ in range(text_length):
        i = (i + 1) % 256
        j = (j + s_copy[i]) % 256
        s_copy[i], s_copy[j] = s_copy[j], s_copy[i]
        t = (s_copy[i] + s_copy[j]) % 256
        keystream.append(s_copy[t])
        
    return keystream

def rc4_crypt(data_bytes, key_bytes):
    """
    RC4加解密核心函数 (RC4的加密和解密逻辑是完全相同的)
    :param data_bytes: 明文或密文的字节序列
    :param key_bytes: 密钥的字节序列
    :return: 异或后的字节序列
    """
    # 1. 初始化S盒
    s = rc4_ksa(key_bytes)
    # 2. 生成密钥流
    keystream = rc4_prga(s, len(data_bytes))
   
    # 3. 异或操作
    # 使用 zip 将数据和密钥流一一对应进行异或
    res_bytes = bytearray()
    for data_byte, key_byte in zip(data_bytes, keystream):
        res_bytes.append(data_byte ^ key_byte)
        
    return bytes(res_bytes)

if __name__ == "__main__":
    print("\n" + "=" * 50)
   
    # 接收输入并统一转换为 UTF-8 字节流
    key_str = input("请输入密钥 (支持任意字符): ")
    plaintext_str = input("请输入要加密的明文 (支持中文): ")
   
    key_bytes = key_str.encode('utf-8')
    plaintext_bytes = plaintext_str.encode('utf-8')
   
    # 加密
    ciphertext_bytes = rc4_crypt(plaintext_bytes, key_bytes)
    print("\n--- 加密完成 ---")
    print(f"密文长度:{len(ciphertext_bytes)} 字节")
    print(f"密文 (Hex): {ciphertext_bytes.hex()}")
   
    # 解密 (将密文再扔进 rc4_crypt 即可解密)
    decrypted_bytes = rc4_crypt(ciphertext_bytes, key_bytes)
    decrypted_str = decrypted_bytes.decode('utf-8')
    print("\n--- 解密完成 ---")
    print(f"解密结果: {decrypted_str}")
   
    # 验证
    if decrypted_str == plaintext_str:
        print("\n√ 验证成功: 解密结果与原文一致!")
    else:
        print("\n× 验证失败!")
```

### 主要改进总结:
1. **支持了全字符集**:通过 `.encode('utf-8')`,现在的程序可以完美处理包含字母、符号甚至中文字符的密钥和明文。
2. **合并加解密函数**:由于 RC4 是对称加密中的流密码,加密(`明文 ^ 密钥流 = 密文`)和解密(`密文 ^ 密钥流 = 明文`)的过程在代码层面上是**完全等价**的,因此只需要一个 `rc4_crypt` 函数即可,减少了代码重复。
3. **消除冗余逻辑**:去掉了 `k` 表的手动填充,使用 `key_bytes[i % key_length]` 更加优雅。

你的基础打得很扎实,逻辑也很清晰,希望这些改进能帮助你在密码学的代码实现上更进一步!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-9-20 17:10

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表