You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python3实现Vernam加密时返回非预期十六进制字符如何解决?

核心问题本质

你看到的\x开头的十六进制转义不是密文本身包含的内容,是Python输出含不可打印控制字符的字符串时,自动用repr()逻辑做的显示层转义。内存中ciphertext变量存储的就是异或后的正确原始字符,直接传入解密逻辑做异或就能正常还原,解密失败基本是两个操作错误导致的:

  • 手动复制了控制台打印的带\x转义的文本作为密文输入,此时原本1字节的控制字符已经变成了\、x加两位十六进制数的多字符文本,和原始密文完全不一致
  • 密文以文本模式写入、读取时,不可打印字符触发了编码自动转换,读回的内容和原始密文不匹配

你提到的两种方案实现方式&固有缺陷

方案1:将输出中的十六进制转义转换为对应Unicode字符

这个方案仅在你拿到的是控制台输出的、带字面量\x转义的文本字符串场景下生效,内存中存储的原始ciphertext变量不需要做这个转换。
实现代码:

import codecs
def unescape_hex_str(s: str) -> str:
    return codecs.decode(s, "unicode_escape")

该方案存在明确的歧义风险:如果异或生成的密文里本身就存在连续的\x加两位十六进制数的可打印字符序列,转换时会被错误识别为转义序列,直接导致密文损坏,不推荐在生产场景使用。

方案2:调整解密算法自动识别十六进制转义字符

这个方案和方案1逻辑完全一致,只是把转义解码步骤放到了解密流程的入口处,示例实现:

import codecs
def vernam_decrypt(ciphertext_str: str, key_list: list[str]) -> str:
    # 先解码转义字符再做异或
    real_cipher = codecs.decode(ciphertext_str, "unicode_escape")
    plaintext = ""
    for c, k in zip(real_cipher, key_list):
        plaintext += chr(ord(c) ^ ord(k))
    return plaintext

该方案和方案1有完全相同的转义歧义问题,属于补丁式修复,没有解决不可打印字符导致的传输、存储、显示易损坏的根本问题。


推荐的无问题实现

不要直接把异或生成的含不可打印控制字符的内容当普通文本传输、存储,这类二进制数据在IDE控制台、文本编辑器、编码转换环节很容易损坏。通用做法是先把二进制密文编码为全可打印字符格式再输出,最常用的是base64编码,彻底规避转义问题。
修正后的加密函数:

import secrets
import string
import base64

def vernam(plaintext: str) -> str:
    cipher_bytes = bytearray()
    vernamkey = []
    for letter in plaintext:
        key_char = secrets.choice(string.ascii_letters)
        vernamkey.append(key_char)
        # 异或结果直接存为字节
        cipher_bytes.append(ord(letter) ^ ord(key_char))
    # 字节转base64可打印字符串,全环境可正常显示、复制、存储
    ciphertext_b64 = base64.b64encode(cipher_bytes).decode("ascii")
    # 密钥全是大小写字母,本身就是可打印字符,直接写入文件即可
    with open("vkey.txt", "w", encoding="utf-8") as f:
        f.write("\n".join(vernamkey))
    return ciphertext_b64

对应的解密函数:

import base64

def vernam_decrypt(ciphertext_b64: str, key_path: str = "vkey.txt") -> str:
    # 读取密钥
    with open(key_path, "r", encoding="utf-8") as f:
        key_list = [line.strip() for line in f if line.strip()]
    # base64字符串转回原始密文字节
    cipher_bytes = base64.b64decode(ciphertext_b64)
    plaintext = ""
    for c_byte, k_char in zip(cipher_bytes, key_list):
        plaintext += chr(c_byte ^ ord(k_char))
    return plaintext

该实现完全不会出现不可打印字符导致的转义问题,控制台输出、复制粘贴、文件读写全流程都不会损坏密文,也不存在转义歧义风险。

内容的提问来源于stack exchange,提问作者Hackerman4356

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 19:54:23