Ejemplo n.º 1
0
    def decrypt(self, key: SymmetricKey, alg: Optional['CoseAlgorithms'] = None) -> bytes:
        """ Key unwrapping. """

        if key is None:
            raise CoseIllegalKeyType("COSE Key cannot be None")

        return key.key_unwrap(self.payload, alg=alg)
Ejemplo n.º 2
0
    def encrypt(self,
                nonce: bytes,
                key: SymmetricKey,
                alg: Optional[CoseAlgorithms] = None) -> bytes:
        """
        Encrypts the payload.

        :param nonce: Nonce for decryption. Length tof the nonce depends on the AEAD. Nonce cannot be empty or None.
        :param key: A Symmetric COSE key object containing the symmetric key bytes and a optionally an AEAD algorithm.
        :param alg: If the 'alg' parameter is unset in the COSE key object, this parameter cannot be None.

        :raises ValueError: When the nonce is empty or None
        :raises CoseIllegalKeyType: When the key is not of type 'SymmetricKey'.

        :returns: ciphertext as bytes
        """

        if nonce == b"" or nonce is None:
            raise ValueError(f"{nonce} is not a valid nonce value")

        if not isinstance(key, SymmetricKey):
            raise CoseIllegalKeyType(
                "COSE key should be of type 'SymmetricKey', got {}".format(
                    type(key)))

        return key.encrypt(plaintext=self.payload,
                           aad=self._enc_structure,
                           nonce=nonce,
                           alg=alg)
Ejemplo n.º 3
0
    def __init__(self,
                 crv: Union[Type['CoseCurve'], str, int],
                 x: bytes = b'',
                 d: bytes = b'',
                 optional_params: Optional[dict] = None,
                 allow_unknown_key_attrs: bool = True):
        """
        Create an COSE OKP key.

        :param crv: An OKP elliptic curve.
        :param x: Public value of the OKP key.
        :param d: Private value of the OKP key.
        :param optional_params: A dictionary with optional key parameters.
        :param allow_unknown_key_attrs: Allow unknown key attributes (not registered at the IANA registry)
        """

        transformed_dict = {KpKty: KtyOKP}

        if optional_params is None:
            optional_params = {}

        for _key_attribute, _value in optional_params.items():
            try:
                # translate the key_attribute
                kp = OKPKeyParam.from_id(_key_attribute,
                                         allow_unknown_key_attrs)

                # parse the value of the key attribute if possible
                if hasattr(kp, 'value_parser') and hasattr(
                        kp.value_parser, '__call__'):
                    _value = kp.value_parser(_value)

                # store in new dict
                transformed_dict[kp] = _value
            except ValueError:
                transformed_dict[_key_attribute] = _value

        # final check if key type is correct
        if transformed_dict.get(KpKty) != KtyOKP:
            raise CoseIllegalKeyType(
                f"Illegal key type in OKP COSE Key: {transformed_dict.get(KpKty)}"
            )

        super(OKPKey, self).__init__(transformed_dict)

        if len(x) == 0 and len(d) == 0:
            raise CoseInvalidKey(
                "Either the public values or the private value must be specified"
            )

        if crv is not None:
            self.crv = crv
        else:
            raise CoseInvalidKey("COSE curve cannot be None")
        if x != b'':
            self.x = x
        if d != b'':
            self.d = d
Ejemplo n.º 4
0
    def verify_tag(self,
                   key: SymmetricKey,
                   alg: Optional[CoseAlgorithms] = None) -> bool:
        """ Verifies the authentication tag of a received message. """

        if not isinstance(key, SymmetricKey):
            raise CoseIllegalKeyType(
                "COSE key should be of type 'SymmetricKey', got {}".format(
                    type(key)))

        return key.verify_tag(self.auth_tag, self._mac_structure, alg)
Ejemplo n.º 5
0
    def compute_tag(self,
                    key: SymmetricKey,
                    alg: Optional[CoseAlgorithms] = None) -> bytes:
        """ Computes the authentication tag of a COSE_Mac or COSE_Mac0 message. """

        if not isinstance(key, SymmetricKey):
            raise CoseIllegalKeyType(
                "COSE key should be of type 'SymmetricKey', got {}".format(
                    type(key)))

        self.auth_tag = key.compute_tag(self._mac_structure, alg)
        return self.auth_tag
