예제 #1
0
    def encrypt(self, target_alg: '_EncAlg') -> bytes:
        alg = self.get_attr(headers.Algorithm)

        if len(self.phdr):
            raise CoseException(
                f"Protected header must be empty when using an AE algorithm: {alg}"
            )

        if alg is None:
            raise CoseException(
                "The algorithm parameter should at least be included in the unprotected header"
            )

        elif alg in {A128KW, A192KW, A256KW}:
            key_ops = [WrapOp, EncryptOp]
            kek = SymmetricKey(k=self._compute_kek(target_alg, ops='encrypt'),
                               optional_params={
                                   KpAlg: alg,
                                   KpKeyOps: key_ops
                               })
            kek.verify(SymmetricKey, alg, [WrapOp, EncryptOp])
        elif alg in {RsaesOaepSha512, RsaesOaepSha256, RsaesOaepSha1}:
            kek = self.key
            kek.verify(RSAKey, alg, [WrapOp, EncryptOp])
        else:
            raise CoseIllegalAlgorithm(f"Algorithm {alg} for {self.__name__}")

        return alg.key_wrap(kek, self.payload)
예제 #2
0
    def decrypt(self, target_alg: '_EncAlg') -> bytes:
        alg = self.get_attr(headers.Algorithm)

        kek = SymmetricKey(k=self._compute_kek(target_alg, 'decrypt'),
                           optional_params={
                               KpAlg: alg,
                               KpKeyOps: [DecryptOp, UnwrapOp]
                           })
        kek.verify(SymmetricKey, alg, [UnwrapOp, DecryptOp])

        return alg.key_unwrap(kek, self.payload)
예제 #3
0
    def decrypt(self, target_alg: '_EncAlg') -> bytes:
        alg = self.get_attr(headers.Algorithm)

        key_ops = [DecryptOp, UnwrapOp]

        if alg in {A128KW, A192KW, A256KW}:
            kek = SymmetricKey(k=self._compute_kek(target_alg, 'decrypt'),
                               optional_params={
                                   KpAlg: alg,
                                   KpKeyOps: key_ops
                               })
            kek.verify(SymmetricKey, alg, [UnwrapOp, DecryptOp])
        elif alg in {RsaesOaepSha512, RsaesOaepSha256, RsaesOaepSha1}:
            kek = self.key
            kek.verify(RSAKey, alg, [UnwrapOp, DecryptOp])
        else:
            raise CoseException(
                f"Unsupported algorithm for key unwrapping: {alg}")

        return alg.key_unwrap(kek, self.payload)
예제 #4
0
    def decrypt(self, target_alg: '_EncAlg') -> bytes:
        alg = self.get_attr(headers.Algorithm)
        _ = target_alg

        if alg in {EcdhEsA256KW, EcdhEsA192KW, EcdhEsA128KW}:
            peer_key = self.get_attr(headers.EphemeralKey)
        elif alg in {EcdhSsA256KW, EcdhSsA192KW, EcdhSsA128KW}:
            peer_key = self.get_attr(headers.StaticKey)
        else:
            raise CoseIllegalAlgorithm(
                f"Algorithm {alg} unsupported for {self.__name__}")

        kek = SymmetricKey(k=self._compute_kek(alg.get_key_wrap_func(),
                                               peer_key, self.key, alg),
                           optional_params={
                               KpAlg: alg,
                               KpKeyOps: [UnwrapOp, DecryptOp]
                           })

        kek.verify(SymmetricKey, alg, [UnwrapOp, DecryptOp])

        return alg.get_key_wrap_func().key_unwrap(kek, self.payload)
