relay_crypto_tor1.c (9735B)
1 /* Copyright (c) 2001 Matej Pfajfar. 2 * Copyright (c) 2001-2004, Roger Dingledine. 3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 4 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 5 /* See LICENSE for licensing information */ 6 7 /** 8 * @file relay_crypto_tor1.c 9 * @brief Implementation for legacy (tor1) relay cell encryption. 10 **/ 11 12 #include "core/or/or.h" 13 #include "lib/crypt_ops/crypto_cipher.h" 14 #include "lib/crypt_ops/crypto_util.h" 15 #include "core/crypto/hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN 16 #include "core/crypto/relay_crypto_tor1.h" 17 #include "lib/cc/ctassert.h" 18 19 #include "core/or/cell_st.h" 20 #include "core/crypto/relay_crypto_st.h" 21 22 /* Offset of digest within relay cell body for v0 cells. */ 23 #define V0_DIGEST_OFFSET 5 24 #define V0_DIGEST_LEN 4 25 #define V0_RECOGNIZED_OFFSET 1 26 27 /** Update digest from the payload of cell. Assign integrity part to 28 * cell. Record full 20-byte digest in `buf`. 29 */ 30 static void 31 tor1_set_digest_v0(crypto_digest_t *digest, cell_t *cell, uint8_t *buf) 32 { 33 crypto_digest_add_bytes(digest, (char*)cell->payload, CELL_PAYLOAD_SIZE); 34 crypto_digest_get_digest(digest, (char*)buf, DIGEST_LEN); 35 // log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.", 36 // integrity[0], integrity[1], integrity[2], integrity[3]); 37 memcpy(cell->payload + V0_DIGEST_OFFSET, buf, V0_DIGEST_LEN); 38 } 39 40 /** Does the digest for this circuit indicate that this cell is for us? 41 * 42 * Update digest from the payload of cell (with the integrity part set 43 * to 0). If the integrity part is valid, 44 * return 1 and save the full digest in the 20-byte buffer `buf`, 45 * else restore digest 46 * and cell to their original state and return 0. 47 */ 48 static int 49 tor1_relay_digest_matches_v0(crypto_digest_t *digest, cell_t *cell, 50 uint8_t *buf) 51 { 52 uint32_t received_integrity, calculated_integrity; 53 uint8_t calculated_digest[DIGEST_LEN]; 54 crypto_digest_checkpoint_t backup_digest; 55 56 CTASSERT(sizeof(uint32_t) == V0_DIGEST_LEN); 57 58 crypto_digest_checkpoint(&backup_digest, digest); 59 60 memcpy(&received_integrity, cell->payload + V0_DIGEST_OFFSET, V0_DIGEST_LEN); 61 memset(cell->payload + V0_DIGEST_OFFSET, 0, V0_DIGEST_LEN); 62 63 // log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.", 64 // received_integrity[0], received_integrity[1], 65 // received_integrity[2], received_integrity[3]); 66 67 crypto_digest_add_bytes(digest, (char*) cell->payload, CELL_PAYLOAD_SIZE); 68 crypto_digest_get_digest(digest, (char*) calculated_digest, DIGEST_LEN); 69 calculated_integrity = get_uint32(calculated_digest); 70 71 int rv = 1; 72 73 if (calculated_integrity != received_integrity) { 74 // log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing."); 75 // (%d vs %d).", received_integrity, calculated_integrity); 76 /* restore digest to its old form */ 77 crypto_digest_restore(digest, &backup_digest); 78 /* restore the relay header */ 79 memcpy(cell->payload + V0_DIGEST_OFFSET, &received_integrity, 80 V0_DIGEST_LEN); 81 rv = 0; 82 } else { 83 memcpy(buf, calculated_digest, DIGEST_LEN); 84 } 85 86 memwipe(&backup_digest, 0, sizeof(backup_digest)); 87 return rv; 88 } 89 90 static inline bool 91 relay_cell_is_recognized_v0(const cell_t *cell) 92 { 93 return get_uint16(cell->payload + V0_RECOGNIZED_OFFSET) == 0; 94 } 95 96 /** Apply <b>cipher</b> to CELL_PAYLOAD_SIZE bytes of <b>in</b> 97 * (in place). 98 * 99 * Note that we use the same operation for encrypting and for decrypting. 100 */ 101 static void 102 tor1_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in) 103 { 104 crypto_cipher_crypt_inplace(cipher, (char*) in, CELL_PAYLOAD_SIZE); 105 } 106 107 /** Encrypt and authenticate `cell` using the cryptographic 108 * material in `tor1`. 109 * 110 * This method should be used for the first encryption performed 111 * by the client - that is, the one corresponding to the exit node. 112 */ 113 void 114 tor1_crypt_client_originate(tor1_crypt_t *tor1, 115 cell_t *cell) 116 { 117 tor1_set_digest_v0(tor1->f_digest, cell, tor1->sendme_digest); 118 tor1_crypt_one_payload(tor1->f_crypto, cell->payload); 119 } 120 121 /** Encrypt and authenticate `cell`, using the cryptographic 122 * material in `tor1`. 123 * 124 * This method should be used by relays when originating cells toward the 125 * client. 126 */ 127 void 128 tor1_crypt_relay_originate(tor1_crypt_t *tor1, 129 cell_t *cell) 130 { 131 tor1_set_digest_v0(tor1->b_digest, cell, tor1->sendme_digest); 132 tor1_crypt_one_payload(tor1->b_crypto, cell->payload); 133 } 134 135 /** Encrypt `cell` using the cryptographic material in `tor1`. 136 * 137 * This method should be used by clients for cryptographic layers 138 * that are _not_ the final recipient of the cell. */ 139 void 140 tor1_crypt_client_forward(tor1_crypt_t *tor1, cell_t *cell) 141 { 142 tor1_crypt_one_payload(tor1->f_crypto, cell->payload); 143 } 144 145 /** Encrypt `cell` using the cryptographic material in `tor1`. 146 * 147 * This method should be used by relays on cells that are moving 148 * toward the client. */ 149 void 150 tor1_crypt_relay_backward(tor1_crypt_t *tor1, cell_t *cell) 151 { 152 tor1_crypt_one_payload(tor1->b_crypto, cell->payload); 153 } 154 155 /** Decrypt `cell` using the cryptographic material in `tor1`. 156 * 157 * Return `true` when we are the destination for this cell. 158 * 159 * This method should be used by relays on cells 160 * that are moving away from the client. */ 161 bool 162 tor1_crypt_relay_forward(tor1_crypt_t *tor1, cell_t *cell) 163 { 164 tor1_crypt_one_payload(tor1->f_crypto, cell->payload); 165 if (relay_cell_is_recognized_v0(cell)) { 166 if (tor1_relay_digest_matches_v0(tor1->f_digest, cell, 167 tor1->sendme_digest)) { 168 return true; 169 } 170 } 171 return false; 172 } 173 174 /** Decrypt `cell` using the cryptographic material in `tor1`. 175 * 176 * Return `true` when this cell is recognized and authenticated 177 * as coming from the relay that also holds this cryptographic material. 178 * 179 * This method should be used by clients on incoming cells. */ 180 bool 181 tor1_crypt_client_backward(tor1_crypt_t *tor1, cell_t *cell) 182 { 183 tor1_crypt_one_payload(tor1->b_crypto, cell->payload); 184 185 if (relay_cell_is_recognized_v0(cell)) { 186 if (tor1_relay_digest_matches_v0(tor1->b_digest, cell, 187 tor1->sendme_digest)) { 188 return true; 189 } 190 } 191 return false; 192 } 193 194 /** Return the number of bytes that tor1_crypt_init expects. */ 195 size_t 196 tor1_key_material_len(bool is_hs) 197 { 198 if (is_hs) 199 return HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN; 200 else 201 return CPATH_KEY_MATERIAL_LEN; 202 } 203 204 /** Initialize <b>crypto</b> from the key material in key_data. 205 * 206 * If <b>is_hs_v3</b> is set, this cpath will be used for next gen hidden 207 * service circuits and <b>key_data</b> must be 208 * HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN bytes in length. 209 * 210 * If <b>is_hs_v3</b> is not set, key_data must contain CPATH_KEY_MATERIAL_LEN 211 * bytes, which are used as follows: 212 * - 20 to initialize f_digest 213 * - 20 to initialize b_digest 214 * - 16 to key f_crypto 215 * - 16 to key b_crypto 216 * 217 * (If 'reverse' is true, then f_XX and b_XX are swapped.) 218 * 219 * Return 0 if init was successful, else -1 if it failed. 220 */ 221 int 222 tor1_crypt_init(tor1_crypt_t *crypto, 223 const char *key_data, size_t key_data_len, 224 int reverse, int is_hs_v3) 225 { 226 crypto_digest_t *tmp_digest; 227 crypto_cipher_t *tmp_crypto; 228 size_t digest_len = 0; 229 size_t cipher_key_len = 0; 230 231 tor_assert(crypto); 232 tor_assert(key_data); 233 tor_assert(!(crypto->f_crypto || crypto->b_crypto || 234 crypto->f_digest || crypto->b_digest)); 235 236 /* Basic key size validation */ 237 if (is_hs_v3 && BUG(key_data_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) { 238 goto err; 239 } else if (!is_hs_v3 && BUG(key_data_len != CPATH_KEY_MATERIAL_LEN)) { 240 goto err; 241 } 242 243 /* If we are using this crypto for next gen onion services use SHA3-256, 244 otherwise use good ol' SHA1 */ 245 if (is_hs_v3) { 246 digest_len = DIGEST256_LEN; 247 cipher_key_len = CIPHER256_KEY_LEN; 248 crypto->f_digest = crypto_digest256_new(DIGEST_SHA3_256); 249 crypto->b_digest = crypto_digest256_new(DIGEST_SHA3_256); 250 } else { 251 digest_len = DIGEST_LEN; 252 cipher_key_len = CIPHER_KEY_LEN; 253 crypto->f_digest = crypto_digest_new(); 254 crypto->b_digest = crypto_digest_new(); 255 } 256 257 tor_assert(digest_len != 0); 258 tor_assert(cipher_key_len != 0); 259 const int cipher_key_bits = (int) cipher_key_len * 8; 260 261 crypto_digest_add_bytes(crypto->f_digest, key_data, digest_len); 262 crypto_digest_add_bytes(crypto->b_digest, key_data+digest_len, digest_len); 263 264 crypto->f_crypto = crypto_cipher_new_with_bits(key_data+(2*digest_len), 265 cipher_key_bits); 266 if (!crypto->f_crypto) { 267 log_warn(LD_BUG,"Forward cipher initialization failed."); 268 goto err; 269 } 270 271 crypto->b_crypto = crypto_cipher_new_with_bits( 272 key_data+(2*digest_len)+cipher_key_len, 273 cipher_key_bits); 274 if (!crypto->b_crypto) { 275 log_warn(LD_BUG,"Backward cipher initialization failed."); 276 goto err; 277 } 278 279 if (reverse) { 280 tmp_digest = crypto->f_digest; 281 crypto->f_digest = crypto->b_digest; 282 crypto->b_digest = tmp_digest; 283 tmp_crypto = crypto->f_crypto; 284 crypto->f_crypto = crypto->b_crypto; 285 crypto->b_crypto = tmp_crypto; 286 } 287 288 return 0; 289 err: 290 tor1_crypt_clear(crypto); 291 return -1; 292 } 293 294 /** Assert that <b>crypto</b> is valid and set. */ 295 void 296 tor1_crypt_assert_ok(const tor1_crypt_t *crypto) 297 { 298 tor_assert(crypto->f_crypto); 299 tor_assert(crypto->b_crypto); 300 tor_assert(crypto->f_digest); 301 tor_assert(crypto->b_digest); 302 } 303 304 void 305 tor1_crypt_clear(tor1_crypt_t *crypto) 306 { 307 if (BUG(!crypto)) 308 return; 309 crypto_cipher_free(crypto->f_crypto); 310 crypto_cipher_free(crypto->b_crypto); 311 crypto_digest_free(crypto->f_digest); 312 crypto_digest_free(crypto->b_digest); 313 }