由openssl和PyCrypto加密AES_128_CTR

Dra*_*uan 4 python encryption openssl aes pycrypto

想知道通过openssl将AES_128_CTR加密转换为PyCrypto的正确方法.

首先,我通过openssl进行了加密,如下所示:

openssl enc -aes-128-ctr -in input.mp4 -out output.openssl.mp4 -K 7842f0a1ebc38f44e3e0c81943f68582 -iv d01f40dfc8ec8cd9
Run Code Online (Sandbox Code Playgroud)

然后,我尝试通过PyCrypto做同样的事情:

from Crypto.Cipher import AES
from Crypto.Util import Counter
key = '7842f0a1ebc38f44e3e0c81943f68582'
iv = 'd01f40dfc8ec8cd9'

ctr_e = Counter.new(128, initial_value=int(iv, 16))
encryptor = AES.new(key.decode('hex'), AES.MODE_CTR, counter=ctr_e)

with open('output.pycrypto.mp4', 'wb') as fout:
    with open('input.mp4', 'rb') as fin:
        fout.write(encryptor.encrypt(fin.read()))
Run Code Online (Sandbox Code Playgroud)

我认为他们应该是相似的,但它不是:

diff output.openssl.mp4 output.pycrypto.mp4
Binary files output.openssl.mp4 and output.pycrypto.mp4 differ
Run Code Online (Sandbox Code Playgroud)

Maa*_*wes 5

OpenSSL的行为符合预期(幸运的是,因为命令行缺少对此事实的记录)并且使用给定的IV作为大端计数器的最左边字节.换句话说,给出的字节是16字节计数器中最重要的部分.问题中的代码使用IV作为初始计数器值,即它被解释为计数器的最不重要部分.

现在我花了一些时间修复Python代码,因为Counter我必须解决的类有两个问题:

  • 如果使用8字节的前缀,则计数器的大小应为64位而不是128位; 这是一个设计功能,但是如果为计数器保留的位数很小,它可能会导致溢出(虽然当前设置为64位但是没有)
  • 默认初始计数器值设置为1,而CTR模式始终从0开始计数; 这可能是Counter设计中的一个错误

所以不用多说:

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

key = '7842f0a1ebc38f44e3e0c81943f68582'.decode('hex')
iv = 'd01f40dfc8ec8cd9'.decode('hex')

ctr_e = Counter.new(64, prefix=iv, initial_value=0)
encryptor = AES.new(key, AES.MODE_CTR, counter=ctr_e)

with open('output.pycrypto.mp4', 'wb') as fout:
    with open('input.mp4', 'rb') as fin:
        fout.write(encryptor.encrypt(fin.read()))
Run Code Online (Sandbox Code Playgroud)