ratchet.rs (57720B)
1 use crate::error::RadrootsSimplexSmpCryptoError; 2 use crate::message::{ 3 RADROOTS_SIMPLEX_SMP_NONCE_LENGTH, RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH, decrypt_padded, 4 encrypt_padded, 5 }; 6 use crate::official_ratchet::{ 7 RADROOTS_SIMPLEX_OFFICIAL_AES_IV_LENGTH, RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION, 8 RADROOTS_SIMPLEX_OFFICIAL_SNTRUP761_PRIVATE_KEY_LENGTH, 9 RADROOTS_SIMPLEX_OFFICIAL_SNTRUP761_PUBLIC_KEY_LENGTH, 10 RADROOTS_SIMPLEX_OFFICIAL_X448_KEY_LENGTH, RadrootsSimplexOfficialAesGcmPayload, 11 RadrootsSimplexOfficialEncryptedHeader, RadrootsSimplexOfficialEncryptedMessage, 12 RadrootsSimplexOfficialMsgHeader, RadrootsSimplexOfficialSntrup761Keypair, 13 RadrootsSimplexOfficialX3dhInit, decapsulate_official_sntrup761, 14 decode_official_encrypted_header, decode_official_encrypted_message, 15 decode_official_msg_header, derive_official_x448_shared_secret, encapsulate_official_sntrup761, 16 encode_official_encrypted_header, encode_official_encrypted_message, 17 encode_official_msg_header, generate_official_sntrup761_keypair, 18 generate_official_x448_keypair, official_aes_gcm_decrypt_padded, 19 official_aes_gcm_encrypt_padded, official_chain_kdf, official_ratchet_header_len, 20 official_root_kdf, 21 }; 22 use alloc::vec::Vec; 23 use hkdf::Hkdf; 24 use sha2::Sha512; 25 26 const RADROOTS_SIMPLEX_AGENT_RATCHET_INFO: &[u8] = b"SimpleXAgentRatchetMessage"; 27 const RADROOTS_SIMPLEX_AGENT_RATCHET_OUTPUT_LENGTH: usize = 28 RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH + RADROOTS_SIMPLEX_SMP_NONCE_LENGTH; 29 const RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES: u32 = 512; 30 31 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 32 pub enum RadrootsSimplexSmpRatchetRole { 33 Initiator, 34 Responder, 35 } 36 37 #[derive(Debug, Clone, PartialEq, Eq)] 38 pub struct RadrootsSimplexSmpRatchetHeader { 39 pub previous_sending_chain_length: u32, 40 pub message_number: u32, 41 pub dh_public_key: Vec<u8>, 42 pub pq_public_key: Option<Vec<u8>>, 43 pub pq_ciphertext: Option<Vec<u8>>, 44 } 45 46 impl RadrootsSimplexSmpRatchetHeader { 47 pub fn validate(&self) -> Result<(), RadrootsSimplexSmpCryptoError> { 48 if self.dh_public_key.is_empty() { 49 return Err(RadrootsSimplexSmpCryptoError::MissingRatchetKey( 50 "dh_public_key", 51 )); 52 } 53 if self.pq_ciphertext.is_some() && self.pq_public_key.is_none() { 54 return Err(RadrootsSimplexSmpCryptoError::IncompletePqHeader); 55 } 56 Ok(()) 57 } 58 } 59 60 #[derive(Debug, Clone, PartialEq, Eq)] 61 pub struct RadrootsSimplexSmpSkippedMessageKey { 62 pub header_key: Vec<u8>, 63 pub message_number: u32, 64 pub message_key: Vec<u8>, 65 pub message_iv: [u8; RADROOTS_SIMPLEX_OFFICIAL_AES_IV_LENGTH], 66 } 67 68 #[derive(Debug, Clone, PartialEq, Eq)] 69 pub struct RadrootsSimplexSmpRatchetState { 70 pub role: RadrootsSimplexSmpRatchetRole, 71 pub root_epoch: u64, 72 pub previous_sending_chain_length: u32, 73 pub sending_chain_length: u32, 74 pub receiving_chain_length: u32, 75 pub local_dh_public_key: Vec<u8>, 76 pub remote_dh_public_key: Vec<u8>, 77 pub current_pq_public_key: Option<Vec<u8>>, 78 pub remote_pq_public_key: Option<Vec<u8>>, 79 pub pending_outbound_pq_ciphertext: Option<Vec<u8>>, 80 pub pending_inbound_pq_ciphertext: Option<Vec<u8>>, 81 pub current_pq_shared_secret: Option<Vec<u8>>, 82 pub local_pq_private_key: Option<Vec<u8>>, 83 pub local_dh_private_key: Option<Vec<u8>>, 84 pub official_associated_data: Option<Vec<u8>>, 85 pub official_root_key: Option<Vec<u8>>, 86 pub official_sending_chain_key: Option<Vec<u8>>, 87 pub official_receiving_chain_key: Option<Vec<u8>>, 88 pub official_sending_header_key: Option<Vec<u8>>, 89 pub official_receiving_header_key: Option<Vec<u8>>, 90 pub official_next_sending_header_key: Option<Vec<u8>>, 91 pub official_next_receiving_header_key: Option<Vec<u8>>, 92 pub official_skipped_message_keys: Vec<RadrootsSimplexSmpSkippedMessageKey>, 93 } 94 95 impl RadrootsSimplexSmpRatchetState { 96 pub fn initiator( 97 local_dh_public_key: Vec<u8>, 98 remote_dh_public_key: Vec<u8>, 99 remote_pq_public_key: Option<Vec<u8>>, 100 ) -> Result<Self, RadrootsSimplexSmpCryptoError> { 101 validate_public_key(&local_dh_public_key)?; 102 validate_public_key(&remote_dh_public_key)?; 103 if let Some(key) = remote_pq_public_key.as_deref() { 104 validate_public_key(key)?; 105 } 106 107 Ok(Self { 108 role: RadrootsSimplexSmpRatchetRole::Initiator, 109 root_epoch: 0, 110 previous_sending_chain_length: 0, 111 sending_chain_length: 0, 112 receiving_chain_length: 0, 113 local_dh_public_key, 114 remote_dh_public_key, 115 current_pq_public_key: None, 116 remote_pq_public_key, 117 pending_outbound_pq_ciphertext: None, 118 pending_inbound_pq_ciphertext: None, 119 current_pq_shared_secret: None, 120 local_pq_private_key: None, 121 local_dh_private_key: None, 122 official_associated_data: None, 123 official_root_key: None, 124 official_sending_chain_key: None, 125 official_receiving_chain_key: None, 126 official_sending_header_key: None, 127 official_receiving_header_key: None, 128 official_next_sending_header_key: None, 129 official_next_receiving_header_key: None, 130 official_skipped_message_keys: Vec::new(), 131 }) 132 } 133 134 pub fn responder( 135 local_dh_public_key: Vec<u8>, 136 remote_dh_public_key: Vec<u8>, 137 local_pq_public_key: Option<Vec<u8>>, 138 ) -> Result<Self, RadrootsSimplexSmpCryptoError> { 139 validate_public_key(&local_dh_public_key)?; 140 validate_public_key(&remote_dh_public_key)?; 141 if let Some(key) = local_pq_public_key.as_deref() { 142 validate_public_key(key)?; 143 } 144 145 Ok(Self { 146 role: RadrootsSimplexSmpRatchetRole::Responder, 147 root_epoch: 0, 148 previous_sending_chain_length: 0, 149 sending_chain_length: 0, 150 receiving_chain_length: 0, 151 local_dh_public_key, 152 remote_dh_public_key, 153 current_pq_public_key: local_pq_public_key, 154 remote_pq_public_key: None, 155 pending_outbound_pq_ciphertext: None, 156 pending_inbound_pq_ciphertext: None, 157 current_pq_shared_secret: None, 158 local_pq_private_key: None, 159 local_dh_private_key: None, 160 official_associated_data: None, 161 official_root_key: None, 162 official_sending_chain_key: None, 163 official_receiving_chain_key: None, 164 official_sending_header_key: None, 165 official_receiving_header_key: None, 166 official_next_sending_header_key: None, 167 official_next_receiving_header_key: None, 168 official_skipped_message_keys: Vec::new(), 169 }) 170 } 171 172 pub fn initialize_official_sender( 173 &mut self, 174 local_dh_private_key: Vec<u8>, 175 init: RadrootsSimplexOfficialX3dhInit, 176 ) -> Result<(), RadrootsSimplexSmpCryptoError> { 177 validate_official_private_key(&local_dh_private_key)?; 178 let root_dh = 179 derive_official_x448_shared_secret(&local_dh_private_key, &self.remote_dh_public_key)?; 180 let root = official_root_kdf( 181 &init.ratchet_key, 182 &root_dh, 183 init.accepted_pq_shared_secret.as_deref(), 184 )?; 185 self.local_dh_private_key = Some(local_dh_private_key); 186 self.official_associated_data = Some(init.associated_data); 187 self.official_root_key = Some(root.root_key); 188 self.official_sending_chain_key = Some(root.chain_key); 189 self.official_receiving_chain_key = None; 190 self.current_pq_shared_secret = init.accepted_pq_shared_secret; 191 self.official_sending_header_key = Some(init.sending_header_key); 192 self.official_receiving_header_key = None; 193 self.official_next_sending_header_key = Some(root.next_header_key); 194 self.official_next_receiving_header_key = Some(init.receiving_next_header_key); 195 self.previous_sending_chain_length = 0; 196 self.sending_chain_length = 0; 197 self.receiving_chain_length = 0; 198 self.root_epoch = 0; 199 Ok(()) 200 } 201 202 pub fn initialize_official_receiver( 203 &mut self, 204 local_dh_private_key: Vec<u8>, 205 init: RadrootsSimplexOfficialX3dhInit, 206 ) -> Result<(), RadrootsSimplexSmpCryptoError> { 207 validate_official_private_key(&local_dh_private_key)?; 208 self.local_dh_private_key = Some(local_dh_private_key); 209 self.official_associated_data = Some(init.associated_data); 210 self.official_root_key = Some(init.ratchet_key); 211 self.current_pq_shared_secret = init.accepted_pq_shared_secret; 212 self.official_sending_chain_key = None; 213 self.official_receiving_chain_key = None; 214 self.official_sending_header_key = None; 215 self.official_receiving_header_key = None; 216 self.official_next_sending_header_key = Some(init.receiving_next_header_key); 217 self.official_next_receiving_header_key = Some(init.sending_header_key); 218 self.previous_sending_chain_length = 0; 219 self.sending_chain_length = 0; 220 self.receiving_chain_length = 0; 221 self.root_epoch = 0; 222 Ok(()) 223 } 224 225 pub fn stage_outbound_pq_step( 226 &mut self, 227 pq_public_key: Vec<u8>, 228 pq_ciphertext: Vec<u8>, 229 shared_secret: Vec<u8>, 230 ) -> Result<(), RadrootsSimplexSmpCryptoError> { 231 validate_public_key(&pq_public_key)?; 232 if pq_ciphertext.is_empty() { 233 return Err(RadrootsSimplexSmpCryptoError::InvalidCiphertextLength(0)); 234 } 235 if shared_secret.is_empty() { 236 return Err(RadrootsSimplexSmpCryptoError::InvalidSharedSecretLength(0)); 237 } 238 239 self.current_pq_public_key = Some(pq_public_key); 240 self.pending_outbound_pq_ciphertext = Some(pq_ciphertext); 241 self.current_pq_shared_secret = Some(shared_secret); 242 self.root_epoch = self.root_epoch.saturating_add(1); 243 Ok(()) 244 } 245 246 pub fn next_outbound_header( 247 &mut self, 248 ) -> Result<RadrootsSimplexSmpRatchetHeader, RadrootsSimplexSmpCryptoError> { 249 validate_public_key(&self.local_dh_public_key)?; 250 let header = RadrootsSimplexSmpRatchetHeader { 251 previous_sending_chain_length: self.previous_sending_chain_length, 252 message_number: self.sending_chain_length, 253 dh_public_key: self.local_dh_public_key.clone(), 254 pq_public_key: self.current_pq_public_key.clone(), 255 pq_ciphertext: self.pending_outbound_pq_ciphertext.clone(), 256 }; 257 header.validate()?; 258 self.sending_chain_length = self.sending_chain_length.saturating_add(1); 259 Ok(header) 260 } 261 262 pub fn apply_inbound_header( 263 &mut self, 264 header: &RadrootsSimplexSmpRatchetHeader, 265 next_local_dh_public_key: Option<Vec<u8>>, 266 ) -> Result<bool, RadrootsSimplexSmpCryptoError> { 267 header.validate()?; 268 let dh_advanced = header.dh_public_key != self.remote_dh_public_key; 269 270 if dh_advanced { 271 self.previous_sending_chain_length = self.sending_chain_length; 272 self.sending_chain_length = 0; 273 self.remote_dh_public_key = header.dh_public_key.clone(); 274 if let Some(next_local_key) = next_local_dh_public_key { 275 validate_public_key(&next_local_key)?; 276 self.local_dh_public_key = next_local_key; 277 } 278 self.root_epoch = self.root_epoch.saturating_add(1); 279 } else if header.message_number < self.receiving_chain_length { 280 return Err(RadrootsSimplexSmpCryptoError::RatchetMessageRegression { 281 received: header.message_number, 282 current: self.receiving_chain_length, 283 }); 284 } 285 286 self.receiving_chain_length = header.message_number.saturating_add(1); 287 if let Some(public_key) = header.pq_public_key.as_ref() { 288 self.remote_pq_public_key = Some(public_key.clone()); 289 } 290 if let Some(ciphertext) = header.pq_ciphertext.as_ref() { 291 self.pending_inbound_pq_ciphertext = Some(ciphertext.clone()); 292 } 293 294 Ok(dh_advanced) 295 } 296 297 pub fn complete_inbound_pq_step( 298 &mut self, 299 shared_secret: Vec<u8>, 300 ) -> Result<(), RadrootsSimplexSmpCryptoError> { 301 if shared_secret.is_empty() { 302 return Err(RadrootsSimplexSmpCryptoError::InvalidSharedSecretLength(0)); 303 } 304 self.current_pq_shared_secret = Some(shared_secret); 305 self.pending_inbound_pq_ciphertext = None; 306 self.root_epoch = self.root_epoch.saturating_add(1); 307 Ok(()) 308 } 309 310 pub fn encrypt_payload( 311 &mut self, 312 shared_secret: &[u8], 313 plaintext: &[u8], 314 padded_len: usize, 315 ) -> Result<(RadrootsSimplexSmpRatchetHeader, Vec<u8>), RadrootsSimplexSmpCryptoError> { 316 let header = self.next_outbound_header()?; 317 let associated_data = ratchet_header_associated_data(&header)?; 318 let (message_key, nonce) = derive_ratchet_message_key( 319 shared_secret, 320 self.current_pq_shared_secret.as_deref(), 321 self.root_epoch, 322 &associated_data, 323 )?; 324 let ciphertext = encrypt_padded(&message_key, &nonce, plaintext, padded_len)?; 325 Ok((header, ciphertext)) 326 } 327 328 pub fn decrypt_payload( 329 &mut self, 330 shared_secret: &[u8], 331 header: &RadrootsSimplexSmpRatchetHeader, 332 ciphertext: &[u8], 333 ) -> Result<Vec<u8>, RadrootsSimplexSmpCryptoError> { 334 header.validate()?; 335 if header.message_number < self.receiving_chain_length { 336 return Err(RadrootsSimplexSmpCryptoError::RatchetMessageRegression { 337 received: header.message_number, 338 current: self.receiving_chain_length, 339 }); 340 } 341 let associated_data = ratchet_header_associated_data(header)?; 342 let (message_key, nonce) = derive_ratchet_message_key( 343 shared_secret, 344 self.current_pq_shared_secret.as_deref(), 345 self.root_epoch, 346 &associated_data, 347 )?; 348 let plaintext = decrypt_padded(&message_key, &nonce, ciphertext)?; 349 self.apply_inbound_header(header, None)?; 350 Ok(plaintext) 351 } 352 353 pub fn encrypt_official_payload( 354 &mut self, 355 _shared_secret: &[u8], 356 plaintext: &[u8], 357 padded_len: usize, 358 ) -> Result<Vec<u8>, RadrootsSimplexSmpCryptoError> { 359 let message_number = self.sending_chain_length; 360 let header = RadrootsSimplexSmpRatchetHeader { 361 previous_sending_chain_length: self.previous_sending_chain_length, 362 message_number, 363 dh_public_key: self.local_dh_public_key.clone(), 364 pq_public_key: self.current_pq_public_key.clone(), 365 pq_ciphertext: self.pending_outbound_pq_ciphertext.clone(), 366 }; 367 header.validate()?; 368 let header_plaintext = encode_official_msg_header( 369 RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION, 370 &official_msg_header_from_ratchet_header(&header), 371 )?; 372 let ratchet_ad = self.official_associated_data.clone().ok_or( 373 RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_associated_data"), 374 )?; 375 let sending_header_key = self.official_sending_header_key.clone().ok_or( 376 RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_sending_header_key"), 377 )?; 378 let sending_chain_key = self.official_sending_chain_key.clone().ok_or( 379 RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_sending_chain_key"), 380 )?; 381 let chain = official_chain_kdf(&sending_chain_key)?; 382 let header_payload = official_aes_gcm_encrypt_padded( 383 &sending_header_key, 384 &chain.header_iv, 385 &header_plaintext, 386 official_ratchet_header_len( 387 RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION, 388 self.pq_enabled(), 389 )?, 390 &ratchet_ad, 391 )?; 392 let encrypted_header = encode_official_encrypted_header(&official_encrypted_header( 393 chain.header_iv, 394 header_payload, 395 )?)?; 396 let message_ad = official_message_associated_data(&ratchet_ad, &encrypted_header); 397 let message_payload = official_aes_gcm_encrypt_padded( 398 &chain.message_key, 399 &chain.message_iv, 400 plaintext, 401 padded_len, 402 &message_ad, 403 )?; 404 self.official_sending_chain_key = Some(chain.chain_key); 405 self.sending_chain_length = self.sending_chain_length.saturating_add(1); 406 encode_official_encrypted_message( 407 RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION, 408 &RadrootsSimplexOfficialEncryptedMessage { 409 encrypted_header, 410 auth_tag: message_payload.auth_tag, 411 body: message_payload.ciphertext, 412 }, 413 ) 414 } 415 416 pub fn decrypt_official_payload( 417 &mut self, 418 _shared_secret: &[u8], 419 encrypted_message: &[u8], 420 ) -> Result<Vec<u8>, RadrootsSimplexSmpCryptoError> { 421 let message = decode_official_encrypted_message(encrypted_message)?; 422 let header = decode_official_encrypted_header(&message.encrypted_header)?; 423 let ratchet_ad = self.official_associated_data.clone().ok_or( 424 RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_associated_data"), 425 )?; 426 if let Some(plaintext) = 427 self.decrypt_official_skipped_payload(&header, &message, &ratchet_ad)? 428 { 429 return Ok(plaintext); 430 } 431 let (ratchet_step, ratchet_header) = self.decrypt_official_header(&header, &ratchet_ad)?; 432 if ratchet_header.message_number < self.receiving_chain_length { 433 return Err(RadrootsSimplexSmpCryptoError::RatchetMessageRegression { 434 received: ratchet_header.message_number, 435 current: self.receiving_chain_length, 436 }); 437 } 438 if ratchet_step == OfficialRatchetStep::Advance { 439 self.skip_official_receiving_messages_until( 440 ratchet_header.previous_sending_chain_length, 441 )?; 442 self.advance_official_receiving_ratchet(&ratchet_header)?; 443 } 444 self.skip_official_receiving_messages_until(ratchet_header.message_number)?; 445 let receiving_chain_key = self.official_receiving_chain_key.clone().ok_or( 446 RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_receiving_chain_key"), 447 )?; 448 let chain = official_chain_kdf(&receiving_chain_key)?; 449 let message_ad = official_message_associated_data(&ratchet_ad, &message.encrypted_header); 450 let plaintext = official_aes_gcm_decrypt_padded( 451 &chain.message_key, 452 &chain.message_iv, 453 &RadrootsSimplexOfficialAesGcmPayload { 454 auth_tag: message.auth_tag, 455 ciphertext: message.body, 456 }, 457 &message_ad, 458 )?; 459 self.official_receiving_chain_key = Some(chain.chain_key); 460 self.apply_inbound_header(&ratchet_header, None)?; 461 Ok(plaintext) 462 } 463 464 pub fn is_official_payload_replay( 465 &self, 466 encrypted_message: &[u8], 467 ) -> Result<bool, RadrootsSimplexSmpCryptoError> { 468 let message = decode_official_encrypted_message(encrypted_message)?; 469 let header = decode_official_encrypted_header(&message.encrypted_header)?; 470 let ratchet_ad = self.official_associated_data.clone().ok_or( 471 RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_associated_data"), 472 )?; 473 for skipped in &self.official_skipped_message_keys { 474 if let Ok(ratchet_header) = 475 decrypt_official_header_with_key(&header, &skipped.header_key, &ratchet_ad) 476 && ratchet_header.message_number == skipped.message_number 477 { 478 return Ok(false); 479 } 480 } 481 if let Some(receiving_header_key) = self.official_receiving_header_key.as_ref() 482 && let Ok(ratchet_header) = 483 decrypt_official_header_with_key(&header, receiving_header_key, &ratchet_ad) 484 { 485 return Ok(ratchet_header.message_number < self.receiving_chain_length); 486 } 487 if let Some(next_receiving_header_key) = self.official_next_receiving_header_key.as_ref() 488 && let Ok(ratchet_header) = 489 decrypt_official_header_with_key(&header, next_receiving_header_key, &ratchet_ad) 490 { 491 return Ok(ratchet_header.message_number < self.receiving_chain_length 492 && ratchet_header.previous_sending_chain_length < self.receiving_chain_length); 493 } 494 Ok(false) 495 } 496 497 fn decrypt_official_skipped_payload( 498 &mut self, 499 header: &RadrootsSimplexOfficialEncryptedHeader, 500 message: &RadrootsSimplexOfficialEncryptedMessage, 501 ratchet_ad: &[u8], 502 ) -> Result<Option<Vec<u8>>, RadrootsSimplexSmpCryptoError> { 503 for skipped in self.official_skipped_message_keys.clone() { 504 let Ok(ratchet_header) = 505 decrypt_official_header_with_key(header, &skipped.header_key, ratchet_ad) 506 else { 507 continue; 508 }; 509 if ratchet_header.message_number != skipped.message_number { 510 continue; 511 } 512 let position = self 513 .official_skipped_message_keys 514 .iter() 515 .position(|entry| { 516 entry.header_key == skipped.header_key 517 && entry.message_number == skipped.message_number 518 }) 519 .ok_or(RadrootsSimplexSmpCryptoError::RatchetMessageRegression { 520 received: ratchet_header.message_number, 521 current: self.receiving_chain_length, 522 })?; 523 let skipped = self.official_skipped_message_keys.remove(position); 524 let message_ad = 525 official_message_associated_data(ratchet_ad, &message.encrypted_header); 526 let plaintext = official_aes_gcm_decrypt_padded( 527 &skipped.message_key, 528 &skipped.message_iv, 529 &RadrootsSimplexOfficialAesGcmPayload { 530 auth_tag: message.auth_tag.clone(), 531 ciphertext: message.body.clone(), 532 }, 533 &message_ad, 534 )?; 535 return Ok(Some(plaintext)); 536 } 537 Ok(None) 538 } 539 540 fn skip_official_receiving_messages_until( 541 &mut self, 542 until_message_number: u32, 543 ) -> Result<(), RadrootsSimplexSmpCryptoError> { 544 if self.receiving_chain_length > until_message_number { 545 return Err(RadrootsSimplexSmpCryptoError::RatchetMessageRegression { 546 received: until_message_number, 547 current: self.receiving_chain_length, 548 }); 549 } 550 let skipped = until_message_number.saturating_sub(self.receiving_chain_length); 551 if skipped > RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES { 552 return Err(RadrootsSimplexSmpCryptoError::RatchetTooManySkipped { 553 skipped, 554 max: RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES, 555 }); 556 } 557 if skipped == 0 { 558 return Ok(()); 559 } 560 let mut receiving_chain_key = self.official_receiving_chain_key.clone().ok_or( 561 RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_receiving_chain_key"), 562 )?; 563 let receiving_header_key = self.official_receiving_header_key.clone().ok_or( 564 RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_receiving_header_key"), 565 )?; 566 while self.receiving_chain_length < until_message_number { 567 let chain = official_chain_kdf(&receiving_chain_key)?; 568 self.official_skipped_message_keys 569 .push(RadrootsSimplexSmpSkippedMessageKey { 570 header_key: receiving_header_key.clone(), 571 message_number: self.receiving_chain_length, 572 message_key: chain.message_key, 573 message_iv: chain.message_iv, 574 }); 575 receiving_chain_key = chain.chain_key; 576 self.receiving_chain_length = self.receiving_chain_length.saturating_add(1); 577 } 578 self.official_receiving_chain_key = Some(receiving_chain_key); 579 Ok(()) 580 } 581 582 fn decrypt_official_header( 583 &self, 584 header: &RadrootsSimplexOfficialEncryptedHeader, 585 ratchet_ad: &[u8], 586 ) -> Result<(OfficialRatchetStep, RadrootsSimplexSmpRatchetHeader), RadrootsSimplexSmpCryptoError> 587 { 588 if let Some(receiving_header_key) = self.official_receiving_header_key.as_ref() 589 && let Ok(ratchet_header) = 590 decrypt_official_header_with_key(header, receiving_header_key, ratchet_ad) 591 { 592 return Ok((OfficialRatchetStep::Same, ratchet_header)); 593 } 594 let next_receiving_header_key = self.official_next_receiving_header_key.as_ref().ok_or( 595 RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_next_receiving_header_key"), 596 )?; 597 decrypt_official_header_with_key(header, next_receiving_header_key, ratchet_ad) 598 .map(|ratchet_header| (OfficialRatchetStep::Advance, ratchet_header)) 599 } 600 601 fn advance_official_receiving_ratchet( 602 &mut self, 603 header: &RadrootsSimplexSmpRatchetHeader, 604 ) -> Result<(), RadrootsSimplexSmpCryptoError> { 605 let pq_step = self.official_pq_receiving_step(header)?; 606 let local_private_key = self.local_dh_private_key.clone().ok_or( 607 RadrootsSimplexSmpCryptoError::MissingRatchetKey("local_dh_private_key"), 608 )?; 609 let root_key = self.official_root_key.clone().ok_or( 610 RadrootsSimplexSmpCryptoError::MissingRatchetKey("official_root_key"), 611 )?; 612 let receiving_dh = 613 derive_official_x448_shared_secret(&local_private_key, &header.dh_public_key)?; 614 let receiving_root = official_root_kdf( 615 &root_key, 616 &receiving_dh, 617 pq_step.receiving_shared_secret.as_deref(), 618 )?; 619 let next_local_keypair = generate_official_x448_keypair()?; 620 let sending_dh = derive_official_x448_shared_secret( 621 &next_local_keypair.private_key, 622 &header.dh_public_key, 623 )?; 624 let sending_root = official_root_kdf( 625 &receiving_root.root_key, 626 &sending_dh, 627 pq_step.sending_shared_secret.as_deref(), 628 )?; 629 self.previous_sending_chain_length = self.sending_chain_length; 630 self.sending_chain_length = 0; 631 self.receiving_chain_length = 0; 632 self.remote_dh_public_key = header.dh_public_key.clone(); 633 self.remote_pq_public_key = header.pq_public_key.clone(); 634 self.pending_inbound_pq_ciphertext = header.pq_ciphertext.clone(); 635 if let Some(next_pq_keypair) = pq_step.next_local_keypair { 636 self.current_pq_public_key = Some(next_pq_keypair.public_key); 637 self.local_pq_private_key = Some(next_pq_keypair.private_key); 638 self.pending_outbound_pq_ciphertext = pq_step.pending_outbound_pq_ciphertext; 639 self.current_pq_shared_secret = pq_step.sending_shared_secret; 640 } else if pq_step.receiving_shared_secret.is_some() { 641 self.current_pq_shared_secret = pq_step.receiving_shared_secret; 642 } 643 self.local_dh_public_key = next_local_keypair.public_key; 644 self.local_dh_private_key = Some(next_local_keypair.private_key); 645 self.official_root_key = Some(sending_root.root_key); 646 self.official_receiving_chain_key = Some(receiving_root.chain_key); 647 self.official_receiving_header_key = self.official_next_receiving_header_key.take(); 648 self.official_next_receiving_header_key = Some(receiving_root.next_header_key); 649 self.official_sending_chain_key = Some(sending_root.chain_key); 650 self.official_sending_header_key = self.official_next_sending_header_key.take(); 651 self.official_next_sending_header_key = Some(sending_root.next_header_key); 652 Ok(()) 653 } 654 655 fn official_pq_receiving_step( 656 &self, 657 header: &RadrootsSimplexSmpRatchetHeader, 658 ) -> Result<OfficialPqReceivingStep, RadrootsSimplexSmpCryptoError> { 659 let Some(remote_pq_public_key) = header.pq_public_key.as_deref() else { 660 return Ok(OfficialPqReceivingStep::default()); 661 }; 662 validate_official_pq_public_key(remote_pq_public_key)?; 663 let receiving_shared_secret = match header.pq_ciphertext.as_deref() { 664 Some(ciphertext) => { 665 let local_pq_private_key = self.local_pq_private_key.as_deref().ok_or( 666 RadrootsSimplexSmpCryptoError::MissingRatchetKey("local_pq_private_key"), 667 )?; 668 validate_official_pq_private_key(local_pq_private_key)?; 669 Some(decapsulate_official_sntrup761( 670 local_pq_private_key, 671 ciphertext, 672 )?) 673 } 674 None => None, 675 }; 676 if !self.pq_enabled() { 677 return Ok(OfficialPqReceivingStep { 678 receiving_shared_secret, 679 ..OfficialPqReceivingStep::default() 680 }); 681 } 682 let next_local_keypair = generate_official_sntrup761_keypair()?; 683 let seed = random_official_pq_seed()?; 684 let (pending_outbound_pq_ciphertext, sending_shared_secret) = 685 encapsulate_official_sntrup761(remote_pq_public_key, &seed)?; 686 Ok(OfficialPqReceivingStep { 687 receiving_shared_secret, 688 next_local_keypair: Some(next_local_keypair), 689 pending_outbound_pq_ciphertext: Some(pending_outbound_pq_ciphertext), 690 sending_shared_secret: Some(sending_shared_secret), 691 }) 692 } 693 694 fn pq_enabled(&self) -> bool { 695 self.current_pq_public_key.is_some() 696 || self.remote_pq_public_key.is_some() 697 || self.current_pq_shared_secret.is_some() 698 || self.local_pq_private_key.is_some() 699 } 700 } 701 702 #[derive(Debug, Default, Clone, PartialEq, Eq)] 703 struct OfficialPqReceivingStep { 704 receiving_shared_secret: Option<Vec<u8>>, 705 next_local_keypair: Option<RadrootsSimplexOfficialSntrup761Keypair>, 706 pending_outbound_pq_ciphertext: Option<Vec<u8>>, 707 sending_shared_secret: Option<Vec<u8>>, 708 } 709 710 fn validate_public_key(value: &[u8]) -> Result<(), RadrootsSimplexSmpCryptoError> { 711 if value.is_empty() { 712 return Err(RadrootsSimplexSmpCryptoError::InvalidPublicKeyLength(0)); 713 } 714 Ok(()) 715 } 716 717 fn validate_official_pq_public_key(value: &[u8]) -> Result<(), RadrootsSimplexSmpCryptoError> { 718 if value.len() != RADROOTS_SIMPLEX_OFFICIAL_SNTRUP761_PUBLIC_KEY_LENGTH { 719 return Err(RadrootsSimplexSmpCryptoError::InvalidPqKeyLength( 720 value.len(), 721 )); 722 } 723 Ok(()) 724 } 725 726 fn validate_official_pq_private_key(value: &[u8]) -> Result<(), RadrootsSimplexSmpCryptoError> { 727 if value.len() != RADROOTS_SIMPLEX_OFFICIAL_SNTRUP761_PRIVATE_KEY_LENGTH { 728 return Err(RadrootsSimplexSmpCryptoError::InvalidPrivateKeyLength( 729 value.len(), 730 )); 731 } 732 Ok(()) 733 } 734 735 fn random_official_pq_seed() -> Result<[u8; 32], RadrootsSimplexSmpCryptoError> { 736 let mut seed = [0_u8; 32]; 737 getrandom::getrandom(&mut seed) 738 .map_err(|_| RadrootsSimplexSmpCryptoError::EntropyUnavailable)?; 739 Ok(seed) 740 } 741 742 fn validate_official_private_key(value: &[u8]) -> Result<(), RadrootsSimplexSmpCryptoError> { 743 if value.len() != RADROOTS_SIMPLEX_OFFICIAL_X448_KEY_LENGTH { 744 return Err(RadrootsSimplexSmpCryptoError::InvalidPrivateKeyLength( 745 value.len(), 746 )); 747 } 748 Ok(()) 749 } 750 751 fn derive_ratchet_message_key( 752 shared_secret: &[u8], 753 pq_shared_secret: Option<&[u8]>, 754 root_epoch: u64, 755 associated_data: &[u8], 756 ) -> Result<(Vec<u8>, [u8; RADROOTS_SIMPLEX_SMP_NONCE_LENGTH]), RadrootsSimplexSmpCryptoError> { 757 let mut ikm = Vec::with_capacity(shared_secret.len() + pq_shared_secret.map_or(0, <[u8]>::len)); 758 ikm.extend_from_slice(shared_secret); 759 if let Some(secret) = pq_shared_secret { 760 ikm.extend_from_slice(secret); 761 } 762 let mut salt = Vec::with_capacity(8 + associated_data.len()); 763 salt.extend_from_slice(&root_epoch.to_be_bytes()); 764 salt.extend_from_slice(associated_data); 765 let hkdf = Hkdf::<Sha512>::new(Some(&salt), &ikm); 766 let mut output = [0_u8; RADROOTS_SIMPLEX_AGENT_RATCHET_OUTPUT_LENGTH]; 767 hkdf.expand(RADROOTS_SIMPLEX_AGENT_RATCHET_INFO, &mut output) 768 .map_err(|_| { 769 RadrootsSimplexSmpCryptoError::InvalidKeyDerivationLength( 770 RADROOTS_SIMPLEX_AGENT_RATCHET_OUTPUT_LENGTH, 771 ) 772 })?; 773 let mut nonce = [0_u8; RADROOTS_SIMPLEX_SMP_NONCE_LENGTH]; 774 nonce.copy_from_slice(&output[RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH..]); 775 Ok(( 776 output[..RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH].to_vec(), 777 nonce, 778 )) 779 } 780 781 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 782 enum OfficialRatchetStep { 783 Same, 784 Advance, 785 } 786 787 fn decrypt_official_header_with_key( 788 header: &RadrootsSimplexOfficialEncryptedHeader, 789 header_key: &[u8], 790 ratchet_ad: &[u8], 791 ) -> Result<RadrootsSimplexSmpRatchetHeader, RadrootsSimplexSmpCryptoError> { 792 let header_plaintext = official_aes_gcm_decrypt_padded( 793 header_key, 794 &header.iv, 795 &RadrootsSimplexOfficialAesGcmPayload { 796 auth_tag: header.auth_tag.clone(), 797 ciphertext: header.body.clone(), 798 }, 799 ratchet_ad, 800 )?; 801 Ok(ratchet_header_from_official_msg_header( 802 decode_official_msg_header(header.version, &header_plaintext)?, 803 )) 804 } 805 806 fn official_encrypted_header( 807 iv: [u8; crate::official_ratchet::RADROOTS_SIMPLEX_OFFICIAL_AES_IV_LENGTH], 808 payload: RadrootsSimplexOfficialAesGcmPayload, 809 ) -> Result<RadrootsSimplexOfficialEncryptedHeader, RadrootsSimplexSmpCryptoError> { 810 Ok(RadrootsSimplexOfficialEncryptedHeader { 811 version: RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION, 812 iv, 813 auth_tag: payload.auth_tag, 814 body: payload.ciphertext, 815 }) 816 } 817 818 fn official_message_associated_data(ratchet_ad: &[u8], encrypted_header: &[u8]) -> Vec<u8> { 819 let mut associated_data = Vec::with_capacity(ratchet_ad.len() + encrypted_header.len()); 820 associated_data.extend_from_slice(ratchet_ad); 821 associated_data.extend_from_slice(encrypted_header); 822 associated_data 823 } 824 825 fn official_msg_header_from_ratchet_header( 826 header: &RadrootsSimplexSmpRatchetHeader, 827 ) -> RadrootsSimplexOfficialMsgHeader { 828 RadrootsSimplexOfficialMsgHeader { 829 max_version: RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION, 830 dh_public_key: header.dh_public_key.clone(), 831 pq_public_key: header.pq_public_key.clone(), 832 pq_ciphertext: header.pq_ciphertext.clone(), 833 previous_sending_chain_length: header.previous_sending_chain_length, 834 message_number: header.message_number, 835 } 836 } 837 838 fn ratchet_header_from_official_msg_header( 839 header: RadrootsSimplexOfficialMsgHeader, 840 ) -> RadrootsSimplexSmpRatchetHeader { 841 RadrootsSimplexSmpRatchetHeader { 842 previous_sending_chain_length: header.previous_sending_chain_length, 843 message_number: header.message_number, 844 dh_public_key: header.dh_public_key, 845 pq_public_key: header.pq_public_key, 846 pq_ciphertext: header.pq_ciphertext, 847 } 848 } 849 850 fn ratchet_header_associated_data( 851 header: &RadrootsSimplexSmpRatchetHeader, 852 ) -> Result<Vec<u8>, RadrootsSimplexSmpCryptoError> { 853 let mut buffer = Vec::new(); 854 buffer.extend_from_slice(&header.previous_sending_chain_length.to_be_bytes()); 855 buffer.extend_from_slice(&header.message_number.to_be_bytes()); 856 push_large_bytes(&mut buffer, &header.dh_public_key)?; 857 push_maybe_large_bytes(&mut buffer, header.pq_public_key.as_deref())?; 858 push_maybe_large_bytes(&mut buffer, header.pq_ciphertext.as_deref())?; 859 Ok(buffer) 860 } 861 862 fn push_maybe_large_bytes( 863 buffer: &mut Vec<u8>, 864 value: Option<&[u8]>, 865 ) -> Result<(), RadrootsSimplexSmpCryptoError> { 866 match value { 867 Some(value) => { 868 buffer.push(1); 869 push_large_bytes(buffer, value) 870 } 871 None => { 872 buffer.push(0); 873 Ok(()) 874 } 875 } 876 } 877 878 fn push_large_bytes( 879 buffer: &mut Vec<u8>, 880 value: &[u8], 881 ) -> Result<(), RadrootsSimplexSmpCryptoError> { 882 if value.len() > u16::MAX as usize { 883 return Err(RadrootsSimplexSmpCryptoError::InvalidMessageLength { 884 actual: value.len(), 885 padded: u16::MAX as usize, 886 }); 887 } 888 buffer.extend_from_slice(&(value.len() as u16).to_be_bytes()); 889 buffer.extend_from_slice(value); 890 Ok(()) 891 } 892 893 #[cfg(test)] 894 mod tests { 895 use super::*; 896 use crate::official_ratchet::{ 897 RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION, RADROOTS_SIMPLEX_OFFICIAL_E2E_KDF_VERSION, 898 RadrootsSimplexOfficialX3dhParams, decode_official_encrypted_header, 899 decode_official_encrypted_message, official_sntrup761_keypair_from_seed, 900 official_x3dh_receiver_init, official_x3dh_receiver_init_accepting_pq, 901 official_x3dh_sender_init, official_x3dh_sender_init_accepting_pq, 902 official_x448_keypair_from_seed, 903 }; 904 use radroots_simplex_smp_proto::prelude::RadrootsSimplexSmpVersionRange; 905 906 fn official_sender_receiver_ratchets() -> ( 907 RadrootsSimplexSmpRatchetState, 908 RadrootsSimplexSmpRatchetState, 909 ) { 910 let receiver_key_1 = official_x448_keypair_from_seed(b"rr-synth-ratchet-rcv-1"); 911 let receiver_key_2 = official_x448_keypair_from_seed(b"rr-synth-ratchet-rcv-2"); 912 let sender_key_1 = official_x448_keypair_from_seed(b"rr-synth-ratchet-snd-1"); 913 let sender_key_2 = official_x448_keypair_from_seed(b"rr-synth-ratchet-snd-2"); 914 let receiver_params = RadrootsSimplexOfficialX3dhParams { 915 version_range: RadrootsSimplexSmpVersionRange::new( 916 RADROOTS_SIMPLEX_OFFICIAL_E2E_KDF_VERSION, 917 RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION, 918 ) 919 .unwrap(), 920 key_1: receiver_key_1.public_key.clone(), 921 key_2: receiver_key_2.public_key.clone(), 922 pq_public_key: None, 923 pq_ciphertext: None, 924 }; 925 let sender_params = RadrootsSimplexOfficialX3dhParams { 926 version_range: receiver_params.version_range, 927 key_1: sender_key_1.public_key.clone(), 928 key_2: sender_key_2.public_key.clone(), 929 pq_public_key: None, 930 pq_ciphertext: None, 931 }; 932 let sender_init = 933 official_x3dh_sender_init(&sender_key_1, &sender_key_2, &receiver_params).unwrap(); 934 let receiver_init = 935 official_x3dh_receiver_init(&receiver_key_1, &receiver_key_2, &sender_params).unwrap(); 936 let mut sender = RadrootsSimplexSmpRatchetState::responder( 937 sender_key_2.public_key.clone(), 938 receiver_key_2.public_key.clone(), 939 None, 940 ) 941 .unwrap(); 942 sender 943 .initialize_official_sender(sender_key_2.private_key, sender_init) 944 .unwrap(); 945 let mut receiver = RadrootsSimplexSmpRatchetState::initiator( 946 receiver_key_2.public_key.clone(), 947 receiver_key_1.public_key.clone(), 948 None, 949 ) 950 .unwrap(); 951 receiver 952 .initialize_official_receiver(receiver_key_2.private_key, receiver_init) 953 .unwrap(); 954 (sender, receiver) 955 } 956 957 fn official_pq_sender_receiver_ratchets() -> ( 958 RadrootsSimplexSmpRatchetState, 959 RadrootsSimplexSmpRatchetState, 960 ) { 961 let receiver_key_1 = official_x448_keypair_from_seed(b"rr-synth-pq-ratchet-rcv-1"); 962 let receiver_key_2 = official_x448_keypair_from_seed(b"rr-synth-pq-ratchet-rcv-2"); 963 let receiver_pq_keypair = official_sntrup761_keypair_from_seed(b"rr-synth-pq-rcv-kem"); 964 let sender_key_1 = official_x448_keypair_from_seed(b"rr-synth-pq-ratchet-snd-1"); 965 let sender_key_2 = official_x448_keypair_from_seed(b"rr-synth-pq-ratchet-snd-2"); 966 let sender_pq_keypair = official_sntrup761_keypair_from_seed(b"rr-synth-pq-snd-kem"); 967 let receiver_params = RadrootsSimplexOfficialX3dhParams { 968 version_range: RadrootsSimplexSmpVersionRange::new( 969 RADROOTS_SIMPLEX_OFFICIAL_E2E_KDF_VERSION, 970 RADROOTS_SIMPLEX_OFFICIAL_E2E_CURRENT_VERSION, 971 ) 972 .unwrap(), 973 key_1: receiver_key_1.public_key.clone(), 974 key_2: receiver_key_2.public_key.clone(), 975 pq_public_key: Some(receiver_pq_keypair.public_key.clone()), 976 pq_ciphertext: None, 977 }; 978 let sender_init = official_x3dh_sender_init_accepting_pq( 979 &sender_key_1, 980 &sender_key_2, 981 sender_pq_keypair, 982 &receiver_params, 983 b"rr-synth-pq-x3dh-accept", 984 ) 985 .unwrap(); 986 let receiver_init = official_x3dh_receiver_init_accepting_pq( 987 &receiver_key_1, 988 &receiver_key_2, 989 &receiver_pq_keypair, 990 &sender_init.sender_params, 991 ) 992 .unwrap(); 993 let mut sender = RadrootsSimplexSmpRatchetState::responder( 994 sender_key_2.public_key.clone(), 995 receiver_key_2.public_key.clone(), 996 sender_init.sender_params.pq_public_key.clone(), 997 ) 998 .unwrap(); 999 sender 1000 .initialize_official_sender(sender_key_2.private_key, sender_init.init) 1001 .unwrap(); 1002 sender.current_pq_public_key = sender_init.sender_params.pq_public_key.clone(); 1003 sender.pending_outbound_pq_ciphertext = sender_init.sender_params.pq_ciphertext.clone(); 1004 sender.local_pq_private_key = Some(sender_init.local_pq_keypair.private_key); 1005 let mut receiver = RadrootsSimplexSmpRatchetState::initiator( 1006 receiver_key_2.public_key.clone(), 1007 receiver_key_1.public_key.clone(), 1008 None, 1009 ) 1010 .unwrap(); 1011 receiver.current_pq_public_key = Some(receiver_pq_keypair.public_key); 1012 receiver.local_pq_private_key = Some(receiver_pq_keypair.private_key); 1013 receiver 1014 .initialize_official_receiver(receiver_key_2.private_key, receiver_init.init) 1015 .unwrap(); 1016 (sender, receiver) 1017 } 1018 1019 #[test] 1020 fn stages_outbound_pq_state_and_emits_header() { 1021 let mut state = RadrootsSimplexSmpRatchetState::responder( 1022 b"bob-dh".to_vec(), 1023 b"alice-dh".to_vec(), 1024 Some(b"bob-pq".to_vec()), 1025 ) 1026 .unwrap(); 1027 state 1028 .stage_outbound_pq_step( 1029 b"bob-pq-next".to_vec(), 1030 b"ciphertext".to_vec(), 1031 b"shared-secret".to_vec(), 1032 ) 1033 .unwrap(); 1034 1035 let header = state.next_outbound_header().unwrap(); 1036 assert_eq!(header.message_number, 0); 1037 assert_eq!(header.pq_public_key, Some(b"bob-pq-next".to_vec())); 1038 assert_eq!(header.pq_ciphertext, Some(b"ciphertext".to_vec())); 1039 assert_eq!(state.sending_chain_length, 1); 1040 } 1041 1042 #[test] 1043 fn applies_inbound_dh_and_pq_transition() { 1044 let mut state = RadrootsSimplexSmpRatchetState::initiator( 1045 b"alice-dh".to_vec(), 1046 b"bob-dh".to_vec(), 1047 Some(b"bob-pq".to_vec()), 1048 ) 1049 .unwrap(); 1050 state.sending_chain_length = 4; 1051 1052 let advanced = state 1053 .apply_inbound_header( 1054 &RadrootsSimplexSmpRatchetHeader { 1055 previous_sending_chain_length: 2, 1056 message_number: 0, 1057 dh_public_key: b"bob-dh-next".to_vec(), 1058 pq_public_key: Some(b"bob-pq-next".to_vec()), 1059 pq_ciphertext: Some(b"ciphertext".to_vec()), 1060 }, 1061 Some(b"alice-dh-next".to_vec()), 1062 ) 1063 .unwrap(); 1064 1065 assert!(advanced); 1066 assert_eq!(state.previous_sending_chain_length, 4); 1067 assert_eq!(state.sending_chain_length, 0); 1068 assert_eq!(state.receiving_chain_length, 1); 1069 assert_eq!(state.remote_pq_public_key, Some(b"bob-pq-next".to_vec())); 1070 assert_eq!( 1071 state.pending_inbound_pq_ciphertext, 1072 Some(b"ciphertext".to_vec()) 1073 ); 1074 1075 state 1076 .complete_inbound_pq_step(b"shared-secret".to_vec()) 1077 .unwrap(); 1078 assert_eq!( 1079 state.current_pq_shared_secret, 1080 Some(b"shared-secret".to_vec()) 1081 ); 1082 assert_eq!(state.pending_inbound_pq_ciphertext, None); 1083 } 1084 1085 #[test] 1086 fn rejects_incomplete_pq_header() { 1087 let header = RadrootsSimplexSmpRatchetHeader { 1088 previous_sending_chain_length: 0, 1089 message_number: 0, 1090 dh_public_key: b"dh".to_vec(), 1091 pq_public_key: None, 1092 pq_ciphertext: Some(b"ciphertext".to_vec()), 1093 }; 1094 1095 let error = header.validate().unwrap_err(); 1096 assert_eq!(error, RadrootsSimplexSmpCryptoError::IncompletePqHeader); 1097 } 1098 1099 #[test] 1100 fn encrypts_payload_and_advances_receive_state() { 1101 let mut sender = 1102 RadrootsSimplexSmpRatchetState::initiator(vec![1_u8; 56], vec![2_u8; 56], None) 1103 .unwrap(); 1104 let mut receiver = 1105 RadrootsSimplexSmpRatchetState::responder(vec![2_u8; 56], vec![1_u8; 56], None) 1106 .unwrap(); 1107 let shared_secret = [7_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH]; 1108 1109 let (header, ciphertext) = sender 1110 .encrypt_payload(&shared_secret, b"agent body", 64) 1111 .unwrap(); 1112 1113 assert_ne!(ciphertext, b"agent body"); 1114 let plaintext = receiver 1115 .decrypt_payload(&shared_secret, &header, &ciphertext) 1116 .unwrap(); 1117 assert_eq!(plaintext, b"agent body"); 1118 assert_eq!(receiver.receiving_chain_length, 1); 1119 } 1120 1121 #[test] 1122 fn rejects_tampered_ratchet_header() { 1123 let mut sender = 1124 RadrootsSimplexSmpRatchetState::initiator(vec![1_u8; 56], vec![2_u8; 56], None) 1125 .unwrap(); 1126 let mut receiver = 1127 RadrootsSimplexSmpRatchetState::responder(vec![2_u8; 56], vec![1_u8; 56], None) 1128 .unwrap(); 1129 let shared_secret = [9_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH]; 1130 let (mut header, ciphertext) = sender 1131 .encrypt_payload(&shared_secret, b"agent body", 64) 1132 .unwrap(); 1133 header.message_number = header.message_number.saturating_add(1); 1134 1135 let error = receiver 1136 .decrypt_payload(&shared_secret, &header, &ciphertext) 1137 .unwrap_err(); 1138 assert!(matches!( 1139 error, 1140 RadrootsSimplexSmpCryptoError::InvalidCiphertextLength(_) 1141 )); 1142 } 1143 1144 #[test] 1145 fn stages_large_pq_material_in_header() { 1146 let mut sender = RadrootsSimplexSmpRatchetState::initiator( 1147 b"alice-dh".to_vec(), 1148 b"bob-dh".to_vec(), 1149 None, 1150 ) 1151 .unwrap(); 1152 sender 1153 .stage_outbound_pq_step(vec![1_u8; 1158], vec![2_u8; 1039], vec![3_u8; 32]) 1154 .unwrap(); 1155 1156 let header = sender.next_outbound_header().unwrap(); 1157 assert_eq!(header.pq_public_key.as_ref().unwrap().len(), 1158); 1158 assert_eq!(header.pq_ciphertext.as_ref().unwrap().len(), 1039); 1159 assert!(ratchet_header_associated_data(&header).unwrap().len() > 2200); 1160 } 1161 1162 #[test] 1163 fn encrypts_official_payload_as_opaque_message() { 1164 let (mut sender, mut receiver) = official_sender_receiver_ratchets(); 1165 let shared_secret = [11_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH]; 1166 1167 let encrypted = sender 1168 .encrypt_official_payload(&shared_secret, b"official agent body", 96) 1169 .unwrap(); 1170 assert_ne!(encrypted, b"official agent body"); 1171 assert_eq!(encrypted.len(), 2 + 124 + 16 + 96); 1172 1173 let plaintext = receiver 1174 .decrypt_official_payload(&shared_secret, &encrypted) 1175 .unwrap(); 1176 assert_eq!(plaintext, b"official agent body"); 1177 assert_eq!(receiver.receiving_chain_length, 1); 1178 } 1179 1180 #[test] 1181 fn detects_official_payload_replay_without_consuming_skipped_messages() { 1182 let (mut sender, mut receiver) = official_sender_receiver_ratchets(); 1183 let shared_secret = [14_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH]; 1184 let first = sender 1185 .encrypt_official_payload(&shared_secret, b"first", 96) 1186 .unwrap(); 1187 let second = sender 1188 .encrypt_official_payload(&shared_secret, b"second", 96) 1189 .unwrap(); 1190 let third = sender 1191 .encrypt_official_payload(&shared_secret, b"third", 96) 1192 .unwrap(); 1193 1194 assert_eq!( 1195 receiver 1196 .decrypt_official_payload(&shared_secret, &second) 1197 .unwrap(), 1198 b"second" 1199 ); 1200 assert!(!receiver.is_official_payload_replay(&first).unwrap()); 1201 assert_eq!( 1202 receiver 1203 .decrypt_official_payload(&shared_secret, &third) 1204 .unwrap(), 1205 b"third" 1206 ); 1207 assert_eq!( 1208 receiver 1209 .decrypt_official_payload(&shared_secret, &first) 1210 .unwrap(), 1211 b"first" 1212 ); 1213 assert!(receiver.is_official_payload_replay(&first).unwrap()); 1214 } 1215 1216 #[test] 1217 fn advances_official_pq_ratchet_in_both_directions() { 1218 let (mut sender, mut receiver) = official_pq_sender_receiver_ratchets(); 1219 let shared_secret = [21_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH]; 1220 1221 let encrypted = sender 1222 .encrypt_official_payload(&shared_secret, b"pq first", 96) 1223 .unwrap(); 1224 let plaintext = receiver 1225 .decrypt_official_payload(&shared_secret, &encrypted) 1226 .unwrap(); 1227 assert_eq!(plaintext, b"pq first"); 1228 assert!(receiver.pending_outbound_pq_ciphertext.is_some()); 1229 assert!(receiver.local_pq_private_key.is_some()); 1230 1231 let reply = receiver 1232 .encrypt_official_payload(&shared_secret, b"pq reply", 96) 1233 .unwrap(); 1234 let reply_plaintext = sender 1235 .decrypt_official_payload(&shared_secret, &reply) 1236 .unwrap(); 1237 assert_eq!(reply_plaintext, b"pq reply"); 1238 assert!(sender.pending_outbound_pq_ciphertext.is_some()); 1239 assert!(sender.local_pq_private_key.is_some()); 1240 } 1241 1242 #[test] 1243 fn retains_accepted_pq_ciphertext_across_same_sending_chain_headers() { 1244 let (mut sender, _) = official_pq_sender_receiver_ratchets(); 1245 let shared_secret = [22_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH]; 1246 let header_key = sender.official_sending_header_key.clone().unwrap(); 1247 let ratchet_ad = sender.official_associated_data.clone().unwrap(); 1248 let first = sender 1249 .encrypt_official_payload(&shared_secret, b"pq first", 96) 1250 .unwrap(); 1251 let second = sender 1252 .encrypt_official_payload(&shared_secret, b"pq second", 96) 1253 .unwrap(); 1254 1255 let first_message = decode_official_encrypted_message(&first).unwrap(); 1256 let first_header = decrypt_official_header_with_key( 1257 &decode_official_encrypted_header(&first_message.encrypted_header).unwrap(), 1258 &header_key, 1259 &ratchet_ad, 1260 ) 1261 .unwrap(); 1262 let second_message = decode_official_encrypted_message(&second).unwrap(); 1263 let second_header = decrypt_official_header_with_key( 1264 &decode_official_encrypted_header(&second_message.encrypted_header).unwrap(), 1265 &header_key, 1266 &ratchet_ad, 1267 ) 1268 .unwrap(); 1269 1270 assert!(first_header.pq_ciphertext.is_some()); 1271 assert_eq!(first_header.pq_ciphertext, second_header.pq_ciphertext); 1272 assert_eq!(second_header.message_number, 1); 1273 } 1274 1275 #[test] 1276 fn decrypts_official_skipped_messages_once() { 1277 let (mut sender, mut receiver) = official_sender_receiver_ratchets(); 1278 let shared_secret = [12_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH]; 1279 let first = sender 1280 .encrypt_official_payload(&shared_secret, b"first", 96) 1281 .unwrap(); 1282 let second = sender 1283 .encrypt_official_payload(&shared_secret, b"second", 96) 1284 .unwrap(); 1285 let third = sender 1286 .encrypt_official_payload(&shared_secret, b"third", 96) 1287 .unwrap(); 1288 1289 assert_eq!( 1290 receiver 1291 .decrypt_official_payload(&shared_secret, &third) 1292 .unwrap(), 1293 b"third" 1294 ); 1295 assert_eq!(receiver.receiving_chain_length, 3); 1296 assert_eq!(receiver.official_skipped_message_keys.len(), 2); 1297 assert_eq!( 1298 receiver 1299 .decrypt_official_payload(&shared_secret, &first) 1300 .unwrap(), 1301 b"first" 1302 ); 1303 assert_eq!( 1304 receiver 1305 .decrypt_official_payload(&shared_secret, &second) 1306 .unwrap(), 1307 b"second" 1308 ); 1309 assert!(receiver.official_skipped_message_keys.is_empty()); 1310 1311 let replay = receiver 1312 .decrypt_official_payload(&shared_secret, &first) 1313 .unwrap_err(); 1314 assert!(matches!( 1315 replay, 1316 RadrootsSimplexSmpCryptoError::RatchetMessageRegression { 1317 received: 0, 1318 current: 3 1319 } 1320 )); 1321 } 1322 1323 #[test] 1324 fn rejects_too_many_official_skipped_messages() { 1325 let (mut sender, mut receiver) = official_sender_receiver_ratchets(); 1326 let shared_secret = [13_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH]; 1327 let mut encrypted = Vec::new(); 1328 for index in 0..=RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES + 1 { 1329 encrypted = sender 1330 .encrypt_official_payload(&shared_secret, &index.to_be_bytes(), 96) 1331 .unwrap(); 1332 } 1333 1334 let error = receiver 1335 .decrypt_official_payload(&shared_secret, &encrypted) 1336 .unwrap_err(); 1337 assert_eq!( 1338 error, 1339 RadrootsSimplexSmpCryptoError::RatchetTooManySkipped { 1340 skipped: RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES + 1, 1341 max: RADROOTS_SIMPLEX_OFFICIAL_MAX_SKIPPED_MESSAGES 1342 } 1343 ); 1344 assert_eq!( 1345 error.to_string(), 1346 "SMP ratchet skipped 513 messages, exceeding maximum 512" 1347 ); 1348 } 1349 1350 #[test] 1351 fn rejects_tampered_official_payload_body() { 1352 let (mut sender, mut receiver) = official_sender_receiver_ratchets(); 1353 let shared_secret = [12_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH]; 1354 let mut encrypted = sender 1355 .encrypt_official_payload(&shared_secret, b"official agent body", 96) 1356 .unwrap(); 1357 let last = encrypted.len() - 1; 1358 encrypted[last] ^= 1; 1359 1360 let error = receiver 1361 .decrypt_official_payload(&shared_secret, &encrypted) 1362 .unwrap_err(); 1363 assert_eq!( 1364 error, 1365 RadrootsSimplexSmpCryptoError::AesGcmAuthenticationFailed 1366 ); 1367 } 1368 1369 #[test] 1370 fn decrypts_official_payloads_received_out_of_order() { 1371 let (mut sender, mut receiver) = official_sender_receiver_ratchets(); 1372 let shared_secret = [13_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH]; 1373 let encrypted_0 = sender 1374 .encrypt_official_payload(&shared_secret, b"first official body", 96) 1375 .unwrap(); 1376 let encrypted_1 = sender 1377 .encrypt_official_payload(&shared_secret, b"second official body", 96) 1378 .unwrap(); 1379 1380 let plaintext_1 = receiver 1381 .decrypt_official_payload(&shared_secret, &encrypted_1) 1382 .unwrap(); 1383 assert_eq!(plaintext_1, b"second official body"); 1384 assert_eq!(receiver.receiving_chain_length, 2); 1385 assert_eq!(receiver.official_skipped_message_keys.len(), 1); 1386 1387 let plaintext_0 = receiver 1388 .decrypt_official_payload(&shared_secret, &encrypted_0) 1389 .unwrap(); 1390 assert_eq!(plaintext_0, b"first official body"); 1391 assert!(receiver.official_skipped_message_keys.is_empty()); 1392 assert_eq!(receiver.receiving_chain_length, 2); 1393 } 1394 1395 #[test] 1396 fn rejects_too_many_official_skipped_payloads() { 1397 let (mut sender, mut receiver) = official_sender_receiver_ratchets(); 1398 let shared_secret = [14_u8; RADROOTS_SIMPLEX_SMP_SHARED_SECRET_LENGTH]; 1399 let mut encrypted = Vec::new(); 1400 for index in 0..514 { 1401 encrypted = sender 1402 .encrypt_official_payload(&shared_secret, &[index as u8], 96) 1403 .unwrap(); 1404 } 1405 1406 let error = receiver 1407 .decrypt_official_payload(&shared_secret, &encrypted) 1408 .unwrap_err(); 1409 assert_eq!( 1410 error, 1411 RadrootsSimplexSmpCryptoError::RatchetTooManySkipped { 1412 skipped: 513, 1413 max: 512 1414 } 1415 ); 1416 } 1417 }