Beispiel #1
0
def load_crypto_meta(value):
    """
    Build the crypto_meta from the json object.

    Note that json.loads always produces unicode strings; to ensure the
    resultant crypto_meta matches the original object:
        * cast all keys to str (effectively a no-op on py3),
        * base64 decode 'key' and 'iv' values to bytes, and
        * encode remaining string values as UTF-8 on py2 (while leaving them
          as native unicode strings on py3).

    :param value: a string serialization of a crypto meta dict
    :returns: a dict containing crypto meta items
    :raises EncryptionException: if an error occurs while parsing the
                                 crypto meta
    """
    def b64_decode_meta(crypto_meta):
        return {
            str(name):
            (base64.b64decode(val)
             if name in ('iv', 'key') else b64_decode_meta(val) if isinstance(
                 val, dict) else val.encode('utf8') if six.PY2 else val)
            for name, val in crypto_meta.items()
        }

    try:
        if not isinstance(value, six.string_types):
            raise ValueError('crypto meta not a string')
        val = json.loads(urlparse.unquote_plus(value))
        if not isinstance(val, collections.Mapping):
            raise ValueError('crypto meta not a Mapping')
        return b64_decode_meta(val)
    except (KeyError, ValueError, TypeError) as err:
        msg = 'Bad crypto meta %r: %s' % (value, err)
        raise EncryptionException(msg)
Beispiel #2
0
    def decrypt_value_with_meta(self, value, key, required=False):
        """
        Base64-decode and decrypt a value if crypto meta can be extracted from
        the value itself, otherwise return the value unmodified.

        A value should either be a string that does not contain the ';'
        character or should be of the form:

            <base64-encoded ciphertext>;swift_meta=<crypto meta>

        :param value: value to decrypt
        :param key: crypto key to use
        :param required: if True then the value is required to be decrypted
                         and an EncryptionException will be raised if the
                         header cannot be decrypted due to missing crypto meta.
        :returns: decrypted value if crypto meta is found, otherwise the
                  unmodified value
        :raises EncryptionException: if an error occurs while parsing crypto
                                     meta or if the header value was required
                                     to be decrypted but crypto meta was not
                                     found.
        """
        extracted_value, crypto_meta = extract_crypto_meta(value)
        if crypto_meta:
            self.crypto.check_crypto_meta(crypto_meta)
            value = self.decrypt_value(extracted_value, key, crypto_meta)
        elif required:
            raise EncryptionException("Missing crypto meta in value %s" %
                                      value)

        return value
Beispiel #3
0
def load_crypto_meta(value):
    """
    Build the crypto_meta from the json object.

    Note that json.loads always produces unicode strings, to ensure the
    resultant crypto_meta matches the original object cast all key and value
    data to a str except the key and iv which are base64 decoded. This will
    work in py3 as well where all strings are unicode implying the cast is
    effectively a no-op.

    :param value: a string serialization of a crypto meta dict
    :returns: a dict containing crypto meta items
    :raises EncryptionException: if an error occurs while parsing the
                                 crypto meta
    """
    def b64_decode_meta(crypto_meta):
        return {
            str(name): (base64.b64decode(val) if name in ('iv', 'key')
                        else b64_decode_meta(val) if isinstance(val, dict)
                        else val.encode('utf8'))
            for name, val in crypto_meta.items()}

    try:
        if not isinstance(value, six.string_types):
            raise ValueError('crypto meta not a string')
        val = json.loads(urlparse.unquote_plus(value))
        if not isinstance(val, collections.Mapping):
            raise ValueError('crypto meta not a Mapping')
        return b64_decode_meta(val)
    except (KeyError, ValueError, TypeError) as err:
        msg = 'Bad crypto meta %r: %s' % (value, err)
        raise EncryptionException(msg)
Beispiel #4
0
    def check_crypto_meta(self, meta):
        """
        Check that crypto meta dict has valid items.

        :param meta: a dict
        :raises EncryptionException: if an error is found in the crypto meta
        """
        try:
            if meta['cipher'] != self.cipher:
                raise EncryptionException(
                    'Bad crypto meta: Cipher must be %s' % self.cipher)
            if len(meta['iv']) != self.iv_length:
                raise EncryptionException(
                    'Bad crypto meta: IV must be length %s bytes' %
                    self.iv_length)
        except KeyError as err:
            raise EncryptionException('Bad crypto meta: Missing %s' % err)