@@ -461,6 +461,30 @@ pub fn seal_at<E: Encode, A: Encode>(
461461 domain,
462462 timestamp,
463463 ) ;
464+ // Encrypt the signed message to the recipient
465+ encrypt ( & signed, Raw ( msg_to_auth) , recipient, domain)
466+ }
467+
468+ /// encrypt encrypts an already-signed COSE_Sign1 to a recipient.
469+ ///
470+ /// For most use cases, prefer [`seal`] which signs and encrypts in one step.
471+ /// Use this only when re-encrypting a message (from [`decrypt`]) to a different
472+ /// recipient without access to the original signer's key.
473+ ///
474+ /// - `sign1`: The COSE_Sign1 structure (e.g., from [`decrypt`])
475+ /// - `msg_to_auth`: The same additional authenticated data used during sealing
476+ /// - `recipient`: The xHPKE public key to encrypt to
477+ /// - `domain`: Application domain for HPKE key derivation
478+ ///
479+ /// Returns the serialized COSE_Encrypt0 structure.
480+ pub fn encrypt < A : Encode > (
481+ sign1 : & [ u8 ] ,
482+ msg_to_auth : A ,
483+ recipient : & xhpke:: PublicKey ,
484+ domain : & [ u8 ] ,
485+ ) -> Result < Vec < u8 > , Error > {
486+ // Pre-encode for EncStructure (which needs raw bytes for external_aad)
487+ let msg_to_auth = cbor:: encode ( msg_to_auth) ;
464488
465489 // Build protected header with recipient's fingerprint
466490 let protected = cbor:: encode ( & EncProtectedHeader {
@@ -473,7 +497,7 @@ pub fn seal_at<E: Encode, A: Encode>(
473497 // Build and seal Enc_structure
474498 let ( encap_key, ciphertext) = recipient
475499 . seal (
476- & signed ,
500+ sign1 ,
477501 & EncStructure {
478502 context : "Encrypt0" ,
479503 protected : & protected,
@@ -494,63 +518,6 @@ pub fn seal_at<E: Encode, A: Encode>(
494518 } ) )
495519}
496520
497- /// decrypt decrypts a sealed message without verifying the signature.
498- ///
499- /// This allows inspecting the signer before verification. Use [`signer`] to
500- /// extract the signer's fingerprint, then [`verify`] or [`verify_at`] to verify.
501- ///
502- /// - `msg_to_open`: The serialized COSE_Encrypt0 structure
503- /// - `msg_to_auth`: The same additional authenticated data used during sealing
504- /// - `recipient`: The xHPKE secret key to decrypt with
505- /// - `domain`: Application domain for HPKE key derivation
506- ///
507- /// Returns the decrypted COSE_Sign1 structure (not yet verified).
508- pub fn decrypt < A : Encode > (
509- msg_to_open : & [ u8 ] ,
510- msg_to_auth : A ,
511- recipient : & xhpke:: SecretKey ,
512- domain : & [ u8 ] ,
513- ) -> Result < Vec < u8 > , Error > {
514- // Pre-encode for EncStructure (which needs raw bytes for external_aad)
515- let msg_to_auth = cbor:: encode ( msg_to_auth) ;
516-
517- // Restrict the user's domain to the context of this library
518- let info = [ DOMAIN_PREFIX , domain] . concat ( ) ;
519-
520- // Parse COSE_Encrypt0
521- let encrypt0: CoseEncrypt0 = cbor:: decode ( msg_to_open) ?;
522-
523- // Verify protected header
524- verify_enc_protected_header ( & encrypt0. protected , ALGORITHM_ID_XHPKE , recipient) ?;
525-
526- // Extract encapsulated key from the unprotected headers
527- let encap_key: & [ u8 ; xhpke:: ENCAP_KEY_SIZE ] = encrypt0
528- . unprotected
529- . encap_key
530- . as_slice ( )
531- . try_into ( )
532- . map_err ( |_| {
533- Error :: InvalidEncapKeySize ( encrypt0. unprotected . encap_key . len ( ) , xhpke:: ENCAP_KEY_SIZE )
534- } ) ?;
535-
536- // Rebuild and open Enc_structure
537- let decrypted = recipient
538- . open (
539- encap_key,
540- & encrypt0. ciphertext ,
541- & EncStructure {
542- context : "Encrypt0" ,
543- protected : & encrypt0. protected ,
544- external_aad : & msg_to_auth,
545- }
546- . encode_cbor ( ) ,
547- & info,
548- )
549- . map_err ( |e| Error :: DecryptionFailed ( e. to_string ( ) ) ) ?;
550-
551- Ok ( decrypted)
552- }
553-
554521/// open decrypts and verifies a sealed message.
555522///
556523/// Uses the current system time for drift checking. For testing or custom
@@ -616,6 +583,63 @@ pub fn open_at<E: Decode, A: Encode + Clone>(
616583 Ok ( cbor:: decode ( & raw . 0 ) ?)
617584}
618585
586+ /// decrypt decrypts a sealed message without verifying the signature.
587+ ///
588+ /// This allows inspecting the signer before verification. Use [`signer`] to
589+ /// extract the signer's fingerprint, then [`verify`] or [`verify_at`] to verify.
590+ ///
591+ /// - `msg_to_open`: The serialized COSE_Encrypt0 structure
592+ /// - `msg_to_auth`: The same additional authenticated data used during sealing
593+ /// - `recipient`: The xHPKE secret key to decrypt with
594+ /// - `domain`: Application domain for HPKE key derivation
595+ ///
596+ /// Returns the decrypted COSE_Sign1 structure (not yet verified).
597+ pub fn decrypt < A : Encode > (
598+ msg_to_open : & [ u8 ] ,
599+ msg_to_auth : A ,
600+ recipient : & xhpke:: SecretKey ,
601+ domain : & [ u8 ] ,
602+ ) -> Result < Vec < u8 > , Error > {
603+ // Pre-encode for EncStructure (which needs raw bytes for external_aad)
604+ let msg_to_auth = cbor:: encode ( msg_to_auth) ;
605+
606+ // Restrict the user's domain to the context of this library
607+ let info = [ DOMAIN_PREFIX , domain] . concat ( ) ;
608+
609+ // Parse COSE_Encrypt0
610+ let encrypt0: CoseEncrypt0 = cbor:: decode ( msg_to_open) ?;
611+
612+ // Verify protected header
613+ verify_enc_protected_header ( & encrypt0. protected , ALGORITHM_ID_XHPKE , recipient) ?;
614+
615+ // Extract encapsulated key from the unprotected headers
616+ let encap_key: & [ u8 ; xhpke:: ENCAP_KEY_SIZE ] = encrypt0
617+ . unprotected
618+ . encap_key
619+ . as_slice ( )
620+ . try_into ( )
621+ . map_err ( |_| {
622+ Error :: InvalidEncapKeySize ( encrypt0. unprotected . encap_key . len ( ) , xhpke:: ENCAP_KEY_SIZE )
623+ } ) ?;
624+
625+ // Rebuild and open Enc_structure
626+ let decrypted = recipient
627+ . open (
628+ encap_key,
629+ & encrypt0. ciphertext ,
630+ & EncStructure {
631+ context : "Encrypt0" ,
632+ protected : & encrypt0. protected ,
633+ external_aad : & msg_to_auth,
634+ }
635+ . encode_cbor ( ) ,
636+ & info,
637+ )
638+ . map_err ( |e| Error :: DecryptionFailed ( e. to_string ( ) ) ) ?;
639+
640+ Ok ( decrypted)
641+ }
642+
619643/// recipient extracts the recipient's fingerprint from a COSE_Encrypt0 message
620644/// without decrypting it.
621645///
0 commit comments