【问题标题】:AES decryption with PyCryptodome does not produce the expected result使用 PyCryptodome 进行 AES 解密不会产生预期的结果
【发布时间】:2019-12-23 10:31:48
【问题描述】:

我在 python 中重现 AES 加密和解密时遇到了一些困难。

上下文:一年前,我使用this javascript library 创建了一个基于 django 的小型应用程序,用于客户端加密。基本上,一些用户的输入使用密钥加密并作为十六进制字符串发送以进行存储。

为了说明,我将重点关注bd45bcccd0(又名“Masha”,使用 john 的密钥加密:3ed8bd71327aafd855aac37921519767

用当前js库加解密

  • 加密 utf-8 -> 字节 -> 加密字节 -> 十六进制
  • 解密 十六进制 -> 加密字节 -> 字节 -> utf-8

id_password 是用户密码的 MD5 哈希值。它存储在会话存储中并用作密钥

  function encrypt(t){
    var key = aesjs.utils.hex.toBytes(sessionStorage.getItem("id_password"));
    var textBytes = aesjs.utils.utf8.toBytes(t);
    var aesCtr = new aesjs.ModeOfOperation.ctr(key);
    var encryptedBytes = aesCtr.encrypt(textBytes);
    var encryptedHex = aesjs.utils.hex.fromBytes(encryptedBytes);
    return encryptedHex;
    }

  function decrypt(t){
    var key = aesjs.utils.hex.toBytes(sessionStorage.getItem("id_password"));
    var textBytes = aesjs.utils.hex.toBytes(t);
    var aesCtr = new aesjs.ModeOfOperation.ctr(key);
    var decriptedBytes = aesCtr.decrypt(textBytes);
    var decrypted_utf8 = aesjs.utils.utf8.fromBytes(decriptedBytes);
    return decrypted_utf8;
    }

key 中加载后,我会得到一个 16 项数组(所以我猜是执行 AES 128 位 CTR):

var key = aesjs.utils.hex.toBytes(sessionStorage.getItem("id_password"));
console.log(key)
Array(16) [ 62, 216, 189, 113, 50, 122, 175, 216, 85, 170, … ]

用当前代码,加解密工作

Python 实现

出于单元测试的目的,我希望能够解密。我正在使用this library。为了尽可能模仿客户端,我尝试了以下方法:

john_key = "3ed8bd71327aafd855aac37921519767"
cipher = AES.new(codecs.decode(john_key,'hex_codec'), AES.MODE_CTR)
d = cipher.decrypt(codecs.decode('bd45bcccd0', 'hex_codec'))
d.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xac in position 0: invalid start byte

这就是问题所在,但我不确定它发生在哪个阶段。这是我检查的内容:

# key's length is correct
k = codecs.decode(john_key,'hex_codec')
k
b'>\xd8\xbdq2z\xaf\xd8U\xaa\xc3y!Q\x97g'
len(k)
16
# decoded message's length is correct
d = cipher.decrypt(codecs.decode('bd45bcccd0', 'hex_codec'))
len(d)
5

由于我不能依赖库,我无法重现结果,我想知道我是否误用了 PyCryptodome,或者这个 javascript 库实现 AES CTR 加密的方式是否可靠。有什么见解吗?

【问题讨论】:

  • 一些有用的东西 - 试试 pyaes - 它也是写 aes-js 的 bit ricmoo。我最喜欢的其实是 Cryptography.io(url) 虽然

标签: javascript python encoding cryptography aes


【解决方案1】:

CTR-模式需要IV。由于您没有显式创建 IV,因此使用隐式创建的 IV。但是,两个代码生成不同的 IV,因此解密失败。在 Python 代码中,生成了一个 random IV,在 aes-js-code 中使用了一个 fixed IV (1)。

为了可以使用 Python 代码进行解密,此处必须使用与 aes-js 代码中相同的 IV(herehere)。为此:

cipher = AES.new(codecs.decode(john_key,'hex_codec'), AES.MODE_CTR)

必须替换为

counter = Counter.new(128, initial_value = 1)
cipher = AES.new(codecs.decode(john_key,'hex_codec'), AES.MODE_CTR, counter = counter) 

将密文解密为Maria(但不是Masha)。


出于安全原因,CTR 强制要求密钥/IV 对只能使用一次,即如果应用相同的密钥,则必须为每次加密生成一个新的 IV。当前代码的弱点是使用相同的密钥时密钥/IV 对会重复。更好的方法是为每个加密生成一个随机 IV,将此 IV 与密文一起发送给接收者(IV 不是秘密,因此它通常被添加到密文中),在那里它可以用于解密.

【讨论】:

  • 我认为 iv 是用于 CBC 密码的。对使用的好评,这显然是一个弱点。我会试试你的解决方案。谢谢
猜你喜欢
  • 2014-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多