core.c 4.0 KB

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