继续我之前的pycryptodome问题,我的要求现在更改为支持90G数据进行加密。所以我做了一些设计上的改变,解构了加密代码,让它们都在子进程中运行。
tar zcvf - /array22/vol4/home | openssl des3 -salt | dd of=/dev/st0
上面的想法是从这里触发的
现在我有2个文件:
encutil.py
#!/usr/bin/python
import sys, os, pwd
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Random import get_random_bytes
symmetric_key = get_random_bytes(16 * 2)
cipher_rsa = PKCS1_OAEP.new(RSA.import_key(open("./public.pem").read()))
enc_symmetric_key = cipher_rsa.encrypt(symmetric_key)
cipher = AES.new(symmetric_key, AES.MODE_GCM)
[sys.stdout.write(x) for x in (enc_symmetric_key, cipher.nonce,"".join(reversed(cipher.encrypt_and_digest(sys.stdin.read()))))]
主文件
#! /usr/bin/python
import os, sys, time
import tarfile, StringIO, time
from subprocess import Popen, PIPE, call
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Random import get_random_bytes
print "Start time %s"%time.time()
try:
p1=Popen("tar -czf - ./src", shell=True, stdout=PIPE)
p2=Popen("python ./encutil.py", shell=True, stdin=p1.stdout, stdout=PIPE)
FNULL = open(os.devnull, 'w')
p3=Popen("/bin/dd bs=10M iflag=fullblock oflag=direct,sync conv=fsync,notrunc,noerror status=progress of=./data.bin", shell=True, stdin=p2.stdout, stderr=FNULL)
p3.wait()
except Exception,e:
raise str(e)
finally:
p2.stdout.close()
p1.stdout.close()
def doRestore():
try:
privKey = RSA.import_key(open("./private.pem").read())
cipher_rsa = PKCS1_OAEP.new(privKey)
file_in = open("./data.bin", "rb")
enc_symmetric_key, nonce, tag, ciphertext = [file_in.read(x) for x in (privKey.size_in_bytes(), 16, 16, -1)]
symmetric_key = cipher_rsa.decrypt(enc_symmetric_key)
cipher = AES.new(symmetric_key, AES.MODE_GCM, nonce)
tar = tarfile.open(fileobj=StringIO.StringIO(cipher.decrypt_and_verify(ciphertext, tag)), mode='r|*')
tar.extractall(path='./dst')
except Exception,e:
print e
finally:
if file_in != None:
file_in.close()
if tar != None:
tar.close()
os.remove("./data.bin")
doRestore()
print "End time %s"%time.time()
假设公钥和私钥都可用且到位。
而且,当我在执行一段时间后执行以下命令时,我收到错误:长度不正确的密文,没有任何回溯:
/usr/bin/systemd-run --scope -p MemoryLimit=80G ./main.py
但它对于较少的数据输入运行成功,例如40G的数据
我的系统详细信息是:
HW: HP ProLiant DL360 Gen10 with more than 500G of HDD space and 125G of RAM
OS: RHEL7.4 64-bit Kernel: 3.10.0-693.el7.x86_64
Python version: 2.7.5
Pycryptodome version: 3.7.2
如果我不通过systemd-run控制内存资源,那么 Python 会在某个执行点抛出MemoryError并以相同的方式失败,并显示“ Ciphertext with wrong length. ”消息
Traceback (most recent call last):
File "./encutil.py", line 12, in <module>
[sys.stdout.write(x) for x in (enc_symmetric_key, cipher.nonce,"".join(reversed(cipher.encrypt_and_digest(sys.stdin.read()))))]
File "/opt/LEBackupandRestore/lib/3pp/Crypto/Cipher/_mode_gcm.py", line 547, in encrypt_and_digest
return self.encrypt(plaintext, output=output), self.digest()
File "/opt/LEBackupandRestore/lib/3pp/Crypto/Cipher/_mode_gcm.py", line 374, in encrypt
ciphertext = self._cipher.encrypt(plaintext, output=output)
File "/opt/LEBackupandRestore/lib/3pp/Crypto/Cipher/_mode_ctr.py", line 211, in encrypt
return get_raw_buffer(ciphertext)
File "/opt/LEBackupandRestore/lib/3pp/Crypto/Util/_raw_api.py", line 187, in get_raw_buffer
return buf.raw
MemoryError
Ciphertext with incorrect length.
我无法从stackoverflow中已经提出的解决方案中得到任何线索
修改前的原代码设计如下:
#! /usr/bin/python
import os, pwd, sys
from subprocess import Popen, PIPE, check_call
from BackupRestoreException import BackupRestoreException, ErrorCode
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad,unpad
import tarfile,StringIO,time
# Key Generation
key = RSA.generate(2048)
private_key = key.export_key()
file_out = open("private.pem", "wb")
file_out.write(private_key)
file_out.close()
public_key = key.publickey().export_key()
file_out = open("public.pem", "wb")
file_out.write(public_key)
file_out.close()
public_key = RSA.import_key(open("public.pem").read())
session_key = get_random_bytes(16)
cipher_rsa = PKCS1_OAEP.new(public_key)
enc_session_key = cipher_rsa.encrypt(session_key)
def archiveData():
cmd = ["tar", "--acls", "--selinux", "-zcPf", "-", "./src"]
return Popen(cmd,stdout=PIPE).communicate()[0]
# Encryption
cipher_aes = AES.new(session_key, AES.MODE_EAX)
ciphertext, tag = cipher_aes.encrypt_and_digest(archiveData())
file_out = open("data.bin", "wb")
[ file_out.write(x) for x in (enc_session_key, cipher_aes.nonce, tag, ciphertext) ]
file_out.close()
# Decryption
private_key = RSA.import_key(open("private.pem").read())
file_in = open("data.bin", "rb")
enc_session_key, nonce, tag, ciphertext = [ file_in.read(x) for x in (private_key.size_in_bytes(), 16, 16, -1) ]
file_in.close()
cipher_rsa = PKCS1_OAEP.new(private_key)
session_key = cipher_rsa.decrypt(enc_session_key)
cipher = AES.new(session_key, AES.MODE_EAX, nonce)
tar = tarfile.open(fileobj=StringIO.StringIO(cipher.decrypt_and_verify(ciphertext, tag)), mode='r|*')
os.chdir("/home/cfuser/target")
tar.extractall(path='.')