1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! # Ratcheting
//!
//! Ratcheting keys as of [RFC 9605 Section 5.1](https://www.rfc-editor.org/rfc/rfc9605.html#section-5.1):
//! the sender derives the next key from the current one instead of distributing a new one, so a
//! member who left the call cannot decrypt what follows.
//!
//! A [`RatchetingKeyId`] splits the 64 bit `SFrame` Key ID in two, using `R` bits
//! ([`RatchetBits`]) for the Ratchet Step and the rest for the Key Generation:
//!
//! ```text
//! 64-R bits R bits
//! <-----------------><------>
//! +------------------+------+
//! | Key Generation | Step |
//! +------------------+------+
//! ```
//!
//! - the **Key Generation** ([`Generation`]) changes when the application distributes new key
//! material, and is what a receiver stores a key under
//! - the **Ratchet Step** ([`RatchetStep`]) changes on every `ratchet` of a
//! `RatchetingEncryptionKey` and wraps around after `2^R - 1`
//!
//! Receivers keep one key per Key Generation in a `RatchetingKeyStore` and catch up with the
//! Ratchet Step of an incoming frame. That step comes from an unauthenticated header, so the
//! store bounds how far it will catch up per frame and only keeps the ratcheted key once the
//! frame decrypted. It is a [`KeyStore`](crate::key::KeyStore) like any other, so the frame API
//! takes it directly - mutably, as it ratchets.
//!
//! ## Example
//!
//! ```rust
//! use sframe::{
//! CipherSuite,
//! frame::{MediaFrame, MonotonicCounter},
//! ratchet::{
//! Generation, RatchetBits, RatchetStepDiff, RatchetingDecryptionKey,
//! RatchetingEncryptionKey, RatchetingKeyId, RatchetingKeyStore,
//! },
//! };
//!
//! # fn main() -> sframe::error::Result<()> {
//! const CIPHER_SUITE: CipherSuite = CipherSuite::AesGcm256Sha512;
//! // how many bits carry the Ratchet Step is agreed on for the session
//! let n_ratchet_bits = RatchetBits::new(4);
//! let key_id = RatchetingKeyId::new(Generation::from(42u64), n_ratchet_bits);
//!
//! let enc_key = RatchetingEncryptionKey::derive_from(CIPHER_SUITE, key_id, "pw123")?;
//!
//! // the receiver stores the key of the Key Generation, catching up at most 2 steps per frame
//! let mut keys = RatchetingKeyStore::new(n_ratchet_bits, RatchetStepDiff::from(2));
//! keys.insert(RatchetingDecryptionKey::derive_from(CIPHER_SUITE, key_id, "pw123")?);
//!
//! // a member leaves: the sender ratchets forward and encrypts with the new key
//! let enc_key = enc_key.ratchet()?;
//!
//! let mut counter = MonotonicCounter::default();
//! let media_frame = MediaFrame::try_new(&mut counter, "Something secret")?;
//! let encrypted_frame = media_frame.encrypt(enc_key.as_ref())?;
//!
//! // the store reads the Ratchet Step off the header and catches up with it, keeping the
//! // ratcheted key only because the frame decrypted
//! let decrypted = encrypted_frame.decrypt(&mut keys)?;
//!
//! assert_eq!(decrypted.payload(), b"Something secret");
//! # Ok(())
//! # }
//! ```
//!
//! The `sender_receiver` example wires this into a full session, including the replay protection
//! a ratcheting receiver needs.
//!
//! As with [`crate::key`], the types are generic over the crypto backend
//! ([`GenericRatchetingEncryptionKey`] and friends). The names used above are aliases pinned to
//! the backend feature in use.
pub
pub
pub
pub
pub use ;
pub use ;
pub use GenericRatchetingKeyMaterial;
pub use ;
// With a backend feature enabled the generic ratcheting types are additionally exposed as aliases
// pinned to that backend, so callers never spell out the type parameters.
cfg_if!