Пример #1
0
    def verify(self,
               to_be_signed: bytes,
               signature: bytes,
               alg: Optional[CoseAlgorithms] = None,
               curve: Optional[EllipticCurveType] = None) -> bool:
        """
        Verifies the digital signature over 'to_be_signed'. The parameter 'alg' and 'curve' parameters are optional in
        case they are already provided by one of the COSE key objects.

        :param to_be_signed: data that was signed
        :param signature: signature to verify
        :param alg: an optional algorithm parameter (specifies the exact algorithm used for the signature).
        :param curve: an optional curve
        """

        self._check_key_conf(algorithm=alg,
                             key_operation=KeyOps.VERIFY,
                             curve=curve)

        try:
            alg_cfg = config(CoseAlgorithms(self.alg))
        except KeyError as err:
            raise CoseInvalidAlgorithm(err)

        p = Point(curve=alg_cfg.curve.curve,
                  x=int(hexlify(self.x), 16),
                  y=int(hexlify(self.y), 16))
        vk = VerifyingKey.from_public_point(p,
                                            alg_cfg.curve,
                                            alg_cfg.hash,
                                            validate_point=True)

        return vk.verify(signature, to_be_signed)
Пример #2
0
    def sign(self,
             to_be_signed: bytes,
             alg: Optional[CoseAlgorithms] = None,
             curve: EllipticCurveType = None) -> bytes:
        """
        Computes a digital signature over 'to_be_signed'. The parameter 'alg' and 'curve' parameters are optional in
        case they are already provided by one of the COSE key objects.

        :param to_be_signed: data over which the signature is calculated
        :param alg: an optional algorithm parameter (specifies the exact algorithm used for the signature).
        :param curve: an optional curve
        """

        self._check_key_conf(algorithm=alg,
                             key_operation=KeyOps.SIGN,
                             curve=curve)

        try:
            alg_cfg = config(CoseAlgorithms(self.alg))
        except KeyError as err:
            raise CoseInvalidAlgorithm(err)

        sk = SigningKey.from_secret_exponent(int(hexlify(self.d), 16),
                                             curve=alg_cfg.curve)

        return sk.sign_deterministic(to_be_signed, hashfunc=alg_cfg.hash)
Пример #3
0
    def _prepare_cipher(self):
        alg_cfg = config(CoseAlgorithms(self.alg))

        if alg_cfg.tag_length is not None:
            cipher: Union[AESGCM, AESCCM] = alg_cfg.primitive(
                self.k, tag_length=alg_cfg.tag_length)
        else:
            cipher = alg_cfg.primitive(self.k)

        return cipher
Пример #4
0
    def key_unwrap(self,
                   wrapped_key: bytes,
                   alg: Optional[CoseAlgorithms] = None) -> bytes:
        self._check_key_conf(alg, KeyOps.UNWRAP)

        try:
            alg_cfg = config(CoseAlgorithms(self.alg))
        except KeyError as err:
            raise CoseInvalidAlgorithm(err)

        return alg_cfg.primitive.aes_key_unwrap(self.k, wrapped_key,
                                                default_backend())
Пример #5
0
    def ecdh_key_derivation(
            self,
            public_key: 'EC2',
            context: CoseKDFContext,
            alg: Optional[CoseAlgorithms] = None,
            curve: Optional[EllipticCurveType] = None) -> Tuple[bytes, bytes]:
        """
        Derives a CEK with ECDH + HKDF algorithm. The parameter 'alg' and 'curve' parameters are optional in case they
        are already provided by one of the COSE key objects.

        :param public_key: an EC2 key containing public key bytes.
        :param context: a CoseKDFContext for the HKDF algorithm.
        :param alg: an optional algorithm parameter (specifies the exact algorithm used for the key derivation).
        :param curve: an optional curve
        """

        self._check_key_conf(alg, KeyOps.DERIVE_KEY, public_key, curve)

        try:
            alg_cfg = config(CoseAlgorithms(self.alg))
        except KeyError as err:
            raise CoseInvalidAlgorithm(err)

        try:
            curve = self.KEY_DERIVATION_CURVES[self.crv]()
        except KeyError:
            raise CoseIllegalCurve(curve)

        d = ec.derive_private_key(int(hexlify(self.d), 16), curve,
                                  default_backend())
        p = ec.EllipticCurvePublicNumbers(int(hexlify(public_key.x), 16),
                                          int(hexlify(public_key.y), 16),
                                          curve)
        p = p.public_key(default_backend())

        shared_key = d.exchange(ECDH(), p)

        derived_key = alg_cfg.kdf(
            algorithm=alg_cfg.hash(),
            length=int(context.supp_pub_info.key_data_length / 8),
            salt=None,
            info=context.encode(),
            backend=default_backend()).derive(shared_key)

        return shared_key, derived_key
