bridge_table.rs 15 KB

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