summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMicah Anderson <micah@riseup.net>2013-07-15 11:33:25 +0100
committerMicah Anderson <micah@riseup.net>2013-07-18 11:33:51 -0400
commit4e9f0ec03e730a2a9cf7a3b6d01e2b5bdfa88b65 (patch)
treeea22c0cf2dc9837b47bb2f8dbdd5eaefe492191e
parent4ee69b253ad378b18d168c3082025be0c9e1a1a0 (diff)
update to 0.2.2 released version
-rw-r--r--CHANGELOG6
-rw-r--r--debian/changelog2
-rw-r--r--debian/pydist-overrides2
-rw-r--r--soledad/setup.py2
-rw-r--r--soledad/src/leap/soledad/__init__.py65
-rw-r--r--soledad/src/leap/soledad/tests/test_soledad.py34
-rw-r--r--soledad_server/pkg/soledad2
-rw-r--r--soledad_server/setup.py3
8 files changed, 110 insertions, 6 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 72229567..93ce5071 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,9 @@
+0.2.2 Jul 12:
+Client:
+ o Add method for password change.
+Server:
+ o Use the right name as the WSGI server
+
0.2.1 Jun 28:
Client:
o Do not list the backends in the __init__'s __all__ to allow not
diff --git a/debian/changelog b/debian/changelog
index 92e47ba1..f18b54ea 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-soledad (0.2.1) unstable; urgency=low
+soledad (0.2.2) unstable; urgency=low
* Initial debian package
diff --git a/debian/pydist-overrides b/debian/pydist-overrides
new file mode 100644
index 00000000..59e30938
--- /dev/null
+++ b/debian/pydist-overrides
@@ -0,0 +1,2 @@
+pysqlcipher python-sqlcipher
+leap.soledad soledad-common \ No newline at end of file
diff --git a/soledad/setup.py b/soledad/setup.py
index cda7f9f7..747b02bd 100644
--- a/soledad/setup.py
+++ b/soledad/setup.py
@@ -62,7 +62,7 @@ trove_classifiers = (
setup(
name='leap.soledad',
- version='0.2.1',
+ version='0.2.2',
url='https://leap.se/',
license='GPLv3+',
description='Synchronization of locally encrypted data among devices.',
diff --git a/soledad/src/leap/soledad/__init__.py b/soledad/src/leap/soledad/__init__.py
index 2e1155f9..956f47a7 100644
--- a/soledad/src/leap/soledad/__init__.py
+++ b/soledad/src/leap/soledad/__init__.py
@@ -164,6 +164,20 @@ SECRETS_DOC_ID_HASH_PREFIX = 'uuid-'
# Soledad: local encrypted storage and remote encrypted sync.
#
+class NoStorageSecret(Exception):
+ """
+ Raised when trying to use a storage secret but none is available.
+ """
+ pass
+
+
+class PassphraseTooShort(Exception):
+ """
+ Raised when trying to change the passphrase but the provided passphrase is
+ too short.
+ """
+
+
class Soledad(object):
"""
Soledad provides encrypted data storage and sync.
@@ -232,6 +246,12 @@ class Soledad(object):
encryption.
"""
+ MINIMUM_PASSPHRASE_LENGTH = 6
+ """
+ The minimum length for a passphrase. The passphrase length is only checked
+ when the user changes her passphras, not when she instantiates Soledad.
+ """
+
IV_SEPARATOR = ":"
"""
A separator used for storing the encryption initial value prepended to the
@@ -246,6 +266,8 @@ class Soledad(object):
KDF_KEY = 'kdf'
KDF_SALT_KEY = 'kdf_salt'
KDF_LENGTH_KEY = 'kdf_length'
+ KDF_SCRYPT = 'scrypt'
+ CIPHER_AES256 = 'aes256'
"""
Keys used to access storage secrets in recovery documents.
"""
@@ -563,10 +585,10 @@ class Soledad(object):
self._secrets[secret_id] = {
# leap.soledad.crypto submodule uses AES256 for symmetric
# encryption.
- self.KDF_KEY: 'scrypt', # TODO: remove hard coded kdf
+ self.KDF_KEY: self.KDF_SCRYPT,
self.KDF_SALT_KEY: binascii.b2a_base64(salt),
self.KDF_LENGTH_KEY: len(key),
- self.CIPHER_KEY: 'aes256', # TODO: remove hard coded cipher
+ self.CIPHER_KEY: self.CIPHER_AES256,
self.LENGTH_KEY: len(secret),
self.SECRET_KEY: '%s%s%s' % (
str(iv), self.IV_SEPARATOR, binascii.b2a_base64(ciphertext)),
@@ -600,6 +622,45 @@ class Soledad(object):
with open(self._secrets_path, 'w') as f:
f.write(json.dumps(data))
+ def change_passphrase(self, new_passphrase):
+ """
+ Change the passphrase that encrypts the storage secret.
+
+ @param new_passphrase: The new passphrase.
+ @type new_passphrase: str
+
+ @raise NoStorageSecret: Raised if there's no storage secret available.
+ """
+ # maybe we want to add more checks to guarantee passphrase is
+ # reasonable?
+ soledad_assert_type(new_passphrase, str)
+ if len(new_passphrase) < self.MINIMUM_PASSPHRASE_LENGTH:
+ raise PassphraseTooShort(
+ 'Passphrase must be at least %d characters long!' %
+ self.MINIMUM_PASSPHRASE_LENGTH)
+ # ensure there's a secret for which the passphrase will be changed.
+ if not self._has_secret():
+ raise NoStorageSecret()
+ secret = self._get_storage_secret()
+ # generate random salt
+ new_salt = os.urandom(self.SALT_LENGTH)
+ # get a 256-bit key
+ key = scrypt.hash(new_passphrase, new_salt, buflen=32)
+ iv, ciphertext = self._crypto.encrypt_sym(secret, key)
+ self._secrets[self._secret_id] = {
+ # leap.soledad.crypto submodule uses AES256 for symmetric
+ # encryption.
+ self.KDF_KEY: self.KDF_SCRYPT, # TODO: remove hard coded kdf
+ self.KDF_SALT_KEY: binascii.b2a_base64(new_salt),
+ self.KDF_LENGTH_KEY: len(key),
+ self.CIPHER_KEY: self.CIPHER_AES256,
+ self.LENGTH_KEY: len(secret),
+ self.SECRET_KEY: '%s%s%s' % (
+ str(iv), self.IV_SEPARATOR, binascii.b2a_base64(ciphertext)),
+ }
+ self._store_secrets()
+ self._passphrase = new_passphrase
+
#
# General crypto utility methods.
#
diff --git a/soledad/src/leap/soledad/tests/test_soledad.py b/soledad/src/leap/soledad/tests/test_soledad.py
index 281b7a0f..875ecc56 100644
--- a/soledad/src/leap/soledad/tests/test_soledad.py
+++ b/soledad/src/leap/soledad/tests/test_soledad.py
@@ -28,6 +28,7 @@ import simplejson as json
from mock import Mock
+from pysqlcipher.dbapi2 import DatabaseError
from leap.common.testing.basetest import BaseLeapTest
from leap.common.events import events_pb2 as proto
from leap.soledad.tests import (
@@ -106,6 +107,39 @@ class AuxMethodsTestCase(BaseSoledadTest):
sol.local_db_path)
self.assertEqual('value_1', sol.server_url)
+ def test_change_passphrase(self):
+ """
+ Test if passphrase can be changed.
+ """
+ sol = self._soledad_instance(
+ 'leap@leap.se',
+ passphrase='123')
+ doc = sol.create_doc({'simple': 'doc'})
+ doc_id = doc.doc_id
+ # change the passphrase
+ sol.change_passphrase('654321')
+ # assert we can not use the old passphrase anymore
+ self.assertRaises(
+ DatabaseError,
+ self._soledad_instance, 'leap@leap.se', '123')
+ # use new passphrase and retrieve doc
+ sol2 = self._soledad_instance('leap@leap.se', '654321')
+ doc2 = sol2.get_doc(doc_id)
+ self.assertEqual(doc, doc2)
+
+ def test_change_passphrase_with_short_passphrase_raises(self):
+ """
+ Test if attempt to change passphrase passing a short passphrase
+ raises.
+ """
+ sol = self._soledad_instance(
+ 'leap@leap.se',
+ passphrase='123')
+ # check that soledad complains about new passphrase length
+ self.assertRaises(
+ soledad.PassphraseTooShort,
+ sol.change_passphrase, '54321')
+
class SoledadSharedDBTestCase(BaseSoledadTest):
"""
diff --git a/soledad_server/pkg/soledad b/soledad_server/pkg/soledad
index c640a94d..b1d898cc 100644
--- a/soledad_server/pkg/soledad
+++ b/soledad_server/pkg/soledad
@@ -12,7 +12,7 @@
PATH=/sbin:/bin:/usr/sbin:/usr/bin
PIDFILE=/var/run/soledad.pid
RUNDIR=/var/lib/soledad/
-OBJ=leap.soledad.server.application
+OBJ=leap.soledad_server.application
LOGFILE=/var/log/soledad.log
HTTPS_PORT=2424
PLAIN_PORT=65534
diff --git a/soledad_server/setup.py b/soledad_server/setup.py
index 5e5fa058..f9cdd07f 100644
--- a/soledad_server/setup.py
+++ b/soledad_server/setup.py
@@ -34,6 +34,7 @@ install_requirements = [
'six==1.1.0',
'routes',
'PyOpenSSL',
+ 'leap.soledad>=0.2.1',
]
@@ -59,7 +60,7 @@ trove_classifiers = (
setup(
name='leap.soledad_server',
- version='0.2.1',
+ version='0.2.2',
url='https://leap.se/',
license='GPLv3+',
description='Synchronization of locally encrypted data among devices.',