Pycrypto:CTR模式下的计数器增量

4

我仍然无法使这个工作。我的问题是如何使解密行起作用。以下是我的代码:

class IVCounter(object):
    @staticmethod
    def incrIV(self):
        temp = hex(int(self, 16)+1)[2:34]
        return array.array('B', temp.decode("hex")).tostring()


def decryptCTR(key, ciphertext):

    iv = ciphertext[:32] #extracts the first 32 characters of the ciphertext

    #convert the key into a 16 byte string
    key = array.array('B', key.decode("hex")).tostring()

    print AES.new(key, AES.MODE_CTR, counter=IVCounter.incrIV(iv)).decrypt(ciphertext)
    return

我的错误信息是:

ValueError: 'counter' 参数必须是可调用的对象

我就是想不明白pycrypto希望我如何组织new方法的第三个参数。

有人能帮忙吗?谢谢!

编辑 按照下面的建议实施后的新代码。仍然卡住了!

class IVCounter(object):
    def __init__(self, start=1L):
        print start #outputs the number 1 (not my IV as hoped)
        self.value = long(start)

   def __call__(self):
        print self.value  #outputs 1 - need this to be my iv in long int form
        print self.value + 1L  #outputs 2
        self.value += 1L
        return somehow_convert_this_to_a_bitstring(self.value) #to be written

def decryptCTR(key, ciphertext):

    iv = ciphertext[:32] #extracts the first 32 characters of the ciphertext
    iv = int(iv, 16)

    #convert the key into a 16 byte string
    key = array.array('B', key.decode("hex")).tostring()

    ctr = IVCounter()
    Crypto.Util.Counter.new(128, initial_value = iv)

    print AES.new(key, AES.MODE_CTR, counter=ctr).decrypt(ciphertext)
    return

编辑:仍然无法让这个工作起来。非常沮丧,完全没有头绪。以下是最新的代码:(请注意,我的输入字符串是32位十六进制字符串,必须以两位数字对进行解释以转换为长整型。)

class IVCounter(object):
    def __init__(self, start=1L):
        self.value = long(start)

    def __call__(self):
        self.value += 1L
        return hex(self.value)[2:34]

def decryptCTR(key, ciphertext):
    iv = ciphertext[:32] #extracts the first 32 characters of the ciphertext
    iv = array.array('B', iv.decode("hex")).tostring()

    ciphertext = ciphertext[32:]

    #convert the key into a 16 byte string
    key = array.array('B', key.decode("hex")).tostring()

    #ctr = IVCounter(long(iv))
    ctr = Crypto.Util.Counter.new(16, iv)

    print AES.new(key, AES.MODE_CTR, counter=ctr).decrypt(ciphertext)
    return

TypeError: CTR计数器函数返回的字符串长度不是16
1个回答

15
在Python中,将函数视为对象是完全有效的。同样,将任何定义了__call__(self, ...)的对象视为函数也是完全有效的。
所以你想要的可能是这样的:
class IVCounter(object):
    def __init__(self, start=1L):
        self.value = long(start)
    def __call__(self):
        self.value += 1L
        return somehow_convert_this_to_a_bitstring(self.value)

ctr = IVCounter()
... make some keys and ciphertext ...
print AES.new(key, AES.MODE_CTR, counter=ctr).decrypt(ciphertext)

然而,PyCrypto为你提供了一个计数器方法,它应该比纯Python更快:

import Crypto.Util.Counter
ctr = Crypto.Util.Counter.new(NUM_COUNTER_BITS)

ctr现在是一个有状态的函数(同时也是可调用对象),每次调用时会增加并返回其内部状态。然后您可以执行

print AES.new(key, AES.MODE_CTR, counter=ctr).decrypt(ciphertext)

与以前一样。

以下是使用Crypto.Cipher.AES在CTR模式下带有用户指定的初始化向量的工作示例:

import Crypto.Cipher.AES
import Crypto.Util.Counter

key = "0123456789ABCDEF" # replace this with a sensible value, preferably the output of a hash
iv = "0000000000009001" # replace this with a RANDOMLY GENERATED VALUE, and send this with the ciphertext!

plaintext = "Attack at dawn" # replace with your actual plaintext

ctr = Crypto.Util.Counter.new(128, initial_value=long(iv.encode("hex"), 16))

cipher = Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_CTR, counter=ctr)
print cipher.encrypt(plaintext)

1
当然。在CTR模式下,初始化向量仅是计数器的初始值。如果您想将特定IV传递给正在创建的计数器,您只需要执行ctr = Crypto.Util.Counter.new(NUM_COUNTER_BITS, initial_value = 90000001L),其中initial_value是以长整型形式表示的IV。我们认为'ctr'是一个有状态的函数的原因是因为它在内部存储了自己的计数器。每次调用ctr()时,其内部计数器会增加一。因此,通过使用您需要的IV来初始化此函数,然后您就可以递增'您的'IV。 - atomicinf
1
如果您看我的示例还不太理解,可调用对象(将其视为C++函数对象)在初始化时可以带一个参数“start”;然后,它自己的内部计数器被设置为您想要的任何值。每次调用该特定实例的IVCounter时,它自己的内部计数器(由您初始化)都会递增。原则上,您可以定义多个相互独立的IVCounter实例。 - atomicinf
1
当然可以,@usr55410。您当前代码存在两个问题:在初始化变量后,您没有使用变量“iv”;如果您正在使用我的IVCounter,则要说“ctr = IVCounter(long(iv))”或类似的方式来设置计数器的初始状态。如果您使用Crypto.Util.Counter(速度更快),则要说ctr = Crypto.Util.Counter.new(256, long(iv))。第二个问题(前面的问题也解决了)是Crypto.Util.Counter.new返回一个函数,您没有将其分配在任何地方。 - atomicinf
1
另外,还要注意一件事:PyCrypto的加密例程期望(并返回)字节串,这些字节串在加密形式下肯定无法远程可读。您需要找出如何将字符串转换为其十六进制表示形式以及从十六进制表示形式中进行转换;这不是一个难题,在https://dev59.com/-nE95IYBdhLWcg3wXsuR上已经解决。最后一件事:由于通常希望IV很长(比int通常提供的要长得多),因此您需要使用`long()`而不是`int()`来声明iv。 - atomicinf
1
1: 我的密钥字符串是二进制数据;我的IV字符串是十六进制字符串(例如baadf00d)。 2: 在解密之前,您需要重置计数器,即使用相同的IV创建一个新的计数器,然后使用新的计数器创建一个新的密码上下文,并使用该上下文进行解密。 - atomicinf
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接