From f5f8065dd3548ebcff176bda1feace773b263884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Borgstr=C3=B6m?= Date: Sun, 24 Oct 2010 20:18:18 +0200 Subject: [PATCH] Verify cindex integrity on archive open --- dedupestore/archive.py | 40 ++++++++++++++++++++++++++-------------- dedupestore/cache.py | 5 +++-- dedupestore/crypto.py | 17 +++++++++-------- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/dedupestore/archive.py b/dedupestore/archive.py index cbab48c47..b6deb2a40 100644 --- a/dedupestore/archive.py +++ b/dedupestore/archive.py @@ -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 diff --git a/dedupestore/cache.py b/dedupestore/cache.py index f520d1edd..918ae86fe 100644 --- a/dedupestore/cache.py +++ b/dedupestore/cache.py @@ -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) diff --git a/dedupestore/crypto.py b/dedupestore/crypto.py index 2be0efb8a..69ea64022 100644 --- a/dedupestore/crypto.py +++ b/dedupestore/crypto.py @@ -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)) +