pub async fn sealed_sender_encrypt_from_usmc<R: Rng + CryptoRng>(
    destination: &ProtocolAddress,
    usmc: &UnidentifiedSenderMessageContent,
    identity_store: &dyn IdentityKeyStore,
    rng: &mut R,
) -> Result<Vec<u8>>
Expand description

This method implements the single-key single-recipient KEM described in this Signal blog post, a.k.a. Sealed Sender v1.

sealed_sender_decrypt is used in the client to decrypt the Sealed Sender message produced by this method.

§Contrast with Sealed Sender v2

The single-recipient KEM scheme implemented by this method partially derives the encryption key from the recipient’s identity key, which would then require re-encrypting the same message multiple times to send to multiple recipients. In contrast, Sealed Sender v2 uses a multi-recipient KEM scheme which avoids this repeated work, but makes a few additional design tradeoffs.

§High-level algorithmic overview

The KEM scheme implemented by this method is described in this Signal blog post. The high-level steps of this process are listed below:

  1. Generate a random key pair.
  2. Derive a symmetric chain key, cipher key, and MAC key from the recipient’s public key and the sender’s public/private key pair.
  3. Symmetrically encrypt the sender’s public key using the cipher key and MAC key from (2) with AES-256 in CTR mode.
  4. Derive a second symmetric cipher key and MAC key from the sender’s private key, the recipient’s public key, and the chain key from (2).
  5. Symmetrically encrypt the underlying UnidentifiedSenderMessageContent using the cipher key and MAC key from (4) with AES-256 in CTR mode.
  6. Send the ephemeral public key from (1) and the encrypted public key from (3) to the recipient, along with the encrypted message (5).

§Pseudocode

 e_pub, e_priv                  = X25519.generateEphemeral()
 e_chain, e_cipherKey, e_macKey = HKDF(salt="UnidentifiedDelivery" || recipientIdentityPublic || e_pub, ikm=ECDH(recipientIdentityPublic, e_priv), info="")
 e_ciphertext                   = AES_CTR(key=e_cipherKey, input=senderIdentityPublic)
 e_mac                          = Hmac256(key=e_macKey, input=e_ciphertext)

 s_cipherKey, s_macKey = HKDF(salt=e_chain || e_ciphertext || e_mac, ikm=ECDH(recipientIdentityPublic, senderIdentityPrivate), info="")
 s_ciphertext          = AES_CTR(key=s_cipherKey, input=sender_certificate || message_ciphertext)
 s_mac                 = Hmac256(key=s_macKey, input=s_ciphertext)

 message_to_send = s_ciphertext || s_mac

§Wire Format

The output of this method is encoded as an UnidentifiedSenderMessage.Message from sealed_sender.proto, prepended with an additional byte to indicate the version of Sealed Sender in use (see further documentation on the version byte).