예제 #5
0
class KeyWrap(CoseRecipient):
    @classmethod
    def from_cose_obj(cls, cose_obj: list, *args, **kwargs) -> 'KeyWrap':
        msg = super().from_cose_obj(cose_obj)
        msg.context = kwargs.get('context')

        # only AE algorithms supported thus the protected header must be empty
        alg = msg.get_attr(headers.Algorithm)
        if alg in {A128KW, A192KW, A256KW} and len(msg.phdr):
            raise CoseMalformedMessage(
                f"Recipient class KEY_WRAP with alg {alg} must have a zero-length protected header"
            )

        if msg.payload == b'':
            raise CoseMalformedMessage(
                f'Recipient class KEY_WRAP must carry the encrypted CEK in its payload'
            )

        msg.recipients = [
            CoseRecipient.create_recipient(r, context='Rec_Recipient')
            for r in msg.recipients
        ]

        return msg

    @property
    def context(self):
        return self._context

    @context.setter
    def context(self, context: str):
        self._context = context

    def encode(self, *args, **kwargs) -> list:

        recipient = [
            self.phdr_encoded, self.uhdr_encoded,
            self.encrypt(kwargs.get('target_alg'))
        ]

        if len(self.recipients):
            recipient.append(
                [r.encode(*args, **kwargs) for r in self.recipients])

        return recipient

    def _compute_kek(self, target_alg: '_EncAlg', ops: 'str') -> bytes:

        if self.key is None:
            #  try to derive from this recipients' recipient list
            if not len(self.recipients):
                raise CoseException(f"No key found to {ops} the CEK")
            else:
                r_types = CoseRecipient.verify_recipients(self.recipients)

                if ops == 'encrypt':

                    if DirectKeyAgreement in r_types:
                        self.key = self.recipients[0].compute_cek(target_alg)

                    elif KeyWrap in r_types or KeyAgreementWithKeyWrap in r_types:
                        key_bytes = os.urandom(self.get_attr(
                            headers.Algorithm))
                        for r in self.recipients:
                            r.payload = key_bytes
                        self.key = SymmetricKey(k=key_bytes)
                    else:
                        raise CoseException('Unsupported COSE recipient class')
                else:
                    if DirectKeyAgreement in r_types or KeyWrap in r_types or KeyAgreementWithKeyWrap in r_types:
                        self.key = self.recipients[0].decrypt(
                            self.get_attr(headers.Algorithm))
                    else:
                        raise CoseException('Unsupported COSE recipient class')

        if self.key is None:
            raise CoseException("No key found to decrypt the CEK")

        return self.key.k

    def compute_cek(self, target_alg: '_EncAlg', ops: str) -> Optional['SK']:
        if ops == "encrypt":
            if self.payload == b'':
                return None
            else:
                return SymmetricKey(k=self.payload,
                                    optional_params={
                                        KpAlg: target_alg,
                                        KpKeyOps: [EncryptOp]
                                    })
        else:
            return SymmetricKey(k=self.decrypt(target_alg),
                                optional_params={
                                    KpAlg: target_alg,
                                    KpKeyOps: [DecryptOp]
                                })

    def encrypt(self, target_alg: '_EncAlg') -> bytes:
        alg = self.get_attr(headers.Algorithm)

        if A128KW.identifier >= alg.identifier >= A256KW.identifier:
            if len(self.phdr):
                raise CoseException(
                    f"Protected header must be empty when using an AE algorithm: {alg}"
                )

            if alg is None:
                raise CoseException(
                    "The algorithm parameter should at least be included in the unprotected header"
                )

            self.key = SymmetricKey(k=self._compute_kek(target_alg,
                                                        ops='encrypt'),
                                    optional_params={
                                        KpAlg: alg,
                                        KpKeyOps: [WrapOp, EncryptOp]
                                    })
            self.key.verify(SymmetricKey, alg, [WrapOp, EncryptOp])

            return alg.key_wrap(self.key, self.payload)
        else:
            raise CoseIllegalAlgorithm(f"Algorithm {alg} for {self.__name__}")

    def decrypt(self, target_alg: '_EncAlg') -> bytes:
        alg = self.get_attr(headers.Algorithm)

        kek = SymmetricKey(k=self._compute_kek(target_alg, 'decrypt'),
                           optional_params={
                               KpAlg: alg,
                               KpKeyOps: [DecryptOp, UnwrapOp]
                           })
        kek.verify(SymmetricKey, alg, [UnwrapOp, DecryptOp])

        return alg.key_unwrap(kek, self.payload)

    def __repr__(self) -> str:
        phdr, uhdr = self._hdr_repr()

        return f'<COSE_Recipient: [{phdr}, {uhdr}, {utils.truncate(self._payload)}, {str(self.recipients)}]>'