summaryrefslogtreecommitdiff
path: root/lib/liboqs/src/common/rand/rand.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/liboqs/src/common/rand/rand.c')
-rw-r--r--lib/liboqs/src/common/rand/rand.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/lib/liboqs/src/common/rand/rand.c b/lib/liboqs/src/common/rand/rand.c
new file mode 100644
index 000000000..cb7404a4e
--- /dev/null
+++ b/lib/liboqs/src/common/rand/rand.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: MIT
+
+#include <stdio.h>
+#if defined(_WIN32)
+#include <windows.h>
+#include <wincrypt.h>
+#define strcasecmp _stricmp
+#else
+#include <unistd.h>
+#include <strings.h>
+#if defined(__APPLE__)
+#include <TargetConditionals.h>
+#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
+#include <Security/SecRandom.h>
+#else
+#include <sys/random.h>
+#endif
+#else
+#include <unistd.h>
+#endif
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include <oqs/oqs.h>
+
+void OQS_randombytes_system(uint8_t *random_array, size_t bytes_to_read);
+void OQS_randombytes_nist_kat(uint8_t *random_array, size_t bytes_to_read);
+#ifdef OQS_USE_OPENSSL
+void OQS_randombytes_openssl(uint8_t *random_array, size_t bytes_to_read);
+#endif
+
+#ifdef OQS_USE_OPENSSL
+#include <openssl/rand.h>
+// Use OpenSSL's RAND_bytes as the default PRNG
+static void (*oqs_randombytes_algorithm)(uint8_t *, size_t) = &OQS_randombytes_openssl;
+#else
+static void (*oqs_randombytes_algorithm)(uint8_t *, size_t) = &OQS_randombytes_system;
+#endif
+OQS_API OQS_STATUS OQS_randombytes_switch_algorithm(const char *algorithm) {
+ if (0 == strcasecmp(OQS_RAND_alg_system, algorithm)) {
+ oqs_randombytes_algorithm = &OQS_randombytes_system;
+ return OQS_SUCCESS;
+ } else if (0 == strcasecmp(OQS_RAND_alg_nist_kat, algorithm)) {
+ oqs_randombytes_algorithm = &OQS_randombytes_nist_kat;
+ return OQS_SUCCESS;
+ } else if (0 == strcasecmp(OQS_RAND_alg_openssl, algorithm)) {
+#ifdef OQS_USE_OPENSSL
+ oqs_randombytes_algorithm = &OQS_randombytes_openssl;
+ return OQS_SUCCESS;
+#else
+ return OQS_ERROR;
+#endif
+ } else {
+ return OQS_ERROR;
+ }
+}
+
+OQS_API void OQS_randombytes_custom_algorithm(void (*algorithm_ptr)(uint8_t *, size_t)) {
+ oqs_randombytes_algorithm = algorithm_ptr;
+}
+
+OQS_API void OQS_randombytes(uint8_t *random_array, size_t bytes_to_read) {
+ oqs_randombytes_algorithm(random_array, bytes_to_read);
+}
+
+#if !defined(_WIN32)
+#if defined(OQS_HAVE_GETENTROPY)
+void OQS_randombytes_system(uint8_t *random_array, size_t bytes_to_read) {
+ while (bytes_to_read > 256) {
+ if (getentropy(random_array, 256)) {
+ exit(EXIT_FAILURE);
+ }
+ random_array += 256;
+ bytes_to_read -= 256;
+ }
+ if (getentropy(random_array, bytes_to_read)) {
+ exit(EXIT_FAILURE);
+ }
+}
+#else
+#if defined(__APPLE__) && (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)
+void OQS_randombytes_system(uint8_t *random_array, size_t bytes_to_read) {
+ int status =
+ SecRandomCopyBytes(kSecRandomDefault, bytes_to_read, random_array);
+
+ if (status == errSecSuccess) {
+ perror("OQS_randombytes");
+ exit(EXIT_FAILURE);
+ }
+}
+#else
+void OQS_randombytes_system(uint8_t *random_array, size_t bytes_to_read) {
+ FILE *handle;
+ size_t bytes_read;
+
+ handle = fopen("/dev/urandom", "rb");
+ if (!handle) {
+ perror("OQS_randombytes");
+ exit(EXIT_FAILURE);
+ }
+
+ bytes_read = fread(random_array, 1, bytes_to_read, handle);
+ if (bytes_read < bytes_to_read || ferror(handle)) {
+ perror("OQS_randombytes");
+ exit(EXIT_FAILURE);
+ }
+
+ fclose(handle);
+}
+#endif
+#endif
+#else
+void OQS_randombytes_system(uint8_t *random_array, size_t bytes_to_read) {
+ HCRYPTPROV hCryptProv;
+ if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) ||
+ !CryptGenRandom(hCryptProv, (DWORD) bytes_to_read, random_array)) {
+ exit(EXIT_FAILURE); // better to fail than to return bad random data
+ }
+ CryptReleaseContext(hCryptProv, 0);
+}
+#endif
+
+#ifdef OQS_USE_OPENSSL
+#define OQS_RAND_POLL_RETRY 3 // in case failure to get randomness is a temporary problem, allow some repeats
+void OQS_randombytes_openssl(uint8_t *random_array, size_t bytes_to_read) {
+ int rep = OQS_RAND_POLL_RETRY;
+ SIZE_T_TO_INT_OR_EXIT(bytes_to_read, bytes_to_read_int)
+ do {
+ if (RAND_status() == 1) {
+ break;
+ }
+ RAND_poll();
+ } while (rep-- >= 0);
+ if (RAND_bytes(random_array, bytes_to_read_int) != 1) {
+ fprintf(stderr, "No OpenSSL randomness retrieved. DRBG available?\n");
+ // because of void signature we have no other way to signal the problem
+ // we cannot possibly return without randomness
+ exit(EXIT_FAILURE);
+ }
+}
+#endif