Ejemplo n.º 6
0
    def __init__(self,
                 crv: Union[Type['CoseCurve'], str, int],
                 x: bytes = b'',
                 y: bytes = b'',
                 d: bytes = b'',
                 optional_params: Optional[dict] = None,
                 allow_unknown_key_attrs: bool = True):
        transformed_dict = {}

        if len(x) == 0 and len(y) == 0 and len(d) == 0:
            raise CoseInvalidKey(
                "Either the public values or the private value must be specified"
            )

        if (len(x) == 0 and len(y) != 0) or (len(x) != 0 and len(y) == 0):
            raise CoseInvalidKey("Missing public coordinate X/Y")

        new_dict = dict({KpKty: KtyEC2, EC2KpCurve: crv})

        if len(x) != 0 and len(y) != 0:
            new_dict.update({EC2KpX: x, EC2KpY: y})
        if len(d) != 0:
            new_dict.update({EC2KpD: d})

        if optional_params is not None:
            new_dict.update(optional_params)

        for _key_attribute, _value in new_dict.items():
            try:
                # translate the key_attribute
                kp = EC2KeyParam.from_id(_key_attribute,
                                         allow_unknown_key_attrs)

                # parse the value of the key attribute if possible
                if hasattr(kp, 'value_parser') and hasattr(
                        kp.value_parser, '__call__'):
                    _value = kp.value_parser(_value)

                # store in new dict
                transformed_dict[kp] = _value
            except ValueError:
                transformed_dict[_key_attribute] = _value

        # final check if key type is correct
        if transformed_dict.get(KpKty) != KtyEC2:
            raise CoseIllegalKeyType(
                f"Illegal key type in EC2 COSE Key: {transformed_dict.get(KpKty)}"
            )

        super(EC2Key, self).__init__(transformed_dict)
Ejemplo n.º 7
0
    def verify_signature(self,
                         public_key: Union[EC2, OKP],
                         alg: Optional['CoseAlgorithms'] = None,
                         curve: Optional['CoseEllipticCurves'] = None) -> bool:
        """
        Verifies the signature of a received COSE message.

        :param public_key: A COSE key of type EC2 or OKP
        :param alg: An optional CoseAlgorithm
        :param curve: An optional CoseEllipticCurve
        :raises CoseIllegalKeyType: When the key type is not of EC2 or OKP
        :raises CoseIllegalAlgorithm: When the algorithm configuration is invalid
        :returns: True for a valid signature or False for an invalid signature
        """
        if not isinstance(public_key, EC2) and not isinstance(public_key, OKP):
            raise CoseIllegalKeyType(
                "COSE key should be of type 'EC2' or 'OKP', got {}".format(
                    type(public_key)))

        return public_key.verify(self._sig_structure, self.signature, alg,
                                 curve)
Ejemplo n.º 8
0
    def from_dict(cls, received: dict) -> 'CK':
        """
        Initialize a COSE key from a dictionary.

        :param received: Dictionary to translate to COSE key.
        :return: An initialized COSE Key object.
        """

        if KpKty in received:
            key_obj = cls._key_types[received[KpKty]].from_dict(received)
        elif KpKty.identifier in received:
            key_obj = cls._key_types[received[KpKty.identifier]].from_dict(
                received)
        elif KpKty.fullname in received:
            key_obj = cls._key_types[received[KpKty.fullname]].from_dict(
                received)
        else:
            raise CoseIllegalKeyType(
                "Could not decode CoseKey type, KpKty not set or unknown.")

        return key_obj
Ejemplo n.º 9
0
    def __init__(self,
                 k: bytes,
                 optional_params: Optional[dict] = None,
                 allow_unknown_key_attrs: bool = True):
        transformed_dict = {}

        if len(k) not in [16, 24, 32]:
            raise CoseInvalidKey(
                "Key length should be either 16, 24, or 32 bytes")

        new_dict = dict({KpKty: KtySymmetric, SymKpK: k})

        if optional_params is not None:
            new_dict.update(optional_params)

        for _key_attribute, _value in new_dict.items():
            try:
                # translate the key_attribute
                kp = SymmetricKeyParam.from_id(_key_attribute,
                                               allow_unknown_key_attrs)

                # parse the value of the key attribute if possible
                if hasattr(kp, 'value_parser') and hasattr(
                        kp.value_parser, '__call__'):
                    _value = kp.value_parser(_value)

                # store in new dict
                transformed_dict[kp] = _value
            except ValueError:
                transformed_dict[_key_attribute] = _value

        # final check if key type is correct
        if transformed_dict.get(KpKty) != KtySymmetric:
            raise CoseIllegalKeyType(
                f"Illegal key type in Symmetric COSE Key: {transformed_dict.get(KpKty)}"
            )

        super(SymmetricKey, self).__init__(transformed_dict)
