Пример #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 x25519_key_derivation(
            self,
            public_key: 'OKP',
            context: CoseKDFContext = b'',
            alg: Optional[CoseAlgorithms] = None,
            curve: Optional[CoseEllipticCurves] = None) -> Tuple[bytes, bytes]:

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

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

        p = X25519PublicKey.from_public_bytes(public_key.x)
        d = X25519PrivateKey.from_private_bytes(self.d)

        shared_secret = d.exchange(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_secret)

        return shared_secret, derived_key
Пример #3
0
    def hmac_key_derivation(self,
                            context: CoseKDFContext,
                            alg: Optional[CoseAlgorithms] = None,
                            salt: bytes = b'') -> bytes:
        """
        HMAC-based key derivation based on secret bytes and a CoseKDFContext object.

        :param context: A CoseKDFContext object which contains necessary input for the KDF algorithm.
        :param alg: An optional CoseAlgorithm parameter.
        :param salt: And optional salt parameter.
        :return: A cryptographic key with a length specified in the CoseKDFContext object.
        """

        self._check_key_conf(alg, KeyOps.DERIVE_KEY)

        try:
            alg_cfg = config(CoseAlgorithms(self.alg))
        except KeyError as err:
            raise CoseIllegalAlgorithm(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
Пример #4
0
    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__}")
Пример #5
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 CoseIllegalAlgorithm(err)

        return alg_cfg.primitive.aes_key_unwrap(self.k, wrapped_key,
                                                default_backend())
Пример #6
0
    def encrypt(self, plaintext: bytes, aad: bytes, nonce: bytes,
                alg: Optional[CoseAlgorithms]) -> bytes:
        self._check_key_conf(alg, KeyOps.ENCRYPT)

        try:
            cipher = self._prepare_cipher()
            ciphertext = cipher.encrypt(nonce=nonce,
                                        data=plaintext,
                                        associated_data=aad)
        except KeyError as err:
            raise CoseIllegalAlgorithm(err)

        return ciphertext
Пример #7
0
    def compute_tag(self,
                    to_be_maced: bytes,
                    alg: Optional[CoseAlgorithms] = None) -> bytes:
        """
        Compute the MAC over the payload.

        :param to_be_maced: The payload over which the authentication tag will be calculated.
        :param alg: An optional CoseAlgorithm for computing the authentication tag.
        :return: The authentication tag.
        """

        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 CoseIllegalAlgorithm(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
Пример #8
0
    def compute_hash(self) -> bytes:
        try:
            alg_cfg = config(CoseAlgorithms(self.alg))
        except KeyError as err:
            raise CoseIllegalAlgorithm(err)

        h = Hash(algorithm=alg_cfg.hash(), backend=openssl.backend)
        h.update(self.certificate)
        digest = h.finalize()

        if alg_cfg.tag_length is not None:
            digest = digest[:8]

        return digest
Пример #9
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 CoseIllegalAlgorithm(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 CoseIllegalAlgorithm(
                f"Key wrap requires one of the following algorithms: \
            {(CoseAlgorithms.A256KW, CoseAlgorithms.A192KW, CoseAlgorithms.A128KW, CoseAlgorithms.DIRECT)}"
            )
Пример #10
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)
Пример #11
0
    def verify(self, key_type: Type['CK'], algorithm: Type['CoseAlg'],
               key_ops: List[Type['KEYOPS']]):
        """ Verify attributes of the COSE_key object."""

        if not isinstance(self, key_type):
            raise CoseException("Wrong key type")

        if self.alg is not None and self.alg.identifier != algorithm.identifier:
            raise CoseIllegalAlgorithm(
                "Conflicting algorithms in key and COSE headers")

        if len(self.key_ops):
            match_key_ops = False

            for k in key_ops:
                if k in self.key_ops:
                    match_key_ops = True

            if not match_key_ops:
                raise CoseIllegalKeyOps(
                    f"Illegal key operations specified. Allowed: {key_ops}, found: {self.key_ops}"
                )
Пример #12
0
    def compute_cek(self, target_alg: '_EncAlg', ops: str) -> 'SK':
        alg = self.get_attr(headers.Algorithm)

        if alg in {EcdhSsHKDF256, EcdhSsHKDF512, EcdhEsHKDF256, EcdhEsHKDF512}:
            if ops == "encrypt":
                peer_key = self.local_attrs.get(headers.StaticKey)
            else:
                if alg in {EcdhSsHKDF256, EcdhSsHKDF512}:
                    peer_key = self.get_attr(headers.StaticKey)
                else:
                    peer_key = self.get_attr(headers.EphemeralKey)
        else:
            raise CoseIllegalAlgorithm(
                f"Algorithm {alg} unsupported for {self.__name__}")

        if peer_key is None:
            raise CoseException("Unknown static receiver public key")

        peer_key.verify(EC2Key, alg, [DeriveKeyOp, DeriveBitsOp])
        self.key.verify(EC2Key, alg, [DeriveKeyOp, DeriveBitsOp])

        return SymmetricKey(k=self._compute_kek(target_alg, peer_key, self.key,
                                                alg),
                            optional_params={KpAlg: target_alg})