1use std::fmt;
7use std::sync::LazyLock;
8
9use hmac::{Hmac, HmacReset, KeyInit, Mac};
10use sha2::Sha256;
11
12use crate::protocol::{PrivateKey, PublicKey, Result, crypto, stores::session_structure};
13
14pub enum MessageKeyGenerator {
21 Seed(([u8; 32], u32)),
23 Serialized(session_structure::chain::MessageKey),
25}
26
27impl MessageKeyGenerator {
28 #[inline]
29 pub fn new_from_seed(seed: &[u8; 32], counter: u32) -> Self {
30 Self::Seed((*seed, counter))
31 }
32
33 pub fn generate_keys(self) -> MessageKeys {
36 match self {
37 Self::Seed((seed, counter)) => MessageKeys::derive_keys(&seed, None, counter),
38 Self::Serialized(pb) => {
39 let cipher_key = pb
45 .cipher_key
46 .as_deref()
47 .and_then(|b| <[u8; 32]>::try_from(b).ok());
48 let mac_key = pb
49 .mac_key
50 .as_deref()
51 .and_then(|b| <[u8; 32]>::try_from(b).ok());
52 let iv = pb.iv.as_deref().and_then(|b| <[u8; 16]>::try_from(b).ok());
53
54 debug_assert!(
55 cipher_key.is_some() && mac_key.is_some() && iv.is_some(),
56 "Serialized MessageKeyGenerator has invalid field lengths - from_pb should have rejected this"
57 );
58
59 MessageKeys {
60 cipher_key: cipher_key.unwrap_or([0u8; 32]),
61 mac_key: mac_key.unwrap_or([0u8; 32]),
62 iv: iv.unwrap_or([0u8; 16]),
63 counter: pb.index.unwrap_or(0),
64 }
65 }
66 }
67 }
68
69 pub fn into_pb(self) -> session_structure::chain::MessageKey {
76 match self {
77 Self::Serialized(pb) => pb,
79 Self::Seed((seed, counter)) => {
81 use bytes::BytesMut;
82 let keys = MessageKeys::derive_keys(&seed, None, counter);
83 let mut material = BytesMut::with_capacity(
87 keys.cipher_key().len() + keys.mac_key().len() + keys.iv().len() + seed.len(),
88 );
89 material.extend_from_slice(keys.cipher_key());
90 material.extend_from_slice(keys.mac_key());
91 material.extend_from_slice(keys.iv());
92 material.extend_from_slice(&seed);
93
94 let mut material = material.freeze();
95 let cipher_key = material.split_to(keys.cipher_key().len());
96 let mac_key = material.split_to(keys.mac_key().len());
97 let iv = material.split_to(keys.iv().len());
98 session_structure::chain::MessageKey {
99 cipher_key: Some(cipher_key),
100 mac_key: Some(mac_key),
101 iv: Some(iv),
102 index: Some(keys.counter()),
103 seed: Some(material),
104 }
105 }
106 }
107 }
108
109 pub fn from_pb(
111 pb: session_structure::chain::MessageKey,
112 ) -> std::result::Result<Self, &'static str> {
113 if pb.cipher_key.as_ref().is_some_and(|b| b.len() == 32)
115 && pb.mac_key.as_ref().is_some_and(|b| b.len() == 32)
116 && pb.iv.as_ref().is_some_and(|b| b.len() == 16)
117 {
118 Ok(Self::Serialized(pb))
120 } else {
121 Err("invalid message key format")
122 }
123 }
124
125 #[inline]
127 pub fn counter(&self) -> u32 {
128 match self {
129 Self::Seed((_, counter)) => *counter,
130 Self::Serialized(pb) => pb.index.unwrap_or(0),
131 }
132 }
133}
134
135#[derive(Clone, Copy)]
136pub struct MessageKeys {
137 cipher_key: [u8; 32],
138 mac_key: [u8; 32],
139 iv: [u8; 16],
140 counter: u32,
141}
142
143static MESSAGE_KEY_EXTRACT_HMAC: LazyLock<Hmac<Sha256>> =
147 LazyLock::new(|| Hmac::<Sha256>::new_from_slice(&[0u8; 32]).expect("32-byte HMAC key"));
148
149impl MessageKeys {
150 pub fn derive_keys(
151 input_key_material: &[u8],
152 optional_salt: Option<&[u8]>,
153 counter: u32,
154 ) -> Self {
155 let mut okm = [0; 80];
156 match optional_salt {
157 None => {
158 let mut extract = MESSAGE_KEY_EXTRACT_HMAC.clone();
159 extract.update(input_key_material);
160 let prk = extract.finalize().into_bytes();
161 hkdf::Hkdf::<Sha256>::from_prk(&prk)
162 .expect("PRK is hash-sized")
163 .expand(b"WhisperMessageKeys", &mut okm)
164 .expect("valid output length");
165 }
166 Some(salt) => {
167 hkdf::Hkdf::<Sha256>::new(Some(salt), input_key_material)
168 .expand(b"WhisperMessageKeys", &mut okm)
169 .expect("valid output length");
170 }
171 }
172
173 let (cipher_key, rest) = okm.split_first_chunk::<32>().expect("80-byte OKM");
177 let (mac_key, rest) = rest.split_first_chunk::<32>().expect("80-byte OKM");
178 let (iv, _) = rest.split_first_chunk::<16>().expect("80-byte OKM");
179
180 MessageKeys {
181 cipher_key: *cipher_key,
182 mac_key: *mac_key,
183 iv: *iv,
184 counter,
185 }
186 }
187
188 #[inline]
189 pub fn cipher_key(&self) -> &[u8; 32] {
190 &self.cipher_key
191 }
192
193 #[inline]
194 pub fn mac_key(&self) -> &[u8; 32] {
195 &self.mac_key
196 }
197
198 #[inline]
199 pub fn iv(&self) -> &[u8; 16] {
200 &self.iv
201 }
202
203 #[inline]
204 pub fn counter(&self) -> u32 {
205 self.counter
206 }
207}
208
209#[derive(Clone, Copy, Debug)]
210pub struct ChainKey {
211 key: [u8; 32],
212 index: u32,
213}
214
215impl ChainKey {
216 const MESSAGE_KEY_SEED: [u8; 1] = [0x01u8];
217 const CHAIN_KEY_SEED: [u8; 1] = [0x02u8];
218
219 pub fn new(key: [u8; 32], index: u32) -> Self {
220 Self { key, index }
221 }
222
223 #[inline]
224 pub fn key(&self) -> &[u8; 32] {
225 &self.key
226 }
227
228 #[inline]
229 pub fn index(&self) -> u32 {
230 self.index
231 }
232
233 pub fn next_chain_key(&self) -> Result<Self> {
234 Ok(Self {
235 key: self.calculate_base_material(Self::CHAIN_KEY_SEED),
236 index: self.index.checked_add(1).ok_or_else(|| {
237 crate::protocol::SignalProtocolError::InvalidState(
238 "next_chain_key",
239 "chain key index overflow (u32::MAX)".to_string(),
240 )
241 })?,
242 })
243 }
244
245 pub fn message_keys(&self) -> MessageKeyGenerator {
246 MessageKeyGenerator::new_from_seed(
247 &self.calculate_base_material(Self::MESSAGE_KEY_SEED),
248 self.index,
249 )
250 }
251
252 #[inline]
254 pub fn step_with_message_keys(&self) -> Result<(MessageKeyGenerator, Self)> {
255 let mut hmac = HmacReset::<Sha256>::new_from_slice(&self.key)
256 .expect("HMAC-SHA256 should accept any size key");
257
258 hmac.update(&Self::MESSAGE_KEY_SEED);
259 let message_key_seed: [u8; 32] = hmac.finalize_reset().into_bytes().into();
260
261 hmac.update(&Self::CHAIN_KEY_SEED);
262 let next_key: [u8; 32] = hmac.finalize().into_bytes().into();
263
264 let message_keys = MessageKeyGenerator::new_from_seed(&message_key_seed, self.index);
265 let next_chain = Self {
266 key: next_key,
267 index: self.index.checked_add(1).ok_or_else(|| {
268 crate::protocol::SignalProtocolError::InvalidState(
269 "step_with_message_keys",
270 "chain key index overflow (u32::MAX)".to_string(),
271 )
272 })?,
273 };
274
275 Ok((message_keys, next_chain))
276 }
277
278 fn calculate_base_material(&self, seed: [u8; 1]) -> [u8; 32] {
279 crypto::hmac_sha256(&self.key, &seed)
280 }
281}
282
283#[derive(Clone, Debug)]
284pub struct RootKey {
285 key: [u8; 32],
286}
287
288impl RootKey {
289 pub fn new(key: [u8; 32]) -> Self {
290 Self { key }
291 }
292
293 pub fn key(&self) -> &[u8; 32] {
294 &self.key
295 }
296
297 pub fn create_chain(
298 self,
299 their_ratchet_key: &PublicKey,
300 our_ratchet_key: &PrivateKey,
301 ) -> Result<(RootKey, ChainKey)> {
302 let shared_secret = our_ratchet_key.calculate_agreement(their_ratchet_key)?;
303 let mut derived_secret_bytes = [0; 64];
304 hkdf::Hkdf::<Sha256>::new(Some(&self.key), &shared_secret)
305 .expand(b"WhisperRatchet", &mut derived_secret_bytes)
306 .expect("valid output length");
307
308 let (root_key, chain_key) = derived_secret_bytes
309 .split_first_chunk::<32>()
310 .expect("64-byte OKM");
311 let (chain_key, _) = chain_key.split_first_chunk::<32>().expect("64-byte OKM");
312
313 Ok((
314 RootKey { key: *root_key },
315 ChainKey {
316 key: *chain_key,
317 index: 0,
318 },
319 ))
320 }
321}
322
323impl fmt::Display for RootKey {
324 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
325 write!(f, "{}", hex::encode(self.key))
326 }
327}
328
329#[cfg(test)]
330mod tests {
331 use super::*;
332
333 #[test]
337 fn derive_keys_no_salt_matches_plain_hkdf() {
338 let mut ikms: Vec<Vec<u8>> = (0..16u8)
339 .map(|i| vec![i.wrapping_mul(31).wrapping_add(7); 32])
340 .collect();
341 ikms.push(Vec::new());
342 ikms.push(vec![0xAB; 3]);
343 ikms.push(vec![0x5Au8; 64]);
344
345 for (i, ikm) in ikms.iter().enumerate() {
346 let keys = MessageKeys::derive_keys(ikm, None, i as u32);
347
348 let mut okm = [0u8; 80];
349 hkdf::Hkdf::<Sha256>::new(None, ikm)
350 .expand(b"WhisperMessageKeys", &mut okm)
351 .expect("valid output length");
352
353 assert_eq!(&keys.cipher_key()[..], &okm[0..32]);
354 assert_eq!(&keys.mac_key()[..], &okm[32..64]);
355 assert_eq!(&keys.iv()[..], &okm[64..80]);
356 assert_eq!(keys.counter(), i as u32);
357 }
358 }
359
360 #[test]
363 fn test_chain_key_stepping() {
364 let initial_key = [0x42u8; 32];
365 let chain_key = ChainKey::new(initial_key, 0);
366
367 let chain1 = chain_key.next_chain_key().expect("chain key step");
369 let chain2 = chain1.next_chain_key().expect("chain key step");
370 let chain3 = chain2.next_chain_key().expect("chain key step");
371
372 assert_eq!(chain_key.index(), 0);
374 assert_eq!(chain1.index(), 1);
375 assert_eq!(chain2.index(), 2);
376 assert_eq!(chain3.index(), 3);
377
378 assert_ne!(chain_key.key(), chain1.key());
380 assert_ne!(chain1.key(), chain2.key());
381 assert_ne!(chain2.key(), chain3.key());
382
383 let chain_key_copy = ChainKey::new(initial_key, 0);
385 let chain1_copy = chain_key_copy.next_chain_key().expect("chain key step");
386 assert_eq!(chain1.key(), chain1_copy.key());
387 assert_eq!(chain1.index(), chain1_copy.index());
388 }
389
390 #[test]
392 fn test_message_keys_derivation() {
393 let chain_key = ChainKey::new([0x55u8; 32], 10);
394 let message_keys_gen = chain_key.message_keys();
395 let message_keys = message_keys_gen.generate_keys();
396
397 assert_eq!(message_keys.counter(), 10);
399
400 assert_eq!(message_keys.cipher_key().len(), 32);
402 assert_eq!(message_keys.mac_key().len(), 32);
403 assert_eq!(message_keys.iv().len(), 16);
404
405 let chain_key2 = ChainKey::new([0x55u8; 32], 10);
407 let message_keys2 = chain_key2.message_keys().generate_keys();
408 assert_eq!(message_keys.cipher_key(), message_keys2.cipher_key());
409 assert_eq!(message_keys.mac_key(), message_keys2.mac_key());
410 assert_eq!(message_keys.iv(), message_keys2.iv());
411 }
412
413 #[test]
415 fn test_message_keys_differ_by_counter() {
416 let key = [0xAAu8; 32];
417 let chain_key_0 = ChainKey::new(key, 0);
418 let chain_key_1 = ChainKey::new(key, 1);
419
420 let mk0 = chain_key_0.message_keys().generate_keys();
421 let mk1 = chain_key_1.message_keys().generate_keys();
422
423 assert_eq!(mk0.counter(), 0);
426 assert_eq!(mk1.counter(), 1);
427
428 let chain_advanced = chain_key_0.next_chain_key().expect("chain key step");
431 let mk_advanced = chain_advanced.message_keys().generate_keys();
432
433 assert_ne!(mk0.cipher_key(), mk_advanced.cipher_key());
434 }
435
436 #[test]
438 fn test_root_key_basic() {
439 let key_bytes = [0x12u8; 32];
440 let root_key = RootKey::new(key_bytes);
441
442 assert_eq!(root_key.key(), &key_bytes);
443
444 let display = format!("{}", root_key);
446 assert_eq!(display, hex::encode(key_bytes));
447 }
448
449 #[test]
451 fn test_chain_key_long_chain() {
452 let mut chain = ChainKey::new([0x01u8; 32], 0);
453
454 for i in 0..100 {
455 assert_eq!(chain.index(), i);
456 chain = chain.next_chain_key().expect("chain key step");
457 }
458
459 assert_eq!(chain.index(), 100);
460 }
461
462 #[test]
464 fn test_message_key_generator_from_seed() {
465 let seed = [0xBBu8; 32];
466 let counter = 42;
467
468 let generator = MessageKeyGenerator::new_from_seed(&seed, counter);
469 let keys = generator.generate_keys();
470
471 assert_eq!(keys.counter(), counter);
472 assert_eq!(keys.cipher_key().len(), 32);
473 assert_eq!(keys.mac_key().len(), 32);
474 assert_eq!(keys.iv().len(), 16);
475
476 let generator2 = MessageKeyGenerator::new_from_seed(&seed, counter);
478 let keys2 = generator2.generate_keys();
479 assert_eq!(keys.cipher_key(), keys2.cipher_key());
480 }
481
482 #[test]
485 fn into_pb_persists_the_seed_next_to_the_derived_keys() {
486 let seed = [0x3Cu8; 32];
487 let pb = MessageKeyGenerator::new_from_seed(&seed, 11).into_pb();
488 let expected = MessageKeys::derive_keys(&seed, None, 11);
489
490 assert_eq!(pb.index, Some(11));
491 assert_eq!(pb.seed.as_deref(), Some(&seed[..]));
492 assert_eq!(pb.cipher_key.as_deref(), Some(&expected.cipher_key()[..]));
493 assert_eq!(pb.mac_key.as_deref(), Some(&expected.mac_key()[..]));
494 assert_eq!(pb.iv.as_deref(), Some(&expected.iv()[..]));
495 }
496
497 #[test]
503 fn reloaded_keys_come_from_the_persisted_derived_material() {
504 use bytes::Bytes;
505
506 let seed = [0x9Eu8; 32];
507 let mut pb = MessageKeyGenerator::new_from_seed(&seed, 4).into_pb();
508 pb.cipher_key = Some(Bytes::from_static(&[0x11; 32]));
509 pb.mac_key = Some(Bytes::from_static(&[0x22; 32]));
510 pb.iv = Some(Bytes::from_static(&[0x33; 16]));
511 let from_seed = MessageKeys::derive_keys(&seed, None, 4);
512
513 let reloaded = MessageKeyGenerator::from_pb(pb)
514 .expect("key stays loadable")
515 .generate_keys();
516
517 assert_eq!(reloaded.cipher_key(), &[0x11; 32]);
518 assert_eq!(reloaded.mac_key(), &[0x22; 32]);
519 assert_eq!(reloaded.iv(), &[0x33; 16]);
520 assert_eq!(reloaded.counter(), 4);
521 assert_ne!(reloaded.cipher_key(), from_seed.cipher_key());
522 }
523
524 #[test]
527 fn seedless_persisted_keys_still_load() {
528 let seed = [0x9Eu8; 32];
529 let mut pb = MessageKeyGenerator::new_from_seed(&seed, 4).into_pb();
530 let expected = MessageKeys::derive_keys(&seed, None, 4);
531 pb.seed = None;
532
533 let reloaded = MessageKeyGenerator::from_pb(pb)
534 .expect("seedless key stays loadable")
535 .generate_keys();
536
537 assert_eq!(reloaded.cipher_key(), expected.cipher_key());
538 assert_eq!(reloaded.mac_key(), expected.mac_key());
539 assert_eq!(reloaded.iv(), expected.iv());
540 assert_eq!(reloaded.counter(), 4);
541 }
542
543 #[test]
547 fn from_pb_still_rejects_a_key_without_derived_material() {
548 let mut pb = MessageKeyGenerator::new_from_seed(&[0x2Bu8; 32], 0).into_pb();
549 pb.cipher_key = None;
550
551 assert!(MessageKeyGenerator::from_pb(pb).is_err());
552 }
553
554 #[test]
556 fn test_message_keys_derive_with_salt() {
557 let input_key_material = [0x11u8; 32];
558 let salt = [0x22u8; 32];
559 let counter = 5;
560
561 let keys1 = MessageKeys::derive_keys(&input_key_material, Some(&salt), counter);
562 let keys2 = MessageKeys::derive_keys(&input_key_material, None, counter);
563
564 assert_ne!(keys1.cipher_key(), keys2.cipher_key());
566 assert_ne!(keys1.mac_key(), keys2.mac_key());
567 assert_ne!(keys1.iv(), keys2.iv());
568
569 assert_eq!(keys1.counter(), counter);
571 assert_eq!(keys2.counter(), counter);
572 }
573
574 #[test]
577 fn test_step_with_message_keys_equivalence() {
578 let initial_key = [0x77u8; 32];
579 let chain_key = ChainKey::new(initial_key, 5);
580
581 let message_keys_separate = chain_key.message_keys().generate_keys();
583 let next_chain_separate = chain_key.next_chain_key().expect("chain key step");
584
585 let (message_keys_gen_combined, next_chain_combined) = chain_key
587 .step_with_message_keys()
588 .expect("step with message keys");
589 let message_keys_combined = message_keys_gen_combined.generate_keys();
590
591 assert_eq!(
593 message_keys_separate.cipher_key(),
594 message_keys_combined.cipher_key()
595 );
596 assert_eq!(
597 message_keys_separate.mac_key(),
598 message_keys_combined.mac_key()
599 );
600 assert_eq!(message_keys_separate.iv(), message_keys_combined.iv());
601 assert_eq!(
602 message_keys_separate.counter(),
603 message_keys_combined.counter()
604 );
605
606 assert_eq!(next_chain_separate.key(), next_chain_combined.key());
608 assert_eq!(next_chain_separate.index(), next_chain_combined.index());
609 }
610
611 #[test]
613 fn test_step_with_message_keys_chain() {
614 let initial_key = [0x88u8; 32];
615 let mut chain_separate = ChainKey::new(initial_key, 0);
616 let mut chain_combined = ChainKey::new(initial_key, 0);
617
618 for i in 0..10 {
620 let msg_keys_sep = chain_separate.message_keys().generate_keys();
621 chain_separate = chain_separate.next_chain_key().expect("chain key step");
622
623 let (msg_keys_gen_comb, next_chain) = chain_combined
624 .step_with_message_keys()
625 .expect("step with message keys");
626 let msg_keys_comb = msg_keys_gen_comb.generate_keys();
627 chain_combined = next_chain;
628
629 assert_eq!(
631 msg_keys_sep.cipher_key(),
632 msg_keys_comb.cipher_key(),
633 "cipher_key mismatch at iteration {i}"
634 );
635
636 assert_eq!(
638 chain_separate.key(),
639 chain_combined.key(),
640 "chain key mismatch at iteration {i}"
641 );
642 assert_eq!(chain_separate.index(), chain_combined.index());
643 }
644 }
645
646 #[test]
648 fn test_chain_key_overflow_regression() {
649 let chain = ChainKey::new([0xFFu8; 32], u32::MAX);
650 assert!(matches!(
651 chain.next_chain_key(),
652 Err(crate::protocol::SignalProtocolError::InvalidState(..))
653 ));
654 }
655
656 #[test]
658 fn test_chain_key_overflow_step_with_message_keys() {
659 let chain = ChainKey::new([0xEEu8; 32], u32::MAX);
660 assert!(matches!(
661 chain.step_with_message_keys(),
662 Err(crate::protocol::SignalProtocolError::InvalidState(..))
663 ));
664 }
665
666 #[test]
668 fn test_chain_key_overflow_boundary() {
669 let chain_at_max = ChainKey::new([0xDDu8; 32], u32::MAX - 1)
670 .next_chain_key()
671 .expect("advance to u32::MAX");
672 assert_eq!(chain_at_max.index(), u32::MAX);
673 assert!(chain_at_max.next_chain_key().is_err());
674 }
675
676 #[test]
678 fn test_chain_key_overflow_chained_advances() {
679 let c1 = ChainKey::new([0xCCu8; 32], u32::MAX - 3);
680 let c2 = c1.next_chain_key().expect("to MAX-2");
681 let c3 = c2.next_chain_key().expect("to MAX-1");
682 let c4 = c3.next_chain_key().expect("to MAX");
683 assert_eq!(c4.index(), u32::MAX);
684 assert!(c4.next_chain_key().is_err());
685 }
686}