使用带有 CBC 模式的 AES 将 UTF-16 加密为 UTF-16

Using AES with CBC mode to encrypt UTF-16 into UTF-16

提问人:user21815993 提问时间:11/14/2023 最后编辑:Maarten Bodewesuser21815993 更新时间:11/14/2023 访问量:65

问:

我在我的应用程序中使用 pycryptodome 进行加密。 应用程序的一部分要求我打开一个文件,加密文件中的数据,并加密文件的名称。我使用了带有 CBC 模式的 AES(因为它是我在处理文件时的首选方法),并且文件加密类效果很好:

class Cipher:
    def __init__(self, password: str, key: bytes = None):
        self.key = PBKDF2(password, key if key else password_as_key(password), dkLen=32)
        self.cipher = AES.new(self.key, AES.MODE_CBC, iv=get_random_bytes(16))

    def encrypt(self, data: bytes) -> bytes:
        return self.cipher.encrypt(pad(data, AES.block_size)) + self.cipher.iv

    # decryption is the same as encryption, but it's necessary to remove the IV before
    def decrypt(self, data: bytes) -> bytes:
        encrypted_data = data[:-16]
        iv = data[-16:]
        self.cipher = AES.new(self.key, AES.MODE_CBC, iv=iv)
        return unpad(self.cipher.decrypt(encrypted_data), AES.block_size)

我也想将这种加密用于名称加密,但有一个问题。加密文件名时,我需要将文件保存在文件系统上,因此我不能将名称保存为一堆字节。但是,简单地解码文本是不可能的,因为 AES 会进行大量字节转换,因此我无法确保文件保持任何编码,无论是 UTF-8、UTF-16 还是 base64(我都尝试了,它们都失败了)。所以我想知道,在这种情况下,有没有办法将字符串加密成字符串?

顺便说一句,我知道我在标题中说过,我想使用带有 CBC 模式的 AES 进行加密,这仍然是正确的。但是,如果没有其他方法可以解决这个问题,那么我可以使用其他加密方法,只要它们与AES加密一样安全和快速。

python 字符串 加密 aes pycryptodome

评论

1赞 Alastair McCormack 11/14/2023
这取决于什么操作系统。在 Linux(可能是 *nix)上,文件名只是一个字节字符串 - 它可以是任何东西。IIRC,在 Python 中使用字符串来绕过语言环境转换。文件列表时,将目录作为字节字符串传递以获取 byestring 路径。但是,没有什么可以阻止您使用 base64 ascii hex for Windows (>NT 3.51) 或 *nix。如果说加密文件名听起来不是一个好主意,那将是我的失职!b''
1赞 Maarten Bodewes 11/14/2023
我的大脑还没有运转,我已经将 base 64 转换添加到我的答案中:)
0赞 Alastair McCormack 11/14/2023
@MaartenBodewes如果是我,我会选择你的选项 3 :)
0赞 user21815993 11/14/2023
@AlastairMcCormack我经历了大量的故障排除,以使我的应用程序不依赖于操作系统(我只使用不依赖于操作系统的软件包,并进行了大量的集成测试),所以我宁愿找到一个效果更差的解决方法,但你的答案可能是最好的。如果我不让它不依赖于操作系统,那么我会使用你的。
0赞 Alastair McCormack 11/15/2023
对我的断言略有更正 - 在 Linux 上,如果传递给的字节字符串看起来包含对目录的 ascii 引用,则会引发异常。例如 , , .空字节也会引发错误,因此如果您疯狂到尝试它,那将是不可靠的解决方案;)IsADirectoryErroropen()/...

答:

3赞 Maarten Bodewes 11/14/2023 #1

我可以看到不少于三个选项:

  1. FPS 或格式保留加密:这可能是最符合您要求的选项。它将使用任何字母将文本加密为具有相同字母和大小的内容。问题在于,这是一项非常困难的任务,并且 FF1 和 FF3 等 FPS 的实现并不常见。FPS 安全是一个棘手的话题,它不会那么快 - 但可能足够快。

  2. CBC + 基数转换:可以使用任何方案(如 CBC)进行加密,然后对仅包含对文件名有效的字符(可能点除外)的字母表中的索引执行基数转换。这将扩展文件名,因为 CBC 有开销,并且因为密文使用字节的所有可能值。

    一个。如果要使用所有可能的字符(对于特定操作系统),则在用于较大的密文时,基本转换可能会很棘手;如果实施不当,它会占用大量 CPU。

    b.为了方便起见,您可以使用 base64url 对加密文件进行编码 名称,例如,制作它,但要注意文件名和路径的大小限制。<base64offullfilename>.b64

  3. 将其存储为元信息:可能最简单的选择是将文件名存储为密文的一部分,然后使用序列号或类似信息(例如)。如果你这样做,你只需要将文件名与内容区分开来。如果您不想自己这样做,您可以将文件放入存档中并对其进行加密。encrypted_file_001.bin

在这一点上,你可能必须先做出选择,然后才能进行任何实现。由于第一个确实需要很多理解,第二个是相当多的工作,我建议采取选项 2b 或 3。

言论:

  • 并非所有 UTF-16 字符串都是有效的文件名;冒号和斜杠之类的东西通常不会放在文件名中;
  • base64URL 也被明确地用于文件名是安全的。