bridge_table.rs 15 KB

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