Улучшение производительности кода шифрования Python Pycryptodome AES-GCM - PullRequest
0 голосов
/ 05 октября 2018

У меня около 19G данных, которые я делаю tar и затем шифрую.Я использую приведенный ниже код для выполнения этой работы.

from subprocess import call
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import sys

cmd = ["tar","--acls","--selinux","-czPf","./out.tar.gz","./src"]
proc = call(cmd)
data = open("./out.tar.gz", "rb").read()
key = get_random_bytes(32)
cipher = AES.new(key, AES.MODE_GCM)
ciphertext, tag = cipher.encrypt_and_digest(data)

out = open("./out.bin", "wb")
[out.write(x) for x in (cipher.nonce, tag, ciphertext)]
out.close()

Я использую аппаратное обеспечение HP Gen10 с 48 ядрами ЦП и 128 ГБ памяти и 1800,3 ГБ на жестком диске.Почти 100% используется только одно ядро, а использование памяти составляет около 43%.Весь процесс занимает больше дня.Я ищу способы улучшить производительность в приведенном выше коде.

Я сделал значительные улучшения в коде после SquareRootOfTwentyThree комментарии:

from subprocess import call
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import StringIO

key = get_random_bytes(32)

def readLargeFile(filename):
    with open(filename, "rb") as f:
        while True:
            data = f.read(1024)
            if not data:
                break
            yield data

cmd = ["tar","--acls","--selinux","-czPf","./out.tar.gz","./src"]
call(cmd)

cipher = AES.new(key, AES.MODE_GCM)
ciphertext = []

for data in readLargeFile("./out.tar.gz"):
    ciphertext.append(cipher.encrypt(data))

out = open("./out.bin", "wb")
[out.write(x) for x in (cipher.nonce, cipher.digest(), b"".join(ciphertext))]
out.close()

file_in = open("./out.bin", "rb")
nonce, tag, ciphertext = [file_in.read(x) for x in (16, 16, -1)]
cipher = AES.new(key, AES.MODE_GCM, nonce)
#data = cipher.decrypt_and_verify(ciphertext, tag)
data = []
for buf in StringIO.StringIO(ciphertext).read(1024):
    data.append(cipher.decrypt(buf))
cipher.verify(tag)
with open("./dst/out.tar.gz", "wb") as f:
    f.write(b''.join(data))
cmd = ["tar","-xzPf","./dst/out.tar.gz","-C","./dst"]
proc = call(cmd)

Шифрование успешноно decrypt verify () вызывает ValueError: Ошибка проверки MAC
Примечание: я использую PyCryptodome v3.6.6

Каким-то образом я успешно продолжил работу с расшифровка и ниже - мой последний код:

#! /usr/bin/python
from subprocess import Popen,PIPE,call
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import StringIO,io,tarfile
import os,sys
import datetime

print "*** Encryption Starts *** " + str(datetime.datetime.now())
key = get_random_bytes(32)

def readLargeFile(filename):
    with open(filename, "rb") as f:
        while True:
            data = f.read(1024)
            if not data:
                break
            yield data

cmd = ["tar --acls --selinux -czPf /nfs/out.tar.gz ./encrypt_disk/src/*"]
call(cmd, shell=True)

cipher = AES.new(key, AES.MODE_GCM)
ciphertext = []

for data in readLargeFile("/nfs/out.tar.gz"):
    ciphertext.append(cipher.encrypt(data))

out = open("/nfs/out.bin", "wb")
[out.write(x) for x in (cipher.nonce, cipher.digest(), b"".join(ciphertext))]
out.close()
print "*** Encryption Ends *** " + str(datetime.datetime.now())


print "*** Decryption Starts *** " + str(datetime.datetime.now())
file_in = open("/nfs/out.bin", "rb")
nonce, tag, ciphertext = [file_in.read(x) for x in (16, 16, -1)]
cipher = AES.new(key, AES.MODE_GCM, nonce)
tar = tarfile.open(fileobj=StringIO.StringIO(cipher.decrypt_and_verify(ciphertext, tag)), mode='r|*')
os.chdir("/nfs/dst")
tar.extractall(path='.')
print "*** Decryption Ends *** " + str(datetime.datetime.now())

1 Ответ

0 голосов
/ 08 октября 2018

GCM сложно (хотя и не невозможно) распараллелить.Тем не менее, на моем 3-летнем ноутбуке x86 (с ускоренными инструкциями AESNI и CLMUL) я получаю 150 МБ / с с помощью GCM PyCryptodome.Это всего 2 минуты на 19 ГБ, а не день!Я использовал следующий игрушечный код:

data = os.urandom(1024*1024)
cipher = AES.new(key, AES.MODE_GCM)
for _ in range(1024):
    cipher.encrypt(data)
tag = cipher.digest()

Код не может напрямую использоваться для вашего случая использования, но он указывает, что может быть проблема с шифрованием всего 19 ГБ за один раз.Возможно, вам следует вместо этого разбить обработку на куски.

Некоторые другие комментарии:

  • Используйте профилировщик, чтобы определить, где ваша программа занимает больше всего времени.Это может быть не там, где вы думаете (например, что насчет шага tar).
  • Убедитесь, что вы используете последнюю версию PyCryptodome (3.6.6), так как было добавлено ускорение CLMUL только недавно .
  • GCM может шифровать не более 256 ГБ - вы не так уж далеки с 19 ГБ.
...