Ejemplo n.º 10
0
    def compute_signature(
            self,
            private_key: Union[EC2, OKP] = None,
            alg: Optional['CoseAlgorithms'] = None,
            curve: Optional['CoseEllipticCurves'] = None) -> bytes:
        """
        Computes the signature over a COSE message.

        :param private_key: A COSE key of type EC2 or OKP
        :param alg: An optional CoseAlgorithm
        :param curve: An optional CoseEllipticCurve
        :raises CoseIllegalKeyType: When the key type is not of EC2 or OKP
        :raises CoseIllegalAlgorithm: When the algorithm configuration is invalid
        :returns: True or False
        """

        if not isinstance(private_key, EC2) and not isinstance(
                private_key, OKP):
            raise CoseIllegalKeyType(
                "COSE key should be of type 'EC2' or 'OKP', got {}".format(
                    type(private_key)))

        return private_key.sign(self._sig_structure, alg, curve)
Ejemplo n.º 11
0
    def __init__(self,
                 k: bytes,
                 optional_params: Optional[dict] = None,
                 allow_unknown_key_attrs: bool = True):
        transformed_dict = {KpKty: KtySymmetric}

        if optional_params is None:
            optional_params = {}

        for _key_attribute, _value in optional_params.items():
            try:
                # translate the key_attribute
                kp = SymmetricKeyParam.from_id(_key_attribute,
                                               allow_unknown_key_attrs)

                # parse the value of the key attribute if possible
                if hasattr(kp, 'value_parser') and hasattr(
                        kp.value_parser, '__call__'):
                    _value = kp.value_parser(_value)

                # store in new dict
                transformed_dict[kp] = _value
            except ValueError:
                transformed_dict[_key_attribute] = _value

        # final check if key type is correct
        if transformed_dict.get(KpKty) != KtySymmetric:
            raise CoseIllegalKeyType(
                f"Illegal key type in Symmetric COSE Key: {transformed_dict.get(KpKty)}"
            )

        super(SymmetricKey, self).__init__(transformed_dict)

        if k != b'':
            self.k = k
        else:
            raise CoseInvalidKey("SymKpK parameter cannot be None")
Ejemplo n.º 12
0
    def __init__(self,
                 crv: Union[Type['CoseCurve'], str, int],
                 x: bytes = b'',
                 y: bytes = b'',
                 d: bytes = b'',
                 optional_params: Optional[dict] = None,
                 allow_unknown_key_attrs: bool = True):
        """Initialize a COSE key from its components

        Not passing a `y` component is accepted; in this case, one (of the two)
        valid `y` will be found for the `x`. This is good enough for everything
        that only operates on the `x` of any derived outputs (in "compact"
        mode), as per RFC 6090 Section 4.2.
        """
        transformed_dict = {KpKty: KtyEC2}

        if optional_params is None:
            optional_params = {}

        for _key_attribute, _value in optional_params.items():
            try:
                # transform the key_attribute
                kp = EC2KeyParam.from_id(_key_attribute,
                                         allow_unknown_key_attrs)

                # parse the value of the key attribute if possible
                if hasattr(kp, 'value_parser') and hasattr(
                        kp.value_parser, '__call__'):
                    _value = kp.value_parser(_value)

                # store in new dict
                transformed_dict[kp] = _value
            except ValueError:
                transformed_dict[_key_attribute] = _value

        # final check if key type is correct
        if transformed_dict.get(KpKty) != KtyEC2:
            raise CoseIllegalKeyType(
                f"Illegal key type in EC2 COSE Key: {transformed_dict.get(KpKty)}"
            )

        super(EC2Key, self).__init__(transformed_dict)

        if crv is not None:
            self.crv = crv
        else:
            raise CoseInvalidKey("COSE curve cannot be None")

        if not x and not y and not d:
            raise CoseInvalidKey(
                "Either the public values or the private value must be specified"
            )

        if not d and not x:
            raise CoseInvalidKey("Missing public coordinate X")

        if d:
            public_nums = ec.derive_private_key(
                int.from_bytes(d, byteorder="big"),
                curve=self.crv.curve_obj()).public_key().public_numbers()
            if x:
                assert x == public_nums.x.to_bytes(self.crv.size, 'big')
            else:
                x = public_nums.x.to_bytes(self.crv.size, 'big')

            if y:
                assert y == public_nums.y.to_bytes(self.crv.size, 'big')
            else:
                y = public_nums.y.to_bytes(self.crv.size, 'big')

        if x and not y:
            # try to derive y from x
            key = ec.EllipticCurvePublicKey.from_encoded_point(
                self.crv.curve_obj(),
                # don't care which of the two possible Y values we get
                b'\x03' + x  # or [::-1]?
            )
            # Just to check the endianness of the conversions -- if we get the
            # right X back out, then the X and Y are consistent, and anyway the
            # crypto backend will check whether the point is on the curve
            assert x == key.public_numbers().x.to_bytes(self.crv.size, 'big')
            y = key.public_numbers().y.to_bytes(self.crv.size, 'big')

        if x != b'':
            self.x = x
        if y != b'':
            self.y = y
        if d != b'':
            self.d = d
