async def verify_message( self, message: Union[List[bytes], bytes], signature: bytes, from_verkey: str, key_type: KeyType, ) -> bool: """ Verify a signature against the public key of the signer. Args: message: The message to verify signature: The signature to verify from_verkey: Verkey to use in verification key_type: The key type to derive the signature verification algorithm from Returns: True if verified, else False Raises: WalletError: If the verkey is not provided WalletError: If the signature is not provided WalletError: If the message is not provided WalletError: If another backend error occurs """ if not from_verkey: raise WalletError("Verkey not provided") if not signature: raise WalletError("Signature not provided") if not message: raise WalletError("Message not provided") verkey = b58_to_bytes(from_verkey) if key_type == KeyType.ED25519: try: pk = Key.from_public_bytes(KeyAlg.ED25519, verkey) return pk.verify_signature(message, signature) except AskarError as err: raise WalletError( "Exception when verifying message signature") from err # other key types are currently verified outside of Askar return verify_signed_message( message=message, signature=signature, verkey=verkey, key_type=key_type, )
def _pack_message(to_verkeys: Sequence[str], from_key: Optional[Key], message: bytes) -> bytes: """Encode a message using the DIDComm v1 'pack' algorithm.""" wrapper = JweEnvelope() cek = Key.generate(KeyAlg.C20P) # avoid converting to bytes object: this way the only copy is zeroed afterward cek_b = key_get_secret_bytes(cek._handle) sender_vk = (bytes_to_b58(from_key.get_public_bytes()).encode("utf-8") if from_key else None) sender_xk = from_key.convert_key(KeyAlg.X25519) if from_key else None for target_vk in to_verkeys: target_xk = Key.from_public_bytes(KeyAlg.ED25519, b58_to_bytes(target_vk)).convert_key( KeyAlg.X25519) if sender_vk: enc_sender = crypto_box.crypto_box_seal(target_xk, sender_vk) nonce = crypto_box.random_nonce() enc_cek = crypto_box.crypto_box(target_xk, sender_xk, cek_b, nonce) wrapper.add_recipient( JweRecipient( encrypted_key=enc_cek, header=OrderedDict([ ("kid", target_vk), ("sender", b64url(enc_sender)), ("iv", b64url(nonce)), ]), )) else: enc_sender = None nonce = None enc_cek = crypto_box.crypto_box_seal(target_xk, cek_b) wrapper.add_recipient( JweRecipient(encrypted_key=enc_cek, header={"kid": target_vk})) wrapper.set_protected( OrderedDict([ ("enc", "xchacha20poly1305_ietf"), ("typ", "JWM/1.0"), ("alg", "Authcrypt" if from_key else "Anoncrypt"), ]), auto_flatten=False, ) enc = cek.aead_encrypt(message, aad=wrapper.protected_bytes) ciphertext, tag, nonce = enc.parts wrapper.set_payload(ciphertext, nonce, tag) return wrapper.to_json().encode("utf-8")
def _extract_payload_key(sender_cek: dict, recip_secret: Key) -> Tuple[bytes, str]: """ Extract the payload key from pack recipient details. Returns: A tuple of the CEK and sender verkey """ recip_x = recip_secret.convert_key(KeyAlg.X25519) if sender_cek["nonce"] and sender_cek["sender"]: sender_vk = crypto_box.crypto_box_seal_open( recip_x, sender_cek["sender"]).decode("utf-8") sender_x = Key.from_public_bytes( KeyAlg.ED25519, b58_to_bytes(sender_vk)).convert_key(KeyAlg.X25519) cek = crypto_box.crypto_box_open(recip_x, sender_x, sender_cek["key"], sender_cek["nonce"]) else: sender_vk = None cek = crypto_box.crypto_box_seal_open(recip_x, sender_cek["key"]) return cek, sender_vk