-
-
Notifications
You must be signed in to change notification settings - Fork 421
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move docs for sealed sender v1/v2 to the appropriate method docstrings #366
Move docs for sealed sender v1/v2 to the appropriate method docstrings #366
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
There's a public/private distinction that's important here: As an aside, there's nothing wrong with Sealed Sender v1. In fact, it's a smaller payload on the receiving side than Sealed Sender v2. But its encryption key is derived at least partially from the recipient's identity key, so even if the same content is sent to multiple recipients, it has to be re-encrypted each time. SSv2's real change is separating the encryption key from the recipient's identity key, so that only a per-recipient needs to be encrypted differently. |
1c0d3ab
to
6cee7e3
Compare
Ok, thanks! That was super helpful! In light of this I have expanded the scope of this PR to also cover documenting the mechanics of v1 sealed sender in I also made a quick change just now in a3e0031 to explicitly append the AES-GCM-SIV authentication tag to the end of the symmetric ciphertext in
Thanks! In light of this, all of the docs I've just added also explicitly avoid referring to "v1" or "v2" sealed sender mechanisms, instead referring to the single- and multi-recipient KEM schemes described in the docstrings for It was a fun exercise writing these docs but if they're more than you'd like to review / aren't appropriate for the repo for some reason feel free to tell me to cut them down! |
I've pushed a rendered version of the docs from |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pile of comments but I appreciate this work! I think you've done well separating the public and private parts.
rust/protocol/src/sealed_sender.rs
Outdated
/// 5. Use the keypair from (2) to symmetrically encrypt the underlying | ||
/// [UnidentifiedSenderMessageContent]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mm, I think I got this wrong too; the symmetric key is separately derived from (1). At some point we really are just spelling out the pseudocode, though…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think I got to that realization as well. I tried deleting this numbered list section and I think I still prefer having it, but we can probably afford to be more concise since the pseudocode + paper link is actually extremely useful.
rust/protocol/src/sealed_sender.rs
Outdated
/// the encoded message returned by this method does *not* correspond to a specific protobuf schema | ||
/// due to the complex web of cryptographic data dependencies in different segments of the resulting | ||
/// encoded message. See the documentation of our [single-recipient KEM] for a discussion of the | ||
/// design tradeoffs of using this particular multi-recipient KEM. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh. It could have been protobuf, but that's just wasting space in a format with so many fixed-width fields. We went back and forth but decided that the only thing protobuf would buy us is extensibility, and we could add another version instead.
I wrote up this document internally on the format; maybe some form of it belongs here or in the repository somewhere as well:
multi_recipient_sealed_sender.md.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rustdoc book mentions it does not have support for bare markdown files, which would certainly be convenient here. I think this looks brief and appropriate enough for the "Wire Format" section of the sealed_sender_multi_recipient_encrypt()
docstring, so I'll try adapting it there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmmm, rust-lang/rust#76709 certainly seems to imply it is possible to use rustdoc against markdown files directly. I will try to apply that feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so it's possible to use rustdoc against markdown files directly as a command-line argument, but it seems that isn't integrated into cargo doc
(either providing files as CLI arguments, or using raw markdown files). In 562c1a5 I took the liberty of merging this doc into the "Wire Format" section of sealed_sender_multi_recipient_encrypt()
, and linking into the resulting "The version byte" section from the "Wire Format" section of sealed_sender_encrypt_from_usmc()
.
In these changes I have also referred to "Sealed Sender v1" and "Sealed Sender v2" instead of "the single-/multi-recipient KEM". See the "Wire Format" section for Sealed Sender v2 rendered at https://cosmicexplorer.github.io/libsignal-client/target/doc/libsignal_protocol/fn.sealed_sender_multi_recipient_encrypt.html#wire-format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't necessarily thinking "in the repository" had to mean "included in the rustdoc", but it seems to work, especially since functions get their own pages. (Thanks for rendering the docs!) You can include a Markdown file using #[doc = include_str!("foo.md")]
(if we're on a new enough Rust, h/t the Rustdoc book), but I think this is better anyway.
96fa412
to
562c1a5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, this one's nearly all copyediting-type comments—all the structure looks good to me now. I'm sorry there are so many! But it's definitely converging. And again I appreciate you having generated the docs; that makes it much easier to read and review.
rust/protocol/src/sealed_sender.rs
Outdated
/// This method calls [sealed_sender_decrypt_to_usmc] to extract the sender information, including | ||
/// the embedded [SenderCertificate]. The sender certificate is then validated against the | ||
/// `trust_root` provided by the backend server to ensure that the sender's identity was not forged. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's worth adding something like "For more details on the sealed sender formats, see [sealed_sender_encrypt_from_usmc
] and [sealed_sender_multi_recipient_encrypt
]."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trust_root
isn't actually provided by the server; it's baked into the apps. The root signs the server certificate, which signs the sender certificate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this very very helpful clarification!! I have added both of these comments here.
4128f6b
to
8968d72
Compare
- clarify the mechanism of v2 sealed sender - clarify the role of `sealed_sender_multi_recipient_fan_out()` - rewrite the module docstring and add small docstrings for the methods involved - remove all references to private members and add a test for SSv2 - add similar documentation to SSv1 - modify SSv1 structs to use fixed-size arrays - make SSv1 look a lot more like SSv2 impl and add a test - make SSv2 methods return fixed-size arrays - clarify which variables are symmetric vs asymmetric authentication keys - clarify the relationship between sealed_sender_decrypt{,_to_usmc}() - integrate the sealed sender markdown document from review comments - make all references to functions and structs use `...`
8968d72
to
5e95fcb
Compare
Ok, I've addressed most of your comments and left 9 of them unresolved for further review! As before, the compiled
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Answered your open questions (mostly in agreement) and I think these'll be my last comments!
Ok, cf048dd integrates your notes on Of course, please feel free to make any further comments on code or docs changes, it's very easy for me to oblige. I'll also probably do a once-over again and see if there's anything else I think could be improved. I think the result is DRASTICALLY better than my initial attempt here and I learned quite a lot from this PR :DDDD. Thanks again for that. |
After reviewing the docs again, I think I can sign off on this so merge it whenever! Thanks again for your time making this amazing, it helped me a lot and I hope many others too :))) |
Hello! I am going to finish up my other pending PRs to this repo soon :).
Problem
The sealed sender single-recipient and multi-recipient KEM schemes in Sealed Sender v1/v2 are super neat, and documentation for how they work exists in some (very helpful!) source comments. However, it's not immediately clear e.g. that the Signal server receives the result of
sealed_sender_multi_recipient_encrypt()
, splits the output into constituent sealed-sender v2 messages, then routes them individually to clients forsealed_sender_multi_recipient_decrypt()
. Additionally, the design tradeoffs between v1 and v2 sealed sender mechanisms in general are not made clear in documentation of these public methods.Solution
sealed_sender_encrypt_from_usmc()
andsealed_sender_multi_recipient_encrypt()
.sealed_sender_multi_recipient_fan_out()
in testing.sealed_sender_multi_recipient_encrypt()
.sealed_sender_multi_recipient_encrypt()
which describes the pros and cons of the single-recipient vs multi-recipient KEM schemes implemented in thesealed_sender_v1
andsealed_sender_v2
modules.sealed_sender_v1::{EphemeralKeys,StaticKeys}
to avoid repeatedResult<Box<...>>
ing, and makeStaticKeys::calculate()
accept&IdentityKeyPair
and&IdentityKey
instead of structs fromcurve.rs
.sealed_sender_v2::{apply_agreement_xor,compute_authentication_tag}
accept and return fixed-size arrays instead of unsized slices.tag
from the rest of theciphertext
insealed_sender_multi_recipient_encrypt()
in order to differentiate it from the asymmetric authentication tagsat_i
computed later in the function when looping over the recipients.Result
A rendered version of the docs can be seen here: https://cosmicexplorer.github.io/libsignal-client/target/doc/libsignal_protocol/.
This is a great codebase!!