Ejemplo n.º 13
0
    def __init__(self,
                 n: bytes = b'',
                 e: bytes = b'',
                 d: bytes = b'',
                 p: bytes = b'',
                 q: bytes = b'',
                 dp: bytes = b'',
                 dq: bytes = b'',
                 qinv: bytes = b'',
                 other: Optional[List[dict]] = None,
                 r_i: bytes = b'',
                 d_i: bytes = b'',
                 t_i: bytes = b'',
                 optional_params: Optional[dict] = None,
                 allow_unknown_key_attrs: bool = True):
        transformed_dict = {KpKty: KtyRSA}

        if other is None:
            other = []

        if optional_params is None:
            optional_params = {}

        # public key, n and e must be defined
        if len(n) != 0 and len(e) != 0 and all(
                map(lambda x: len(x) == 0,
                    [d, p, q, dp, dq, qinv, other, r_i, d_i, t_i])):
            is_valid_key = True

        # private keys with two primes, except other, r_i, t_i and d_i, all other parameters need to be defined
        elif all(map(lambda x: len(x) == 0, [other, r_i, t_i, d_i])) and \
                all(map(lambda x: len(x) != 0, [n, e, d, p, q, dp, dq, qinv])):
            is_valid_key = True

        # private keys with more than two primes, everything needs to be defined
        elif all(
                map(lambda x: len(x) != 0,
                    [n, e, d, p, q, dp, dq, qinv, other, r_i, d_i, t_i])):
            is_valid_key = True
            # TODO: verify contents of other
        else:
            is_valid_key = False

        if not is_valid_key:
            raise CoseInvalidKey(
                "Invalid RSA key: not a public key, private key with two primes or private key "
                "with more than two primes")

        for _key_attribute, _value in optional_params.items():
            try:
                # transform the key_attribute
                kp = RSAKeyParam.from_id(_key_attribute,
                                         allow_unknown_key_attrs)

                # parse the value of the key attribute if possible
                if hasattr(kp, 'value_parser') and hasattr(
                        kp.value_parser, '__call__'):
                    _value = kp.value_parser(_value)

                # store in new dict
                transformed_dict[kp] = _value
            except ValueError:
                transformed_dict[_key_attribute] = _value

        # final check if key type is correct
        if transformed_dict.get(KpKty) != KtyRSA:
            raise CoseIllegalKeyType(
                f"Illegal key type in RSA COSE Key: {transformed_dict.get(KpKty)}"
            )

        super(RSAKey, self).__init__(transformed_dict)

        self.e = e
        self.n = n

        if d != b'':
            self.d = d
        if p != b'':
            self.p = p
        if q != b'':
            self.q = q
        if dp != b'':
            self.dp = dp
        if dq != b'':
            self.dq = dq
        if qinv != b'':
            self.qinv = qinv
        if other:
            self.other = other
        if r_i != b'':
            self.r_i = r_i
        if d_i != b'':
            self.d_i = d_i
        if t_i != b'':
            self.t_i = t_i