chapter268, [SORA][SORA Network] We implement the strong random and fixed allocator for OpenSSL

We have been ported random number processing from the latest core.

random/random.cpp
https://github.com/FromHDDtoSSD/SorachanCoin-qt/blob/develop/src/random/random.cpp

However, we have significantly fixed OpenSSL’s multithreaded support.

Bitcoin code (random.cpp):
RNGState& GetRNGState() noexcept
{
  // This C++11 idiom relies on the guarantee that static variable are initialized
  // on first call, even when multiple parallel calls are permitted.
  static std::vector<RNGState, secure_allocator<RNGState>> g_rng(1);
  return g_rng[0];
}

Static variables are called when they are used,
so this implementation enables multithreading there when OpenSSL was used in this class.

Since this class is responsible for OpenSSL random numbers,
if processing other than random numbers is executed by OpenSSL before random number processing,
a mutex for thread control has NOT been generated,
so there is a possibility of conflicts in multiple threads.

SorachanCoin, OpenSSL startup and new delete Secure allocator:
static unsigned char g_dummy[10] = {0};
class OpenSSL_startup {
public:
  OpenSSL_startup() noexcept {
    unsigned char ch[32] = {0};
    CSHA512 hasher;
    hasher.Write(ch, sizeof(ch));
    RNGState &obj = RNGState::GetRNGState(); // generate RNGState
    obj.MixExtract(g_dummy, sizeof(g_dummy)/sizeof(char) – 1, std::move(hasher), false);
    g_dummy[9] = ‘\0’;
    DEBUG_LSYNC_CS(“called OpenSSL_startup()”);
  }
};
OpenSSL_startup dummy_openssl;

void *operator new(size_t size, const std::nothrow_t &) noexcept {
  DEBUG_LSYNC_CS(“called GetRNGState() new operator”);
  unsigned char *p = (unsigned char *)::malloc(size + sizeof(size_t));
  if(! p) return nullptr;
  *((size_t *)p) = size + sizeof(size_t);
  return (void *)(p + sizeof(size_t));
}
void *operator new(size_t size)=delete;
void *operator new[](size_t size)=delete;
void operator delete(void *p) noexcept {
  DEBUG_LSYNC_CS(“called GetRNGState() delete operator”);
  unsigned char *head = (unsigned char *)p – sizeof(size_t);
  const size_t size = *((size_t *)head);
  cleanse::OPENSSL_cleanse(head, size);
  ::free(head);
}
void operator delete[](void *p)=delete;

static RNGState &GetRNGState() noexcept {
  class manage {
  private:
    RNGState *m_ptr;
  public:
    manage() : m_ptr(nullptr) {
    m_ptr = new (std::nothrow) RNGState;
    if(! m_ptr)
      throw std::runtime_error(“Out of memory: RNGState manage()”);
    }
    ~manage() {
      if(m_ptr) delete m_ptr;
    }
    RNGState &get() noexcept {
      return *m_ptr;
    }
  };

  // This C++11 idiom relies on the guarantee that static variable are initialized
  // on first call, even when multiple parallel calls are permitted.
  DEBUG_LSYNC_CS(“called GetRNGState()”);
  static manage obj;
  return obj.get();
}

Init mutex [RNGState()]:
// Init OpenSSL library multithreading support
DEBUG_LSYNC_CS(“called RNGState() 2”);
m_pmutexOpenSSL = (Mutex *)OPENSSL_malloc(::CRYPTO_num_locks() * sizeof(Mutex));
if(! m_pmutexOpenSSL)
  throw std::runtime_error(“Out of memory: Init OpenSSL library multithreading support”);
for(int i=0; i<::CRYPTO_num_locks(); ++i)
  new(m_pmutexOpenSSL + i) Mutex;

release mutex[~RNGState()]:
DEBUG_LSYNC_CS(“called ~RNGState()”);
// Securely erase the memory used by the OpenSSL PRNG
::RAND_cleanup();
// Shutdown OpenSSL library multithreading support
::CRYPTO_set_locking_callback(nullptr);
for (int i=0; i<::CRYPTO_num_locks(); ++i)
  (m_pmutexOpenSSL + i)->~Mutex();
cleanse::OPENSSL_cleanse(m_pmutexOpenSSL, ::CRYPTO_num_locks() * sizeof(Mutex));
OPENSSL_free(m_pmutexOpenSSL);


Now you anywhere can use the OpenSSL functions
you want to keep during the porting from old core.

Of course, we will aim to emerge from OpenSSL,
but we may that C++23 will be required.

thanks.

暗号通貨短編