Esempio n. 1
0
    def deserialize_compact(self, s, key, decode=None):
        """Exact JWS Compact Serialization, and validate with the given key.

        :param s: text of JWS Compact Serialization
        :param key: key used to verify the signature
        :param decode: a function to decode plaintext data
        :return: dict
        """
        try:
            s = to_bytes(s)
            protected_s, ek_s, iv_s, ciphertext_s, tag_s = s.rsplit(b'.')
        except ValueError:
            raise DecodeError('Not enough segments')

        protected = extract_header(protected_s, DecodeError)
        ek = extract_segment(ek_s, DecodeError, 'encryption key')
        iv = extract_segment(iv_s, DecodeError, 'initialization vector')
        ciphertext = extract_segment(ciphertext_s, DecodeError, 'ciphertext')
        tag = extract_segment(tag_s, DecodeError, 'authentication tag')

        self._pre_validate_header(protected)
        algorithm, enc_alg, key = self._prepare_alg_enc_key(protected,
                                                            key,
                                                            private=True)
        self._post_validate_header(protected, algorithm)

        cek = algorithm.unwrap(ek, protected, key)
        aad = to_bytes(protected_s, 'ascii')
        msg = enc_alg.decrypt(ciphertext, aad, iv, tag, cek)

        payload = self._zip_decompress(msg, protected)
        if decode:
            payload = decode(payload)
        return {'header': protected, 'payload': payload}
Esempio n. 2
0
def _extract_payload(payload_segment):
    return extract_segment(payload_segment, DecodeError, 'payload')
Esempio n. 3
0
def _extract_signature(signature_segment):
    return extract_segment(signature_segment, DecodeError, 'signature')
Esempio n. 4
0
    def deserialize_json(self, obj, key, decode=None, sender_key=None):
        """Extract JWE JSON Serialization.

        :param obj: JWE JSON Serialization as dict or str
        :param key: Private key used to decrypt payload
            (optionally can be a tuple of kid and essentially key)
        :param decode: Function to decode payload data
        :param sender_key: Sender's public key in case
            JWEAlgorithmWithTagAwareKeyAgreement is used
        :return: dict with `header` and `payload` keys where `header` value is
            a dict containing `protected`, `unprotected`, `recipients` and/or
            `aad` keys
        """
        obj = ensure_dict(obj, 'JWE')
        obj = deepcopy(obj)

        if 'protected' in obj:
            protected = extract_header(to_bytes(obj['protected']), DecodeError)
        else:
            protected = None

        unprotected = obj.get('unprotected')

        recipients = obj['recipients']
        for recipient in recipients:
            if 'header' not in recipient:
                recipient['header'] = {}
            recipient['encrypted_key'] = extract_segment(
                to_bytes(recipient['encrypted_key']), DecodeError, 'encrypted key')

        if 'aad' in obj:
            jwe_aad = extract_segment(to_bytes(obj['aad']), DecodeError, 'JWE AAD')
        else:
            jwe_aad = None

        iv = extract_segment(to_bytes(obj['iv']), DecodeError, 'initialization vector')

        ciphertext = extract_segment(to_bytes(obj['ciphertext']), DecodeError, 'ciphertext')

        tag = extract_segment(to_bytes(obj['tag']), DecodeError, 'authentication tag')

        shared_header = JWESharedHeader(protected, unprotected)

        alg = self.get_header_alg(shared_header)
        enc = self.get_header_enc(shared_header)
        zip_alg = self.get_header_zip(shared_header)

        self._validate_sender_key(sender_key, alg)
        self._validate_private_headers(shared_header, alg)
        for recipient in recipients:
            self._validate_private_headers(recipient['header'], alg)

        kid = None
        if isinstance(key, tuple) and len(key) == 2:
            # Extract separately provided kid and essentially key
            kid = key[0]
            key = key[1]

        key = alg.prepare_key(key)

        if kid is None:
            # If kid has not been provided separately, try to get it from key itself
            kid = key.kid

        if sender_key is not None:
            sender_key = alg.prepare_key(sender_key)

        def _unwrap_with_sender_key_and_tag(ek, header):
            return alg.unwrap(enc, ek, header, key, sender_key, tag)

        def _unwrap_with_sender_key_and_without_tag(ek, header):
            return alg.unwrap(enc, ek, header, key, sender_key)

        def _unwrap_without_sender_key_and_tag(ek, header):
            return alg.unwrap(enc, ek, header, key)

        def _unwrap_for_matching_recipient(unwrap_func):
            if kid is not None:
                for recipient in recipients:
                    if recipient['header'].get('kid') == kid:
                        header = JWEHeader(protected, unprotected, recipient['header'])
                        return unwrap_func(recipient['encrypted_key'], header)

            # Since no explicit match has been found, iterate over all the recipients
            error = None
            for recipient in recipients:
                header = JWEHeader(protected, unprotected, recipient['header'])
                try:
                    return unwrap_func(recipient['encrypted_key'], header)
                except Exception as e:
                    error = e
            else:
                if error is None:
                    raise KeyMismatchError()
                else:
                    raise error

        if isinstance(alg, JWEAlgorithmWithTagAwareKeyAgreement):
            # For a JWE algorithm with tag-aware key agreement:
            if alg.key_size is not None:
                # In case key agreement with key wrapping mode is used:
                # Provide authentication tag to .unwrap method
                cek = _unwrap_for_matching_recipient(_unwrap_with_sender_key_and_tag)
            else:
                # Otherwise, don't provide authentication tag to .unwrap method
                cek = _unwrap_for_matching_recipient(_unwrap_with_sender_key_and_without_tag)
        else:
            # For any other JWE algorithm:
            # Don't provide authentication tag to .unwrap method
            cek = _unwrap_for_matching_recipient(_unwrap_without_sender_key_and_tag)

        aad = to_bytes(obj.get('protected', ''))
        if 'aad' in obj:
           aad += b'.' + to_bytes(obj['aad'])
        aad = to_bytes(aad, 'ascii')

        msg = enc.decrypt(ciphertext, aad, iv, tag, cek)

        if zip_alg:
            payload = zip_alg.decompress(to_bytes(msg))
        else:
            payload = msg

        if decode:
            payload = decode(payload)

        for recipient in recipients:
            if not recipient['header']:
                del recipient['header']
            for member in set(recipient.keys()):
                if member != 'header':
                    del recipient[member]

        header = {}
        if protected:
            header['protected'] = protected
        if unprotected:
            header['unprotected'] = unprotected
        header['recipients'] = recipients
        if jwe_aad is not None:
            header['aad'] = jwe_aad

        return {
            'header': header,
            'payload': payload
        }
