diff options
| author | Victor Shyba <victor1984@riseup.net> | 2016-11-24 21:09:33 -0300 | 
|---|---|---|
| committer | drebs <drebs@leap.se> | 2016-12-12 09:17:51 -0200 | 
| commit | 8b091951e8adebadc4be4dc5b2fb4f8b63c6900e (patch) | |
| tree | 9cfe8d0a946ed123e04830b27dc37d40ffec0015 | |
| parent | 89d5c898527c32baec8454d6e3c749935d00a313 (diff) | |
[docs] add docstrings for _crypto
Also explaining how we are using Twisted's consumer interfaces.
| -rw-r--r-- | client/src/leap/soledad/client/_crypto.py | 109 | 
1 files changed, 101 insertions, 8 deletions
| diff --git a/client/src/leap/soledad/client/_crypto.py b/client/src/leap/soledad/client/_crypto.py index d8d37f55..4a59159c 100644 --- a/client/src/leap/soledad/client/_crypto.py +++ b/client/src/leap/soledad/client/_crypto.py @@ -75,11 +75,30 @@ docinfo = namedtuple('docinfo', 'doc_id rev')  class SoledadCrypto(object): - +    """ +    This class provides convenient methods for document encryption and +    decryption using BlobEncryptor and BlobDecryptor classes. +    """      def __init__(self, secret): +        """ +        Initialize the crypto object. + +        :param secret: The Soledad remote storage secret. +        :type secret: str +        """          self.secret = secret      def encrypt_doc(self, doc): +        """ +        Creates and configures a BlobEncryptor, asking it to start encryption +        and wrapping the result as a simple JSON string with a "raw" key. + +        :param doc: the document to be encrypted. +        :type doc: SoledadDocument +        :return: A deferred whose callback will be invoked with a JSON string +            containing the ciphertext as the value of "raw" key. +        :rtype: twisted.internet.defer.Deferred +        """          def put_raw(blob):              raw = blob.getvalue() @@ -95,6 +114,15 @@ class SoledadCrypto(object):          return d      def decrypt_doc(self, doc): +        """ +        Creates and configures a BlobDecryptor, asking it decrypt and returning +        the decrypted cleartext content from the encrypted document. + +        :param doc: the document to be decrypted. +        :type doc: SoledadDocument +        :return: The decrypted cleartext content of the document. +        :rtype: str +        """          info = docinfo(doc.doc_id, doc.rev)          ciphertext = BytesIO()          payload = doc.content['raw'] @@ -106,6 +134,18 @@ class SoledadCrypto(object):  def encrypt_sym(data, key): +    """ +    Encrypt data using AES-256 cipher in CTR mode. + +    :param data: The data to be encrypted. +    :type data: str +    :param key: The key used to encrypt data (must be 256 bits long). +    :type key: str + +    :return: A tuple with the initialization vector and the ciphertext, both +        encoded as base64. +    :rtype: (str, str) +    """      iv = os.urandom(16)      encryptor = AESEncryptor(key, iv)      encryptor.write(data) @@ -115,6 +155,20 @@ def encrypt_sym(data, key):  def decrypt_sym(data, key, iv): +    """ +    Decrypt data using AES-256 cipher in CTR mode. + +    :param data: The data to be decrypted. +    :type data: str +    :param key: The symmetric key used to decrypt data (must be 256 bits +                long). +    :type key: str +    :param iv: The base64 encoded initialization vector. +    :type iv: str + +    :return: The decrypted data. +    :rtype: str +    """      _iv = base64.b64decode(str(iv))      decryptor = AESDecryptor(key, _iv)      decryptor.write(data) @@ -124,11 +178,16 @@ def decrypt_sym(data, key, iv):  class BlobEncryptor(object): -      """ -    Encrypts a payload associated with a given Document. +    Produces encrypted data from the cleartext data associated with a given +    SoledadDocument using AES-256 cipher in CTR mode, together with a +    HMAC-SHA512 Message Authentication Code. +    The production happens using a Twisted's FileBodyProducer, which uses a +    Cooperator to schedule calls and can be paused/resumed. Each call takes at +    most 65536 bytes from the input. +    Both the production input and output are file descriptors, so they can be +    applied to a stream of data.      """ -      def __init__(self, doc_info, content_fd, result=None, secret=None,                   iv=None):          if iv is None: @@ -162,11 +221,25 @@ class BlobEncryptor(object):          self._crypter = VerifiedEncrypter(self._aes, self._hmac)      def encrypt(self): +        """ +        Starts producing encrypted data from the cleartext data. + +        :return: A deferred which will be fired when encryption ends and whose +            callback will be invoked with the resulting ciphertext. +        :rtype: twisted.internet.defer.Deferred +        """          d = self._producer.startProducing(self._crypter)          d.addCallback(self._end_crypto_stream)          return d      def encrypt_whole(self): +        """ +        Encrypts the input data at once and returns the resulting ciphertext +        wrapped into a JSON string under the "raw" key. + +        :return: The resulting ciphertext JSON string. +        :rtype: str +        """          self._crypter.write(self._content_fd.getvalue())          self._end_crypto_stream(None)          return '{"raw":"' + self.result.getvalue() + '"}' @@ -281,7 +354,10 @@ class BlobDecryptor(object):  class AESEncryptor(object): - +    """ +    A Twisted's Consumer implementation that takes an input file descriptor and +    applies AES-256 cipher in CTR mode. +    """      implements(interfaces.IConsumer)      def __init__(self, key, iv, fd=None): @@ -311,7 +387,10 @@ class AESEncryptor(object):  class HMACWriter(object): - +    """ +    A Twisted's Consumer implementation that takes an input file descriptor and +    produces a HMAC-SHA512 Message Authentication Code. +    """      implements(interfaces.IConsumer)      hashtype = 'sha512' @@ -327,7 +406,10 @@ class HMACWriter(object):  class VerifiedEncrypter(object): - +    """ +    A Twisted's Consumer implementation combining AESEncryptor and HMACWriter. +    It directs the resulting ciphertext into HMAC-SHA512 processing. +    """      implements(interfaces.IConsumer)      def __init__(self, crypter, hmac): @@ -340,7 +422,10 @@ class VerifiedEncrypter(object):  class AESDecryptor(object): - +    """ +    A Twisted's Consumer implementation that consumes data encrypted with +    AES-256 in CTR mode from a file descriptor and generates decrypted data. +    """      implements(interfaces.IConsumer)      def __init__(self, key, iv, fd=None): @@ -373,6 +458,14 @@ class AESDecryptor(object):  def is_symmetrically_encrypted(doc): +    """ +    Return True if the document was symmetrically encrypted. + +    :param doc: The document to check. +    :type doc: SoledadDocument + +    :rtype: bool +    """      payload = doc.content      if not payload or 'raw' not in payload:          return False | 
