di_ops.c (9413B)
1 /* Copyright (c) 2011-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 /** 5 * \file di_ops.c 6 * \brief Functions for data-independent operations. 7 **/ 8 9 #include "orconfig.h" 10 #include "lib/ctime/di_ops.h" 11 #include "lib/err/torerr.h" 12 #include "lib/malloc/malloc.h" 13 14 #include <string.h> 15 16 /** 17 * Timing-safe version of memcmp. As memcmp, compare the <b>sz</b> bytes at 18 * <b>a</b> with the <b>sz</b> bytes at <b>b</b>, and return less than 0 if 19 * the bytes at <b>a</b> lexically precede those at <b>b</b>, 0 if the byte 20 * ranges are equal, and greater than zero if the bytes at <b>a</b> lexically 21 * follow those at <b>b</b>. 22 * 23 * This implementation differs from memcmp in that its timing behavior is not 24 * data-dependent: it should return in the same amount of time regardless of 25 * the contents of <b>a</b> and <b>b</b>. 26 * 27 * Note that if all you care about is equality, this implementation is 28 * overkill: it would be better to use tor_memeq() or tor_memneq(). 29 */ 30 int 31 tor_memcmp(const void *a, const void *b, size_t len) 32 { 33 #ifdef HAVE_TIMINGSAFE_MEMCMP 34 return timingsafe_memcmp(a, b, len); 35 #else 36 const uint8_t *x = a; 37 const uint8_t *y = b; 38 size_t i = len; 39 int retval = 0; 40 41 /* This loop goes from the end of the arrays to the start. At the 42 * start of every iteration, before we decrement i, we have set 43 * "retval" equal to the result of memcmp(a+i,b+i,len-i). During the 44 * loop, we update retval by leaving it unchanged if x[i]==y[i] and 45 * setting it to x[i]-y[i] if x[i]!= y[i]. 46 * 47 * The following assumes we are on a system with two's-complement 48 * arithmetic. We check for this at configure-time with the check 49 * that sets USING_TWOS_COMPLEMENT. If we aren't two's complement, then 50 * torint.h will stop compilation with an error. 51 */ 52 while (i--) { 53 int v1 = x[i]; 54 int v2 = y[i]; 55 int equal_p = v1 ^ v2; 56 57 /* The following sets bits 8 and above of equal_p to 'equal_p == 58 * 0', and thus to v1 == v2. (To see this, note that if v1 == 59 * v2, then v1^v2 == equal_p == 0, so equal_p-1 == -1, which is the 60 * same as ~0 on a two's-complement machine. Then note that if 61 * v1 != v2, then 0 < v1 ^ v2 < 256, so 0 <= equal_p - 1 < 255.) 62 */ 63 --equal_p; 64 65 equal_p >>= 8; 66 /* Thanks to (sign-preserving) arithmetic shift, equal_p is now 67 * equal to -(v1 == v2), which is exactly what we need below. 68 * (Since we're assuming two's-complement arithmetic, -1 is the 69 * same as ~0 (all bits set).) 70 * 71 * (The result of an arithmetic shift on a negative value is 72 * actually implementation-defined in standard C. So how do we 73 * get away with assuming it? Easy. We check.) */ 74 #if ((-60 >> 8) != -1) 75 #error "cpp says right-shift doesn't perform sign-extension." 76 #endif 77 #ifndef RSHIFT_DOES_SIGN_EXTEND 78 #error "configure says right-shift doesn't perform sign-extension." 79 #endif 80 81 /* If v1 == v2, equal_p is ~0, so this will leave retval 82 * unchanged; otherwise, equal_p is 0, so this will zero it. */ 83 retval &= equal_p; 84 85 /* If v1 == v2, then this adds 0, and leaves retval unchanged. 86 * Otherwise, we just zeroed retval, so this sets it to v1 - v2. */ 87 retval += (v1 - v2); 88 89 /* There. Now retval is equal to its previous value if v1 == v2, and 90 * equal to v1 - v2 if v1 != v2. */ 91 } 92 93 return retval; 94 #endif /* defined(HAVE_TIMINGSAFE_MEMCMP) */ 95 } 96 97 /** 98 * Timing-safe memory comparison. Return true if the <b>sz</b> bytes at 99 * <b>a</b> are the same as the <b>sz</b> bytes at <b>b</b>, and 0 otherwise. 100 * 101 * This implementation differs from !memcmp(a,b,sz) in that its timing 102 * behavior is not data-dependent: it should return in the same amount of time 103 * regardless of the contents of <b>a</b> and <b>b</b>. It differs from 104 * !tor_memcmp(a,b,sz) by being faster. 105 */ 106 int 107 tor_memeq(const void *a, const void *b, size_t sz) 108 { 109 /* Treat a and b as byte ranges. */ 110 const uint8_t *ba = a, *bb = b; 111 uint32_t any_difference = 0; 112 while (sz--) { 113 /* Set byte_diff to all of those bits that are different in *ba and *bb, 114 * and advance both ba and bb. */ 115 const uint8_t byte_diff = *ba++ ^ *bb++; 116 117 /* Set bits in any_difference if they are set in byte_diff. */ 118 any_difference |= byte_diff; 119 } 120 121 /* Now any_difference is 0 if there are no bits different between 122 * a and b, and is nonzero if there are bits different between a 123 * and b. Now for paranoia's sake, let's convert it to 0 or 1. 124 * 125 * (If we say "!any_difference", the compiler might get smart enough 126 * to optimize-out our data-independence stuff above.) 127 * 128 * To unpack: 129 * 130 * If any_difference == 0: 131 * any_difference - 1 == ~0 132 * (any_difference - 1) >> 8 == 0x00ffffff 133 * 1 & ((any_difference - 1) >> 8) == 1 134 * 135 * If any_difference != 0: 136 * 0 < any_difference < 256, so 137 * 0 <= any_difference - 1 < 255 138 * (any_difference - 1) >> 8 == 0 139 * 1 & ((any_difference - 1) >> 8) == 0 140 */ 141 142 /*coverity[overflow]*/ 143 return 1 & ((any_difference - 1) >> 8); 144 } 145 146 /* Implement di_digest256_map_t as a linked list of entries. */ 147 struct di_digest256_map_t { 148 /** Pointer to the next entry in the list. */ 149 struct di_digest256_map_t *next; 150 /** Key for this entry. */ 151 uint8_t key[32]; 152 /** Value for this entry. */ 153 void *val; 154 }; 155 156 /** Release all storage held in <b>map</b>, calling free_fn on each value 157 * as we go. */ 158 void 159 dimap_free_(di_digest256_map_t *map, dimap_free_fn free_fn) 160 { 161 while (map) { 162 di_digest256_map_t *victim = map; 163 map = map->next; 164 if (free_fn) 165 free_fn(victim->val); 166 tor_free(victim); 167 } 168 } 169 170 /** Adjust the map at *<b>map</b>, adding an entry for <b>key</b> -> 171 * <b>val</b>, where <b>key</b> is a DIGEST256_LEN-byte key. 172 * 173 * The caller MUST NOT add a key that already appears in the map. 174 */ 175 void 176 dimap_add_entry(di_digest256_map_t **map, 177 const uint8_t *key, void *val) 178 { 179 di_digest256_map_t *new_ent; 180 { 181 void *old_val = dimap_search(*map, key, NULL); 182 raw_assert(! old_val); 183 raw_assert(val); 184 } 185 new_ent = tor_malloc_zero(sizeof(di_digest256_map_t)); 186 new_ent->next = *map; 187 memcpy(new_ent->key, key, 32); 188 new_ent->val = val; 189 *map = new_ent; 190 } 191 192 /** Search the map at <b>map</b> for an entry whose key is <b>key</b> (a 193 * DIGEST256_LEN-byte key) returning the corresponding value if we found one, 194 * and returning <b>dflt_val</b> if the key wasn't found. 195 * 196 * This operation takes an amount of time dependent only on the length of 197 * <b>map</b>, not on the position or presence of <b>key</b> within <b>map</b>. 198 */ 199 void * 200 dimap_search(const di_digest256_map_t *map, const uint8_t *key, 201 void *dflt_val) 202 { 203 uintptr_t result = (uintptr_t)dflt_val; 204 205 while (map) { 206 uintptr_t r = (uintptr_t) tor_memeq(map->key, key, 32); 207 r -= 1; /* Now r is (uintptr_t)-1 if memeq returned false, and 208 * 0 if memeq returned true. */ 209 210 result &= r; 211 result |= ((uintptr_t)(map->val)) & ~r; 212 213 map = map->next; 214 } 215 216 return (void *)result; 217 } 218 219 /** 220 * Return true iff the <b>sz</b> bytes at <b>mem</b> are all zero. Runs in 221 * time independent of the contents of <b>mem</b>. 222 */ 223 int 224 safe_mem_is_zero(const void *mem, size_t sz) 225 { 226 uint32_t total = 0; 227 const uint8_t *ptr = mem; 228 229 while (sz--) { 230 total |= *ptr++; 231 } 232 233 /*coverity[overflow]*/ 234 return 1 & ((total - 1) >> 8); 235 } 236 237 /** Time-invariant 64-bit greater-than; works on two integers in the range 238 * (0,INT64_MAX). */ 239 #if SIZEOF_VOID_P == 8 240 #define gt_i64_timei(a,b) ((a) > (b)) 241 #else 242 static inline int 243 gt_i64_timei(uint64_t a, uint64_t b) 244 { 245 int64_t diff = (int64_t) (b - a); 246 int res = diff >> 63; 247 return res & 1; 248 } 249 #endif /* SIZEOF_VOID_P == 8 */ 250 251 /** 252 * Given an array of list of <b>n_entries</b> uint64_t values, whose sum is 253 * <b>total</b>, find the first i such that the total of all elements 0...i is 254 * greater than rand_val. 255 * 256 * Try to perform this operation in a constant-time way. 257 */ 258 int 259 select_array_member_cumulative_timei(const uint64_t *entries, int n_entries, 260 uint64_t total, uint64_t rand_val) 261 { 262 int i, i_chosen=-1, n_chosen=0; 263 uint64_t total_so_far = 0; 264 265 for (i = 0; i < n_entries; ++i) { 266 total_so_far += entries[i]; 267 if (gt_i64_timei(total_so_far, rand_val)) { 268 i_chosen = i; 269 n_chosen++; 270 /* Set rand_val to INT64_MAX rather than stopping the loop. This way, 271 * the time we spend in the loop does not leak which element we chose. */ 272 rand_val = INT64_MAX; 273 } 274 } 275 raw_assert(total_so_far == total); 276 raw_assert(n_chosen == 1); 277 raw_assert(i_chosen >= 0); 278 raw_assert(i_chosen < n_entries); 279 280 return i_chosen; 281 } 282 283 /** 284 * If <b>s</b> is true, then copy <b>n</b> bytes from <b>src</b> to 285 * <b>dest</b>. Otherwise leave <b>dest</b> alone. 286 * 287 * This function behaves the same as 288 * 289 * if (s) 290 * memcpy(dest, src, n); 291 * 292 * except that it tries to run in the same amount of time whether <b>s</b> is 293 * true or not. 294 **/ 295 void 296 memcpy_if_true_timei(bool s, void *dest, const void *src, size_t n) 297 { 298 // If s is true, mask will be ~0. If s is false, mask will be 0. 299 const char mask = (char) -(signed char)s; 300 301 char *destp = dest; 302 const char *srcp = src; 303 for (size_t i = 0; i < n; ++i) { 304 *destp = (*destp & ~mask) | (*srcp & mask); 305 ++destp; 306 ++srcp; 307 } 308 }