summaryrefslogtreecommitdiff
path: root/lib/liboqs/src/common/rand
diff options
context:
space:
mode:
Diffstat (limited to 'lib/liboqs/src/common/rand')
-rw-r--r--lib/liboqs/src/common/rand/Makefile49
-rw-r--r--lib/liboqs/src/common/rand/config.mk12
-rw-r--r--lib/liboqs/src/common/rand/manifest.mn24
-rw-r--r--lib/liboqs/src/common/rand/rand.c142
-rw-r--r--lib/liboqs/src/common/rand/rand.gyp33
-rw-r--r--lib/liboqs/src/common/rand/rand.h73
-rw-r--r--lib/liboqs/src/common/rand/rand_nist.c151
7 files changed, 484 insertions, 0 deletions
diff --git a/lib/liboqs/src/common/rand/Makefile b/lib/liboqs/src/common/rand/Makefile
new file mode 100644
index 000000000..fe090f3ff
--- /dev/null
+++ b/lib/liboqs/src/common/rand/Makefile
@@ -0,0 +1,49 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+USE_GCOV =
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include config.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
+
+WARNING_CFLAGS = $(NULL)
+
diff --git a/lib/liboqs/src/common/rand/config.mk b/lib/liboqs/src/common/rand/config.mk
new file mode 100644
index 000000000..3bd40a5ea
--- /dev/null
+++ b/lib/liboqs/src/common/rand/config.mk
@@ -0,0 +1,12 @@
+# DO NOT EDIT: generated from config.mk.subdirs.template
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# add fixes for platform integration issues here.
+#
+# liboqs programs expect the public include files to be in oqs/xxxx,
+# So we put liboqs in it's own module, oqs, and point to the dist files
+INCLUDES += -I$(CORE_DEPTH)/lib/liboqs/src/common/pqclean_shims -I$(CORE_DEPTH)/lib/liboqs/src/common/sha3/xkcp_low/KeccakP-1600/plain-64bits
+DEFINES +=
diff --git a/lib/liboqs/src/common/rand/manifest.mn b/lib/liboqs/src/common/rand/manifest.mn
new file mode 100644
index 000000000..227c76619
--- /dev/null
+++ b/lib/liboqs/src/common/rand/manifest.mn
@@ -0,0 +1,24 @@
+# DO NOT EDIT: generated from manifest.mn.subdirs.template
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+CORE_DEPTH = ../../../../..
+
+MODULE = oqs
+
+LIBRARY_NAME = oqs_src_common_rand
+SHARED_LIBRARY = $(NULL)
+
+CSRCS = \
+ rand.c \
+ rand_nist.c \
+ $(NULL)
+
+# only add module debugging in opt builds if DEBUG_PKCS11 is set
+ifdef DEBUG_PKCS11
+ DEFINES += -DDEBUG_MODULE
+endif
+
+# This part of the code, including all sub-dirs, can be optimized for size
+export ALLOW_OPT_CODE_SIZE = 1
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
diff --git a/lib/liboqs/src/common/rand/rand.gyp b/lib/liboqs/src/common/rand/rand.gyp
new file mode 100644
index 000000000..50f88427e
--- /dev/null
+++ b/lib/liboqs/src/common/rand/rand.gyp
@@ -0,0 +1,33 @@
+# DO NOT EDIT: generated from subdir.gyp.template
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../../../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'oqs_src_common_rand',
+ 'type': 'static_library',
+ 'sources': [
+ 'rand.c',
+ 'rand_nist.c',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ]
+ }
+ ],
+ 'target_defaults': {
+ 'defines': [
+ ],
+ 'include_dirs': [
+ '<(DEPTH)/lib/liboqs/src/common/pqclean_shims',
+ '<(DEPTH)/lib/liboqs/src/common/sha3/xkcp_low/KeccakP-1600/plain-64bits',
+ ]
+ },
+ 'variables': {
+ 'module': 'oqs'
+ }
+}
diff --git a/lib/liboqs/src/common/rand/rand.h b/lib/liboqs/src/common/rand/rand.h
new file mode 100644
index 000000000..3499c2593
--- /dev/null
+++ b/lib/liboqs/src/common/rand/rand.h
@@ -0,0 +1,73 @@
+/**
+ * \file rand.h
+ * \brief Random number generator.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef OQS_RANDOM_H
+#define OQS_RANDOM_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <oqs/common.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/** Algorithm identifier for system PRNG. */
+#define OQS_RAND_alg_system "system"
+/** Algorithm identifier for NIST deterministic RNG for KATs. */
+#define OQS_RAND_alg_nist_kat "NIST-KAT"
+/** Algorithm identifier for using OpenSSL's PRNG. */
+#define OQS_RAND_alg_openssl "OpenSSL"
+
+/**
+ * Switches OQS_randombytes to use the specified algorithm.
+ *
+ * @param[in] algorithm The name of the algorithm to use.
+ * @return OQS_SUCCESS if `algorithm` is a supported algorithm name, OQS_ERROR otherwise.
+ */
+OQS_API OQS_STATUS OQS_randombytes_switch_algorithm(const char *algorithm);
+
+/**
+ * Switches OQS_randombytes to use the given function.
+ *
+ * This allows additional custom RNGs besides the provided ones. The provided RNG
+ * function must have the same signature as `OQS_randombytes`.
+ *
+ * @param[in] algorithm_ptr Pointer to the RNG function to use.
+ */
+OQS_API void OQS_randombytes_custom_algorithm(void (*algorithm_ptr)(uint8_t *, size_t));
+
+/**
+ * Fills the given memory with the requested number of (pseudo)random bytes.
+ *
+ * This implementation uses whichever algorithm has been selected by
+ * OQS_randombytes_switch_algorithm. The default is OQS_randombytes_system, which
+ * reads bytes directly from `/dev/urandom`.
+ *
+ * The caller is responsible for providing a buffer allocated with sufficient room.
+ *
+ * @param[out] random_array Pointer to the memory to fill with (pseudo)random bytes
+ * @param[in] bytes_to_read The number of random bytes to read into memory
+ */
+OQS_API void OQS_randombytes(uint8_t *random_array, size_t bytes_to_read);
+
+/**
+ * Initializes the NIST DRBG with a given seed and with 256-bit security.
+ *
+ * @param[in] entropy_input The seed; must be exactly 48 bytes
+ * @param[in] personalization_string An optional personalization string;
+ * may be NULL; if not NULL, must be at least 48 bytes long
+ */
+OQS_API void OQS_randombytes_nist_kat_init_256bit(const uint8_t *entropy_input, const uint8_t *personalization_string);
+
+#if defined(__cplusplus)
+} // extern "C"
+#endif
+
+#endif // OQS_RANDOM_H
diff --git a/lib/liboqs/src/common/rand/rand_nist.c b/lib/liboqs/src/common/rand/rand_nist.c
new file mode 100644
index 000000000..b6c6398a7
--- /dev/null
+++ b/lib/liboqs/src/common/rand/rand_nist.c
@@ -0,0 +1,151 @@
+//
+// rng.c
+//
+// Created by Bassham, Lawrence E (Fed) on 8/29/17.
+// Copyright © 2017 Bassham, Lawrence E (Fed). All rights reserved.
+/*
+NIST-developed software is provided by NIST as a public service. You may use, copy, and distribute copies of the software in any medium, provided that you keep intact this entire notice. You may improve, modify, and create derivative works of the software or any portion of the software, and you may copy and distribute such modifications or works. Modified works should carry a notice stating that you changed the software and should note the date and nature of any such change. Please explicitly acknowledge the National Institute of Standards and Technology as the source of the software.
+
+NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED, IN FACT, OR ARISING BY OPERATION OF LAW, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND DATA ACCURACY. NIST NEITHER REPRESENTS NOR WARRANTS THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE CORRECTED. NIST DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE SOFTWARE OR THE RESULTS THEREOF, INCLUDING BUT NOT LIMITED TO THE CORRECTNESS, ACCURACY, RELIABILITY, OR USEFULNESS OF THE SOFTWARE.
+
+You are solely responsible for determining the appropriateness of using and distributing the software and you assume all risks associated with its use, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of operation. This software is not intended to be used in any situation where a failure could cause risk of injury or damage to property. The software developed by NIST employees is not subject to copyright protection within the United States.
+*/
+// SPDX-License-Identifier: Unknown
+// Modified for liboqs by Douglas Stebila
+//
+
+#include <assert.h>
+#include <string.h>
+
+#include <oqs/common.h>
+#include <oqs/rand.h>
+
+#ifdef OQS_USE_OPENSSL
+#include <openssl/conf.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#else
+#include <oqs/aes.h>
+#endif
+
+void OQS_randombytes_nist_kat(unsigned char *x, size_t xlen);
+
+typedef struct {
+ unsigned char Key[32];
+ unsigned char V[16];
+ int reseed_counter;
+} AES256_CTR_DRBG_struct;
+
+static AES256_CTR_DRBG_struct DRBG_ctx;
+static void AES256_CTR_DRBG_Update(unsigned char *provided_data, unsigned char *Key, unsigned char *V);
+
+#ifdef OQS_USE_OPENSSL
+# if defined(_MSC_VER)
+__declspec(noreturn)
+# else
+__attribute__((noreturn))
+# endif
+static void handleErrors(void) {
+ ERR_print_errors_fp(stderr);
+ abort();
+}
+#endif
+
+// Use whatever AES implementation you have. This uses AES from openSSL library
+// key - 256-bit AES key
+// ctr - a 128-bit plaintext value
+// buffer - a 128-bit ciphertext value
+static void AES256_ECB(unsigned char *key, unsigned char *ctr, unsigned char *buffer) {
+#ifdef OQS_USE_OPENSSL
+ EVP_CIPHER_CTX *ctx;
+
+ int len;
+
+ /* Create and initialise the context */
+ if (!(ctx = EVP_CIPHER_CTX_new())) {
+ handleErrors();
+ }
+
+ if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, NULL)) {
+ handleErrors();
+ }
+
+ if (1 != EVP_EncryptUpdate(ctx, buffer, &len, ctr, 16)) {
+ handleErrors();
+ }
+
+ /* Clean up */
+ EVP_CIPHER_CTX_free(ctx);
+#else
+ void *schedule = NULL;
+ OQS_AES256_ECB_load_schedule(key, &schedule);
+ OQS_AES256_ECB_enc(ctr, 16, key, buffer);
+ OQS_AES256_free_schedule(schedule);
+#endif
+}
+
+OQS_API void OQS_randombytes_nist_kat_init_256bit(const uint8_t *entropy_input, const uint8_t *personalization_string) {
+ unsigned char seed_material[48];
+
+ memcpy(seed_material, entropy_input, 48);
+ if (personalization_string)
+ for (int i = 0; i < 48; i++) {
+ seed_material[i] ^= personalization_string[i];
+ }
+ memset(DRBG_ctx.Key, 0x00, 32);
+ memset(DRBG_ctx.V, 0x00, 16);
+ AES256_CTR_DRBG_Update(seed_material, DRBG_ctx.Key, DRBG_ctx.V);
+ DRBG_ctx.reseed_counter = 1;
+}
+
+void OQS_randombytes_nist_kat(unsigned char *x, size_t xlen) {
+ unsigned char block[16];
+ int i = 0;
+
+ while (xlen > 0) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (DRBG_ctx.V[j] == 0xff) {
+ DRBG_ctx.V[j] = 0x00;
+ } else {
+ DRBG_ctx.V[j]++;
+ break;
+ }
+ }
+ AES256_ECB(DRBG_ctx.Key, DRBG_ctx.V, block);
+ if (xlen > 15) {
+ memcpy(x + i, block, 16);
+ i += 16;
+ xlen -= 16;
+ } else {
+ memcpy(x + i, block, xlen);
+ xlen = 0;
+ }
+ }
+ AES256_CTR_DRBG_Update(NULL, DRBG_ctx.Key, DRBG_ctx.V);
+ DRBG_ctx.reseed_counter++;
+}
+
+static void AES256_CTR_DRBG_Update(unsigned char *provided_data, unsigned char *Key, unsigned char *V) {
+ unsigned char temp[48];
+
+ for (int i = 0; i < 3; i++) {
+ //increment V
+ for (int j = 15; j >= 0; j--) {
+ if (V[j] == 0xff) {
+ V[j] = 0x00;
+ } else {
+ V[j]++;
+ break;
+ }
+ }
+
+ AES256_ECB(Key, V, temp + 16 * i);
+ }
+ if (provided_data != NULL)
+ for (int i = 0; i < 48; i++) {
+ temp[i] ^= provided_data[i];
+ }
+ memcpy(Key, temp, 32);
+ memcpy(V, temp + 32, 16);
+}