libsignal_protocol/
ratchet.rs1mod keys;
7mod params;
8
9use rand::{CryptoRng, Rng};
10
11pub(crate) use self::keys::{ChainKey, MessageKeys, RootKey};
12pub use self::params::{AliceSignalProtocolParameters, BobSignalProtocolParameters};
13use crate::protocol::{CIPHERTEXT_MESSAGE_CURRENT_VERSION, CIPHERTEXT_MESSAGE_PRE_KYBER_VERSION};
14use crate::state::SessionState;
15use crate::{KeyPair, Result, SessionRecord};
16
17fn derive_keys(has_kyber: bool, secret_input: &[u8]) -> (RootKey, ChainKey) {
18 let label = if has_kyber {
19 b"WhisperText_X25519_SHA-256_CRYSTALS-KYBER-1024".as_slice()
20 } else {
21 b"WhisperText".as_slice()
22 };
23 derive_keys_with_label(label, secret_input)
24}
25
26fn message_version(has_kyber: bool) -> u8 {
27 if has_kyber {
28 CIPHERTEXT_MESSAGE_CURRENT_VERSION
29 } else {
30 CIPHERTEXT_MESSAGE_PRE_KYBER_VERSION
31 }
32}
33
34fn derive_keys_with_label(label: &[u8], secret_input: &[u8]) -> (RootKey, ChainKey) {
35 let mut secrets = [0; 64];
36 hkdf::Hkdf::<sha2::Sha256>::new(None, secret_input)
37 .expand(label, &mut secrets)
38 .expect("valid length");
39 let (root_key_bytes, chain_key_bytes) = secrets.split_at(32);
40
41 let root_key = RootKey::new(root_key_bytes.try_into().expect("correct length"));
42 let chain_key = ChainKey::new(chain_key_bytes.try_into().expect("correct length"), 0);
43
44 (root_key, chain_key)
45}
46
47pub(crate) fn initialize_alice_session<R: Rng + CryptoRng>(
48 parameters: &AliceSignalProtocolParameters,
49 mut csprng: &mut R,
50) -> Result<SessionState> {
51 let local_identity = parameters.our_identity_key_pair().identity_key();
52
53 let sending_ratchet_key = KeyPair::generate(&mut csprng);
54
55 let mut secrets = Vec::with_capacity(32 * 5);
56
57 secrets.extend_from_slice(&[0xFFu8; 32]); let our_base_private_key = parameters.our_base_key_pair().private_key;
60
61 secrets.extend_from_slice(
62 ¶meters
63 .our_identity_key_pair()
64 .private_key()
65 .calculate_agreement(parameters.their_signed_pre_key())?,
66 );
67
68 secrets.extend_from_slice(
69 &our_base_private_key.calculate_agreement(parameters.their_identity_key().public_key())?,
70 );
71
72 secrets.extend_from_slice(
73 &our_base_private_key.calculate_agreement(parameters.their_signed_pre_key())?,
74 );
75
76 if let Some(their_one_time_prekey) = parameters.their_one_time_pre_key() {
77 secrets
78 .extend_from_slice(&our_base_private_key.calculate_agreement(their_one_time_prekey)?);
79 }
80
81 let kyber_ciphertext = parameters.their_kyber_pre_key().map(|kyber_public| {
82 let (ss, ct) = kyber_public.encapsulate();
83 secrets.extend_from_slice(ss.as_ref());
84 ct
85 });
86 let has_kyber = parameters.their_kyber_pre_key().is_some();
87
88 let (root_key, chain_key) = derive_keys(has_kyber, &secrets);
89
90 let (sending_chain_root_key, sending_chain_chain_key) = root_key.create_chain(
91 parameters.their_ratchet_key(),
92 &sending_ratchet_key.private_key,
93 )?;
94
95 let mut session = SessionState::new(
96 message_version(has_kyber),
97 local_identity,
98 parameters.their_identity_key(),
99 &sending_chain_root_key,
100 ¶meters.our_base_key_pair().public_key,
101 )
102 .with_receiver_chain(parameters.their_ratchet_key(), &chain_key)
103 .with_sender_chain(&sending_ratchet_key, &sending_chain_chain_key);
104
105 if let Some(kyber_ciphertext) = kyber_ciphertext {
106 session.set_kyber_ciphertext(kyber_ciphertext);
107 }
108
109 Ok(session)
110}
111
112pub(crate) fn initialize_bob_session(
113 parameters: &BobSignalProtocolParameters,
114) -> Result<SessionState> {
115 let local_identity = parameters.our_identity_key_pair().identity_key();
116
117 let mut secrets = Vec::with_capacity(32 * 5);
118
119 secrets.extend_from_slice(&[0xFFu8; 32]); secrets.extend_from_slice(
122 ¶meters
123 .our_signed_pre_key_pair()
124 .private_key
125 .calculate_agreement(parameters.their_identity_key().public_key())?,
126 );
127
128 secrets.extend_from_slice(
129 ¶meters
130 .our_identity_key_pair()
131 .private_key()
132 .calculate_agreement(parameters.their_base_key())?,
133 );
134
135 secrets.extend_from_slice(
136 ¶meters
137 .our_signed_pre_key_pair()
138 .private_key
139 .calculate_agreement(parameters.their_base_key())?,
140 );
141
142 if let Some(our_one_time_pre_key_pair) = parameters.our_one_time_pre_key_pair() {
143 secrets.extend_from_slice(
144 &our_one_time_pre_key_pair
145 .private_key
146 .calculate_agreement(parameters.their_base_key())?,
147 );
148 }
149
150 match (
151 parameters.our_kyber_pre_key_pair(),
152 parameters.their_kyber_ciphertext(),
153 ) {
154 (Some(key_pair), Some(ciphertext)) => {
155 let ss = key_pair.secret_key.decapsulate(ciphertext)?;
156 secrets.extend_from_slice(ss.as_ref());
157 }
158 (None, None) => (), _ => {
160 panic!("Either both or none of the kyber key pair and ciphertext can be provided")
161 }
162 }
163 let has_kyber = parameters.our_kyber_pre_key_pair().is_some();
164
165 let (root_key, chain_key) = derive_keys(has_kyber, &secrets);
166
167 let session = SessionState::new(
168 message_version(has_kyber),
169 local_identity,
170 parameters.their_identity_key(),
171 &root_key,
172 parameters.their_base_key(),
173 )
174 .with_sender_chain(parameters.our_ratchet_key_pair(), &chain_key);
175
176 Ok(session)
177}
178
179pub fn initialize_alice_session_record<R: Rng + CryptoRng>(
180 parameters: &AliceSignalProtocolParameters,
181 csprng: &mut R,
182) -> Result<SessionRecord> {
183 Ok(SessionRecord::new(initialize_alice_session(
184 parameters, csprng,
185 )?))
186}
187
188pub fn initialize_bob_session_record(
189 parameters: &BobSignalProtocolParameters,
190) -> Result<SessionRecord> {
191 Ok(SessionRecord::new(initialize_bob_session(parameters)?))
192}