我正在尝试解密 CryptoJS 使用 PyCrypto 创建的密文。我正在使用 AES-256-CTR,带有 12 字节随机前缀和 4 字节计数器。到目前为止,我的成功有限。请阅读我第一次尝试的上一篇文章。
这适用于Javascript:
- 安装 CryptoCat 扩展
- 运行 CryptoCat
- 启动开发者控制台(Chrome/Firefox 中的 F12)
- 运行这些代码行
key = 'b1df40bc2e4a1d4e31c50574735e1c909aa3c8fda58eca09bf2681ce4d117e11';
msg = 'LwFUZbKzuarvPR6pmXM2AiYVD2iL0/Ww2gs/9OpcMy+MWasvvzA2UEmRM8dq4loB\ndfPaYOe65JqGQMWoLOTWo1TreBd9vmPUZt72nFs=';
iv = 'gpG388l8rT02vBH4';
opts = {mode: CryptoJS.mode.CTR, iv: CryptoJS.enc.Base64.parse(iv), padding: CryptoJS.pad.NoPadding};
CryptoJS.AES.decrypt(msg, CryptoJS.enc.Hex.parse(key), opts).toString(CryptoJS.enc.Utf8);
预期输出:"Hello, world!ImiAq7aVLlmZDM9RfhDQgPp0CrAyZE0lyzJ6HDq4VoUmIiKUg7i2xpTSPs28USU8"
.
这是我用 Python 编写的一个脚本,它部分(!)解密了密文:
import struct
import base64
import Crypto.Cipher.AES
import Crypto.Util.Counter
def bytestring_to_int(s):
r = 0
for b in s:
r = r * 256 + ord(b)
return r
class IVCounter(object):
def __init__(self, prefix="", start_val=0):
self.prefix = prefix
self.first = True
self.current_val = start_val
def __call__(self):
if self.first:
self.first = False
else:
self.current_val += 1
postfix = struct.pack(">I", self.current_val)
n = base64.b64decode(self.prefix) + postfix
return n
def decrypt_msg(key, msg, iv):
k = base64.b16decode(key.upper())
ctr = IVCounter(prefix=iv)
#ctr = Crypto.Util.Counter.new(32, prefix=base64.b64decode(iv), initial_value=0, little_endian=False)
aes = Crypto.Cipher.AES.new(k, mode=Crypto.Cipher.AES.MODE_CTR, counter=ctr)
plaintext = aes.decrypt(base64.b64decode(msg))
return plaintext
if __name__ == "__main__":
#original:
key = 'b1df40bc2e4a1d4e31c50574735e1c909aa3c8fda58eca09bf2681ce4d117e11'
msg = 'LwFUZbKzuarvPR6pmXM2AiYVD2iL0/Ww2gs/9OpcMy+MWasvvzA2UEmRM8dq4loB\ndfPaYOe65JqGQMWoLOTWo1TreBd9vmPUZt72nFs='
iv = 'gpG388l8rT02vBH4'
decrypted = decrypt_msg(key, msg, iv)
print "Decrypted message:", repr(decrypt_msg(key, msg, iv))
print decrypted
输出是:
'Hello, world!Imi\xfb+\xf47\x04\xa0\xb1\xa1\xea\xc0I\x03\xec\xc7\x13d\xcf\xe25>l\xdc\xbd\x9f\xa2\x98\x9f$\x13a\xbb\xcb\x13
\xd2#\xc9T\xf4|\xd8\xcbaO)\x94\x9aq<\xa7\x7f\x14\x11\xb5\xb0\xb6\xb5GQ\x92'
问题是,只有输出的前16个字节与预期输出的前 16 个字节匹配!
Hello, world!ImiAq7aVLlmZDM9RfhDQgPp0CrAyZE0lyzJ6HDq4VoUmIiKUg7i2xpTSPs28USU8
当我修改脚本来执行此操作时:
def __init__(self, prefix="", start_val=1):
和
self.current_val += 0 #do not increment
这使得计数器\x00\x00\x00\x01
每次被调用时输出相同的值(),明文是:
\xf2?\xaf:=\xc0\xfd\xbb\xdf\xf6h^\x9f\xe8\x16I\xfb+\xf47\x04\xa0\xb1\xa1\xea\xc0I\x03\xec\xc7\x13dQgPp0CrAyZE0lyzJ\xa8\xcd!?h\xc9\xa0\x8b\xb6\x8b\xb3_*\x7f\xf6\xe8\x89\xd5\x83H\xf2\xcd'\xc5V\x15\x80k]
其中第 2 个 16 字节块 (dQgPp0CrAyZE0lyzJ) 与预期输出匹配。
当我将计数器设置为发出\x00\x00\x00\x02
和\x00\x00\x00\x03
时,我得到了类似的结果——随后的 16 字节块被显示出来。唯一的例外是,对于 0,前 32 个字节被显示。
All 0s: reveals first 32 bytes.
'Hello, world!ImiAq7aVLlmZDM9RfhD\xeb=\x93&b\xaf\xaf\x8d\xc9\xdeA\n\xd2\xd8\x01j\x12\x97\xe2i:%}G\x06\x0f\xb7e\x94\xde\x8d\xc83\x8f@\x1e\xa0!\xfa\t\xe6\x91\x84Q\xe3'
All 1s: reveals next 16 bytes.
"\xf2?\xaf:=\xc0\xfd\xbb\xdf\xf6h^\x9f\xe8\x16I\xfb+\xf47\x04\xa0\xb1\xa1\xea\xc0I\x03\xec\xc7\x13dQgPp0CrAyZE0lyzJ\xa8\xcd!?h\xc9\xa0\x8b\xb6\x8b\xb3_*\x7f\xf6\xe8\x89\xd5\x83H\xf2\xcd'\xc5V\x15\x80k]"
All 2s: reveals next 16 bytes.
'l\xba\xcata_2e\x044\xb2J\xe0\xf0\xd7\xc8e\xae\x91yX?~\x7f1\x02\x93\x17\x93\xdf\xd2\xe5\xcf\xe25>l\xdc\xbd\x9f\xa2\x98\x9f$\x13a\xbb\xcb6HDq4VoUmIiKUg7i\x17P\xe6\x06\xaeR\xe8\x1b\x8d\xd7Z\x7f"'
All 3s: reveals next 13 bytes.
'I\x92\\&\x9c]\xa9L\xb1\xb6\xbb`\xfa\xbet;@\x86\x07+\xa5=\xe5V\x84\x80\x9a=\x89\x91q\x16\xea\xca\xa3l\x91\xde&\xb6\x17\x1a\x96\x0e\t/\x188\x13`\xd2#\xc9T\xf4|\xd8\xcb`aO)\x94\x9a2xpTSPs28USU8'
如果你连接“正确”的块,你会得到预期的明文:
Hello, world!ImiAq7aVLlmZDM9RfhDQgPp0CrAyZE0lyzJ6HDq4VoUmIiKUg7i2xpTSPs28USU8
这真的很奇怪。我肯定在 Python 端做错了什么,因为事情可以被解密,但不能一次全部解密。如果有人可以提供帮助,我将不胜感激。谢谢你。