bridge_table.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /*! The encrypted table of bridges.
  2. The table consists of a number of buckets, each holding some number
  3. (currently up to 3) of bridges. Each bucket is individually encrypted
  4. with a bucket key. Users will have a credential containing a bucket
  5. (number, key) combination, and so will be able to read one of the
  6. buckets. Users will either download the whole encrypted bucket list or
  7. use PIR to download a piece of it, so that the bridge authority does not
  8. learn which bucket the user has access to. */
  9. use super::cred;
  10. use super::IssuerPrivKey;
  11. use super::CMZ_B_TABLE;
  12. use aes_gcm::aead;
  13. use aes_gcm::aead::{generic_array::GenericArray, Aead};
  14. use aes_gcm::{Aes128Gcm, KeyInit};
  15. #[cfg(feature = "bridgeauth")]
  16. #[allow(unused_imports)]
  17. use base64::{engine::general_purpose, Engine as _};
  18. use curve25519_dalek::ristretto::CompressedRistretto;
  19. use curve25519_dalek::ristretto::RistrettoBasepointTable;
  20. use curve25519_dalek::scalar::Scalar;
  21. #[allow(unused_imports)]
  22. use rand::RngCore;
  23. use serde::{Deserialize, Serialize};
  24. use serde_with::{serde_as, DisplayFromStr};
  25. use std::collections::{HashMap, HashSet};
  26. use std::convert::{TryFrom, TryInto};
  27. use subtle::ConstantTimeEq;
  28. /// Each bridge information line is serialized into this many bytes
  29. pub const BRIDGE_BYTES: usize = 250;
  30. /// The max number of bridges per bucket
  31. pub const MAX_BRIDGES_PER_BUCKET: usize = 3;
  32. /// The minimum number of bridges in a bucket that must be reachable for
  33. /// the bucket to get a Bucket Reachability credential that will allow
  34. /// users of that bucket to gain trust levels (once they are already at
  35. /// level 1)
  36. pub const MIN_BUCKET_REACHABILITY: usize = 2;
  37. /// A bridge information line
  38. #[serde_as]
  39. #[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, Debug)]
  40. pub struct BridgeLine {
  41. /// IPv4 or IPv6 address
  42. pub addr: [u8; 16],
  43. /// port
  44. pub port: u16,
  45. /// fingerprint
  46. #[serde_as(as = "DisplayFromStr")]
  47. pub uid_fingerprint: u64,
  48. /// other protocol information, including pluggable transport,
  49. /// public key, etc.
  50. #[serde_as(as = "[_; BRIDGE_BYTES - 26]")]
  51. pub info: [u8; BRIDGE_BYTES - 26],
  52. }
  53. /// A bucket contains MAX_BRIDGES_PER_BUCKET bridges plus the
  54. /// information needed to construct a Bucket Reachability credential,
  55. /// which is a 4-byte date, and a (P,Q) MAC
  56. type Bucket = (
  57. [BridgeLine; MAX_BRIDGES_PER_BUCKET],
  58. Option<cred::BucketReachability>,
  59. );
  60. /// The size of a plaintext bucket
  61. pub const BUCKET_BYTES: usize = BRIDGE_BYTES * MAX_BRIDGES_PER_BUCKET + 4 + 32 + 32;
  62. /// The size of an encrypted bucket
  63. pub const ENC_BUCKET_BYTES: usize = BUCKET_BYTES + 12 + 16;
  64. impl Default for BridgeLine {
  65. /// An "empty" BridgeLine is represented by all zeros
  66. fn default() -> Self {
  67. Self {
  68. addr: [0; 16],
  69. port: 0,
  70. uid_fingerprint: 0,
  71. info: [0; BRIDGE_BYTES - 26],
  72. }
  73. }
  74. }
  75. impl BridgeLine {
  76. /// Encode a BridgeLine to a byte array
  77. pub fn encode(&self) -> [u8; BRIDGE_BYTES] {
  78. let mut res: [u8; BRIDGE_BYTES] = [0; BRIDGE_BYTES];
  79. res[0..16].copy_from_slice(&self.addr);
  80. res[16..18].copy_from_slice(&self.port.to_be_bytes());
  81. res[18..26].copy_from_slice(&self.uid_fingerprint.to_be_bytes());
  82. res[26..].copy_from_slice(&self.info);
  83. res
  84. }
  85. /// Decode a BridgeLine from a byte array
  86. pub fn decode(data: &[u8; BRIDGE_BYTES]) -> Self {
  87. let mut res: Self = Default::default();
  88. res.addr.copy_from_slice(&data[0..16]);
  89. res.port = u16::from_be_bytes(data[16..18].try_into().unwrap());
  90. res.uid_fingerprint = u64::from_be_bytes(data[18..26].try_into().unwrap());
  91. res.info.copy_from_slice(&data[26..]);
  92. res
  93. }
  94. /// Encode a bucket to a byte array, including a Bucket Reachability
  95. /// credential if appropriate
  96. pub fn bucket_encode(
  97. bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET],
  98. reachable: &HashMap<BridgeLine, Vec<(u32, usize)>>,
  99. today: u32,
  100. bucket_attr: &Scalar,
  101. reachability_priv: &IssuerPrivKey,
  102. ) -> [u8; BUCKET_BYTES] {
  103. let mut res: [u8; BUCKET_BYTES] = [0; BUCKET_BYTES];
  104. let mut pos: usize = 0;
  105. let mut num_reachable: usize = 0;
  106. for bridge in bucket {
  107. res[pos..pos + BRIDGE_BYTES].copy_from_slice(&bridge.encode());
  108. if reachable.contains_key(bridge) {
  109. num_reachable += 1;
  110. }
  111. pos += BRIDGE_BYTES;
  112. }
  113. if num_reachable >= MIN_BUCKET_REACHABILITY {
  114. // Construct a Bucket Reachability credential for this
  115. // bucket and today's date
  116. let today_attr: Scalar = today.into();
  117. let mut rng = rand::thread_rng();
  118. let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
  119. let b = Scalar::random(&mut rng);
  120. let P = &b * Btable;
  121. let Q = &(b
  122. * (reachability_priv.x[0]
  123. + reachability_priv.x[1] * today_attr
  124. + reachability_priv.x[2] * bucket_attr))
  125. * Btable;
  126. res[pos..pos + 4].copy_from_slice(&today.to_le_bytes());
  127. res[pos + 4..pos + 36].copy_from_slice(P.compress().as_bytes());
  128. res[pos + 36..].copy_from_slice(Q.compress().as_bytes());
  129. }
  130. res
  131. }
  132. /// Decode a bucket from a byte array, yielding the array of
  133. /// BridgeLine entries and an optional Bucket Reachability
  134. /// credential
  135. fn bucket_decode(data: &[u8; BUCKET_BYTES], bucket_attr: &Scalar) -> Bucket {
  136. let mut pos: usize = 0;
  137. let mut bridges: [BridgeLine; MAX_BRIDGES_PER_BUCKET] = Default::default();
  138. for bridge in bridges.iter_mut().take(MAX_BRIDGES_PER_BUCKET) {
  139. *bridge = BridgeLine::decode(data[pos..pos + BRIDGE_BYTES].try_into().unwrap());
  140. pos += BRIDGE_BYTES;
  141. }
  142. // See if there's a nonzero date in the Bucket Reachability
  143. // Credential
  144. let date = u32::from_le_bytes(data[pos..pos + 4].try_into().unwrap());
  145. let (optP, optQ) = if date > 0 {
  146. (
  147. CompressedRistretto::from_slice(&data[pos + 4..pos + 36])
  148. .expect("Unable to extract P from bucket")
  149. .decompress(),
  150. CompressedRistretto::from_slice(&data[pos + 36..])
  151. .expect("Unable to extract Q from bucket")
  152. .decompress(),
  153. )
  154. } else {
  155. (None, None)
  156. };
  157. if let (Some(P), Some(Q)) = (optP, optQ) {
  158. let date_attr: Scalar = date.into();
  159. (
  160. bridges,
  161. Some(cred::BucketReachability {
  162. P,
  163. Q,
  164. date: date_attr,
  165. bucket: *bucket_attr,
  166. }),
  167. )
  168. } else {
  169. (bridges, None)
  170. }
  171. }
  172. /// Create a random BridgeLine for testing
  173. #[cfg(test)]
  174. pub fn random() -> Self {
  175. let mut rng = rand::thread_rng();
  176. let mut res: Self = Default::default();
  177. // Pick a random 4-byte address
  178. let mut addr: [u8; 4] = [0; 4];
  179. rng.fill_bytes(&mut addr);
  180. // If the leading byte is 224 or more, that's not a valid IPv4
  181. // address. Choose an IPv6 address instead (but don't worry too
  182. // much about it being well formed).
  183. if addr[0] >= 224 {
  184. rng.fill_bytes(&mut res.addr);
  185. } else {
  186. // Store an IPv4 address as a v4-mapped IPv6 address
  187. res.addr[10] = 255;
  188. res.addr[11] = 255;
  189. res.addr[12..16].copy_from_slice(&addr);
  190. };
  191. let ports: [u16; 4] = [443, 4433, 8080, 43079];
  192. let portidx = (rng.next_u32() % 4) as usize;
  193. res.port = ports[portidx];
  194. res.uid_fingerprint = rng.next_u64();
  195. let mut cert: [u8; 52] = [0; 52];
  196. rng.fill_bytes(&mut cert);
  197. let infostr: String = format!(
  198. "obfs4 cert={}, iat-mode=0",
  199. general_purpose::STANDARD_NO_PAD.encode(cert)
  200. );
  201. res.info[..infostr.len()].copy_from_slice(infostr.as_bytes());
  202. res
  203. }
  204. }
  205. #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
  206. #[serde(try_from = "Vec<u8>", into = "Vec<u8>")]
  207. pub struct EncryptedBucket([u8; ENC_BUCKET_BYTES]);
  208. impl From<EncryptedBucket> for Vec<u8> {
  209. fn from(e: EncryptedBucket) -> Vec<u8> {
  210. e.0.into()
  211. }
  212. }
  213. #[derive(thiserror::Error, Debug)]
  214. #[error("wrong slice length")]
  215. pub struct WrongSliceLengthError;
  216. impl TryFrom<Vec<u8>> for EncryptedBucket {
  217. type Error = WrongSliceLengthError;
  218. fn try_from(v: Vec<u8>) -> Result<EncryptedBucket, Self::Error> {
  219. Ok(EncryptedBucket(
  220. *Box::<[u8; ENC_BUCKET_BYTES]>::try_from(v).map_err(|_| WrongSliceLengthError)?,
  221. ))
  222. }
  223. }
  224. #[derive(Debug, Serialize, Deserialize)]
  225. struct K {
  226. encbucket: EncryptedBucket,
  227. }
  228. /// A BridgeTable is the internal structure holding the buckets
  229. /// containing the bridges, the keys used to encrypt the buckets, and
  230. /// the encrypted buckets. The encrypted buckets will be exposed to the
  231. /// users of the system, and each user credential will contain the
  232. /// decryption key for one bucket.
  233. #[serde_as]
  234. #[derive(Debug, Default, Serialize, Deserialize)]
  235. pub struct BridgeTable {
  236. /// All structures in the bridgetable are indexed by counter
  237. pub counter: u32,
  238. /// The keys of all buckets, indexed by counter, that are still part of the bridge table.
  239. pub keys: HashMap<u32, [u8; 16]>,
  240. /// All buckets, indexed by counter corresponding to the key above, that are
  241. /// part of the bridge table.
  242. pub buckets: HashMap<u32, [BridgeLine; MAX_BRIDGES_PER_BUCKET]>,
  243. pub encbuckets: HashMap<u32, EncryptedBucket>,
  244. /// Individual bridges that are reachable.
  245. #[serde_as(as = "HashMap<serde_with::json::JsonString, _>")]
  246. pub reachable: HashMap<BridgeLine, Vec<(u32, usize)>>,
  247. /// Bucket ids of "hot spare" buckets. These buckets are not handed
  248. /// to users, nor do they have any Migration credentials pointing to
  249. /// them. When a new Migration credential is needed, a bucket is
  250. /// removed from this set and used for that purpose.
  251. pub spares: HashSet<u32>,
  252. /// In some instances a single bridge may need to be added to a bucket as a replacement
  253. /// or otherwise. In that case, a spare bucket will be removed from the set of spares, one
  254. /// bridge will be used as the replacement and the left over bridges will be appended to
  255. /// unallocated_bridges.
  256. pub unallocated_bridges: Vec<BridgeLine>,
  257. // To prevent issues with the counter for the hashmap keys, keep a list of keys that
  258. // no longer match any buckets that can be used before increasing the counter.
  259. pub recycleable_keys: Vec<u32>,
  260. // A list of keys that have been blocked (bucket_id: u32), as well as the
  261. // time (julian_date: u32) of their blocking so that they can be repurposed with new
  262. // buckets after the EXPIRY_DATE.
  263. pub blocked_keys: Vec<(u32, u32)>,
  264. // Similarly, a list of open entry buckets (bucket_id: u32) and the time they were
  265. // created (julian_date: u32) so they will be listed as expired after the EXPIRY_DATE.
  266. // TODO: add open entry buckets to the open_inv_keys only once they have been distributed
  267. pub open_inv_keys: Vec<(u32, u32)>,
  268. /// The date the buckets were last encrypted to make the encbucket.
  269. /// The encbucket must be rebuilt at least each day so that the Bucket
  270. /// Reachability credentials in the buckets can be refreshed.
  271. pub date_last_enc: u32,
  272. }
  273. // Invariant: the lengths of the keys and bucket hashmap are the same.
  274. // The encbuckets hashmap only gets updated when encrypt_table is called.
  275. impl BridgeTable {
  276. /// Get the number of buckets in the bridge table
  277. #[cfg(feature = "bridgeauth")]
  278. pub fn num_buckets(&self) -> usize {
  279. self.buckets.len()
  280. }
  281. /// Insert a new bucket into the bridge table, returning its index
  282. #[cfg(feature = "bridgeauth")]
  283. pub fn new_bucket(&mut self, index: u32, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET]) {
  284. // Pick a random key to encrypt this bucket
  285. let mut rng = rand::thread_rng();
  286. let mut key: [u8; 16] = [0; 16];
  287. rng.fill_bytes(&mut key);
  288. self.keys.insert(index, key);
  289. self.buckets.insert(index, *bucket);
  290. // TODO: maybe we don't need this if the hashtable can keep track of available bridges
  291. // Mark the new bridges as available
  292. for (i, b) in bucket.iter().enumerate() {
  293. if b.port > 0 {
  294. if let Some(v) = self.reachable.get_mut(b) {
  295. v.push((index, i));
  296. } else {
  297. let v = vec![(index, i)];
  298. self.reachable.insert(*b, v);
  299. }
  300. }
  301. }
  302. }
  303. /// Create the vector of encrypted buckets from the keys and buckets
  304. /// in the BridgeTable. All of the entries will be (randomly)
  305. /// re-encrypted, so it will be hidden whether any individual bucket
  306. /// has changed (except for entirely new buckets, of course).
  307. /// Bucket Reachability credentials are added to the buckets when
  308. /// enough (at least MIN_BUCKET_REACHABILITY) bridges in the bucket
  309. /// are reachable.
  310. #[cfg(feature = "bridgeauth")]
  311. pub fn encrypt_table(&mut self, today: u32, reachability_priv: &IssuerPrivKey) {
  312. let mut rng = rand::thread_rng();
  313. self.encbuckets.clear();
  314. for (uid, key) in self.keys.iter() {
  315. let bucket = self.buckets.get(uid).unwrap();
  316. let mut encbucket: [u8; ENC_BUCKET_BYTES] = [0; ENC_BUCKET_BYTES];
  317. let plainbucket: [u8; BUCKET_BYTES] = BridgeLine::bucket_encode(
  318. bucket,
  319. &self.reachable,
  320. today,
  321. &to_scalar(*uid, key),
  322. reachability_priv,
  323. );
  324. // Set the AES key
  325. let aeskey = GenericArray::from_slice(key);
  326. // Pick a random nonce
  327. let mut noncebytes: [u8; 12] = [0; 12];
  328. rng.fill_bytes(&mut noncebytes);
  329. let nonce = GenericArray::from_slice(&noncebytes);
  330. // Encrypt
  331. let cipher = Aes128Gcm::new(aeskey);
  332. let ciphertext: Vec<u8> = cipher.encrypt(nonce, plainbucket.as_ref()).unwrap();
  333. encbucket[0..12].copy_from_slice(&noncebytes);
  334. encbucket[12..].copy_from_slice(ciphertext.as_slice());
  335. let k = EncryptedBucket(encbucket);
  336. self.encbuckets.insert(*uid, k);
  337. }
  338. self.date_last_enc = today;
  339. }
  340. /// Decrypt an individual encrypted bucket, given its id, key, and
  341. /// the encrypted bucket itself
  342. pub fn decrypt_bucket(
  343. id: u32,
  344. key: &[u8; 16],
  345. encbucket: &EncryptedBucket,
  346. ) -> Result<Bucket, aead::Error> {
  347. // Set the nonce and the key
  348. let k = K {
  349. encbucket: *encbucket,
  350. };
  351. let nonce = GenericArray::from_slice(&k.encbucket.0[0..12]);
  352. let aeskey = GenericArray::from_slice(key);
  353. // Decrypt
  354. let cipher = Aes128Gcm::new(aeskey);
  355. let plaintext: Vec<u8> = cipher.decrypt(nonce, k.encbucket.0[12..].as_ref())?;
  356. // Convert the plaintext bytes to an array of BridgeLines
  357. Ok(BridgeLine::bucket_decode(
  358. plaintext.as_slice().try_into().unwrap(),
  359. &to_scalar(id, key),
  360. ))
  361. }
  362. /// Decrypt an individual encrypted bucket, given its id and key
  363. #[cfg(feature = "bridgeauth")]
  364. pub fn decrypt_bucket_id(&self, id: u32, key: &[u8; 16]) -> Result<Bucket, aead::Error> {
  365. let encbucket: &EncryptedBucket = match self.encbuckets.get(&id) {
  366. Some(encbucket) => encbucket,
  367. None => panic!("Provided ID not found"),
  368. };
  369. BridgeTable::decrypt_bucket(id, key, encbucket)
  370. }
  371. }
  372. // Unit tests that require access to the testing-only function
  373. // BridgeLine::random()
  374. #[cfg(test)]
  375. mod tests {
  376. use super::*;
  377. #[test]
  378. fn test_bridge_table() -> Result<(), aead::Error> {
  379. // Create private keys for the Bucket Reachability credentials
  380. let reachability_priv = IssuerPrivKey::new(2);
  381. // Create an empty bridge table
  382. let mut btable: BridgeTable = Default::default();
  383. // Make 20 buckets with one random bridge each
  384. for _ in 0..20 {
  385. let bucket: [BridgeLine; 3] =
  386. [BridgeLine::random(), Default::default(), Default::default()];
  387. btable.counter += 1;
  388. btable.new_bucket(btable.counter, &bucket);
  389. }
  390. // And 20 more with three random bridges each
  391. for _ in 0..20 {
  392. let bucket: [BridgeLine; 3] = [
  393. BridgeLine::random(),
  394. BridgeLine::random(),
  395. BridgeLine::random(),
  396. ];
  397. btable.counter += 1;
  398. btable.new_bucket(btable.counter, &bucket);
  399. }
  400. let today: u32 = time::OffsetDateTime::now_utc()
  401. .date()
  402. .to_julian_day()
  403. .try_into()
  404. .unwrap();
  405. // Create the encrypted bridge table
  406. btable.encrypt_table(today, &reachability_priv);
  407. // Try to decrypt a 1-bridge bucket
  408. let key7 = btable.keys.get(&7u32).unwrap();
  409. let bucket7 = btable.decrypt_bucket_id(7, key7)?;
  410. println!("bucket 7 = {:?}", bucket7);
  411. // Try to decrypt a 3-bridge bucket
  412. let key24 = btable.keys.get(&24u32).unwrap();
  413. let bucket24 = btable.decrypt_bucket_id(24, key24)?;
  414. println!("bucket 24 = {:?}", bucket24);
  415. // Try to decrypt a bucket with the wrong key
  416. let key12 = btable.keys.get(&12u32).unwrap();
  417. let res = btable.decrypt_bucket_id(15, key12).unwrap_err();
  418. println!("bucket key mismatch = {:?}", res);
  419. Ok(())
  420. }
  421. }
  422. /// Convert an id and key to a Scalar attribute
  423. pub fn to_scalar(id: u32, key: &[u8; 16]) -> Scalar {
  424. let mut b: [u8; 32] = [0; 32];
  425. // b is a little-endian representation of the Scalar; put the key in
  426. // the low 16 bytes, and the id in the next 4 bytes.
  427. b[0..16].copy_from_slice(key);
  428. b[16..20].copy_from_slice(&id.to_le_bytes());
  429. // This cannot fail, since we're only using the low 20 bytes of b
  430. Scalar::from_canonical_bytes(b).unwrap()
  431. }
  432. /// Convert a Scalar attribute to an id and key if possible
  433. pub fn from_scalar(s: Scalar) -> Result<(u32, [u8; 16]), aead::Error> {
  434. // Check that the top 12 bytes of the Scalar are 0
  435. let sbytes = s.as_bytes();
  436. if sbytes[20..].ct_eq(&[0u8; 12]).unwrap_u8() == 0 {
  437. return Err(aead::Error);
  438. }
  439. let id = u32::from_le_bytes(sbytes[16..20].try_into().unwrap());
  440. let mut key: [u8; 16] = [0; 16];
  441. key.copy_from_slice(&sbytes[..16]);
  442. Ok((id, key))
  443. }