Esempio n. 5
0
    def deserialize_compact(self, s, key, decode=None, sender_key=None):
        """Extract JWE Compact Serialization.

        :param s: JWE Compact Serialization as bytes
        :param key: Private key used to decrypt payload
            (optionally can be a tuple of kid and essentially key)
        :param decode: Function to decode payload data
        :param sender_key: Sender's public key in case
            JWEAlgorithmWithTagAwareKeyAgreement is used
        :return: dict with `header` and `payload` keys where `header` value is
            a dict containing protected header fields
        """
        try:
            s = to_bytes(s)
            protected_s, ek_s, iv_s, ciphertext_s, tag_s = s.rsplit(b'.')
        except ValueError:
            raise DecodeError('Not enough segments')

        protected = extract_header(protected_s, DecodeError)
        ek = extract_segment(ek_s, DecodeError, 'encryption key')
        iv = extract_segment(iv_s, DecodeError, 'initialization vector')
        ciphertext = extract_segment(ciphertext_s, DecodeError, 'ciphertext')
        tag = extract_segment(tag_s, DecodeError, 'authentication tag')

        alg = self.get_header_alg(protected)
        enc = self.get_header_enc(protected)
        zip_alg = self.get_header_zip(protected)

        self._validate_sender_key(sender_key, alg)
        self._validate_private_headers(protected, alg)

        if isinstance(key, tuple) and len(key) == 2:
            # Ignore separately provided kid, extract essentially key only
            key = key[1]

        key = prepare_key(alg, protected, key)

        if sender_key is not None:
            sender_key = alg.prepare_key(sender_key)

        if isinstance(alg, JWEAlgorithmWithTagAwareKeyAgreement):
            # For a JWE algorithm with tag-aware key agreement:
            if alg.key_size is not None:
                # In case key agreement with key wrapping mode is used:
                # Provide authentication tag to .unwrap method
                cek = alg.unwrap(enc, ek, protected, key, sender_key, tag)
            else:
                # Otherwise, don't provide authentication tag to .unwrap method
                cek = alg.unwrap(enc, ek, protected, key, sender_key)
        else:
            # For any other JWE algorithm:
            # Don't provide authentication tag to .unwrap method
            cek = alg.unwrap(enc, ek, protected, key)

        aad = to_bytes(protected_s, 'ascii')
        msg = enc.decrypt(ciphertext, aad, iv, tag, cek)

        if zip_alg:
            payload = zip_alg.decompress(to_bytes(msg))
        else:
            payload = msg

        if decode:
            payload = decode(payload)
        return {'header': protected, 'payload': payload}