bridge_table.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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 aes_gcm::aead;
  10. use aes_gcm::aead::{generic_array::GenericArray, Aead, NewAead};
  11. use aes_gcm::Aes128Gcm;
  12. use curve25519_dalek::scalar::Scalar;
  13. use rand::RngCore;
  14. use std::convert::TryInto;
  15. use subtle::ConstantTimeEq;
  16. /// Each bridge information line is serialized into this many bytes
  17. pub const BRIDGE_BYTES: usize = 220;
  18. /// The max number of bridges per bucket
  19. pub const MAX_BRIDGES_PER_BUCKET: usize = 3;
  20. /// The size of a plaintext bucket
  21. pub const BUCKET_BYTES: usize = BRIDGE_BYTES * MAX_BRIDGES_PER_BUCKET;
  22. /// The size of an encrypted bucket
  23. pub const ENC_BUCKET_BYTES: usize = BUCKET_BYTES + 12 + 16;
  24. /// A bridge information line
  25. #[derive(Copy, Clone, Debug)]
  26. pub struct BridgeLine {
  27. /// IPv4 or IPv6 address
  28. pub addr: [u8; 16],
  29. /// port
  30. pub port: u16,
  31. /// other protocol information, including pluggable transport,
  32. /// public key, etc.
  33. pub info: [u8; BRIDGE_BYTES - 18],
  34. }
  35. impl Default for BridgeLine {
  36. /// An "empty" BridgeLine is represented by all zeros
  37. fn default() -> Self {
  38. Self {
  39. addr: [0; 16],
  40. port: 0,
  41. info: [0; BRIDGE_BYTES - 18],
  42. }
  43. }
  44. }
  45. impl BridgeLine {
  46. /// Encode a BridgeLine to a byte array
  47. pub fn encode(&self) -> [u8; BRIDGE_BYTES] {
  48. let mut res: [u8; BRIDGE_BYTES] = [0; BRIDGE_BYTES];
  49. res[0..16].copy_from_slice(&self.addr);
  50. res[16..18].copy_from_slice(&self.port.to_be_bytes());
  51. res[18..].copy_from_slice(&self.info);
  52. res
  53. }
  54. /// Decode a BridgeLine from a byte array
  55. pub fn decode(data: &[u8; BRIDGE_BYTES]) -> Self {
  56. let mut res: Self = Default::default();
  57. res.addr.copy_from_slice(&data[0..16]);
  58. res.port = u16::from_be_bytes(data[16..18].try_into().unwrap());
  59. res.info.copy_from_slice(&data[18..]);
  60. res
  61. }
  62. /// Encode a bucket to a byte array
  63. pub fn bucket_encode(bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET]) -> [u8; BUCKET_BYTES] {
  64. let mut res: [u8; BUCKET_BYTES] = [0; BUCKET_BYTES];
  65. let mut pos: usize = 0;
  66. for bridge in bucket {
  67. res[pos..pos + BRIDGE_BYTES].copy_from_slice(&bridge.encode());
  68. pos += BRIDGE_BYTES;
  69. }
  70. res
  71. }
  72. /// Decode a bucket from a byte array
  73. pub fn bucket_decode(data: &[u8; BUCKET_BYTES]) -> [BridgeLine; MAX_BRIDGES_PER_BUCKET] {
  74. let mut pos: usize = 0;
  75. let mut res: [BridgeLine; MAX_BRIDGES_PER_BUCKET] = Default::default();
  76. for bridge in res.iter_mut().take(MAX_BRIDGES_PER_BUCKET) {
  77. *bridge = BridgeLine::decode(data[pos..pos + BRIDGE_BYTES].try_into().unwrap());
  78. pos += BRIDGE_BYTES;
  79. }
  80. res
  81. }
  82. /// Create a random BridgeLine for testing
  83. #[cfg(test)]
  84. pub fn random() -> Self {
  85. let mut rng = rand::thread_rng();
  86. let mut res: Self = Default::default();
  87. // Pick a random 4-byte address
  88. let mut addr: [u8; 4] = [0; 4];
  89. rng.fill_bytes(&mut addr);
  90. // If the leading byte is 224 or more, that's not a valid IPv4
  91. // address. Choose an IPv6 address instead (but don't worry too
  92. // much about it being well formed).
  93. if addr[0] >= 224 {
  94. rng.fill_bytes(&mut res.addr);
  95. } else {
  96. // Store an IPv4 address as a v4-mapped IPv6 address
  97. res.addr[10] = 255;
  98. res.addr[11] = 255;
  99. res.addr[12..16].copy_from_slice(&addr);
  100. };
  101. let ports: [u16; 4] = [443, 4433, 8080, 43079];
  102. let portidx = (rng.next_u32() % 4) as usize;
  103. res.port = ports[portidx];
  104. let mut fingerprint: [u8; 20] = [0; 20];
  105. let mut cert: [u8; 52] = [0; 52];
  106. rng.fill_bytes(&mut fingerprint);
  107. rng.fill_bytes(&mut cert);
  108. let infostr: String = format!(
  109. "obfs4 {} cert={} iat-mode=0",
  110. hex_fmt::HexFmt(fingerprint),
  111. base64::encode_config(cert, base64::STANDARD_NO_PAD)
  112. );
  113. res.info[..infostr.len()].copy_from_slice(infostr.as_bytes());
  114. res
  115. }
  116. }
  117. /// A BridgeTable is the internal structure holding the buckets
  118. /// containing the bridges, the keys used to encrypt the buckets, and
  119. /// the encrypted buckets. The encrypted buckets will be exposed to the
  120. /// users of the system, and each user credential will contain the
  121. /// decryption key for one bucket.
  122. #[derive(Debug, Default)]
  123. pub struct BridgeTable {
  124. pub keys: Vec<[u8; 16]>,
  125. pub buckets: Vec<[BridgeLine; MAX_BRIDGES_PER_BUCKET]>,
  126. pub encbuckets: Vec<[u8; ENC_BUCKET_BYTES]>,
  127. }
  128. // Invariant: the lengths of the keys and buckets vectors are the same.
  129. // The encbuckets vector only gets updated when encrypt_table is called.
  130. impl BridgeTable {
  131. /// Get the number of buckets in the bridge table
  132. pub fn num_buckets(&self) -> usize {
  133. self.buckets.len()
  134. }
  135. /// Append a new bucket to the bridge table
  136. pub fn new_bucket(&mut self, bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET]) {
  137. // Pick a random key to encrypt this bucket
  138. let mut rng = rand::thread_rng();
  139. let mut key: [u8; 16] = [0; 16];
  140. rng.fill_bytes(&mut key);
  141. self.keys.push(key);
  142. self.buckets.push(bucket);
  143. }
  144. /// Create the vector of encrypted buckets from the keys and buckets
  145. /// in the BridgeTable. All of the entries will be (randomly)
  146. /// re-encrypted, so it will be hidden whether any individual bucket
  147. /// has changed (except for entirely new buckets, of course).
  148. pub fn encrypt_table(&mut self) {
  149. let mut rng = rand::thread_rng();
  150. self.encbuckets.clear();
  151. for (key, bucket) in self.keys.iter().zip(self.buckets.iter()) {
  152. let mut encbucket: [u8; ENC_BUCKET_BYTES] = [0; ENC_BUCKET_BYTES];
  153. let plainbucket: [u8; BUCKET_BYTES] = BridgeLine::bucket_encode(bucket);
  154. // Set the AES key
  155. let aeskey = GenericArray::from_slice(key);
  156. // Pick a random nonce
  157. let mut noncebytes: [u8; 12] = [0; 12];
  158. rng.fill_bytes(&mut noncebytes);
  159. let nonce = GenericArray::from_slice(&noncebytes);
  160. // Encrypt
  161. let cipher = Aes128Gcm::new(aeskey);
  162. let ciphertext: Vec<u8> = cipher.encrypt(&nonce, plainbucket.as_ref()).unwrap();
  163. encbucket[0..12].copy_from_slice(&noncebytes);
  164. encbucket[12..].copy_from_slice(ciphertext.as_slice());
  165. self.encbuckets.push(encbucket);
  166. }
  167. }
  168. /// Decrypt an individual encrypted bucket, given its key
  169. pub fn decrypt_bucket(
  170. key: &[u8; 16],
  171. encbucket: &[u8; ENC_BUCKET_BYTES],
  172. ) -> Result<[BridgeLine; MAX_BRIDGES_PER_BUCKET], aead::Error> {
  173. // Set the nonce and the key
  174. let nonce = GenericArray::from_slice(&encbucket[0..12]);
  175. let aeskey = GenericArray::from_slice(key);
  176. // Decrypt
  177. let cipher = Aes128Gcm::new(aeskey);
  178. let plaintext: Vec<u8> = cipher.decrypt(&nonce, encbucket[12..].as_ref())?;
  179. // Convert the plaintext bytes to an array of BridgeLines
  180. Ok(BridgeLine::bucket_decode(
  181. plaintext.as_slice().try_into().unwrap(),
  182. ))
  183. }
  184. /// Decrypt an individual encrypted bucket, given its id and key
  185. pub fn decrypt_bucket_id(
  186. &self,
  187. id: u32,
  188. key: &[u8; 16],
  189. ) -> Result<[BridgeLine; MAX_BRIDGES_PER_BUCKET], aead::Error> {
  190. let encbucket = self.encbuckets[id as usize];
  191. BridgeTable::decrypt_bucket(key, &encbucket)
  192. }
  193. }
  194. // Unit tests that require access to the testing-only function
  195. // BridgeLine::random()
  196. #[cfg(test)]
  197. mod tests {
  198. use super::*;
  199. #[test]
  200. fn test_bridge_table() -> Result<(), aead::Error> {
  201. // Create an empty bridge table
  202. let mut btable: BridgeTable = Default::default();
  203. // Make 20 buckets with one random bridge each
  204. for _ in 0..20 {
  205. let bucket: [BridgeLine; 3] =
  206. [BridgeLine::random(), Default::default(), Default::default()];
  207. btable.new_bucket(bucket);
  208. }
  209. // And 20 more with three random bridges each
  210. for _ in 0..20 {
  211. let bucket: [BridgeLine; 3] = [
  212. BridgeLine::random(),
  213. BridgeLine::random(),
  214. BridgeLine::random(),
  215. ];
  216. btable.new_bucket(bucket);
  217. }
  218. // Create the encrypted bridge table
  219. btable.encrypt_table();
  220. // Try to decrypt a 1-bridge bucket
  221. let key7 = btable.keys[7];
  222. let bucket7 = btable.decrypt_bucket_id(7, &key7)?;
  223. println!("bucket 7 = {:?}", bucket7);
  224. // Try to decrypt a 3-bridge bucket
  225. let key24 = btable.keys[24];
  226. let bucket24 = btable.decrypt_bucket_id(24, &key24)?;
  227. println!("bucket 24 = {:?}", bucket24);
  228. // Try to decrypt a bucket with the wrong key
  229. let key12 = btable.keys[12];
  230. let res = btable.decrypt_bucket_id(15, &key12).unwrap_err();
  231. println!("bucket key mismatch = {:?}", res);
  232. Ok(())
  233. }
  234. }
  235. /// Convert an id and key to a Scalar attribute
  236. pub fn to_scalar(id: u32, key: &[u8; 16]) -> Scalar {
  237. let mut b: [u8; 32] = [0; 32];
  238. // b is a little-endian representation of the Scalar; put the key in
  239. // the low 16 bytes, and the id in the next 4 bytes.
  240. b[0..16].copy_from_slice(key);
  241. b[16..20].copy_from_slice(&id.to_le_bytes());
  242. // This cannot fail, since we're only using the low 20 bytes of b
  243. Scalar::from_canonical_bytes(b).unwrap()
  244. }
  245. /// Convert a Scalar attribute to an id and key if possible
  246. pub fn from_scalar(s: Scalar) -> Result<(u32, [u8; 16]), aead::Error> {
  247. // Check that the top 12 bytes of the Scalar are 0
  248. let sbytes = s.as_bytes();
  249. if sbytes[20..].ct_eq(&[0u8; 12]).unwrap_u8() == 0 {
  250. return Err(aead::Error);
  251. }
  252. let id = u32::from_le_bytes(sbytes[16..20].try_into().unwrap());
  253. let mut key: [u8; 16] = [0; 16];
  254. key.copy_from_slice(&sbytes[..16]);
  255. Ok((id, key))
  256. }