Ejemplo n.º 1
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
Ejemplo n.º 2
0
    def generate_key(
            algorithm: CoseAlgorithms,
            key_ops: KeyOps,
            curve_type: CoseEllipticCurves = CoseEllipticCurves.X25519
    ) -> 'OKP':
        """
        Generate a random OKP COSE key object.

        :param algorithm: Specify the CoseAlgorithm to use.
        :param key_ops: Specify the key operation (KeyOps).
        :param curve_type: Specify curve, must be X25519 or X448.
        """

        if curve_type == CoseEllipticCurves.X25519:
            private_key = X25519PrivateKey.generate()
        elif curve_type == CoseEllipticCurves.X448:
            private_key = X448PrivateKey.generate()
        else:
            raise CoseIllegalCurve(
                f"curve must be of type {CoseEllipticCurves.X25519} or {CoseEllipticCurves.X448}"
            )

        encoding = Encoding(serialization.Encoding.Raw)
        private_format = PrivateFormat(serialization.PrivateFormat.Raw)
        public_format = PublicFormat(serialization.PublicFormat.Raw)
        encryption = serialization.NoEncryption()

        return OKP(alg=CoseAlgorithms(algorithm),
                   key_ops=KeyOps(key_ops),
                   crv=CoseEllipticCurves(curve_type),
                   x=private_key.public_key().public_bytes(
                       encoding, public_format),
                   d=private_key.private_bytes(encoding, private_format,
                                               encryption))
Ejemplo n.º 3
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
Ejemplo n.º 4
0
    def generate_key(algorithm: CoseAlgorithms,
                     key_ops: KeyOps,
                     key_len: int = 16) -> 'SymmetricKey':
        """
        Generate a random Symmetric COSE key object.

        :param algorithm: Specify the algorithm to use with the key object.
        :param key_ops: Choose a key operation.
        :param key_len: Symmetric key length in bytes, must be of size 16, 24 or 32.
        :raises ValueError: For invalid key lengths.
        :raises CoseIllegalKeyOps: When the key operation is not allowed on this key type.
        :returns: A COSE_key of type SymmetricKey.
        """

        if key_len not in [16, 24, 32]:
            raise ValueError("key_len must be of size 16, 24 or 32")

        if KeyOps(key_ops) not in [
                KeyOps.ENCRYPT, KeyOps.WRAP, KeyOps.DECRYPT, KeyOps.UNWRAP,
                KeyOps.MAC_CREATE, KeyOps.VERIFY
        ]:
            raise CoseIllegalKeyOps(
                f"The key operation {key_ops} is invalid for this key object.")

        return SymmetricKey(alg=CoseAlgorithms(algorithm),
                            key_ops=KeyOps(key_ops),
                            k=os.urandom(key_len))
Ejemplo n.º 5
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
Ejemplo n.º 6
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
Ejemplo n.º 7
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())
Ejemplo n.º 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 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)}"
            )