+namespace {
+
+const char* DEV_HW_RANDOM_FILE = "/dev/hwrng";
+const char* DEV_URANDOM_FILE = "/dev/urandom";
+const size_t RANDOM_BUFFER_LEN = 32;
+
+std::mutex* g_mutexes = NULL;
+
+void lockingCallback(int mode, int type, const char*, int)
+{
+ if(!g_mutexes) {
+ LogError("Openssl mutexes do not exist");
+ return;
+ }
+
+ if (mode & CRYPTO_LOCK)
+ g_mutexes[type].lock();
+ else if (mode & CRYPTO_UNLOCK)
+ g_mutexes[type].unlock();
+}
+
+unsigned long threadIdCallback() {
+ std::hash<std::thread::id> hasher;
+ return hasher(std::this_thread::get_id());
+}
+
+void opensslInstallLocks()
+{
+ g_mutexes = new std::mutex[CRYPTO_num_locks()];
+
+ CRYPTO_set_id_callback(threadIdCallback);
+ CRYPTO_set_locking_callback(lockingCallback);
+}
+
+void opensslUninstallLocks()
+{
+ CRYPTO_set_id_callback(NULL);
+ CRYPTO_set_locking_callback(NULL);
+
+ delete[] g_mutexes;
+ g_mutexes = NULL;
+}
+
+} // namespace anonymous
+
+
+void initOpenSsl() {
+ // Loads all error strings (crypto and ssl)
+ SSL_load_error_strings();
+
+ /*
+ * Initialize libcrypto (add all algorithms, digests & ciphers)
+ * It also does the stuff from SSL_library_init() except for ssl_load_ciphers()
+ */
+ OpenSSL_add_all_algorithms(); // Can be optimized by using EVP_add_cipher instead
+
+ /*
+ * Initialize libssl (OCSP uses it)
+ * SSL_library_init() == OpenSSL_add_ssl_algorithms()
+ * It always returns 1
+ */
+ SSL_library_init();
+
+ // load default configuration (/etc/ssl/openssl.cnf)
+ OPENSSL_config(NULL);
+
+ // enable FIPS mode by default
+ if(0 == FIPS_mode_set(1)) {
+ LogError("Failed to set FIPS mode");
+ }
+
+ /*
+ * Initialize entropy
+ * entropy sources - /dev/random,/dev/urandom(Default)
+ */
+ int ret = 0;
+
+ std::ifstream ifile(DEV_HW_RANDOM_FILE);
+ if(ifile.is_open())
+ ret= RAND_load_file(DEV_HW_RANDOM_FILE, RANDOM_BUFFER_LEN);
+
+ if(ret != RANDOM_BUFFER_LEN ){
+ LogWarning("Error in HW_RAND file load");
+ ret = RAND_load_file(DEV_URANDOM_FILE, RANDOM_BUFFER_LEN);
+
+ if(ret != RANDOM_BUFFER_LEN)
+ LogError("Error in U_RAND_file_load");
+ }
+
+ // Install locks for multithreading support
+ opensslInstallLocks();
+}
+
+void deinitOpenSsl() {
+ opensslUninstallLocks();
+ CONF_modules_unload(1);
+ EVP_cleanup();
+ ERR_free_strings();
+ deinitOpenSslThread();
+}
+
+void deinitOpenSslThread() {
+ CRYPTO_cleanup_all_ex_data();
+ ERR_remove_thread_state(NULL);
+}