diff options
| author | drebs <drebs@leap.se> | 2014-08-04 16:42:56 -0300 | 
|---|---|---|
| committer | drebs <drebs@leap.se> | 2014-08-08 11:49:03 -0300 | 
| commit | 30aa5c040c093aa82be09e94dd403c18597320e5 (patch) | |
| tree | 1291503d4af76169800369c8545936249a4ee829 | |
| parent | aa8fcba828bc917eaf8e6b0dacb76f0de904bf59 (diff) | |
Protect sync db with a password.
| -rw-r--r-- | client/src/leap/soledad/client/__init__.py | 4 | ||||
| -rw-r--r-- | client/src/leap/soledad/client/mp_safe_db.py | 15 | ||||
| -rw-r--r-- | client/src/leap/soledad/client/sqlcipher.py | 28 | ||||
| -rw-r--r-- | scripts/db_access/client_side_db.py | 3 | 
4 files changed, 36 insertions, 14 deletions
diff --git a/client/src/leap/soledad/client/__init__.py b/client/src/leap/soledad/client/__init__.py index e66055e0..0b72be27 100644 --- a/client/src/leap/soledad/client/__init__.py +++ b/client/src/leap/soledad/client/__init__.py @@ -264,6 +264,7 @@ class Soledad(object):          uses the 'raw PRAGMA key' format to handle the key to SQLCipher.          """          key = self._secrets.get_local_storage_key() +        sync_db_key = self._secrets.get_sync_db_key()          self._db = sqlcipher_open(              self._local_db_path,              binascii.b2a_hex(key),  # sqlcipher only accepts the hex version @@ -271,7 +272,8 @@ class Soledad(object):              document_factory=SoledadDocument,              crypto=self._crypto,              raw_key=True, -            defer_encryption=self._defer_encryption) +            defer_encryption=self._defer_encryption, +            sync_db_key=binascii.b2a_hex(sync_db_key))      def close(self):          """ diff --git a/client/src/leap/soledad/client/mp_safe_db.py b/client/src/leap/soledad/client/mp_safe_db.py index a9ab5649..2c6b7e24 100644 --- a/client/src/leap/soledad/client/mp_safe_db.py +++ b/client/src/leap/soledad/client/mp_safe_db.py @@ -23,7 +23,7 @@ Multiprocessing-safe SQLite database.  from threading import Thread  from Queue import Queue -from sqlite3 import connect as sqlite3_connect +from pysqlcipher import dbapi2  # Thanks to http://code.activestate.com/recipes/526618/ @@ -49,7 +49,7 @@ class MPSafeSQLiteDB(Thread):          """          Run the multiprocessing-safe database accessor.          """ -        conn = sqlite3_connect(self._db_path) +        conn = dbapi2.connect(self._db_path)          while True:              req, arg, res = self._requests.get()              if req == self.CLOSE: @@ -99,3 +99,14 @@ class MPSafeSQLiteDB(Thread):          """          self.execute(self.CLOSE)          self.join() + +    def cursor(self): +        """ +        Return a fake cursor object. + +        Not really a cursor, but allows for calling db.cursor().execute(). + +        :return: Self. +        :rtype: MPSafeSQLiteDatabase +        """ +        return self diff --git a/client/src/leap/soledad/client/sqlcipher.py b/client/src/leap/soledad/client/sqlcipher.py index 7823e235..a7ddab24 100644 --- a/client/src/leap/soledad/client/sqlcipher.py +++ b/client/src/leap/soledad/client/sqlcipher.py @@ -91,7 +91,7 @@ SQLITE_ISOLATION_LEVEL = None  def open(path, password, create=True, document_factory=None, crypto=None,           raw_key=False, cipher='aes-256-cbc', kdf_iter=4000, -         cipher_page_size=1024, defer_encryption=False): +         cipher_page_size=1024, defer_encryption=False, sync_db_key=None):      """      Open a database at the given location. @@ -136,7 +136,8 @@ def open(path, password, create=True, document_factory=None, crypto=None,      return SQLCipherDatabase.open_database(          path, password, create=create, document_factory=document_factory,          crypto=crypto, raw_key=raw_key, cipher=cipher, kdf_iter=kdf_iter, -        cipher_page_size=cipher_page_size, defer_encryption=defer_encryption) +        cipher_page_size=cipher_page_size, defer_encryption=defer_encryption, +        sync_db_key=sync_db_key)  # @@ -199,7 +200,7 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):      def __init__(self, sqlcipher_file, password, document_factory=None,                   crypto=None, raw_key=False, cipher='aes-256-cbc', -                 kdf_iter=4000, cipher_page_size=1024): +                 kdf_iter=4000, cipher_page_size=1024, sync_db_key=None):          """          Connect to an existing SQLCipher database, creating a new sqlcipher          database file if needed. @@ -264,7 +265,7 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):          self._sync_db = None          self._sync_db_write_lock = None          self._sync_enc_pool = None -        self._init_sync_db(sqlcipher_file) +        self._init_sync_db(sqlcipher_file, sync_db_key)          if self.defer_encryption:              # initialize sync db @@ -293,7 +294,7 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):      def _open_database(cls, sqlcipher_file, password, document_factory=None,                         crypto=None, raw_key=False, cipher='aes-256-cbc',                         kdf_iter=4000, cipher_page_size=1024, -                       defer_encryption=False): +                       defer_encryption=False, sync_db_key=None):          """          Open a SQLCipher database. @@ -363,13 +364,14 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):          return SQLCipherDatabase._sqlite_registry[v](              sqlcipher_file, password, document_factory=document_factory,              crypto=crypto, raw_key=raw_key, cipher=cipher, kdf_iter=kdf_iter, -            cipher_page_size=cipher_page_size) +            cipher_page_size=cipher_page_size, sync_db_key=sync_db_key)      @classmethod      def open_database(cls, sqlcipher_file, password, create, backend_cls=None,                        document_factory=None, crypto=None, raw_key=False,                        cipher='aes-256-cbc', kdf_iter=4000, -                      cipher_page_size=1024, defer_encryption=False): +                      cipher_page_size=1024, defer_encryption=False, +                      sync_db_key=None):          """          Open a SQLCipher database. @@ -429,7 +431,7 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):                  sqlcipher_file, password, document_factory=document_factory,                  crypto=crypto, raw_key=raw_key, cipher=cipher,                  kdf_iter=kdf_iter, cipher_page_size=cipher_page_size, -                defer_encryption=defer_encryption) +                defer_encryption=defer_encryption, sync_db_key=sync_db_key)          except u1db_errors.DatabaseDoesNotExist:              if not create:                  raise @@ -440,7 +442,8 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):              return backend_cls(                  sqlcipher_file, password, document_factory=document_factory,                  crypto=crypto, raw_key=raw_key, cipher=cipher, -                kdf_iter=kdf_iter, cipher_page_size=cipher_page_size) +                kdf_iter=kdf_iter, cipher_page_size=cipher_page_size, +                sync_db_key=sync_db_key)      def sync(self, url, creds=None, autocreate=True, defer_decryption=True):          """ @@ -561,7 +564,7 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):              'ALTER TABLE document '              'ADD COLUMN syncable BOOL NOT NULL DEFAULT TRUE') -    def _init_sync_db(self, sqlcipher_file): +    def _init_sync_db(self, sqlcipher_file, sync_db_password):          """          Initialize the Symmetrically-Encrypted document to be synced database,          and the queue to communicate with subprocess workers. @@ -575,6 +578,11 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):          else:              sync_db_path = ":memory:"          self._sync_db = MPSafeSQLiteDB(sync_db_path) +        # protect the sync db with a password +        if sync_db_password is not None: +            self._set_crypto_pragmas( +                self._sync_db, sync_db_password, True, +                'aes-256-cbc', 4000, 1024)          self._sync_db_write_lock = threading.Lock()          self._create_sync_db_tables()          self.sync_queue = multiprocessing.Queue() diff --git a/scripts/db_access/client_side_db.py b/scripts/db_access/client_side_db.py index 1c4f3754..67c5dbe1 100644 --- a/scripts/db_access/client_side_db.py +++ b/scripts/db_access/client_side_db.py @@ -120,7 +120,7 @@ def get_soledad_instance(username, provider, passphrase, basedir):          server_url=server_url,          cert_file=cert_file,          auth_token=token, -        defer_encryption=True) +        defer_encryption=False)  # main program @@ -154,3 +154,4 @@ if __name__ == '__main__':      # get the soledad instance      s = get_soledad_instance(          args.username, args.provider, passphrase, basedir) +    s.sync()  | 
