2013-04-05 85 views
0

我想使用PyCrypto库解密一些AES-CTR-256数据。密文是由Cryptocat多方聊天Javascript代码生成的,该代码依赖于CryptoJS库。的IV方案如在Cryptocat Multiparty Protocol Specification描述:CryptoJS中的AES-CTR是否与PyCrypto兼容?

初始化向量(IV)由16个字节:即 随机产生12个字节和4个字节充当计数器,递增 每块一次。

(12个随机字节来的4个计数器字节之前。)

这里是我的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 

这是怎么做同样的事情在Javascript:

  1. 安装CryptoCat扩展
  2. 运行CryptoCat
  3. 火的显影剂控制台(F12在铬/火狐)
  4. 运行的代码
  5. 这些行

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"。正如预期的那样,这对Javascript有效。

但是,Python代码输出乱码。 repr(明文)给出:

'\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' 

我不知道为什么会发生这种情况。我很确定我的IVCounter实现与JS代码使用的方案相匹配。难道是没有CryptoJS NoPadding选项的Python等价物?我很难过。

在此先感谢您的帮助!

+0

您仍然需要使用SSL/TLS。 – rook 2013-04-05 15:49:32

+0

嗨,SSL/TLS与AES-CTR解密有什么关系?或者你是指这个评论主题? http://stackoverflow.com/a/15837593/2249400谢谢。 – user2249400 2013-04-05 23:07:15

+0

我不是蟒蛇专家,但是最初的IV值没有以零或一个结尾?可能是一个错误。 – 2013-04-08 22:42:47

回答

0

我想你想在How come I can't decrypted my AES encrypted message on someone elses AES decryptor?

的方式来看待您所使用的蟒蛇解密需要修改按这个问题的答案quesiton。

+0

谢谢,但CryptoJS在所有加入盐密文?我浏览了代码,但无法找到任何迹象。 – user2249400 2013-04-05 15:38:07

+0

事实上,该规范没有提及产生由盐和密码的密钥和IV的任何功能的。从Cryptocat Javascript代码生成IV作为随机字符串,然后附加一个计数器(\ X00 \ X00 \ X00 \ X00,\ X00 \ X00 \ X00 \ X01 ...)。 – user2249400 2013-04-06 02:47:19

0

这是更正的Python脚本,将工作!

编辑:不是真的 - 只显示明文的前16个字节。我会继续努力。

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