diff options
-rw-r--r-- | changes/feature_use-raw-sqlcipher-key-with-scrypt-as-kdf | 1 | ||||
-rw-r--r-- | src/leap/soledad/__init__.py | 33 | ||||
-rw-r--r-- | src/leap/soledad/backends/sqlcipher.py | 2 |
3 files changed, 28 insertions, 8 deletions
diff --git a/changes/feature_use-raw-sqlcipher-key-with-scrypt-as-kdf b/changes/feature_use-raw-sqlcipher-key-with-scrypt-as-kdf new file mode 100644 index 00000000..385c1c84 --- /dev/null +++ b/changes/feature_use-raw-sqlcipher-key-with-scrypt-as-kdf @@ -0,0 +1 @@ + o Use scrypt to derive the key for local encryption. diff --git a/src/leap/soledad/__init__.py b/src/leap/soledad/__init__.py index c7f8cff3..fba275e3 100644 --- a/src/leap/soledad/__init__.py +++ b/src/leap/soledad/__init__.py @@ -301,17 +301,36 @@ class Soledad(object): """ Initialize the U1DB SQLCipher database for local storage. - The local storage passphrase is hexlified version of the last - C{LOCAL_STORAGE_SECRET_LENGTH} bytes of the storage secret. - """ + Currently, Soledad uses the default SQLCipher cipher, i.e. + 'aes-256-cbc'. We use scrypt to derive a 256-bit encryption key and + uses the 'raw PRAGMA key' format to handle the key to SQLCipher. + + The first C{self.REMOTE_STORAGE_SECRET_LENGTH} bytes of the storage + secret are used for remote storage encryption. We use the next + C{self.LOCAL_STORAGE_SECRET} bytes to derive a key for local storage. + From these bytes, the first C{self.SALT_LENGTH} are used as the salt + and the rest as the password for the scrypt hashing. + """ + # salt indexes + salt_start = self.REMOTE_STORAGE_SECRET_LENGTH + salt_end = salt_start + self.SALT_LENGTH + # password indexes + pwd_start = salt_end + pwd_end = salt_start + self.LOCAL_STORAGE_SECRET_LENGTH + # calculate the key for local encryption + secret = self._get_storage_secret() + key = scrypt.hash( + secret[pwd_start:pwd_end], # the password + secret[salt_start:salt_end], # the salt + buflen=32, # we need a key with 256 bits (32 bytes) + ) self._db = sqlcipher.open( self._local_db_path, - # storage secret is binary but sqlcipher passphrase must be string - binascii.b2a_hex( - self._get_storage_secret()[self.LOCAL_STORAGE_SECRET_LENGTH:]), + binascii.b2a_hex(key), # sqlcipher only accepts the hex version create=True, document_factory=LeapDocument, - crypto=self._crypto) + crypto=self._crypto, + raw_key=True) def close(self): """ diff --git a/src/leap/soledad/backends/sqlcipher.py b/src/leap/soledad/backends/sqlcipher.py index 5825b844..d6d62f21 100644 --- a/src/leap/soledad/backends/sqlcipher.py +++ b/src/leap/soledad/backends/sqlcipher.py @@ -483,7 +483,7 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase): """ if not all(c in string.hexdigits for c in key): raise NotAnHexString(key) - db_handle.cursor().execute('PRAGMA key = "x\'%s"' % passphrase) + db_handle.cursor().execute('PRAGMA key = "x\'%s"' % key) @classmethod def _pragma_cipher(cls, db_handle, cipher='aes-256-cbc'): |