Пример #6
0
    def compute_tag(self,
                    to_be_maced: bytes,
                    alg: Optional[CoseAlgorithms] = None) -> bytes:
        """ Calculate the MAC over the payload """

        self._check_key_conf(alg, KeyOps.MAC_CREATE)

        iv = unhexlify(b"".join([b"00"] * 16))

        try:
            alg_cfg = config(CoseAlgorithms(self.alg))
        except KeyError as err:
            raise CoseInvalidAlgorithm(err)

        if self.alg in {
                CoseAlgorithms.AES_MAC_128_128, CoseAlgorithms.AES_MAC_128_64,
                CoseAlgorithms.AES_MAC_256_64, CoseAlgorithms.AES_MAC_256_128
        }:
            encryptor = Cipher(alg_cfg.primitive(self.k),
                               modes.CBC(iv),
                               backend=default_backend()).encryptor()

            while len(to_be_maced) % 16 != 0:
                to_be_maced += unhexlify(b"00")

            ciphertext = encryptor.update(to_be_maced) + encryptor.finalize()

            if alg_cfg.tag_length is not None:
                # truncate the result to the first 64 bits
                ciphertext = ciphertext[:-8]
                digest = ciphertext[-8:]
            else:
                digest = ciphertext[-16:]
        else:
            h = alg_cfg.primitive(self.k,
                                  alg_cfg.hash(),
                                  backend=default_backend())
            h.update(to_be_maced)
            digest = h.finalize()

            if CoseAlgorithms(self.alg) == CoseAlgorithms.HMAC_256_64:
                # truncate the result to the first 64 bits
                digest = digest[:8]

        return digest
Пример #7
0
    def hmac_key_derivation(self,
                            context: CoseKDFContext,
                            alg: Optional[CoseAlgorithms] = None,
                            salt: bytes = b'') -> bytes:

        self._check_key_conf(alg, KeyOps.DERIVE_KEY)

        try:
            alg_cfg = config(CoseAlgorithms(self.alg))
        except KeyError as err:
            raise CoseInvalidAlgorithm(err)

        derived_key = alg_cfg.kdf(
            algorithm=alg_cfg.hash(),
            length=int(context.supp_pub_info.key_data_length / 8),
            salt=salt,
            info=context.encode(),
            backend=default_backend()).derive(self.k)

        return derived_key
Пример #8
0
    def key_wrap(self,
                 plaintext_key: bytes,
                 alg: Optional[CoseAlgorithms] = None) -> bytes:
        self._check_key_conf(alg, KeyOps.WRAP)

        try:
            alg_cfg = config(CoseAlgorithms(self.alg))
        except KeyError as err:
            raise CoseInvalidAlgorithm(err)

        if self.alg in {
                CoseAlgorithms.A128KW, CoseAlgorithms.A192KW,
                CoseAlgorithms.A256KW
        }:
            return alg_cfg.primitive.aes_key_wrap(self.k, plaintext_key,
                                                  default_backend())
        elif self.alg == CoseAlgorithms.DIRECT:
            return b''
        else:
            raise CoseInvalidAlgorithm(
                f"Key wrap requires one of the following algorithms: \
            {(CoseAlgorithms.A256KW, CoseAlgorithms.A192KW, CoseAlgorithms.A128KW, CoseAlgorithms.DIRECT)}"
            )