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:
- Generate a random key pair.
- Derive a symmetric chain key, cipher key, and MAC key from the recipient’s public key and the sender’s public/private key pair.
- Symmetrically encrypt the sender’s public key using the cipher key and MAC key from (2) with AES-256 in CTR mode.
- 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).
- Symmetrically encrypt the underlying
UnidentifiedSenderMessageContent
using the cipher key and MAC key from (4) with AES-256 in CTR mode. - 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).