1 2 #include <assert.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <time.h> 6 #ifdef _WIN32 7 # include <windows.h> 8 #elif defined(HAVE_PTHREAD) 9 # include <pthread.h> 10 #endif 11 12 #include "core.h" 13 #include "crypto_generichash.h" 14 #include "crypto_onetimeauth.h" 15 #include "crypto_scalarmult.h" 16 #include "crypto_stream_chacha20.h" 17 #include "crypto_stream_salsa20.h" 18 #include "randombytes.h" 19 #include "runtime.h" 20 #include "utils.h" 21 #include "private/implementations.h" 22 #include "private/mutex.h" 23 24 static volatile int initialized; 25 static volatile int locked; 26 27 int sodium_init(void)28sodium_init(void) 29 { 30 if (sodium_crit_enter() != 0) { 31 return -1; /* LCOV_EXCL_LINE */ 32 } 33 if (initialized != 0) { 34 if (sodium_crit_leave() != 0) { 35 return -1; /* LCOV_EXCL_LINE */ 36 } 37 return 1; 38 } 39 _sodium_runtime_get_cpu_features(); 40 randombytes_stir(); 41 _sodium_alloc_init(); 42 _crypto_pwhash_argon2_pick_best_implementation(); 43 _crypto_generichash_blake2b_pick_best_implementation(); 44 _crypto_onetimeauth_poly1305_pick_best_implementation(); 45 _crypto_scalarmult_curve25519_pick_best_implementation(); 46 _crypto_stream_chacha20_pick_best_implementation(); 47 _crypto_stream_salsa20_pick_best_implementation(); 48 initialized = 1; 49 if (sodium_crit_leave() != 0) { 50 return -1; /* LCOV_EXCL_LINE */ 51 } 52 return 0; 53 } 54 55 #ifdef _WIN32 56 57 static CRITICAL_SECTION _sodium_lock; 58 static volatile LONG _sodium_lock_initialized; 59 60 int _sodium_crit_init(void)61_sodium_crit_init(void) 62 { 63 LONG status = 0L; 64 65 while ((status = InterlockedCompareExchange(&_sodium_lock_initialized, 66 1L, 0L)) == 1L) { 67 Sleep(0); 68 } 69 70 switch (status) { 71 case 0L: 72 InitializeCriticalSection(&_sodium_lock); 73 return InterlockedExchange(&_sodium_lock_initialized, 2L) == 1L ? 0 : -1; 74 case 2L: 75 return 0; 76 default: /* should never be reached */ 77 return -1; 78 } 79 } 80 81 int sodium_crit_enter(void)82sodium_crit_enter(void) 83 { 84 if (_sodium_crit_init() != 0) { 85 return -1; /* LCOV_EXCL_LINE */ 86 } 87 EnterCriticalSection(&_sodium_lock); 88 assert(locked == 0); 89 locked = 1; 90 91 return 0; 92 } 93 94 int sodium_crit_leave(void)95sodium_crit_leave(void) 96 { 97 if (locked == 0) { 98 # ifdef EPERM 99 errno = EPERM; 100 # endif 101 return -1; 102 } 103 locked = 0; 104 LeaveCriticalSection(&_sodium_lock); 105 106 return 0; 107 } 108 109 #elif defined(HAVE_PTHREAD) && !defined(__EMSCRIPTEN__) 110 111 static pthread_mutex_t _sodium_lock = PTHREAD_MUTEX_INITIALIZER; 112 113 int sodium_crit_enter(void)114sodium_crit_enter(void) 115 { 116 int ret; 117 118 if ((ret = pthread_mutex_lock(&_sodium_lock)) == 0) { 119 assert(locked == 0); 120 locked = 1; 121 } 122 return ret; 123 } 124 125 int sodium_crit_leave(void)126sodium_crit_leave(void) 127 { 128 if (locked == 0) { 129 # ifdef EPERM 130 errno = EPERM; 131 # endif 132 return -1; 133 } 134 locked = 0; 135 136 return pthread_mutex_unlock(&_sodium_lock); 137 } 138 139 #elif defined(HAVE_ATOMIC_OPS) && !defined(__EMSCRIPTEN__) 140 141 static volatile int _sodium_lock; 142 143 int sodium_crit_enter(void)144sodium_crit_enter(void) 145 { 146 # ifdef HAVE_NANOSLEEP 147 struct timespec q; 148 memset(&q, 0, sizeof q); 149 # endif 150 while (__sync_lock_test_and_set(&_sodium_lock, 1) != 0) { 151 # ifdef HAVE_NANOSLEEP 152 (void) nanosleep(&q, NULL); 153 # elif defined(__x86_64__) || defined(__i386__) 154 __asm__ __volatile__ ("pause"); 155 # endif 156 } 157 return 0; 158 } 159 160 int sodium_crit_leave(void)161sodium_crit_leave(void) 162 { 163 __sync_lock_release(&_sodium_lock); 164 165 return 0; 166 } 167 168 #else 169 170 int sodium_crit_enter(void)171sodium_crit_enter(void) 172 { 173 return 0; 174 } 175 176 int sodium_crit_leave(void)177sodium_crit_leave(void) 178 { 179 return 0; 180 } 181 182 #endif 183 184 static void (*_misuse_handler)(void); 185 186 void sodium_misuse(void)187sodium_misuse(void) 188 { 189 void (*handler)(void); 190 191 (void) sodium_crit_leave(); 192 if (sodium_crit_enter() == 0) { 193 handler = _misuse_handler; 194 if (handler != NULL) { 195 handler(); 196 } 197 } 198 /* LCOV_EXCL_START */ 199 abort(); 200 } 201 /* LCOV_EXCL_STOP */ 202 203 int sodium_set_misuse_handler(void (* handler)(void))204sodium_set_misuse_handler(void (*handler)(void)) 205 { 206 if (sodium_crit_enter() != 0) { 207 return -1; /* LCOV_EXCL_LINE */ 208 } 209 _misuse_handler = handler; 210 if (sodium_crit_leave() != 0) { 211 return -1; /* LCOV_EXCL_LINE */ 212 } 213 return 0; 214 } 215