bridge_table.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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, NewAead};
  14. use aes_gcm::Aes128Gcm;
  15. use curve25519_dalek::ristretto::CompressedRistretto;
  16. use curve25519_dalek::ristretto::RistrettoBasepointTable;
  17. use curve25519_dalek::scalar::Scalar;
  18. use rand::RngCore;
  19. use serde::{Serialize, Deserialize};
  20. use serde_big_array::big_array;
  21. use std::collections::{HashMap, HashSet};
  22. use std::convert::TryInto;
  23. use subtle::ConstantTimeEq;
  24. big_array! {
  25. BigArray;
  26. +202,
  27. }
  28. /// Each bridge information line is serialized into this many bytes
  29. pub const BRIDGE_BYTES: usize = 220;
  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. #[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq, Debug)]
  39. pub struct BridgeLine {
  40. /// IPv4 or IPv6 address
  41. pub addr: [u8; 16],
  42. /// port
  43. pub port: u16,
  44. /// other protocol information, including pluggable transport,
  45. /// public key, etc.
  46. #[serde(with = "BigArray")]
  47. pub info: [u8; BRIDGE_BYTES - 18],
  48. }
  49. /// A bucket contains MAX_BRIDGES_PER_BUCKET bridges plus the
  50. /// information needed to construct a Bucket Reachability credential,
  51. /// which is a 4-byte date, and a (P,Q) MAC
  52. type Bucket = (
  53. [BridgeLine; MAX_BRIDGES_PER_BUCKET],
  54. Option<cred::BucketReachability>,
  55. );
  56. /// The size of a plaintext bucket
  57. pub const BUCKET_BYTES: usize = BRIDGE_BYTES * MAX_BRIDGES_PER_BUCKET + 4 + 32 + 32;
  58. /// The size of an encrypted bucket
  59. pub const ENC_BUCKET_BYTES: usize = BUCKET_BYTES + 12 + 16;
  60. impl Default for BridgeLine {
  61. /// An "empty" BridgeLine is represented by all zeros
  62. fn default() -> Self {
  63. Self {
  64. addr: [0; 16],
  65. port: 0,
  66. info: [0; BRIDGE_BYTES - 18],
  67. }
  68. }
  69. }
  70. impl BridgeLine {
  71. /// Encode a BridgeLine to a byte array
  72. pub fn encode(&self) -> [u8; BRIDGE_BYTES] {
  73. let mut res: [u8; BRIDGE_BYTES] = [0; BRIDGE_BYTES];
  74. res[0..16].copy_from_slice(&self.addr);
  75. res[16..18].copy_from_slice(&self.port.to_be_bytes());
  76. res[18..].copy_from_slice(&self.info);
  77. res
  78. }
  79. /// Decode a BridgeLine from a byte array
  80. pub fn decode(data: &[u8; BRIDGE_BYTES]) -> Self {
  81. let mut res: Self = Default::default();
  82. res.addr.copy_from_slice(&data[0..16]);
  83. res.port = u16::from_be_bytes(data[16..18].try_into().unwrap());
  84. res.info.copy_from_slice(&data[18..]);
  85. res
  86. }
  87. /// Encode a bucket to a byte array, including a Bucket Reachability
  88. /// credential if appropriate
  89. pub fn bucket_encode(
  90. bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET],
  91. reachable: &HashMap<BridgeLine, Vec<(u32, usize)>>,
  92. today: u32,
  93. bucket_attr: &Scalar,
  94. reachability_priv: &IssuerPrivKey,
  95. ) -> [u8; BUCKET_BYTES] {
  96. let mut res: [u8; BUCKET_BYTES] = [0; BUCKET_BYTES];
  97. let mut pos: usize = 0;
  98. let mut num_reachable: usize = 0;
  99. for bridge in bucket {
  100. res[pos..pos + BRIDGE_BYTES].copy_from_slice(&bridge.encode());
  101. if reachable.contains_key(bridge) {
  102. num_reachable += 1;
  103. }
  104. pos += BRIDGE_BYTES;
  105. }
  106. if num_reachable >= MIN_BUCKET_REACHABILITY {
  107. // Construct a Bucket Reachability credential for this
  108. // bucket and today's date
  109. let today_attr: Scalar = today.into();
  110. let mut rng = rand::thread_rng();
  111. let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
  112. let b = Scalar::random(&mut rng);
  113. let P = &b * Btable;
  114. let Q = &(b
  115. * (reachability_priv.x[0]
  116. + reachability_priv.x[1] * today_attr
  117. + reachability_priv.x[2] * bucket_attr))
  118. * Btable;
  119. res[pos..pos + 4].copy_from_slice(&today.to_le_bytes());
  120. res[pos + 4..pos + 36].copy_from_slice(P.compress().as_bytes());
  121. res[pos + 36..].copy_from_slice(Q.compress().as_bytes());
  122. }
  123. res
  124. }
  125. /// Decode a bucket from a byte array, yielding the array of
  126. /// BridgeLine entries and an optional Bucket Reachability
  127. /// credential
  128. fn bucket_decode(data: &[u8; BUCKET_BYTES], bucket_attr: &Scalar) -> Bucket {
  129. let mut pos: usize = 0;
  130. let mut bridges: [BridgeLine; MAX_BRIDGES_PER_BUCKET] = Default::default();
  131. for bridge in bridges.iter_mut().take(MAX_BRIDGES_PER_BUCKET) {
  132. *bridge = BridgeLine::decode(data[pos..pos + BRIDGE_BYTES].try_into().unwrap());
  133. pos += BRIDGE_BYTES;
  134. }
  135. // See if there's a nonzero date in the Bucket Reachability
  136. // Credential
  137. let date = u32::from_le_bytes(data[pos..pos + 4].try_into().unwrap());
  138. let (optP, optQ) = if date > 0 {
  139. (
  140. CompressedRistretto::from_slice(&data[pos + 4..pos + 36]).decompress(),
  141. CompressedRistretto::from_slice(&data[pos + 36..]).decompress(),
  142. )
  143. } else {
  144. (None, None)
  145. };
  146. if let (Some(P), Some(Q)) = (optP, optQ) {
  147. let date_attr: Scalar = date.into();
  148. (
  149. bridges,
  150. Some(cred::BucketReachability {
  151. P,
  152. Q,
  153. date: date_attr,
  154. bucket: *bucket_attr,
  155. }),
  156. )
  157. } else {
  158. (bridges, None)
  159. }
  160. }
  161. /// Create a random BridgeLine for testing
  162. #[cfg(test)]
  163. pub fn random() -> Self {
  164. let mut rng = rand::thread_rng();
  165. let mut res: Self = Default::default();
  166. // Pick a random 4-byte address
  167. let mut addr: [u8; 4] = [0; 4];
  168. rng.fill_bytes(&mut addr);
  169. // If the leading byte is 224 or more, that's not a valid IPv4
  170. // address. Choose an IPv6 address instead (but don't worry too
  171. // much about it being well formed).
  172. if addr[0] >= 224 {
  173. rng.fill_bytes(&mut res.addr);
  174. } else {
  175. // Store an IPv4 address as a v4-mapped IPv6 address
  176. res.addr[10] = 255;
  177. res.addr[11] = 255;
  178. res.addr[12..16].copy_from_slice(&addr);
  179. };
  180. let ports: [u16; 4] = [443, 4433, 8080, 43079];
  181. let portidx = (rng.next_u32() % 4) as usize;
  182. res.port = ports[portidx];
  183. let mut fingerprint: [u8; 20] = [0; 20];
  184. let mut cert: [u8; 52] = [0; 52];
  185. rng.fill_bytes(&mut fingerprint);
  186. rng.fill_bytes(&mut cert);
  187. let infostr: String = format!(
  188. "obfs4 {} cert={} iat-mode=0",
  189. hex_fmt::HexFmt(fingerprint),
  190. base64::encode_config(cert, base64::STANDARD_NO_PAD)
  191. );
  192. res.info[..infostr.len()].copy_from_slice(infostr.as_bytes());
  193. res
  194. }
  195. }
  196. /// A BridgeTable is the internal structure holding the buckets
  197. /// containing the bridges, the keys used to encrypt the buckets, and
  198. /// the encrypted buckets. The encrypted buckets will be exposed to the
  199. /// users of the system, and each user credential will contain the
  200. /// decryption key for one bucket.
  201. #[derive(Debug, Default)]
  202. pub struct BridgeTable {
  203. pub keys: Vec<[u8; 16]>,
  204. pub buckets: Vec<[BridgeLine; MAX_BRIDGES_PER_BUCKET]>,
  205. pub encbuckets: Vec<[u8; ENC_BUCKET_BYTES]>,
  206. /// Individual bridges that are reachable
  207. pub reachable: HashMap<BridgeLine, Vec<(u32, usize)>>,
  208. /// bucket ids of "hot spare" buckets. These buckets are not handed
  209. /// to users, nor do they have any Migration credentials pointing to
  210. /// them. When a new Migration credential is needed, a bucket is
  211. /// removed from this set and used for that purpose.
  212. pub spares: HashSet<u32>,
  213. /// The date the buckets were last encrypted to make the encbucket.
  214. ///
  215. /// The encbucket must be rebuilt each day so that the Bucket
  216. /// Reachability credentials in the buckets can be refreshed.
  217. pub date_last_enc: u32,
  218. }
  219. // Invariant: the lengths of the keys and buckets vectors are the same.
  220. // The encbuckets vector only gets updated when encrypt_table is called.
  221. impl BridgeTable {
  222. /// Get the number of buckets in the bridge table
  223. pub fn num_buckets(&self) -> usize {
  224. self.buckets.len()
  225. }
  226. /// Append a new bucket to the bridge table, returning its index
  227. pub fn new_bucket(&mut self, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET]) -> u32 {
  228. // Pick a random key to encrypt this bucket
  229. let mut rng = rand::thread_rng();
  230. let mut key: [u8; 16] = [0; 16];
  231. rng.fill_bytes(&mut key);
  232. self.keys.push(key);
  233. self.buckets.push(*bucket);
  234. let bucketnum: u32 = (self.buckets.len() - 1).try_into().unwrap();
  235. // Mark the new bridges as available
  236. for (i, b) in bucket.iter().enumerate() {
  237. if b.port > 0 {
  238. if let Some(v) = self.reachable.get_mut(b) {
  239. v.push((bucketnum, i));
  240. } else {
  241. let v = vec![(bucketnum, i)];
  242. self.reachable.insert(*b, v);
  243. }
  244. }
  245. }
  246. bucketnum
  247. }
  248. /// Create the vector of encrypted buckets from the keys and buckets
  249. /// in the BridgeTable. All of the entries will be (randomly)
  250. /// re-encrypted, so it will be hidden whether any individual bucket
  251. /// has changed (except for entirely new buckets, of course).
  252. /// Bucket Reachability credentials are added to the buckets when
  253. /// enough (at least MIN_BUCKET_REACHABILITY) bridges in the bucket
  254. /// are reachable.
  255. pub fn encrypt_table(&mut self, today: u32, reachability_priv: &IssuerPrivKey) {
  256. let mut rng = rand::thread_rng();
  257. self.encbuckets.clear();
  258. // We want id to be a u32, so we use .zip(0u32..) instead of
  259. // enumerate()
  260. for ((key, bucket), id) in self.keys.iter().zip(self.buckets.iter()).zip(0u32..) {
  261. let mut encbucket: [u8; ENC_BUCKET_BYTES] = [0; ENC_BUCKET_BYTES];
  262. let plainbucket: [u8; BUCKET_BYTES] = BridgeLine::bucket_encode(
  263. bucket,
  264. &self.reachable,
  265. today,
  266. &to_scalar(id, key),
  267. reachability_priv,
  268. );
  269. // Set the AES key
  270. let aeskey = GenericArray::from_slice(key);
  271. // Pick a random nonce
  272. let mut noncebytes: [u8; 12] = [0; 12];
  273. rng.fill_bytes(&mut noncebytes);
  274. let nonce = GenericArray::from_slice(&noncebytes);
  275. // Encrypt
  276. let cipher = Aes128Gcm::new(aeskey);
  277. let ciphertext: Vec<u8> = cipher.encrypt(&nonce, plainbucket.as_ref()).unwrap();
  278. encbucket[0..12].copy_from_slice(&noncebytes);
  279. encbucket[12..].copy_from_slice(ciphertext.as_slice());
  280. self.encbuckets.push(encbucket);
  281. }
  282. self.date_last_enc = today;
  283. }
  284. /// Decrypt an individual encrypted bucket, given its id, key, and
  285. /// the encrypted bucket itself
  286. pub fn decrypt_bucket(
  287. id: u32,
  288. key: &[u8; 16],
  289. encbucket: &[u8; ENC_BUCKET_BYTES],
  290. ) -> Result<Bucket, aead::Error> {
  291. // Set the nonce and the key
  292. let nonce = GenericArray::from_slice(&encbucket[0..12]);
  293. let aeskey = GenericArray::from_slice(key);
  294. // Decrypt
  295. let cipher = Aes128Gcm::new(aeskey);
  296. let plaintext: Vec<u8> = cipher.decrypt(&nonce, encbucket[12..].as_ref())?;
  297. // Convert the plaintext bytes to an array of BridgeLines
  298. Ok(BridgeLine::bucket_decode(
  299. plaintext.as_slice().try_into().unwrap(),
  300. &to_scalar(id, key),
  301. ))
  302. }
  303. /// Decrypt an individual encrypted bucket, given its id and key
  304. pub fn decrypt_bucket_id(&self, id: u32, key: &[u8; 16]) -> Result<Bucket, aead::Error> {
  305. let encbucket = self.encbuckets[id as usize];
  306. BridgeTable::decrypt_bucket(id, key, &encbucket)
  307. }
  308. }
  309. // Unit tests that require access to the testing-only function
  310. // BridgeLine::random()
  311. #[cfg(test)]
  312. mod tests {
  313. use super::*;
  314. #[test]
  315. fn test_bridge_table() -> Result<(), aead::Error> {
  316. // Create private keys for the Bucket Reachability credentials
  317. let reachability_priv = IssuerPrivKey::new(2);
  318. // Create an empty bridge table
  319. let mut btable: BridgeTable = Default::default();
  320. // Make 20 buckets with one random bridge each
  321. for _ in 0..20 {
  322. let bucket: [BridgeLine; 3] =
  323. [BridgeLine::random(), Default::default(), Default::default()];
  324. btable.new_bucket(&bucket);
  325. }
  326. // And 20 more with three random bridges each
  327. for _ in 0..20 {
  328. let bucket: [BridgeLine; 3] = [
  329. BridgeLine::random(),
  330. BridgeLine::random(),
  331. BridgeLine::random(),
  332. ];
  333. btable.new_bucket(&bucket);
  334. }
  335. let today: u32 = time::OffsetDateTime::now_utc()
  336. .date()
  337. .julian_day()
  338. .try_into()
  339. .unwrap();
  340. // Create the encrypted bridge table
  341. btable.encrypt_table(today, &reachability_priv);
  342. // Try to decrypt a 1-bridge bucket
  343. let key7 = btable.keys[7];
  344. let bucket7 = btable.decrypt_bucket_id(7, &key7)?;
  345. println!("bucket 7 = {:?}", bucket7);
  346. // Try to decrypt a 3-bridge bucket
  347. let key24 = btable.keys[24];
  348. let bucket24 = btable.decrypt_bucket_id(24, &key24)?;
  349. println!("bucket 24 = {:?}", bucket24);
  350. // Try to decrypt a bucket with the wrong key
  351. let key12 = btable.keys[12];
  352. let res = btable.decrypt_bucket_id(15, &key12).unwrap_err();
  353. println!("bucket key mismatch = {:?}", res);
  354. Ok(())
  355. }
  356. }
  357. /// Convert an id and key to a Scalar attribute
  358. pub fn to_scalar(id: u32, key: &[u8; 16]) -> Scalar {
  359. let mut b: [u8; 32] = [0; 32];
  360. // b is a little-endian representation of the Scalar; put the key in
  361. // the low 16 bytes, and the id in the next 4 bytes.
  362. b[0..16].copy_from_slice(key);
  363. b[16..20].copy_from_slice(&id.to_le_bytes());
  364. // This cannot fail, since we're only using the low 20 bytes of b
  365. Scalar::from_canonical_bytes(b).unwrap()
  366. }
  367. /// Convert a Scalar attribute to an id and key if possible
  368. pub fn from_scalar(s: Scalar) -> Result<(u32, [u8; 16]), aead::Error> {
  369. // Check that the top 12 bytes of the Scalar are 0
  370. let sbytes = s.as_bytes();
  371. if sbytes[20..].ct_eq(&[0u8; 12]).unwrap_u8() == 0 {
  372. return Err(aead::Error);
  373. }
  374. let id = u32::from_le_bytes(sbytes[16..20].try_into().unwrap());
  375. let mut key: [u8; 16] = [0; 16];
  376. key.copy_from_slice(&sbytes[..16]);
  377. Ok((id, key))
  378. }