1
0
Fork 0
mirror of https://github.com/borgbackup/borg.git synced 2024-12-25 09:19:31 +00:00

Verify cindex integrity on archive open

This commit is contained in:
Jonas Borgström 2010-10-24 20:18:18 +02:00
parent 480562570f
commit f5f8065dd3
3 changed files with 38 additions and 24 deletions

View file

@ -2,6 +2,7 @@
import logging
import msgpack
import os
import socket
import stat
import sys
@ -26,34 +27,40 @@ def __init__(self, store, crypto, name=None):
def load(self, id):
self.id = id
archive = msgpack.unpackb(self.crypto.decrypt(self.store.get(NS_ARCHIVES, self.id)))
data, hash = self.crypto.decrypt(self.store.get(NS_ARCHIVES, self.id))
archive = msgpack.unpackb(data)
if archive['version'] != 1:
raise Exception('Archive version %r not supported' % archive['version'])
self.items = archive['items']
self.name = archive['name']
cindex = msgpack.unpackb(self.crypto.decrypt(self.store.get(NS_CINDEX, self.id)))
data, hash = self.crypto.decrypt(self.store.get(NS_CINDEX, self.id))
cindex = msgpack.unpackb(data)
assert cindex['version'] == 1
if archive['cindex'] != hash:
raise Exception('decryption failed')
self.chunks = cindex['chunks']
for i, chunk in enumerate(self.chunks):
self.chunk_idx[i] = chunk[0]
def save(self, name):
self.id = self.crypto.id_hash(name)
archive = {
'version': 1,
'name': name,
'cmdline': sys.argv,
'ts': datetime.utcnow().isoformat(),
'items': self.items,
}
data = self.crypto.encrypt_read(msgpack.packb(archive))
self.store.put(NS_ARCHIVES, self.id, data)
cindex = {
'version': 1,
'chunks': self.chunks,
}
data = self.crypto.encrypt_create(msgpack.packb(cindex))
data, cindex_hash = self.crypto.encrypt_create(msgpack.packb(cindex))
self.store.put(NS_CINDEX, self.id, data)
archive = {
'version': 1,
'name': name,
'cindex': cindex_hash,
'cmdline': sys.argv,
'hostname': socket.gethostname(),
'ts': datetime.utcnow().isoformat(),
'items': self.items,
}
data, hash = self.crypto.encrypt_read(msgpack.packb(archive))
self.store.put(NS_ARCHIVES, self.id, data)
self.store.commit()
def add_chunk(self, id, size):
@ -117,7 +124,10 @@ def extract(self, dest=None):
for chunk in item['chunks']:
id = self.chunk_idx[chunk]
try:
fd.write(self.crypto.decrypt(self.store.get(NS_CHUNKS, id)))
data, hash = self.crypto.decrypt(self.store.get(NS_CHUNKS, id))
if self.crypto.id_hash(data) != id:
raise IntegrityError('chunk id did not match')
fd.write(data)
except ValueError:
raise Exception('Invalid chunk checksum')
self.restore_stat(path, item)
@ -145,7 +155,9 @@ def verify(self):
for chunk in item['chunks']:
id = self.chunk_idx[chunk]
try:
self.crypto.decrypt(self.store.get(NS_CHUNKS, id))
data, hash = self.crypto.decrypt(self.store.get(NS_CHUNKS, id))
if self.crypto.id_hash(data) != id:
raise IntegrityError('chunk id did not match')
except IntegrityError:
logging.error('%s ... ERROR', item['path'])
break

View file

@ -42,7 +42,8 @@ def init(self, crypto):
if self.store.tid == 0:
return
for id in list(self.store.list(NS_CINDEX)):
cindex = msgpack.unpackb(crypto.decrypt(self.store.get(NS_CINDEX, id)))
data, hash = crypto.decrypt(self.store.get(NS_CINDEX, id))
cindex = msgpack.unpackb(data)
for id, size in cindex['chunks']:
try:
count, size = self.chunkmap[id]
@ -68,7 +69,7 @@ def save(self):
def add_chunk(self, id, data, crypto):
if self.seen_chunk(id):
return self.chunk_incref(id)
data = crypto.encrypt_read(data)
data, hash = crypto.encrypt_read(data)
csize = len(data)
self.store.put(NS_CHUNKS, id, data)
self.chunkmap[id] = (1, csize)

View file

@ -68,17 +68,17 @@ def id_hash(self, data):
def encrypt_read(self, data):
data = zlib.compress(data)
hash = SHA256.new(data).digest()
hash = self.id_hash(data)
counter = Counter.new(128, initial_value=bytes_to_long(hash[:16]), allow_wraparound=True)
data = AES.new(self.read_key, AES.MODE_CTR, '', counter=counter).encrypt(data)
return ''.join((self.READ, self.read_encrypted, hash, data))
return ''.join((self.READ, self.read_encrypted, hash, data)), hash
def encrypt_create(self, data):
data = zlib.compress(data)
hash = SHA256.new(data).digest()
hash = self.id_hash(data)
counter = Counter.new(128, initial_value=bytes_to_long(hash[:16]), allow_wraparound=True)
data = AES.new(self.create_key, AES.MODE_CTR, '', counter=counter).encrypt(data)
return ''.join((self.CREATE, self.create_encrypted, hash, data))
return ''.join((self.CREATE, self.create_encrypted, hash, data)), hash
def decrypt_key(self, data, rsa_key):
try:
@ -94,16 +94,17 @@ def decrypt(self, data):
hash = data[257:289]
counter = Counter.new(128, initial_value=bytes_to_long(hash[:16]), allow_wraparound=True)
data = AES.new(key, AES.MODE_CTR, counter=counter).decrypt(data[289:])
if SHA256.new(data).digest() != hash:
if self.id_hash(data) != hash:
raise IntegrityError('decryption failed')
return zlib.decompress(data)
return zlib.decompress(data), hash
elif type == self.CREATE:
key = self.decrypt_key(data[1:257], self.keychain.rsa_create)
hash = data[257:289]
counter = Counter.new(128, initial_value=bytes_to_long(hash[:16]), allow_wraparound=True)
data = AES.new(key, AES.MODE_CTR, '', counter=counter).decrypt(data[289:])
if SHA256.new(data).digest() != hash:
if self.id_hash(data) != hash:
raise IntegrityError('decryption failed')
return zlib.decompress(data)
return zlib.decompress(data), hash
else:
raise Exception('Unknown pack type %d found' % ord(type))