Use addresses instead of keys on the public API
authorRuben Pollan <meskio@sindominio.net>
Thu, 20 Nov 2014 16:55:09 +0000 (10:55 -0600)
committerRuben Pollan <meskio@sindominio.net>
Wed, 26 Nov 2014 05:52:02 +0000 (23:52 -0600)
changes/feature-6346_use_addresses [new file with mode: 0644]
src/leap/keymanager/__init__.py
src/leap/keymanager/tests/test_keymanager.py

diff --git a/changes/feature-6346_use_addresses b/changes/feature-6346_use_addresses
new file mode 100644 (file)
index 0000000..2f32c98
--- /dev/null
@@ -0,0 +1 @@
+- Use addresses instead of keys for encrypt, decrypt, sign & verify (closes #6346)
index e4be9c4..1704e0b 100644 (file)
@@ -43,7 +43,7 @@ except (ImportError, AssertionError):
 import logging
 import requests
 
-from leap.common.check import leap_assert, leap_assert_type
+from leap.common.check import leap_assert
 from leap.common.events import signal
 from leap.common.events import events_pb2 as proto
 from leap.common.decorators import memoized_method
@@ -56,7 +56,6 @@ from leap.keymanager.errors import (
 from leap.keymanager.validation import ValidationLevel, can_upgrade
 
 from leap.keymanager.keys import (
-    EncryptionKey,
     build_key_from_dict,
     KEYMANAGER_KEY_TAG,
     TAGS_PRIVATE_INDEX,
@@ -395,70 +394,92 @@ class KeyManager(object):
     # encrypt/decrypt and sign/verify API
     #
 
-    def encrypt(self, data, pubkey, passphrase=None, sign=None,
-                cipher_algo='AES256'):
+    def encrypt(self, data, address, ktype, passphrase=None, sign=None,
+                cipher_algo='AES256', fetch_remote=True):
         """
-        Encrypt C{data} using public @{key} and sign with C{sign} key.
+        Encrypt C{data} for C{address} and sign with C{sign} address.
 
         :param data: The data to be encrypted.
         :type data: str
-        :param pubkey: The key used to encrypt.
-        :type pubkey: EncryptionKey
+        :param address: The address to encrypt it for.
+        :type address: str
+        :param ktype: The type of the key.
+        :type ktype: subclass of EncryptionKey
         :param passphrase: The passphrase for the secret key used for the
                            signature.
         :type passphrase: str
-        :param sign: The key used for signing.
-        :type sign: EncryptionKey
+        :param sign: The address to be used for signature.
+        :type sign: str
         :param cipher_algo: The cipher algorithm to use.
         :type cipher_algo: str
+        :param fetch_remote: If key not found in local storage try to fetch
+                             from nickserver
+        :type fetch_remote: bool
 
         :return: The encrypted data.
         :rtype: str
+
+        :raise KeyNotFound: If any of the keys was not found both locally and
+                            in keyserver.
+        :raise EncryptError: Raised if failed encrypting for some reason.
         """
-        leap_assert_type(pubkey, EncryptionKey)
-        leap_assert(pubkey.__class__ in self._wrapper_map, 'Unknown key type.')
-        leap_assert(pubkey.private is False, 'Key is not public.')
-        return self._wrapper_map[pubkey.__class__].encrypt(
-            data, pubkey, passphrase, sign, cipher_algo=cipher_algo)
+        pubkey = self.get_key(address, ktype, private=False,
+                              fetch_remote=fetch_remote)
+        privkey = None
+        if sign is not None:
+            privkey = self.get_key(sign, ktype, private=True)
+        return self._wrapper_map[ktype].encrypt(
+            data, pubkey, passphrase, privkey, cipher_algo=cipher_algo)
 
-    def decrypt(self, data, privkey, passphrase=None, verify=None):
+    def decrypt(self, data, address, ktype, passphrase=None, verify=None,
+                fetch_remote=True):
         """
-        Decrypt C{data} using private @{privkey} and verify with C{verify} key.
+        Decrypt C{data} using private key from @{address} and verify with
+        C{verify} address.
 
         :param data: The data to be decrypted.
         :type data: str
-        :param privkey: The key used to decrypt.
-        :type privkey: OpenPGPKey
+        :param address: The address to who was encrypted.
+        :type address: str
+        :param ktype: The type of the key.
+        :type ktype: subclass of EncryptionKey
         :param passphrase: The passphrase for the secret key used for
                            decryption.
         :type passphrase: str
-        :param verify: The key used to verify a signature.
-        :type verify: OpenPGPKey
+        :param verify: The address to be used for signature.
+        :type verify: str
+        :param fetch_remote: If key for verify not found in local storage try
+                             to fetch from nickserver
+        :type fetch_remote: bool
 
         :return: The decrypted data.
         :rtype: str
 
+        :raise KeyNotFound: If any of the keys was not found both locally and
+                            in keyserver.
+        :raise DecryptError: Raised if failed decrypting for some reason.
         :raise InvalidSignature: Raised if unable to verify the signature with
-                                 C{verify} key.
+                                 C{verify} address.
         """
-        leap_assert_type(privkey, EncryptionKey)
-        leap_assert(
-            privkey.__class__ in self._wrapper_map,
-            'Unknown key type.')
-        leap_assert(privkey.private is True, 'Key is not private.')
-        return self._wrapper_map[privkey.__class__].decrypt(
-            data, privkey, passphrase, verify)
+        privkey = self.get_key(address, ktype, private=True)
+        pubkey = None
+        if verify is not None:
+            pubkey = self.get_key(verify, ktype, private=False,
+                                  fetch_remote=fetch_remote)
+        return self._wrapper_map[ktype].decrypt(
+            data, privkey, passphrase, pubkey)
 
-    def sign(self, data, privkey, digest_algo='SHA512', clearsign=False,
+    def sign(self, data, address, ktype, digest_algo='SHA512', clearsign=False,
              detach=True, binary=False):
         """
-        Sign C{data} with C{privkey}.
+        Sign C{data} with C{address}.
 
         :param data: The data to be signed.
         :type data: str
-
-        :param privkey: The private key to be used to sign.
-        :type privkey: EncryptionKey
+        :param address: The address to be used to sign.
+        :type address: EncryptionKey
+        :param ktype: The type of the key.
+        :type ktype: subclass of EncryptionKey
         :param digest_algo: The hash digest to use.
         :type digest_algo: str
         :param clearsign: If True, create a cleartext signature.
@@ -470,36 +491,46 @@ class KeyManager(object):
 
         :return: The signed data.
         :rtype: str
+
+        :raise KeyNotFound: If the key was not found both locally and
+                            in keyserver.
+        :raise SignFailed: If there was any error signing.
         """
-        leap_assert_type(privkey, EncryptionKey)
-        leap_assert(
-            privkey.__class__ in self._wrapper_map,
-            'Unknown key type.')
-        leap_assert(privkey.private is True, 'Key is not private.')
-        return self._wrapper_map[privkey.__class__].sign(
+        privkey = self.get_key(address, ktype, private=True)
+        return self._wrapper_map[ktype].sign(
             data, privkey, digest_algo=digest_algo, clearsign=clearsign,
             detach=detach, binary=binary)
 
-    def verify(self, data, pubkey, detached_sig=None):
+    def verify(self, data, address, ktype, detached_sig=None,
+               fetch_remote=True):
         """
-        Verify signed C{data} with C{pubkey}, eventually using
+        Verify signed C{data} with C{address}, eventually using
         C{detached_sig}.
 
         :param data: The data to be verified.
         :type data: str
-        :param pubkey: The public key to be used on verification.
-        :type pubkey: EncryptionKey
+        :param address: The address to be used to verify.
+        :type address: EncryptionKey
+        :param ktype: The type of the key.
+        :type ktype: subclass of EncryptionKey
         :param detached_sig: A detached signature. If given, C{data} is
                              verified using this detached signature.
         :type detached_sig: str
+        :param fetch_remote: If key for verify not found in local storage try
+                             to fetch from nickserver
+        :type fetch_remote: bool
 
         :return: signature matches
         :rtype: bool
+
+        :raise KeyNotFound: If the key was not found both locally and
+                            in keyserver.
+        :raise InvalidSignature: Raised if unable to verify the signature with
+                                 C{verify} address.
         """
-        leap_assert_type(pubkey, EncryptionKey)
-        leap_assert(pubkey.__class__ in self._wrapper_map, 'Unknown key type.')
-        leap_assert(pubkey.private is False, 'Key is not public.')
-        return self._wrapper_map[pubkey.__class__].verify(
+        pubkey = self.get_key(address, ktype, private=False,
+                              fetch_remote=fetch_remote)
+        return self._wrapper_map[ktype].verify(
             data, pubkey, detached_sig=detached_sig)
 
     def delete_key(self, key):
index 319d2e1..8ae12bf 100644 (file)
@@ -218,10 +218,9 @@ class OpenPGPCryptoTestCase(KeyManagerWithSoledadTestCase):
             self._soledad, gpgbinary=GPG_BINARY_PATH)
         pgp.put_ascii_key(PUBLIC_KEY, ADDRESS)
         data = 'data'
-        pubkey = pgp.get_key(ADDRESS, private=False)
         self.assertRaises(
             AssertionError,
-            pgp.sign, data, pubkey)
+            pgp.sign, data, ADDRESS, OpenPGPKey)
 
     def test_verify_with_wrong_key_raises(self):
         pgp = openpgp.OpenPGPScheme(
@@ -510,34 +509,24 @@ class KeyManagerCryptoTestCase(KeyManagerWithSoledadTestCase):
         km = self._key_manager()
         # put raw private key
         km._wrapper_map[OpenPGPKey].put_ascii_key(PRIVATE_KEY, ADDRESS)
-        # get public key
-        pubkey = km.get_key(
-            ADDRESS, OpenPGPKey, private=False, fetch_remote=False)
         # encrypt
-        encdata = km.encrypt(self.RAW_DATA, pubkey)
+        encdata = km.encrypt(self.RAW_DATA, ADDRESS, OpenPGPKey,
+                             fetch_remote=False)
         self.assertNotEqual(self.RAW_DATA, encdata)
-        # get private key
-        privkey = km.get_key(
-            ADDRESS, OpenPGPKey, private=True, fetch_remote=False)
         # decrypt
-        rawdata = km.decrypt(encdata, privkey)
+        rawdata = km.decrypt(encdata, ADDRESS, OpenPGPKey)
         self.assertEqual(self.RAW_DATA, rawdata)
 
     def test_keymanager_openpgp_sign_verify(self):
         km = self._key_manager()
         # put raw private keys
         km._wrapper_map[OpenPGPKey].put_ascii_key(PRIVATE_KEY, ADDRESS)
-        # get private key for signing
-        privkey = km.get_key(
-            ADDRESS, OpenPGPKey, private=True, fetch_remote=False)
         # encrypt
-        signdata = km.sign(self.RAW_DATA, privkey, detach=False)
+        signdata = km.sign(self.RAW_DATA, ADDRESS, OpenPGPKey, detach=False)
         self.assertNotEqual(self.RAW_DATA, signdata)
-        # get public key for verifying
-        pubkey = km.get_key(
-            ADDRESS, OpenPGPKey, private=False, fetch_remote=False)
         # decrypt
-        self.assertTrue(km.verify(signdata, pubkey))
+        self.assertTrue(km.verify(signdata, ADDRESS, OpenPGPKey,
+                                  fetch_remote=False))
 
 
 # Key material for testing