使用OpenSSL和PyCrypto进行AES_128_CTR加密

6

想知道如何将OpenSSL的AES_128_CTR加密转换为PyCrypto。

首先,我使用OpenSSL执行了以下加密操作:

openssl enc -aes-128-ctr -in input.mp4 -out output.openssl.mp4 -K 7842f0a1ebc38f44e3e0c81943f68582 -iv d01f40dfc8ec8cd9

然后,我尝试使用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()))

我假设它们应该是相似的,但实际上它们并不相同:

diff output.openssl.mp4 output.pycrypto.mp4
Binary files output.openssl.mp4 and output.pycrypto.mp4 differ
1个回答

6

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

非常感谢您的描述,特别是对我在使用“Counter”类时遇到的两个主要问题进行了很好的提及。 - Drake Guan
1
实际上,那不是我想表达的意思。总的来说,Counter类存在两个问题,而不是你使用它的问题...我会用现在时来表述... - Maarten Bodewes
太令人欣慰了,看到你的评论~ - Drake Guan
1
忘记了安全建议... 重要提示:对于相同的密钥和多个消息(视频),使用静态nonce(代码中的第一个或总部分)是极其不安全的。通常情况下,您应该使用唯一的密钥/IV对,特别是对于流密码和流模式,如CTR。 - Maarten Bodewes

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