简体   繁体   English

CryptoJS中的AES-CTR是否与PyCrypto兼容?

[英]Is AES-CTR in CryptoJS compatible with PyCrypto?

I'm trying to decrypt some AES-CTR-256 data using the PyCrypto library. 我正在尝试使用PyCrypto库解密一些AES-CTR-256数据。 The ciphertext was produced by the Cryptocat multiparty chat Javascript code, which relies on the CryptoJS library. 密文由Cryptocat多方聊天Java代码生成,该代码依赖于CryptoJS库。 The IV scheme is as described in the Cryptocat Multiparty Protocol Specification : IV方案如Cryptocat 多方协议规范中所述

The Initialization Vector (IV) is composed of 16 bytes: 12 bytes that are randomly generated and 4 bytes acting as the counter, incremented once per block. 初始化向量(IV)由16个字节组成:随机生成的12个字节和4个字节作为计数器,每个块增加一次。

(The 12 random bytes come before the 4 counter bytes.) (12个随机字节位于4个计数器字节之前。)

Here's my Python code: 这是我的Python代码:

import struct
import base64
import Crypto.Cipher.AES

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="", iv="\x00\x00\x00\x00"):
        self.prefix = prefix
        self.initial_value = iv

    def increment(self, b):
        if b == "\xff\xff\xff\xff":
            raise ValueError("Reached the counter limit")
        return struct.pack(">I", bytestring_to_int(b)+1)

    def __call__(self):
        self.initial_value = self.increment(self.initial_value)
        n = base64.b64decode(self.prefix) + self.initial_value
        return n

def decrypt_msg(key, msg, iv):
    k = base64.b16decode(key.upper())
    ctr = IVCounter(prefix=iv)
    aes = Crypto.Cipher.AES.new(k, Crypto.Cipher.AES.MODE_CTR, counter=ctr)
    plaintext = aes.decrypt(msg)
    return plaintext

if __name__ == "__main__":
    key = 'b1df40bc2e4a1d4e31c50574735e1c909aa3c8fda58eca09bf2681ce4d117e11'
    msg = 'LwFUZbKzuarvPR6pmXM2AiYVD2iL0/Ww2gs/9OpcMy+MWasvvzA2UEmRM8dq4loB\ndfPaYOe65JqGQMWoLOTWo1TreBd9vmPUZt72nFs='
    iv = 'gpG388l8rT02vBH4'
    plaintext = decrypt_msg(key, msg, iv)
    print plaintext

And this is how to do the same thing in Javascript: 这是在Javascript中执行相同操作的方法:

  1. Install the CryptoCat extension 安装CryptoCat扩展
  2. Run CryptoCat 运行CryptoCat
  3. Fire up the developer console (F12 in Chrome/Firefox) 启动开发者控制台(Chrome / Firefox中为F12)
  4. Run these lines of code 运行这些代码行

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);

Expected output: "Hello, world!ImiAq7aVLlmZDM9RfhDQgPp0CrAyZE0lyzJ6HDq4VoUmIiKUg7i2xpTSPs28USU8" . 预期输出: "Hello, world!ImiAq7aVLlmZDM9RfhDQgPp0CrAyZE0lyzJ6HDq4VoUmIiKUg7i2xpTSPs28USU8" As expected, this works on Javascript. 不出所料,这适用于Javascript。

However, the Python code outputs gibberish. 但是,Python代码输出乱码。 repr(plaintext) gives: repr(plaintext)给出:

'\x91I\xbd\n\xd5\x11\x0fkE\xaa\x04\x81V\xc9\x16;.\xe3\xd3#\x92\x85\xd2\x99\xaf;\xc5\xafI\xac\xb6\xbdT\xf4{l\x17\xa1`\x85\x13\xf2\x8e\x844\xac1OS\xad\x9eZ<\xea\xbb6\x9dS\xd5\xbc\xfd\xc4\r\xf94Y~\xaf\xf3\xe0I\xad\xa6.\xfa\x7f\xf8U\x16\x0e\x85\x82\x8c\x8e\x04\xcb,X\x8b\xf7\xef\xb2\xc2\xe3~\xf1\x80\x08L\x8b \x9f\xaf\x0e\x0b'

I'm not sure why this is happening. 我不确定为什么会这样。 I'm pretty sure my IVCounter implementation matches the scheme that the JS code uses. 我非常确定我的IVCounter实现与JS代码使用的方案匹配。 Could it be that there is no Python equivalent of the CryptoJS NoPadding option? 难道没有CryptoJS NoPadding选项的Python等效项吗? I'm stumped. 我很沮丧

Thanks in advance for the help! 先谢谢您的帮助!

I think you want to look at How come I can't decrypted my AES encrypted message on someone elses AES decryptor? 我认为您想看看为什么我无法在其他人的AES解密器上解密我的AES加密消息?

The way you are using the python decrypt needs to be modified as per the answer to that quesiton. 您需要根据该问题的答案来修改使用python解密的方式。

Here is the corrected Python script that will work! 这是正确的Python脚本,它将起作用!

Edit: not really- only the first 16 bytes of the plaintext are revealed. 编辑:不是真的-仅显示纯文本的前16个字节。 I will work on this further. 我将对此做进一步的工作。

import struct
import base64
import Crypto.Cipher.AES

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="", iv="\x00\x00\x00\x00"):
        self.prefix = prefix
        self.initial_value = iv
        self.first = True

    def increment(self, b):
        if b == "\xff\xff\xff\xff":
            raise ValueError("Reached the counter limit")

        if self.first:
            return struct.pack(">I", bytestring_to_int(b))
        else:
            self.first = False
            return struct.pack(">I", bytestring_to_int(b)+1)

    def __call__(self):
        self.initial_value = self.increment(self.initial_value)
        n = base64.b64decode(self.prefix) + self.initial_value
        return n

def decrypt_msg(key, msg, iv):
    k = base64.b16decode(key.upper())
    ctr = IVCounter(prefix=iv)
    aes = Crypto.Cipher.AES.new(k, Crypto.Cipher.AES.MODE_CTR, counter=ctr)
    plaintext = aes.decrypt(base64.b64decode(msg))
    return plaintext

if __name__ == "__main__":
        key = 'b1df40bc2e4a1d4e31c50574735e1c909aa3c8fda58eca09bf2681ce4d117e11'
        msg = 'LwFUZbKzuarvPR6pmXM2AiYVD2iL0/Ww2gs/9OpcMy+MWasvvzA2UEmRM8dq4loB\ndfPaYOe65JqGQMWoLOTWo1TreBd9vmPUZt72nFs='
        iv = 'gpG388l8rT02vBH4'
        print decrypt_msg(key, msg, iv)
        print "Decrypted message:", repr(decrypt_msg(key, msg, iv))

There's something wrong with the way I'm incrementing the counter. 我增加计数器的方式有问题。 Apparently the right counter values are applied to the wrong places. 显然,正确的计数器值应用于错误的位置。 Here's a follow-up question that addresses the issue. 这是解决该问题的后续问题。 Strange issue with AES CTR mode with Python and Javascript 带有Python和Javascript的AES CTR模式的奇怪问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM