我设计了一个拼图算法来获取每个加密块的值,该值指向要加密的下一个块。出于某种特殊原因,我必须使用aes-ctr-128。
我进行虚拟测试,看看它有多快或多慢。
这就是我所做的。我测试了pycrypto和密码学。
我首先创建一个带有随机字节的16MB文件。
我试过两种方式:
方法1。将文件加载到块大小为128位的块列表中。
方法2。只需将文件加载到字符串中即可。
现在我测试了加密每个128位块的总时间。我测试了加密整个文件的总时间。
结果如下:
pycrypto:
逐个加密128位块:每秒61,824 aes-ctr-128
- 醇>
加密整个文件:每秒8,843,713 aes-ctr-128
加密
逐个加密128位块:每秒384,959 aes-ctr-128
- 醇>
加密整个文件:每秒113,417,922 aes-ctr-128
我想知道为什么方法1和2给我带来如此大的差异的结果?这两种方法是否可以提供相同的速度?
这是我的测试代码:
import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
backend = default_backend()
from Crypto.Cipher import AES
from Crypto.Util import Counter
import random
import time
BLOCK_SIZE = 16
def read_block(fname):
block_list = []
blobfo = open(fname)
atEOF = False
while not atEOF:
blobdata = blobfo.read(BLOCK_SIZE)
block_list.append(blobdata)
if len(blobdata) < BLOCK_SIZE:
# we should stop after this...
atEOF = True
return block_list
print 'loading data'
block_list = read_block('mediumdata')
print 'loading finish'
print len(block_list), 'blocks'
print 'start encryption'
NUM_COUNTER_BITS = 128
# Here I just use a random key
key = os.urandom(16)
t1 = time.time()
for block in block_list:
ctr = Counter.new(NUM_COUNTER_BITS)
cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
cipher.encrypt(block)
t2 = time.time()
print 'finish encryption'
print 'total time:', t2 - t1
print 'time for each aes:', (t2 - t1) / len(block_list)
print 'num of aes per sec:', len(block_list) / (t2 - t1)
print 'now try to encrypt whole file'
block = open('mediumdata').read()
print type(block)
print 'start encryption'
NUM_COUNTER_BITS = 128
key = os.urandom(16)
t1 = time.time()
ctr = Counter.new(NUM_COUNTER_BITS)
cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
cipher.encrypt(block)
t2 = time.time()
print 'finish encryption'
print 'total time:', t2 - t1
print 'time for each aes:', (t2 - t1) / len(block_list)
print 'num of aes per sec:', len(block_list) / (t2 - t1)
print 'now try cryptography'
print 'start encryption'
t1 = time.time()
num = random.randint(1, 65530)
nonce = "".join(chr((num >> (i * 8)) & 0xFF) for i in range(16))
backend = default_backend()
cipher = Cipher(algorithms.AES(key), modes.CTR(nonce), backend=backend)
encryptor = cipher.encryptor()
for block in block_list:
ciphertext = encryptor.update(block)
encryptor.finalize()
t2 = time.time()
print 'finish encryption'
print 'total time:', t2 - t1
print 'time for each aes:', (t2 - t1) / len(block_list)
print 'num of aes per sec:', len(block_list) / (t2 - t1)
print 'try a whole file'
block = open('mediumdata').read()
print 'start encryption'
t1 = time.time()
num = random.randint(1, 65530)
nonce = "".join(chr((num >> (i * 8)) & 0xFF) for i in range(16))
backend = default_backend()
cipher = Cipher(algorithms.AES(key), modes.CTR(nonce), backend=backend)
encryptor = cipher.encryptor()
ciphertext = encryptor.update(block)# + encryptor.finalize()
encryptor.finalize()
t2 = time.time()
print 'finish encryption'
print 'total time:', t2 - t1
print 'time for each aes:', (t2 - t1) / len(block_list)
print 'num of aes per sec:', len(block_list) / (t2 - t1)
我在这里错过了什么吗?
有没有办法让方法1更快?
答案 0 :(得分:2)
AES是一种具有多个置换轮的分组密码。每一轮都有自己的圆键,需要从“主”键(代码中的key
)派生。调用AES.new(key, mode, ...)
将自动派生轮密钥,但此密钥计划进程非常繁重。与单呼叫方法相比,对每个块执行密钥调度将大大减慢处理速度,特别是如果实际加密代码使用AES-NI指令集。
此外,正如kennytm在comments中指出的那样,Python是一种解释型语言,因此迭代Python中的块而不是底层的本机加密代码(例如pyCrypto使用C库tomcrypt)必然会产生额外的性能损失。
方法1的代码被破坏,因为您正在为每个块创建一个新的Counter对象,该对象始终初始化为1
。因此,您使用相同的密钥流对每个块进行异或,这会创建many-time pad并且可能使攻击者能够推断出明文。
我们可以通过只有一个Counter对象来解决这个问题。只有一个关键时间表可以大大提高性能。
改进方法1代码:
ctr = Counter.new(NUM_COUNTER_BITS)
cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
for block in block_list:
cipher.encrypt(block)
pyCrypto的结果:
1049887 blocks Method 1 total time: 17.31999993324279785156 time for each aes: 1.64970134245e-05 num of aes per sec: 60617.0325662 Improved Method 1 total time: 0.78299999237060546875 time for each aes: 7.45794540146e-07 num of aes per sec: 1340851.86492 Method 2 total time: 0.147000074387 time for each aes: 1.4001513914e-07 num of aes per sec: 7142084.82126