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
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
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
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())
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
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
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)}" )