main.rs 33 KB

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