"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "Tardis/Regenerator.py" between
Tardis-1.1.1.tar.gz and Tardis-1.1.2.tar.gz

About: Tardis is a system for making encrypted, incremental backups of filesystems.

Regenerator.py  (Tardis-1.1.1):Regenerator.py  (Tardis-1.1.2)
# vim: set et sw=4 sts=4 fileencoding=utf-8: # vim: set et sw=4 sts=4 fileencoding=utf-8:
# #
# Tardis: A Backup System # Tardis: A Backup System
# Copyright 2013-2016, Eric Koldinger, All Rights Reserved. # Copyright 2013-2019, Eric Koldinger, All Rights Reserved.
# kolding@washington.edu # kolding@washington.edu
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met: # modification, are permitted provided that the following conditions are met:
# #
# * Redistributions of source code must retain the above copyright # * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer. # notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright # * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the # notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution. # documentation and/or other materials provided with the distribution.
skipping to change at line 37 skipping to change at line 37
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
import os import os
import binascii import binascii
import logging import logging
import tempfile import tempfile
import shutil import shutil
import hashlib import hashlib
import hmac
import Tardis.CompressedBuffer as CompressedBuffer import Tardis.CompressedBuffer as CompressedBuffer
import Tardis.librsync as librsync import Tardis.librsync as librsync
class RegenerateException(Exception): class RegenerateException(Exception):
pass pass
class Regenerator(object): class Regenerator:
errors = 0 errors = 0
def __init__(self, cache, db, crypt=None, tempdir="/tmp"): def __init__(self, cache, db, crypt=None, tempdir="/tmp"):
self.logger = logging.getLogger("Regenerator") self.logger = logging.getLogger("Regenerator")
self.cacheDir = cache self.cacheDir = cache
self.db = db self.db = db
self.tempdir = tempdir self.tempdir = tempdir
self.crypt = crypt self.crypt = crypt
def decryptFile(self, filename, size, authenticate=True): def decryptFile(self, filename, size, authenticate=True):
self.logger.debug("Decrypting %s", filename) self.logger.debug("Decrypting %s", filename)
if self.crypt is None: if self.crypt is None:
raise Exception("Encrypted file. No password specified") raise Exception("Encrypted file. No password specified")
infile = self.cacheDir.open(filename, 'rb') infile = self.cacheDir.open(filename, 'rb')
hmac = self.crypt.getHash(func=hashlib.sha512) mac = self.crypt.getHash(func=hashlib.sha512)
# Get the IV, if it's not specified. # Get the IV, if it's not specified.
infile.seek(0, os.SEEK_SET) infile.seek(0, os.SEEK_SET)
iv = infile.read(self.crypt.ivLength) iv = infile.read(self.crypt.ivLength)
self.logger.debug("Got IV: %d %s", len(iv), binascii.hexlify(iv)) self.logger.debug("Got IV: %d %s", len(iv), binascii.hexlify(iv))
if authenticate: if authenticate:
hmac.update(iv) mac.update(iv)
# Create the cypher # Create the cypher
cipher = self.crypt.getContentCipher(iv) cipher = self.crypt.getContentCipher(iv)
outfile = tempfile.TemporaryFile() outfile = tempfile.TemporaryFile()
contentSize = size - self.crypt.ivLength - hmac.digest_size contentSize = size - self.crypt.ivLength - mac.digest_size
#self.logger.info("Computed Size: %d. Specified size: %d. Diff: %d", c tSize, size, (ctSize - size)) #self.logger.info("Computed Size: %d. Specified size: %d. Diff: %d", c tSize, size, (ctSize - size))
rem = contentSize rem = contentSize
blocksize = 64 * 1024 blocksize = 64 * 1024
while rem > 0: while rem > 0:
readsize = blocksize if rem > blocksize else rem readsize = blocksize if rem > blocksize else rem
ct = infile.read(readsize) ct = infile.read(readsize)
if authenticate: if authenticate:
hmac.update(ct) mac.update(ct)
pt = cipher.decrypt(ct) pt = cipher.decrypt(ct)
if rem <= blocksize: if rem <= blocksize:
# ie, we're the last block # ie, we're the last block
digest = infile.read(hmac.digest_size) digest = infile.read(mac.digest_size)
self.logger.debug("Got HMAC Digest: %d %s", len(digest), binasci i.hexlify(digest)) self.logger.debug("Got HMAC Digest: %d %s", len(digest), binasci i.hexlify(digest))
readsize += len(digest) readsize += len(digest)
if digest != hmac.digest(): if not hmac.compare_digest(digest, mac.digest()):
self.logger.debug("HMAC's: File: %-128s Computed: %-128s", self.logger.debug("HMAC's: File: %-128s Computed: %-128s",
binascii.hexlify(digest), hmac.hexdigest()) binascii.hexlify(digest), mac.hexdigest())
raise RegenerateException("HMAC did not authenticate.") raise RegenerateException("HMAC did not authenticate.")
pt = self.crypt.unpad(pt) pt = self.crypt.unpad(pt)
outfile.write(pt) outfile.write(pt)
rem -= readsize rem -= readsize
outfile.seek(0) outfile.seek(0)
return outfile return outfile
def recoverChecksum(self, cksum, authenticate=True, chain=None, basisFile=No ne): def recoverChecksum(self, cksum, authenticate=True, chain=None, basisFile=No ne):
self.logger.debug("Recovering checksum: %s", cksum) self.logger.debug("Recovering checksum: %s", cksum)
skipping to change at line 123 skipping to change at line 124
else: else:
cksInfo = self.db.getChecksumInfo(cksum) cksInfo = self.db.getChecksumInfo(cksum)
if cksInfo is None: if cksInfo is None:
self.logger.error("Checksum %s not found", cksum) self.logger.error("Checksum %s not found", cksum)
return None return None
#self.logger.debug(" %s: %s", cksum, str(cksInfo)) #self.logger.debug(" %s: %s", cksum, str(cksInfo))
try: try:
if not cksInfo['isfile']:
raise RegenerateException("{} is not a file".format(cksum))
if cksInfo['basis']: if cksInfo['basis']:
if basisFile: if basisFile:
basis = basisFile basis = basisFile
basis.seek(0) basis.seek(0)
else: else:
basis = self.recoverChecksum(cksInfo['basis'], authenticate, chain) basis = self.recoverChecksum(cksInfo['basis'], authenticate, chain)
if cksInfo['encrypted']: if cksInfo['encrypted']:
patchfile = self.decryptFile(cksum, cksInfo['disksize'], aut henticate) patchfile = self.decryptFile(cksum, cksInfo['disksize'], aut henticate)
else: else:
skipping to change at line 165 skipping to change at line 169
if cksInfo['compressed'] is not None and cksInfo['compressed'].l ower() != 'none': if cksInfo['compressed'] is not None and cksInfo['compressed'].l ower() != 'none':
self.logger.debug("Uncompressing %s", cksum) self.logger.debug("Uncompressing %s", cksum)
temp = tempfile.TemporaryFile() temp = tempfile.TemporaryFile()
buf = CompressedBuffer.UncompressedBufferedReader(output, co mpressor=cksInfo['compressed']) buf = CompressedBuffer.UncompressedBufferedReader(output, co mpressor=cksInfo['compressed'])
shutil.copyfileobj(buf, temp) shutil.copyfileobj(buf, temp)
temp.seek(0) temp.seek(0)
output = temp output = temp
return output return output
except RegenerateException:
raise
except Exception as e: except Exception as e:
self.logger.error("Unable to recover checksum %s: %s", cksum, e) self.logger.error("Unable to recover checksum %s: %s", cksum, e)
self.logger.exception(e) #self.logger.exception(e)
raise RegenerateException("Checksum: {}: Error: {}".format(cksum, e) ) raise RegenerateException("Checksum: {}: Error: {}".format(cksum, e) )
def recoverFile(self, filename, bset=False, nameEncrypted=False, permchecker =None, authenticate=True): def recoverFile(self, filename, bset=False, nameEncrypted=False, permchecker =None, authenticate=True):
self.logger.info("Recovering file: %s", filename) self.logger.info("Recovering file: %s", filename)
name = filename name = filename
if self.crypt and not nameEncrypted: if self.crypt and not nameEncrypted:
name = self.crypt.encryptPath(filename) name = self.crypt.encryptPath(filename)
try: try:
chain = self.db.getChecksumInfoChainByPath(name, bset, permchecker=p ermchecker) chain = self.db.getChecksumInfoChainByPath(name, bset, permchecker=p ermchecker)
if chain: if chain:
 End of changes. 12 change blocks. 
11 lines changed or deleted 17 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)