main.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. //! https://signal.org/docs/specifications/x3dh/x3dh.pdf
  2. //! https://signal.org/docs/specifications/doubleratchet/doubleratchet.pdf
  3. use std::collections::{HashMap, VecDeque};
  4. use aes_gcm_siv::{AeadInPlace, Aes256GcmSiv, KeyInit};
  5. use anyhow::Result;
  6. use digest::Update;
  7. use rand::rngs::OsRng;
  8. use sha3::Sha3_256;
  9. use x25519_dalek::{PublicKey as X25519PublicKey, StaticSecret as X25519SecretKey};
  10. mod hkdf;
  11. use hkdf::Hkdf;
  12. mod hmac;
  13. use hmac::Hmac;
  14. mod xeddsa;
  15. use xeddsa::{XeddsaSigner, XeddsaVerifier};
  16. const AEAD_TAG_SIZE: usize = 16;
  17. const MESSAGE_KEY_CONSTANT: u8 = 0x01;
  18. const CHAIN_KEY_CONSTANT: u8 = 0x02;
  19. const BLANK_NONCE: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  20. // wat do?
  21. const MAX_SKIP: u64 = 500;
  22. /// The server contains published identity keys and prekeys.
  23. #[derive(Default)]
  24. struct Server(HashMap<X25519PublicKey, Keyset>);
  25. impl Server {
  26. pub fn upload(&mut self, ik: X25519PublicKey, keyset: Keyset) {
  27. self.0.insert(ik, keyset);
  28. }
  29. pub fn fetch(&mut self, ik: &X25519PublicKey) -> Option<Bundle> {
  30. if let Some(keyset) = self.0.get_mut(ik) {
  31. // The server should provide one one-time prekey if one exists,
  32. // and then delete it. If all of the one-time prekeys have been
  33. // deleted, the bundle will not contain a one-time prekey.
  34. let onetime_prekey = keyset.onetime_prekeys.pop_front();
  35. return Some(Bundle {
  36. identity_key: *ik,
  37. signed_prekey: keyset.signed_prekey,
  38. prekey_signature: keyset.prekey_signature,
  39. onetime_prekey,
  40. })
  41. }
  42. None
  43. }
  44. }
  45. /// The set of elliptic curve public keys sent uploaded to a server
  46. struct Keyset {
  47. pub signed_prekey: X25519PublicKey,
  48. pub prekey_signature: [u8; 64],
  49. pub onetime_prekeys: VecDeque<X25519PublicKey>,
  50. }
  51. /// The bundle is a structure returned by the server when requesting
  52. /// it for a certain identity key
  53. struct Bundle {
  54. pub identity_key: X25519PublicKey,
  55. pub signed_prekey: X25519PublicKey,
  56. pub prekey_signature: [u8; 64],
  57. pub onetime_prekey: Option<X25519PublicKey>,
  58. }
  59. /// Initial message sent from Alice to Bob (see below how it's used)
  60. struct InitialMessage {
  61. pub identity_key: X25519PublicKey,
  62. pub ephemeral_key: X25519PublicKey,
  63. pub prekey_used: Option<X25519PublicKey>,
  64. pub ciphertext: Vec<u8>,
  65. }
  66. #[derive(Copy, Clone, Debug)]
  67. struct MessageHeader {
  68. /// Ratchet public key
  69. dh: X25519PublicKey,
  70. /// Previous chain length
  71. pn: u64,
  72. /// Message number
  73. n: u64,
  74. }
  75. impl MessageHeader {
  76. /// Creates a new message header containing the DH ratchet public key
  77. /// `dh` the previous chain length `pn`, and the message number `n`.
  78. pub fn new(dh: &X25519SecretKey, pn: u64, n: u64) -> Self {
  79. Self { dh: X25519PublicKey::from(dh), pn, n }
  80. }
  81. pub fn to_bytes(self) -> [u8; 48] {
  82. let mut ret = [0u8; 48];
  83. ret[..32].copy_from_slice(&self.dh.to_bytes());
  84. ret[32..40].copy_from_slice(&self.pn.to_le_bytes());
  85. ret[40..].copy_from_slice(&self.pn.to_le_bytes());
  86. ret
  87. }
  88. pub fn from_bytes(arr: [u8; 48]) -> Self {
  89. let pk_bytes: [u8; 32] = arr[..32].try_into().unwrap();
  90. let dh = X25519PublicKey::from(pk_bytes);
  91. let pn = u64::from_le_bytes(arr[32..40].try_into().unwrap());
  92. let n = u64::from_le_bytes(arr[40..].try_into().unwrap());
  93. Self { dh, pn, n }
  94. }
  95. /// Returns the AEAD encryption of the message header with header key `hk`.
  96. /// Because the same `hk` will be used repeatedly, the AEAD nonce must
  97. /// either be a stateful non-repeating value, or must be a random
  98. /// non-repeating value chosen with at least 128 bits of entropy.
  99. pub fn encrypt(&self, hk: [u8; 32], ad: &[u8]) -> Vec<u8> {
  100. // FIXME: BUG: Don't reuse the nonce.
  101. let nonce = [0u8; 12][..].into();
  102. let mut ciphertext = vec![0u8; 48 + AEAD_TAG_SIZE];
  103. ciphertext[..48].copy_from_slice(&self.to_bytes());
  104. Aes256GcmSiv::new(&hk.into()).encrypt_in_place(nonce, ad, &mut ciphertext).unwrap();
  105. ciphertext
  106. }
  107. /// Returns the authenticated decryption of `ciphertext` with header key `hk`.
  108. pub fn decrypt(ciphertext: &[u8], hk: [u8; 32], ad: &[u8]) -> Option<Self> {
  109. // FIXME: BUG: Don't reuse the nonce.
  110. let nonce = [0u8; 12][..].into();
  111. let mut plaintext = vec![0u8; ciphertext.len()];
  112. plaintext.copy_from_slice(ciphertext);
  113. match Aes256GcmSiv::new(&hk.into()).decrypt_in_place(nonce, ad, &mut plaintext) {
  114. Ok(()) => {
  115. plaintext.resize(plaintext.len() - AEAD_TAG_SIZE, 0);
  116. let message_header = Self::from_bytes(plaintext.try_into().unwrap());
  117. Some(message_header)
  118. }
  119. Err(_) => None,
  120. }
  121. }
  122. }
  123. /// Returns a pair (32-byte chain key, 32-byte message key) as the output of
  124. /// applying a KDF keyed by a 32-byte chain key `ck` to some constant.
  125. /// HMAC with SHA256 is recommended, using `ck` as the HMAC key and using
  126. /// separate constants as input (e.g. a single byte 0x01 as input to produce
  127. /// the message key, and a single byte 0x02 as input to produce the next chain
  128. /// key.
  129. fn kdf_ck(ck: [u8; 32]) -> ([u8; 32], [u8; 32]) {
  130. let mut hmac = Hmac::<Sha3_256>::new_from_slice(&ck);
  131. hmac.update(&[CHAIN_KEY_CONSTANT]);
  132. let chain_key = hmac.finalize();
  133. let mut hmac = Hmac::<Sha3_256>::new_from_slice(&ck);
  134. hmac.update(&[MESSAGE_KEY_CONSTANT]);
  135. let message_key = hmac.finalize();
  136. (chain_key.into(), message_key.into())
  137. }
  138. /// Returns a new root key, chain key, and next header key as the output
  139. /// of applying a KDF keyed by root key `rk` to a Diffie-Hellman output
  140. /// `dh_out`.
  141. /// This function is recommended to be implemented using HKDF with SHA256
  142. /// using `rk` as HKDF salt, `dh_out` as HKDF input key material, and an
  143. /// application-specific byte sequence as HKDF info. The info value should
  144. /// be chosen to be distinct from other uses of HKDF in the application.
  145. fn kdf_rk(rk: [u8; 32], dh_out: [u8; 32]) -> ([u8; 32], [u8; 32], [u8; 32]) {
  146. const KDF_RK_INFO: &[u8] = b"x3dh_double_ratchet_kdf_rk";
  147. const KDF_HE_INFO: &[u8] = b"x3dh_double_ratchet_kdf_rk_he";
  148. let (_root_key, hkdf) = Hkdf::<Sha3_256>::extract(&rk, &dh_out);
  149. let mut chain_key = [0u8; 32];
  150. hkdf.expand(KDF_RK_INFO, &mut chain_key).unwrap();
  151. let (root_key, hkdf) = Hkdf::<Sha3_256>::extract(&rk, &dh_out);
  152. let mut next_header_key = [0u8; 32];
  153. hkdf.expand(KDF_HE_INFO, &mut next_header_key).unwrap();
  154. (root_key.into(), chain_key, next_header_key)
  155. }
  156. #[derive(Clone)]
  157. struct DoubleRatchetSessionState {
  158. /// DH ratchet key pair (the "sending" or "self" ratchet key) (DHRs)
  159. pub dh_sending: X25519SecretKey,
  160. /// DH ratchet public key (the "received" or "remote" key) (DHRr)
  161. pub dh_remote: X25519PublicKey,
  162. /// 32-byte root key (RK)
  163. pub root_key: [u8; 32],
  164. /// 32-byte Chain Key for sending (CKs)
  165. pub chain_key_send: [u8; 32],
  166. /// 32-byte Chain Key for receiving (CKr)
  167. pub chain_key_recv: [u8; 32],
  168. /// Message numbers for sending (Ns)
  169. pub n_send: u64,
  170. /// Message numbers for receiving (Nr)
  171. pub n_recv: u64,
  172. /// Number of messages in previous sending chain (PN)
  173. pub n_prev: u64,
  174. /// Dictionary of skipped-over message keys, indexed by header key
  175. /// and message number. Raises an exception if too many elements
  176. /// are stored.
  177. pub mkskipped: HashMap<([u8; 32], u64), [u8; 32]>,
  178. /// 32-byte Header Key for sending (HKs)
  179. pub header_key_send: [u8; 32],
  180. /// 32-byte Header Key for receiving (HKr)
  181. pub header_key_recv: [u8; 32],
  182. /// 32-byte Next Header Key for sending (NHKs)
  183. pub next_header_key_send: [u8; 32],
  184. /// 32-byte Next Header Key for receiving (NHKr)
  185. pub next_header_key_recv: [u8; 32],
  186. }
  187. impl DoubleRatchetSessionState {
  188. /// This function performs a symmetric-key ratchet step, then encrypts
  189. /// the message with the resulting message key. In addition to the
  190. /// message's _plaintext_ it takes an AD byte sequence which is
  191. /// prepended to the header to form the associated data for the
  192. // underlying AEAD encryption.
  193. pub fn ratchet_encrypt(&mut self, plaintext: &[u8], ad: &[u8]) -> (Vec<u8>, Vec<u8>) {
  194. let (chain_key, message_key) = kdf_ck(self.chain_key_send);
  195. self.chain_key_send = chain_key;
  196. println!("ENCRYPT(): new chain send: {:?}", &chain_key[..5]);
  197. let header = MessageHeader::new(&self.dh_sending, self.n_prev, self.n_send);
  198. let enc_header = header.encrypt(self.header_key_send, &[]);
  199. let mut associated_data = Vec::with_capacity(ad.len() + enc_header.len());
  200. associated_data.extend_from_slice(ad);
  201. associated_data.extend_from_slice(&enc_header);
  202. let mut ciphertext = vec![0u8; plaintext.len() + AEAD_TAG_SIZE];
  203. ciphertext[..plaintext.len()].copy_from_slice(plaintext);
  204. // Because each message key is only used once, the AEAD nonce may be
  205. // handled in several ways:
  206. // * Fixed to a constant
  207. // * Derived from `mk` alongside an independent AEAD encryption key
  208. // * Derived as an additional output from HMAC
  209. // * Chosen randomly and transmitted
  210. // ENCRYPT(message_key, plaintext, (AD || enc_header))
  211. println!("ENCRYPT(): message key: {:?}", &message_key[..5]);
  212. Aes256GcmSiv::new(&message_key.into())
  213. .encrypt_in_place(BLANK_NONCE.into(), &associated_data, &mut ciphertext)
  214. .unwrap();
  215. self.n_send += 1;
  216. (enc_header, ciphertext)
  217. }
  218. /// Decrypt messages. This function does the following:
  219. /// * If the message corresponds to a skipped message key this function
  220. /// decrypts the message, deletes the message key, and returns.
  221. /// * Otherwise, if a new ratchet key has been received, this function
  222. /// stores any skipped message keys from the receiving chain and
  223. /// performs a DH ratchet step to replace the sending and receiving
  224. /// chains.
  225. /// * This function then stores any skipped message keys from the current
  226. /// receiving chain, performs a symmetric-key ratchet step to derive
  227. /// the relevant message key and next chain key, and decrypts the msg.
  228. /// If an exception is raised (e.g. message authentication failure), then
  229. /// the message is discarded and changes to the state object are discarded.
  230. /// Otherwise, the decrypted plaintext is accepted and changes to the state
  231. /// object are stored.
  232. pub fn ratchet_decrypt(&mut self, enc_header: &[u8], ciphertext: &[u8], ad: &[u8]) -> Vec<u8> {
  233. // We clone here so we don't have to worry about mutating the state before
  234. // everything is correct.
  235. let mut state = self.clone();
  236. if let Some(plaintext) = state.try_skipped_message_keys(enc_header, ciphertext, ad) {
  237. println!("found skipped");
  238. *self = state;
  239. return plaintext
  240. }
  241. if let Some((header, dh_ratchet)) = state.decrypt_header(enc_header) {
  242. if dh_ratchet {
  243. state.skip_message_keys(header.pn);
  244. state.dh_ratchet(header);
  245. }
  246. state.skip_message_keys(header.n);
  247. } else {
  248. panic!("couldn't decrypt header")
  249. }
  250. let (chain_key, message_key) = kdf_ck(state.chain_key_recv);
  251. state.chain_key_recv = chain_key;
  252. println!("DECRYPT(): new chain recv: {:?}", &chain_key[..5]);
  253. state.n_recv += 1;
  254. let mut plaintext = vec![0u8; ciphertext.len()];
  255. plaintext.copy_from_slice(ciphertext);
  256. let mut associated_data = Vec::with_capacity(ad.len() + enc_header.len());
  257. associated_data.extend_from_slice(ad);
  258. associated_data.extend_from_slice(enc_header);
  259. // DECRYPT(message_key, ciphertext, (AD || enc_header))
  260. println!("DECRYPT(): message key: {:?}", &message_key[..5]);
  261. Aes256GcmSiv::new(&message_key.into())
  262. .decrypt_in_place(BLANK_NONCE.into(), &associated_data, &mut plaintext)
  263. .unwrap();
  264. // Apply the state change
  265. *self = state;
  266. plaintext.resize(plaintext.len() - AEAD_TAG_SIZE, 0);
  267. plaintext
  268. }
  269. fn try_skipped_message_keys(
  270. &mut self,
  271. enc_header: &[u8],
  272. ciphertext: &[u8],
  273. ad: &[u8],
  274. ) -> Option<Vec<u8>> {
  275. let mut plaintext = ciphertext.to_vec();
  276. let mut rem = None;
  277. for ((hk, n), mk) in self.mkskipped.iter_mut() {
  278. if let Some(header) = MessageHeader::decrypt(enc_header, *hk, &[]) {
  279. if header.n == *n {
  280. rem = Some((*hk, *n));
  281. let mut associated_data = Vec::with_capacity(ad.len() + enc_header.len());
  282. associated_data.extend_from_slice(ad);
  283. associated_data.extend_from_slice(enc_header);
  284. let mk = *mk;
  285. Aes256GcmSiv::new(&mk.into())
  286. .decrypt_in_place(BLANK_NONCE.into(), &associated_data, &mut plaintext)
  287. .unwrap();
  288. plaintext.resize(plaintext.len() - AEAD_TAG_SIZE, 0);
  289. break
  290. }
  291. panic!("Failed to decrypt message from skipped message keys");
  292. }
  293. }
  294. if let Some(found) = rem {
  295. self.mkskipped.remove(&found);
  296. return Some(plaintext)
  297. }
  298. None
  299. }
  300. fn decrypt_header(&mut self, enc_header: &[u8]) -> Option<(MessageHeader, bool)> {
  301. if let Some(header) = MessageHeader::decrypt(enc_header, self.header_key_recv, &[]) {
  302. return Some((header, false))
  303. }
  304. if let Some(header) = MessageHeader::decrypt(enc_header, self.next_header_key_recv, &[]) {
  305. return Some((header, true))
  306. }
  307. println!("Failed to decrypt header");
  308. None
  309. }
  310. fn skip_message_keys(&mut self, until: u64) {
  311. if self.n_recv + MAX_SKIP < until {
  312. panic!("I can't hold all of these lemons");
  313. }
  314. if self.chain_key_recv != [0u8; 32] {
  315. while self.n_recv < until {
  316. let (chain_key_recv, message_key) = kdf_ck(self.chain_key_recv);
  317. self.chain_key_recv = chain_key_recv;
  318. println!("SKIP(): new chain recv: {:?}", &chain_key_recv[..5]);
  319. self.mkskipped.insert((self.header_key_recv, self.n_recv), message_key);
  320. self.n_recv += 1;
  321. }
  322. }
  323. }
  324. fn dh_ratchet(&mut self, header: MessageHeader) {
  325. self.n_prev = self.n_send;
  326. self.n_send = 0;
  327. self.n_recv = 0;
  328. self.header_key_send = self.next_header_key_send;
  329. self.header_key_recv = self.next_header_key_recv;
  330. self.dh_remote = header.dh;
  331. let hkdf_ikm = self.dh_sending.diffie_hellman(&self.dh_remote);
  332. (self.root_key, self.chain_key_recv, self.next_header_key_recv) =
  333. kdf_rk(self.root_key, hkdf_ikm.to_bytes());
  334. let dh_secret_new = X25519SecretKey::new(&mut OsRng);
  335. self.dh_sending = dh_secret_new;
  336. let hkdf_ikm = self.dh_sending.diffie_hellman(&self.dh_remote);
  337. (self.root_key, self.chain_key_send, self.next_header_key_send) =
  338. kdf_rk(self.root_key, hkdf_ikm.to_bytes());
  339. }
  340. }
  341. fn main() -> Result<()> {
  342. // The "server" contains published identity keys and prekeys.
  343. let mut server = Server::default();
  344. // The X3DH protocol has three phases:
  345. // 1. Bob publishes his identity key and prekeys to a server.
  346. // 2. Alice fetches a "prekey bundle" from the server, and uses
  347. // it to send an initial message to Bob.
  348. // 3. Bob receives and processes Alice's initial message.
  349. // Alice's identity key `IK_A`
  350. let alice_ik_secret = X25519SecretKey::new(&mut OsRng);
  351. let alice_ik_public = X25519PublicKey::from(&alice_ik_secret);
  352. // Bob's identity key `IK_B`
  353. let bob_ik_secret = X25519SecretKey::new(&mut OsRng);
  354. let bob_ik_public = X25519PublicKey::from(&bob_ik_secret);
  355. // Bob only needs to upload his identity key to the server once.
  356. // However, Bob may upload new one-time prekeys at other times
  357. // (e.g. when the server informs Bob that the server's store
  358. // of one-time prekeys is getting low).
  359. // Bob will also upload a new signed prekey and prekey signature
  360. // at some interval (e.g. once a week/month). The new signed prekey
  361. // and prekey signature will replace the previous values.
  362. // Bob's signed prekey `SPK_B`
  363. let bob_spk_secret = X25519SecretKey::new(&mut OsRng);
  364. let bob_spk_public = X25519PublicKey::from(&bob_spk_secret);
  365. // Bob's prekey signature `Sig(IK_b, Encode(SPK_B))`
  366. let nonce = [0_u8; 64];
  367. let bob_spk_sig = bob_ik_secret.xeddsa_sign(&bob_spk_public.to_bytes(), &nonce);
  368. // A set of Bob's one-time prekeys `(OPK_B1, OPK_B2, OPK_B3, ...)`
  369. let mut bob_opk_secrets = vec![
  370. X25519SecretKey::new(&mut OsRng),
  371. X25519SecretKey::new(&mut OsRng),
  372. X25519SecretKey::new(&mut OsRng),
  373. ];
  374. let mut bob_opk_publics = VecDeque::new();
  375. bob_opk_publics.push_back(X25519PublicKey::from(&bob_opk_secrets[0]));
  376. bob_opk_publics.push_back(X25519PublicKey::from(&bob_opk_secrets[1]));
  377. bob_opk_publics.push_back(X25519PublicKey::from(&bob_opk_secrets[2]));
  378. let bob_keyset = Keyset {
  379. signed_prekey: bob_spk_public,
  380. prekey_signature: bob_spk_sig,
  381. onetime_prekeys: bob_opk_publics.clone(),
  382. };
  383. // Bob uploads his keyset to the server.
  384. server.upload(bob_ik_public, bob_keyset);
  385. // To perform an X3DH key agreement with Bob, Alice contacts the server
  386. // and fetches a "prekey bundle" containing the following values:
  387. // * Bob's identity key `IK_B`
  388. // * Bob's signed prekey `SPK_B`
  389. // * Bob's prekey signature `Sig(IK_B, Encode(SPK_B))`
  390. // * (Optionally) Bob's one-time prekey `OPK_B`
  391. let bob_keyset = server.fetch(&bob_ik_public).unwrap();
  392. // Alice verifies the prekey signature and aborts the protocol if
  393. // verification fails.
  394. assert!(bob_keyset
  395. .identity_key
  396. .xeddsa_verify(&bob_keyset.signed_prekey.to_bytes(), &bob_keyset.prekey_signature));
  397. // Alice then generates an ephemeral keypair with public key `EK_A`
  398. let alice_ek_secret = X25519SecretKey::new(&mut OsRng);
  399. let alice_ek_public = X25519PublicKey::from(&alice_ek_secret);
  400. // If the bundle does _not_ contain a one-time prekey, she calculates:
  401. // DH1 = DH(IK_A, SPK_B)
  402. // DH2 = DH(EK_A, IK_B)
  403. // DH3 = DH(EK_A, SPK_B)
  404. // SK = KDF(DH1 || DH2 || DH3)
  405. // If the bundle _does_ contain a one-time prekey, additionally she
  406. // does another dh:
  407. // DH4 = DH(EK_A, OPK_B)
  408. // SK = KDF(DH1 || DH2 || DH3 || DH4)
  409. let dh1 = alice_ik_secret.diffie_hellman(&bob_keyset.signed_prekey);
  410. let dh2 = alice_ek_secret.diffie_hellman(&bob_keyset.identity_key);
  411. let dh3 = alice_ek_secret.diffie_hellman(&bob_keyset.signed_prekey);
  412. let mut dh4 = None;
  413. if let Some(opk) = bob_keyset.onetime_prekey {
  414. dh4 = Some(alice_ek_secret.diffie_hellman(&opk));
  415. }
  416. // KDF represents 32 bytes of output from the HKDF algorithm with inputs:
  417. // - HKDF input key material = F || KM, where KM is an input byte sequence
  418. // containing secret key material, and F is a byte sequence containing
  419. // 32 0xFF bytes when the curve is X25519. F is used for cryptographic
  420. // domain separation with XEdDSA.
  421. // - HKDF salt = A zero-filled byte sequence equal to the hash output length.
  422. // - HKDF info - The info parameter.
  423. let info = b"x3dh_info";
  424. let salt = [0u8; 32];
  425. let mut ikm = vec![0xFF; 32];
  426. ikm.extend_from_slice(&dh1.to_bytes());
  427. ikm.extend_from_slice(&dh2.to_bytes());
  428. ikm.extend_from_slice(&dh3.to_bytes());
  429. if let Some(ref opk_dh) = dh4 {
  430. ikm.extend_from_slice(&opk_dh.to_bytes());
  431. }
  432. let hkdf = Hkdf::<Sha3_256>::new(&salt, &ikm);
  433. let mut sk = [0u8; 32];
  434. hkdf.expand(info.as_ref(), &mut sk).unwrap();
  435. // After calculating SK, Alice deletes her ephemeral private key and the
  436. // DH outputs.
  437. drop(alice_ek_secret);
  438. drop(dh1);
  439. drop(dh2);
  440. drop(dh3);
  441. drop(dh4);
  442. // Alice then calculates an "associated data" byte sequence AD that
  443. // contains identity information for both parties:
  444. // AD = Encode(IK_A) || Encode(IK_B)
  445. // Alice may optionally append additional info to AD, such as Alice
  446. // and Bob's usernames, certificates, or other identifying information.
  447. let mut ad = Vec::with_capacity(64);
  448. ad.extend_from_slice(&alice_ik_public.to_bytes());
  449. ad.extend_from_slice(&bob_ik_public.to_bytes());
  450. // Alice then sends Bob an initial message containing:
  451. // - Alice's identity key IK_A
  452. // - Alice's ephemeral key EK_A
  453. // - Identifiers stating which of Bob's prekeys Alice used
  454. // - An initial ciphertext with some AEAD encryption scheme using AD as
  455. // associated data and using an encryption key which is either SK
  456. // or the output of some cryptographic PRF keyed by SK.
  457. let message = b"ohai bob";
  458. let mut ciphertext = vec![0u8; message.len() + AEAD_TAG_SIZE];
  459. ciphertext[..message.len()].copy_from_slice(message);
  460. Aes256GcmSiv::new(&sk.into())
  461. .encrypt_in_place(BLANK_NONCE.into(), &ad, &mut ciphertext)
  462. .unwrap();
  463. let initial_message = InitialMessage {
  464. identity_key: alice_ik_public,
  465. ephemeral_key: alice_ek_public,
  466. prekey_used: bob_keyset.onetime_prekey,
  467. ciphertext,
  468. };
  469. // Upon receiving Alice's initial message, Bob retrieves Alice's
  470. // identity key and ephemeral key from the message. Bob also loads
  471. // his identity private key, and the private key(s) corresponding
  472. // to whichever signed prekey and one-time prekey (if any) Alice used.
  473. // NOTE: In this example, we assume Bob already knows the latest prekey
  474. // he signed and uploaded to the server.
  475. // Using these keys, Bob repeats the DH and KDF calculations from the
  476. // previous section to derive SK, and then deletes the DH values.
  477. let mut onetime_prekey = None;
  478. if let Some(opk_used) = initial_message.prekey_used {
  479. for i in bob_opk_secrets.clone() {
  480. if X25519PublicKey::from(&i.clone()) == opk_used {
  481. onetime_prekey = Some(i);
  482. }
  483. }
  484. }
  485. let dh1 = bob_spk_secret.diffie_hellman(&initial_message.identity_key);
  486. let dh2 = bob_ik_secret.diffie_hellman(&initial_message.ephemeral_key);
  487. let dh3 = bob_spk_secret.diffie_hellman(&initial_message.ephemeral_key);
  488. let mut dh4 = None;
  489. if let Some(ref opk) = onetime_prekey {
  490. dh4 = Some(opk.diffie_hellman(&initial_message.ephemeral_key));
  491. }
  492. let info = b"x3dh_info";
  493. let salt = [0u8; 32];
  494. let mut ikm = vec![0xFF; 32];
  495. ikm.extend_from_slice(&dh1.to_bytes());
  496. ikm.extend_from_slice(&dh2.to_bytes());
  497. ikm.extend_from_slice(&dh3.to_bytes());
  498. if let Some(ref opk_dh) = dh4 {
  499. ikm.extend_from_slice(&opk_dh.to_bytes());
  500. }
  501. let hkdf = Hkdf::<Sha3_256>::new(&salt, &ikm);
  502. let mut sk2 = [0u8; 32];
  503. hkdf.expand(info.as_ref(), &mut sk2).unwrap();
  504. assert_eq!(sk, sk2); // Just to confirm everything's correct
  505. // Bob then constructs the AD byte sequence using IK_A and IK_B
  506. // as Alice did above.
  507. let mut ad = Vec::with_capacity(64);
  508. ad.extend_from_slice(&initial_message.identity_key.to_bytes());
  509. ad.extend_from_slice(&bob_ik_public.to_bytes());
  510. // Finally, Bob attempts to decrypt the initial ciphertext using SK and AD.
  511. // If the initial ciphertext fails to decrypt, Bob aborts the protocol and
  512. // deletes SK.
  513. let mut plaintext = vec![0_u8; initial_message.ciphertext.len()];
  514. plaintext.copy_from_slice(&initial_message.ciphertext);
  515. Aes256GcmSiv::new(&sk2.into())
  516. .decrypt_in_place(BLANK_NONCE.into(), &ad, &mut plaintext)
  517. .unwrap();
  518. plaintext.resize(plaintext.len() - AEAD_TAG_SIZE, 0);
  519. assert_eq!(plaintext, message); // Just to confirm everything's correct
  520. // If the initial ciphertext decrypts successfully, the protocol is complete
  521. // for Bob. Bob deletes any one-time prekey secret key that was used, for
  522. // forward secrecy. Bob may then continue using SK or keys derived from SK
  523. // within the post-X3DH protocol for communication with Alice.
  524. if let Some(opk) = onetime_prekey {
  525. bob_opk_secrets.retain(|x| x.to_bytes() != opk.to_bytes());
  526. }
  527. // =======================+
  528. // Double Ratchet with X3DH
  529. // ========================
  530. // * The SK output from X3DH becomes the SK input to Double Ratchet initialization.
  531. // * The AD output from X3DH becomes the AD input to Double Ratchet {en,de}cryption.
  532. // * Bob's signed prekey SPK_B becomes Bob's initial ratchet public key (and
  533. // corresponding keypair) for Double Ratchet initialization.
  534. // Any Double Ratchet message encrypted using Alice's initial sending chain can
  535. // serve as an "initial ciphertext" for X3DH. To deal with the possibility of
  536. // lost or out-of-order messages, a recommended pattern is for Alice to repeatedly
  537. // send the same X3DH initial message prepended to all of her Double Ratchet
  538. // messages until she receives Bob's first Double Ratchet response message.
  539. // Once Alice and Bob have agreed on SK and Bob's ratchet public key, Alice
  540. // and Bob initialize their states:
  541. // Alice:
  542. let alice_dh_secret = X25519SecretKey::new(&mut OsRng);
  543. // The X3DH secret becomes the HKDF salt, and the ikm is the DH output
  544. // of Alice's DH secret and Bob's SPK_B.
  545. let hkdf_ikm = alice_dh_secret.diffie_hellman(&bob_keyset.signed_prekey);
  546. let (root_key, chain_key_send, next_header_key_send) = kdf_rk(sk, hkdf_ikm.to_bytes());
  547. // TODO: We're using SK here as the initial header encryption keys. Perhaps it's not safe?
  548. let mut ars = DoubleRatchetSessionState {
  549. dh_sending: alice_dh_secret,
  550. dh_remote: bob_keyset.signed_prekey,
  551. root_key,
  552. chain_key_send,
  553. chain_key_recv: [0u8; 32],
  554. n_send: 0,
  555. n_recv: 0,
  556. n_prev: 0,
  557. mkskipped: HashMap::default(),
  558. header_key_send: sk,
  559. header_key_recv: [0u8; 32],
  560. next_header_key_send,
  561. next_header_key_recv: sk,
  562. };
  563. // Bob:
  564. let mut brs = DoubleRatchetSessionState {
  565. dh_sending: bob_spk_secret,
  566. dh_remote: X25519PublicKey::from([0u8; 32]),
  567. root_key: sk,
  568. chain_key_send: [0u8; 32],
  569. chain_key_recv: [0u8; 32],
  570. n_send: 0,
  571. n_recv: 0,
  572. n_prev: 0,
  573. mkskipped: HashMap::default(),
  574. header_key_send: [0u8; 32],
  575. header_key_recv: [0u8; 32],
  576. next_header_key_send: sk,
  577. next_header_key_recv: sk,
  578. };
  579. // TODO: What kind of AD should be used?
  580. // Alice sends it to Bob, and Bob decrypts.
  581. let message_to_bob = b"hai bobz";
  582. println!("Alice: n_recv={}, n_send={}, n_prev={}", ars.n_recv, ars.n_send, ars.n_prev);
  583. let (enc_header, ciphertext) = ars.ratchet_encrypt(message_to_bob, &[]);
  584. println!("Bob: n_recv={}, n_send={}, n_prev={}", brs.n_recv, brs.n_send, brs.n_prev);
  585. let plaintext = brs.ratchet_decrypt(&enc_header, &ciphertext, &[]);
  586. assert_eq!(plaintext, message_to_bob);
  587. println!("Bob decrypted message: {}", String::from_utf8_lossy(&plaintext));
  588. // Bob replies to Alice.
  589. let message_to_alice = b"hai alice, what's up?";
  590. println!("Bob: n_recv={}, n_send={}, n_prev={}", brs.n_recv, brs.n_send, brs.n_prev);
  591. let (enc_header, ciphertext) = brs.ratchet_encrypt(message_to_alice, &[]);
  592. println!("Alice: n_recv={}, n_send={}, n_prev={}", ars.n_recv, ars.n_send, ars.n_prev);
  593. let plaintext = ars.ratchet_decrypt(&enc_header, &ciphertext, &[]);
  594. assert_eq!(plaintext, message_to_alice);
  595. println!("Alice decrypted message: {}", String::from_utf8_lossy(&plaintext));
  596. // Alice loves Bob.
  597. let message_to_bob = b"you schizo";
  598. println!("Alice: n_recv={}, n_send={}, n_prev={}", ars.n_recv, ars.n_send, ars.n_prev);
  599. let (enc_header, ciphertext) = ars.ratchet_encrypt(message_to_bob, &[]);
  600. println!("Bob: n_recv={}, n_send={}, n_prev={}", brs.n_recv, brs.n_send, brs.n_prev);
  601. let plaintext = brs.ratchet_decrypt(&enc_header, &ciphertext, &[]);
  602. assert_eq!(plaintext, message_to_bob);
  603. println!("Bob decrypted message: {}", String::from_utf8_lossy(&plaintext));
  604. // Let's try out of order
  605. let message_to_bob1 = b"hello";
  606. let message_to_bob2 = b"jello";
  607. let (enc_header1, ciphertext1) = ars.ratchet_encrypt(message_to_bob1, &[]);
  608. let (enc_header2, ciphertext2) = ars.ratchet_encrypt(message_to_bob2, &[]);
  609. // Slow Bob
  610. let plaintext = brs.ratchet_decrypt(&enc_header2, &ciphertext2, &[]);
  611. assert_eq!(plaintext, message_to_bob2);
  612. let plaintext = brs.ratchet_decrypt(&enc_header1, &ciphertext1, &[]);
  613. assert_eq!(plaintext, message_to_bob1);
  614. let message_to_alice = b"weaponised autism";
  615. let (enc_header, ciphertext) = brs.ratchet_encrypt(message_to_alice, &[]);
  616. let plaintext = ars.ratchet_decrypt(&enc_header, &ciphertext, &[]);
  617. assert_eq!(plaintext, message_to_alice);
  618. Ok(())
  619. }