[IOT-1313, IOT-1300] Improve random number generation
authorGreg Zaverucha <gregz@microsoft.com>
Tue, 13 Dec 2016 00:20:45 +0000 (16:20 -0800)
committerGreg Zaverucha <gregz@microsoft.com>
Tue, 13 Dec 2016 19:16:18 +0000 (19:16 +0000)
Update ocrandom.c to use platform specific, secure random number
generators instead of rand(). Update the API in ocrandom.h, and make
corresponding updates to callers. Avoid using FP arithmetic in
OCGetRandomRange.

Change-Id: Ic0476dc69f1c649c4a07a46b99643cf7206f83af
Signed-off-by: Greg Zaverucha <gregz@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/15243
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Kevin Kane <kkane@microsoft.com>
Reviewed-by: Dan Mihai <Daniel.Mihai@microsoft.com>
22 files changed:
resource/c_common/ocrandom/include/ocrandom.h
resource/c_common/ocrandom/src/ocrandom.c
resource/c_common/ocrandom/test/SConscript
resource/c_common/ocrandom/test/android/randomtest.cpp [new file with mode: 0644]
resource/c_common/ocrandom/test/arduino/randomtest.cpp
resource/c_common/ocrandom/test/randomtest.cpp
resource/c_common/windows/SConscript
resource/csdk/connectivity/src/adapter_util/ca_adapter_net_ssl.c
resource/csdk/connectivity/src/caconnectivitymanager.c
resource/csdk/connectivity/src/caprotocolmessage.c
resource/csdk/connectivity/src/caretransmission.c
resource/csdk/routing/src/routingmanager.c
resource/csdk/security/provisioning/src/credentialgenerator.c
resource/csdk/security/src/aclresource.c
resource/csdk/security/src/doxmresource.c
resource/csdk/security/src/oxmpincommon.c
resource/csdk/security/src/srmutility.c
resource/csdk/stack/src/ocobserve.c
resource/csdk/stack/src/ocresource.c
resource/csdk/stack/src/ocstack.c
service/notification/src/common/NSUtil.c
service/scene-manager/src/SceneUtils.cpp

index d4af634..e2d2eb5 100644 (file)
 
 #include <stdint.h>
 #include <stdlib.h>
+#include <stdbool.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#ifndef ARDUINO
-#include <time.h>
-#else
+#ifdef ARDUINO
 // MEGA has 16 input pins whereas Due has only 12 input pins
 #define ANALOG_IN (10)
 #endif
 
+ /* Number of bytes in a UUID. */
 #define UUID_SIZE (16)
-// The characters are 36 long, 37 for the null-term
-#define UUID_STRING_SIZE (37)
 
-typedef enum
-{
-    RAND_UUID_OK = 0,
-    RAND_UUID_INVALID_PARAM = -1,
-    RAND_UUID_READ_ERROR = -2,
-    RAND_UUID_CONVERT_ERROR = -3
-} OCRandomUuidResult;
-/**
- * Seed the random number generator. Seeding depends on platform.
- * Android and Linux uses current time. Arduino uses Analog reading on pin ANALOG_IN
- * @retval 0 for Success, otherwise some error value
+/*
+ * Size of a UUID string.
+ * IoTivity formats UUIDs as strings following RFC 4122, Section 3. 
+ * For example, "f81d4fae-7dec-11d0-a765-00a0c91e6bf6".
+ * This requires 36 characters, plus one for the null terminator.
  */
-int8_t OCSeedRandom();
+#define UUID_STRING_SIZE (37)
 
 /**
- * Generate a uniformly [0,2^32] distributed random number
- * @retval On Success, it returns the random value.
+ * Generate a uniformly distributed 32-bit random number.
+ * @retval On success, it returns the random value.
  */
 uint32_t OCGetRandom();
 
 /**
- * Generate a uniformly [0,2^8] distributed random number
- * @retval On Success, it returns the random value, otherwise -1 for error.
- */
-uint8_t OCGetRandomByte(void);
-
-/**
- * Generate a uniformly distributed 8-bit (byte) array random numbers
- * @param[out] location
- *              memory location to start filling with random bytes
+ * Generate an array of uniformly distributed random bytes.
+ * @param[out] output
+ *              Array to fill with random bytes
  * @param[in] len
- *              length of array to be filled with random bytes
+ *              Length of array
+ * @retval true for success, otherwise false and an error is logged
  */
-void OCFillRandomMem(uint8_t * location, uint16_t len);
+bool OCGetRandomBytes(uint8_t * output, size_t len);
 
-/*
- * Generate a uniformly distributed number on the defined bounded range
+/**
+ * Generate a uniformly distributed number in a given range.
  * @param[in] firstBound
- *              the first bound of the range
+ *              The output is greater than or equal to firstBound
  * @param[in] secondBound
- *              the second bound of the range
+ *              The output is less than or equal to secondBound
  */
 uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound);
 
 /**
  * Generate a Uniformly Unique Identifier based on RFC4122 and
- * provide it as a 16 byte byte-array
+ * provide it as UUID_SIZE bytes.
  *
  * @param[out] uuid
- *               the 16 byte array to fill with the UUID data
- *               of a new UUID
+ *               UUID_SIZE array to hold the new UUID
  *
- * @retval RAND_UUID_OK for success, otherwise an error value
+ * @retval true for success, otherwise false and an error is logged
  */
-OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE]);
+bool OCGenerateUuid(uint8_t uuid[UUID_SIZE]);
 
 /**
- * Generate a Uniformly Unique Identifier based on RFC4122 and
- * provide it as a C style string.
- *
- * @param[out] uuidString
- *               a 37-byte length string to fill with the string
- *               representation of a new UUID.  Size is 32 chars
- *               for the hex data, 4 for '-' characters, and 1
- *               for the NULL terminator
- *
- * @retval RAND_UUID_OK for success, otherwise an error value
- */
-OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE]);
-
-/**
- * Convert a UUID generated by OCGenerateUuid to a C style string
- * based on RFC 4122
+ * Convert a UUID generated by OCGenerateUuid to a C string
+ * based on RFC 4122.
  *
  * @param[in]  uuid
- *              The 16 byte array filled with UUID data by OCGenerateUuid
+ *              Array of length UUID_SIZE bytes with output of OCGenerateUuid
  * @param[out] uuidString
- *              a 37 byte length string to fill with the string
- *              representation of the passed UUID.
- * @retval RAND_UUID_OK for success, otherwise an error value
+ *              A UUID_STRING_SIZE length string to hold the string
+ *              representation of the input UUID.
+ * @retval true for success, otherwise false and an error is logged
  */
-OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
+bool OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
         char uuidString[UUID_STRING_SIZE]);
 
 /**
@@ -132,9 +104,9 @@ OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
  *              representation of the passed UUID.
  * @param[out]  uuid
  *              The 16 byte array filled with UUID data
- * @retval RAND_UUID_OK for success, otherwise an error value
+ * @retval true for success, otherwise false and an error is logged
  */
-OCRandomUuidResult OCConvertStringToUuid(const char uuidString[UUID_STRING_SIZE],
+bool OCConvertStringToUuid(const char uuidString[UUID_STRING_SIZE],
                                          uint8_t uuid[UUID_SIZE]);
 
 #ifdef __cplusplus
index e53c594..b41056a 100644 (file)
@@ -31,6 +31,7 @@
 #endif
 
 #include "iotivity_config.h"
+#include "logger.h"
 
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #elif defined(HAVE_STRINGS_H)
 #include <strings.h>
 #endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
 #if defined(__ANDROID__)
 #include <ctype.h>
-#include <linux/time.h>
 #endif
 #ifdef HAVE_WINDOWS_H
 #include <windows.h>
 #endif
+
 #include "ocrandom.h"
 #include <stdio.h>
+#include <stdbool.h>
+#include <assert.h>
 
-#ifdef HAVE_UUID_UUID_H
-#include <uuid/uuid.h>
-#endif
+#define OC_MIN(A,B) ((A)<(B)?(A):(B))
 
-#define NANO_SEC 1000000000
+/**
+* @def OCRANDOM_TAG
+* @brief Logging tag for module name
+*/
+#define OCRANDOM_TAG "OIC_OCRANDOM"
 
 #ifdef ARDUINO
 #include "Arduino.h"
 
-// ARM GCC compiler doesnt define srandom function.
-#if defined(ARDUINO) && !defined(ARDUINO_ARCH_SAM)
-#define HAVE_SRANDOM 1
+/*
+ * ARM GCC compiler doesnt define random/srandom functions, fallback to 
+ * rand/srand.
+ */
+#if !defined(ARDUINO_ARCH_SAM)
+#define OC_arduino_srandom_function srandom
+#define OC_arduino_random_function random
+#elif
+#define OC_arduino_srandom_function srand
+#define OC_arduino_random_function rand
 #endif
 
 uint8_t GetRandomBitRaw()
@@ -116,252 +122,180 @@ uint8_t GetRandomBit()
         // For other cases, try again.
     }
 }
-#endif
 
-int8_t OCSeedRandom()
+/* 
+ * Currently, only the Arduino platform requires seeding. It's done 
+ * automatically on the first call to OCGetRandomBytes. 
+ */
+uint8_t g_isSeeded = 0;
+static void OCSeedRandom()
 {
-#ifndef ARDUINO
-    // Get current time to Seed.
-    uint64_t currentTime = 0;
-#ifdef __ANDROID__
-    struct timespec getTs;
-    clock_gettime(CLOCK_MONOTONIC, &getTs);
-    currentTime = (getTs.tv_sec * (uint64_t)NANO_SEC + getTs.tv_nsec)/1000;
-#elif _WIN32
-    LARGE_INTEGER count;
-    if (QueryPerformanceCounter(&count)) {
-        currentTime = count.QuadPart;
-    }
-#elif  _POSIX_TIMERS > 0
-    struct timespec ts;
-    clock_gettime(CLOCK_MONOTONIC, &ts);
-    currentTime = (ts.tv_sec * (uint64_t)NANO_SEC + ts.tv_nsec)/ 1000;
-#else
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    currentTime = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec;
-#endif
-#if defined(__unix__) || defined(__APPLE__)
-    int32_t fd = open("/dev/urandom", O_RDONLY);
-    if (fd >= 0)
-    {
-        uint32_t randomSeed = 0;
-        uint32_t totalRead = 0; //how many integers were read
-        int32_t currentRead = 0;
-        while (totalRead < sizeof(randomSeed))
-        {
-            currentRead = read(fd, (uint8_t*) &randomSeed + totalRead,
-                    sizeof(randomSeed) - totalRead);
-            if (currentRead > 0)
-            {
-                totalRead += currentRead;
-            }
-        }
-        close(fd);
-        srand(randomSeed | currentTime);
-    }
-    else
-#endif
+    if (g_isSeeded)
     {
-        // Do time based seed when problem in accessing "/dev/urandom"
-        srand(currentTime);
+        return;
     }
-
-    return 0;
-#elif defined ARDUINO
+    
     uint32_t result =0;
     uint8_t i;
     for (i=32; i--;)
     {
         result += result + GetRandomBit();
     }
-#if HAVE_SRANDOM
-    srandom(result);
-#else
-    srand(result);
-#endif
-    return 0;
-#endif
+    OC_arduino_srandom_function(result);
 
+    g_isSeeded = 1;
+    return;
 }
 
-void OCFillRandomMem(uint8_t * location, uint16_t len)
+#endif /* ARDUINO */
+
+bool OCGetRandomBytes(uint8_t * output, size_t len)
 {
-    if (!location)
+    if ( (output == NULL) || (len == 0) )
     {
-        return;
+        return false;
     }
-    for (; len--;)
+
+#if defined(__unix__) || defined(__APPLE__)
+    FILE* urandom = fopen("/dev/urandom", "r");
+    if (urandom == NULL)
     {
-        *location++ = OCGetRandomByte();
+        OIC_LOG(FATAL, OCRANDOM_TAG, "Failed open /dev/urandom!");
+        assert(false);
+        return false;
     }
-}
-
-uint32_t OCGetRandom()
-{
-    uint32_t result = 0;
-    OCFillRandomMem((uint8_t*) &result, 4);
-    return result;
-}
 
-uint8_t OCGetRandomByte(void)
-{
-#ifdef HAVE_SRANDOM
-    return random() & 0x00FF;
-#else
-    return rand() & 0x00FF;
-#endif
-}
-
-uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound)
-{
-    uint32_t base;
-    uint32_t diff;
-    uint32_t result;
-    if (firstBound > secondBound)
+    if (fread(output, sizeof(uint8_t), len, urandom) != len)
     {
-        base = secondBound;
-        diff = firstBound - secondBound;
+        OIC_LOG(FATAL, OCRANDOM_TAG, "Failed while reading /dev/urandom!");
+        assert(false);
+        fclose(urandom);
+        return false;
     }
-    else if (firstBound < secondBound)
+    fclose(urandom);
+
+#elif defined(_WIN32)
+    /*
+     * size_t may be 64 bits, but ULONG is always 32.
+     * If len is larger than the maximum for ULONG, just fail.
+     * It's unlikely anything ever will want to ask for this much randomness.
+     */
+    if (len > 0xFFFFFFFFULL)
     {
-        base = firstBound;
-        diff = secondBound - firstBound;
+        OIC_LOG(FATAL, OCRANDOM_TAG, "Requested number of bytes too large for ULONG");
+        assert(false);
+        return false;
     }
-    else
+
+    NTSTATUS status = BCryptGenRandom(NULL, output, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+    if (!BCRYPT_SUCCESS(status))
     {
-        return secondBound;
+        OIC_LOG_V(FATAL, OCRANDOM_TAG, "BCryptGenRandom failed (%X)!", status);
+        assert(false);
+        return false;
     }
-    result = ((float)OCGetRandom()/((float)(0xFFFFFFFF))*(float)diff) + (float) base;
-    return result;
-}
 
-#if defined(__ANDROID__)
-uint8_t parseUuidChar(char c)
-{
-    if (isdigit(c))
+#elif defined(ARDUINO)
+    if (!g_isSeeded)
     {
-        return c - '0';
+        OCSeedRandom();
     }
-    else
+
+    size_t i;
+    for (i = 0; i < len; i++)
     {
-        return c - 'a' + 10;
+        output[i] = OC_arduino_random_function() & 0x00ff;
     }
-}
-uint8_t parseUuidPart(const char *c)
-{
-    return (parseUuidChar(c[0])<<4) + parseUuidChar(c[1]);
-}
+
+#else
+    #error Unrecognized platform
 #endif
 
-OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE])
+    return true;
+}
+
+uint32_t OCGetRandom()
 {
-    if (!uuid)
+    uint32_t result = 0;
+    if (!OCGetRandomBytes((uint8_t*)&result, sizeof(result)))
     {
-        return RAND_UUID_INVALID_PARAM;
+        OIC_LOG(FATAL, OCRANDOM_TAG, "OCGetRandom failed!");
+        assert(false);
     }
-#if defined(__ANDROID__)
-    char uuidString[UUID_STRING_SIZE];
-    int8_t ret = OCGenerateUuidString(uuidString);
+    return result;
+}
 
-    if (ret < 0)
+/* Return the number of leading zeroes in x.
+ * Binary search algorithm from Section 5-3 of:
+ *     H.S. Warren Jr. Hacker's Delight. Addison-Wesley. 2003.
+ */
+static int nlz(uint32_t x)
+{
+    if (x == 0)
     {
-        return ret;
+        return 32;
     }
 
-    uuid[ 0] = parseUuidPart(&uuidString[0]);
-    uuid[ 1] = parseUuidPart(&uuidString[2]);
-    uuid[ 2] = parseUuidPart(&uuidString[4]);
-    uuid[ 3] = parseUuidPart(&uuidString[6]);
-
-    uuid[ 4] = parseUuidPart(&uuidString[9]);
-    uuid[ 5] = parseUuidPart(&uuidString[11]);
-
-    uuid[ 6] = parseUuidPart(&uuidString[14]);
-    uuid[ 7] = parseUuidPart(&uuidString[16]);
-
-    uuid[ 8] = parseUuidPart(&uuidString[19]);
-    uuid[ 9] = parseUuidPart(&uuidString[21]);
+    int n = 0;
+    if (x <= 0x0000FFFF) { n = n + 16; x = x << 16;}
+    if (x <= 0x00FFFFFF) { n = n + 8;  x = x << 8; }
+    if (x <= 0x0FFFFFFF) { n = n + 4;  x = x << 4; }
+    if (x <= 0x3FFFFFFF) { n = n + 2;  x = x << 2; }
+    if (x <= 0x7FFFFFFF) { n = n + 1;}
 
-    uuid[10] = parseUuidPart(&uuidString[24]);
-    uuid[11] = parseUuidPart(&uuidString[26]);
-    uuid[12] = parseUuidPart(&uuidString[28]);
-    uuid[13] = parseUuidPart(&uuidString[30]);
-    uuid[14] = parseUuidPart(&uuidString[32]);
-    uuid[15] = parseUuidPart(&uuidString[34]);
-
-    return RAND_UUID_OK;
-#elif defined(HAVE_UUID_UUID_H)
-    // note: uuid_t is typedefed as unsigned char[16] on linux/apple
-    uuid_generate(uuid);
-    return RAND_UUID_OK;
-#else
-    // Fallback for all platforms is filling the array with random data
-    OCFillRandomMem(uuid, UUID_SIZE);
-    return RAND_UUID_OK;
-#endif
+    return n;
 }
 
-OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE])
+uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound)
 {
-    if (!uuidString)
+    if (firstBound == secondBound)
     {
-        return RAND_UUID_INVALID_PARAM;
+        return secondBound;
     }
-#if defined(__ANDROID__)
-    int32_t fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
-    if (fd > 0)
+
+    uint32_t rangeBase = OC_MIN(firstBound, secondBound);
+    uint32_t rangeWidth = (firstBound > secondBound) ? (firstBound - secondBound) : (secondBound - firstBound);
+
+    /* 
+     * Compute a random number between 0 and rangeWidth. Avoid using floating 
+     * point types to avoid overflow when rangeWidth is large. The condition
+     * in the while loop will be false with probability at least 1/2. 
+     */
+    uint32_t rangeMask = 0xFFFFFFFF >> nlz(rangeWidth);
+    uint32_t offset = 0;
+    do 
     {
-        ssize_t readResult = read(fd, uuidString, UUID_STRING_SIZE - 1);
-        close(fd);
-        if (readResult < 0)
-        {
-            return RAND_UUID_READ_ERROR;
-        }
-        else if (readResult < UUID_STRING_SIZE - 1)
+        if(!OCGetRandomBytes((uint8_t*)&offset, sizeof(offset)))
         {
-            uuidString[0] = '\0';
-            return RAND_UUID_READ_ERROR;
+            OIC_LOG(FATAL, OCRANDOM_TAG, "OCGetRandomBytes failed");
+            assert(false);
+            return rangeBase; 
         }
+        offset = offset & rangeMask;
+    } 
+    while (offset > rangeWidth);    
 
-        uuidString[UUID_STRING_SIZE - 1] = '\0';
-        for (char* p = uuidString; *p; ++p)
-        {
-            *p = tolower(*p);
-        }
-        return RAND_UUID_OK;
-    }
-    else
-    {
-        close(fd);
-        return RAND_UUID_READ_ERROR;
-    }
-#elif defined(HAVE_UUID_UUID_H)
-    uint8_t uuid[UUID_SIZE];
-    int8_t ret = OCGenerateUuid(uuid);
+    return rangeBase + offset;
+}
 
-    if (ret != 0)
+bool OCGenerateUuid(uint8_t uuid[UUID_SIZE])
+{
+    if (!uuid)
     {
-        return ret;
+        OIC_LOG(ERROR, OCRANDOM_TAG, "Invalid parameter");
+        return false;
     }
 
-    uuid_unparse_lower(uuid, uuidString);
-    return RAND_UUID_OK;
-
-#else
-    uint8_t uuid[UUID_SIZE];
-    OCGenerateUuid(uuid);
-
-    return OCConvertUuidToString(uuid, uuidString);
-#endif
+    return OCGetRandomBytes(uuid, UUID_SIZE);
 }
 
-OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
+bool OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
                                          char uuidString[UUID_STRING_SIZE])
 {
     if (uuid == NULL || uuidString == NULL)
     {
-        return RAND_UUID_INVALID_PARAM;
+        OIC_LOG(ERROR, OCRANDOM_TAG, "Invalid parameter");
+        return false;
     }
 
 
@@ -375,18 +309,20 @@ OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
 
     if (ret != UUID_STRING_SIZE - 1)
     {
-        return RAND_UUID_CONVERT_ERROR;
+        OIC_LOG(ERROR, OCRANDOM_TAG, "snprintf failed");
+        return false;
     }
 
-    return RAND_UUID_OK;
+    return true;
 }
 
-OCRandomUuidResult OCConvertStringToUuid(const char uuidString[UUID_STRING_SIZE],
+bool OCConvertStringToUuid(const char uuidString[UUID_STRING_SIZE],
                                          uint8_t uuid[UUID_SIZE])
 {
     if(NULL == uuidString || NULL == uuid)
     {
-        return RAND_UUID_INVALID_PARAM;
+        OIC_LOG(ERROR, OCRANDOM_TAG, "Invalid parameter");
+        return false;
     }
 
     size_t urnIdx = 0;
@@ -408,11 +344,12 @@ OCRandomUuidResult OCConvertStringToUuid(const char uuidString[UUID_STRING_SIZE]
     }
     else
     {
-        return RAND_UUID_CONVERT_ERROR;
+        OIC_LOG(ERROR, OCRANDOM_TAG, "unexpected string length");
+        return false;
     }
 
     memcpy(uuid, convertedUuid, UUID_SIZE);
 
-    return RAND_UUID_OK;
+    return true;
 }
 
index e3536c1..97fc151 100644 (file)
@@ -29,9 +29,20 @@ target_os = randomtest_env.get('TARGET_OS')
 ######################################################################
 # Build flags
 ######################################################################
+
+randomtest_env.PrependUnique(CPPPATH = [
+        '../include',
+               '../../logger/include',
+               '../../../oc_logger/include',
+               ])
+randomtest_env.AppendUnique(LIBPATH = [randomtest_env.get('BUILD_DIR')])
+randomtest_env.PrependUnique(LIBS = ['octbstack',
+                                      'connectivity_abstraction',
+                                      'uuid'])
+
 randomtest_env.PrependUnique(CPPPATH = ['../include'])
 
-randomtest_env.AppendUnique(LIBPATH = [os.path.join(randomtest_env.get('BUILD_DIR'), 'resource', 'c_common')])
 randomtest_env.PrependUnique(LIBS = ['c_common'])
 
 if target_os in ['linux']:
diff --git a/resource/c_common/ocrandom/test/android/randomtest.cpp b/resource/c_common/ocrandom/test/android/randomtest.cpp
new file mode 100644 (file)
index 0000000..c115ac5
--- /dev/null
@@ -0,0 +1,89 @@
+
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+extern "C" {
+    #include "ocrandom.h"
+}
+
+#include "gtest/gtest.h"
+#include "math.h"
+
+
+TEST(RandomGeneration,OCGetRandom) {
+    uint32_t value = OCGetRandom();
+    EXPECT_LE((uint8_t )0, value);
+    EXPECT_GT(pow(2, 32), value);
+}
+
+TEST(RandomGeneration,OCGetRandomBytes) {
+    uint16_t ARR_SIZE = 20;
+    uint8_t array[ARR_SIZE]={};
+    EXPECT_TRUE(OCGetRandomBytes(array + 1, ARR_SIZE - 2));
+
+    for (int i = 1; i < ARR_SIZE - 2; i++) {
+        uint8_t value = array[i];
+        EXPECT_LE((uint8_t )0, value);
+        EXPECT_GT(pow(2, 8), value);
+    }
+    EXPECT_EQ((uint8_t )0, array[0]);
+    EXPECT_EQ((uint8_t )0, array[ARR_SIZE - 1]);
+}
+
+TEST(RandomGeneration, OCGenerateUuid)
+{
+    EXPECT_EQ(RAND_UUID_INVALID_PARAM, OCGenerateUuid(NULL));
+
+    uint8_t uuid[UUID_SIZE] = {};
+
+    EXPECT_TRUE(OCGenerateUuid(uuid));
+
+    EXPECT_FALSE(uuid[0] == '0' && uuid[1] == '0' &&
+                 uuid[2] == '0' && uuid[3] == '0' &&
+                 uuid[4] == '0' && uuid[5] == '0' &&
+                 uuid[6] == '0' && uuid[7] == '0' &&
+                 uuid[8] == '0' && uuid[9] == '0' &&
+                 uuid[10] == '0' && uuid[11] == '0' &&
+                 uuid[12] == '0' && uuid[13] == '0' &&
+                 uuid[14] == '0' && uuid[15] == '0');
+}
+
+TEST(RandomGeneration, OCGenerateUuidString)
+{
+    char uuidString[UUID_STRING_SIZE] ={};
+    uint8_t uuid[UUID_SIZE] = {};
+
+    EXPECT_TRUE(OCGenerateUuid(uuid));
+    EXPECT_TRUE(OCConvertUuidToString(uuid, uuidString));
+    EXPECT_EQ(0, uuidString[36]);
+    EXPECT_EQ('-', uuidString[8]);
+    EXPECT_EQ('-', uuidString[13]);
+    EXPECT_EQ('-', uuidString[18]);
+    EXPECT_EQ('-', uuidString[23]);
+
+    for(int i = 0; i < 36; ++i)
+    {
+        EXPECT_TRUE(
+                i == 8 || i == 13 || i == 18 || i == 23 ||
+                (uuidString[i] >= 'a' && uuidString[i] <= 'f') ||
+                (uuidString[i] >= '0' && uuidString[i] <= '9'))
+                << "UUID Character out of range: "<< uuidString[i];
+    }
+}
index d9faf0d..b4440f6 100644 (file)
@@ -28,21 +28,6 @@ void setup() {
     Serial.begin(115200);
     Serial.println("Testing Random Number generator for Arduino");
 
-    Serial.print("Testing OCSeedRandom ... ");
-    if (OCSeedRandom() == 0) {
-        Serial.println("[Success]");
-    } else {
-        Serial.println("[Fail]");
-    }
-
-    Serial.print("Testing OCGetRandomByte ... ");
-    uint8_t value8 = OCGetRandomByte();
-    if (value8 >= 0 && value8 < pow(2, 8)) {
-        Serial.println("[Success]");
-    } else {
-        Serial.println("[Fail]");
-    }
-
     Serial.print("Testing OCGetRandom ... ");
     uint32_t value32 = OCGetRandom();
     if (value32 >= 0 && value32 < pow(2, 32)) {
@@ -51,9 +36,11 @@ void setup() {
         Serial.println("[Fail]");
     }
 
-    Serial.print("Testing OCFillRandomMem ... ");
+    Serial.print("Testing OCGetRandomBytes ... ");
     uint8_t array[ARR_SIZE] = {};
-    OCFillRandomMem(array + 1, ARR_SIZE - 2);
+    if (!OCGetRandomBytes(array + 1, ARR_SIZE - 2)) {
+        Serial.println("[Fail]");
+    }
     uint8_t overall = 0;
     uint8_t value82 = 0;
     for (int i = 1; i <= ARR_SIZE - 2; i++) {
index 52d1739..58c7b64 100644 (file)
@@ -25,38 +25,36 @@ extern "C" {
 }
 
 #include "gtest/gtest.h"
+#include "math.h"
 
 #define ARR_SIZE (20)
 
-TEST(RandomGeneration,OCSeedRandom) {
-    EXPECT_EQ(0, OCSeedRandom());
-}
-
-TEST(RandomGeneration,OCGetRandomByte) {
-    EXPECT_NO_THROW(OCGetRandomByte());
-}
-
 TEST(RandomGeneration,OCGetRandom) {
-    EXPECT_NO_THROW(OCGetRandom());
+    uint32_t value = OCGetRandom();
+    EXPECT_LE((uint8_t )0, value);
+    EXPECT_GT(pow(2, 32), value);
 }
 
-TEST(RandomGeneration,OCFillRandomMem_BoundsCheck) {
+TEST(RandomGeneration,OCGetRandomBytes) {
     uint8_t array[ARR_SIZE] = {};
+    EXPECT_TRUE(OCGetRandomBytes(array + 1, ARR_SIZE - 2));
 
-    // Ignore the first and last bytes of the array
-    OCFillRandomMem(array + 1, ARR_SIZE - 2);
-
+    for (int i = 1; i <= ARR_SIZE - 2; i++) {
+        uint8_t value = array[i];
+        EXPECT_LE((uint8_t )0, value);
+        EXPECT_GT(pow(2, 8), value);
+    }
     EXPECT_EQ((uint8_t )0, array[0]);
     EXPECT_EQ((uint8_t )0, array[ARR_SIZE - 1]);
 }
 
 TEST(RandomGeneration, OCGenerateUuid)
 {
-    EXPECT_EQ(RAND_UUID_INVALID_PARAM, OCGenerateUuid(NULL));
+    EXPECT_FALSE(OCGenerateUuid(NULL));
 
-    uint8_t uuid[16] = {};
+    uint8_t uuid[UUID_SIZE] = {};
 
-    EXPECT_EQ(RAND_UUID_OK, OCGenerateUuid(uuid));
+    EXPECT_TRUE(OCGenerateUuid(uuid));
 
     EXPECT_FALSE(uuid[0] == '0' && uuid[1] == '0' &&
                  uuid[2] == '0' && uuid[3] == '0' &&
@@ -70,11 +68,11 @@ TEST(RandomGeneration, OCGenerateUuid)
 
 TEST(RandomGeneration, OCGenerateUuidString)
 {
-    EXPECT_EQ(RAND_UUID_INVALID_PARAM, OCGenerateUuidString(NULL));
-
-    char uuidString[37] = {};
+    char uuidString[UUID_STRING_SIZE] = {};
+    uint8_t uuid[UUID_SIZE] = {};
 
-    EXPECT_EQ(RAND_UUID_OK, OCGenerateUuidString(uuidString));
+    EXPECT_TRUE(OCGenerateUuid(uuid));
+    EXPECT_TRUE(OCConvertUuidToString(uuid, uuidString));
     EXPECT_EQ('\0', uuidString[36]);
     EXPECT_EQ('-', uuidString[8]);
     EXPECT_EQ('-', uuidString[13]);
index 9bed509..9ec7027 100644 (file)
@@ -29,5 +29,5 @@ win_helper_env.UserInstallTargetHeader('include/win_sleep.h', 'c_common/windows/
 win_helper_env.UserInstallTargetHeader('include/pthread_create.h', 'c_common/windows/include', 'pthread_create.h')
 win_helper_env.UserInstallTargetHeader('include/vs12_snprintf.h', 'c_common/windows/include', 'vs12_snprintf.h')
 
-env.AppendUnique(LIBS = ['win_helper'])
+env.AppendUnique(LIBS = ['win_helper', 'bcrypt'])
 
index 5f9bd76..3ae1e1a 100644 (file)
@@ -1752,7 +1752,7 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, uint32_t d
                 {
                     memcpy(uuid, (char*) uuidPos + sizeof(UUID_PREFIX) - 1, UUID_LENGTH * 2 + 4);
                     OIC_LOG_V(DEBUG, NET_SSL_TAG, "certificate uuid string: %s" , uuid);
-                    ret = OCConvertStringToUuid(uuid, peer->sep.identity.id);
+                    ret = (OCConvertStringToUuid(uuid, peer->sep.identity.id)) ? 0 : -1;
                     SSL_CHECK_FAIL(peer, ret, "Failed to convert subject", 1,
                                           CA_STATUS_FAILED, MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT);
                 }
@@ -1766,7 +1766,7 @@ CAResult_t CAdecryptSsl(const CASecureEndpoint_t *sep, uint8_t *data, uint32_t d
                 if (NULL != userIdPos)
                 {
                     memcpy(uuid, (char*) userIdPos + sizeof(USERID_PREFIX) - 1, UUID_LENGTH * 2 + 4);
-                    ret = OCConvertStringToUuid(uuid, peer->sep.userId.id);
+                    ret = (OCConvertStringToUuid(uuid, peer->sep.userId.id)) ? 0 : -1;
                     SSL_CHECK_FAIL(peer, ret, "Failed to convert subject alt name", 1,
                                       CA_STATUS_FAILED, MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT);
                 }
index 8e0d55c..1e469f3 100644 (file)
@@ -62,11 +62,6 @@ CAResult_t CAInitialize()
 
     if (!g_isInitialized)
     {
-        if (0 != OCSeedRandom())
-        {
-            OIC_LOG(ERROR, TAG, "Seed Random Failed");
-        }
-
         CAResult_t res = CAInitializeMessageHandler();
         if (res != CA_STATUS_OK)
         {
index 9a9cd8c..3678841 100644 (file)
@@ -1044,7 +1044,11 @@ CAResult_t CAGenerateTokenInternal(CAToken_t *token, uint8_t tokenLength)
         return CA_MEMORY_ALLOC_FAILED;
     }
 
-    OCFillRandomMem((uint8_t *)temp, tokenLength);
+    if (!OCGetRandomBytes((uint8_t *)temp, tokenLength))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to generate random token");
+        return CA_STATUS_FAILED;
+    }
 
     // save token
     *token = temp;
index 4dd74d4..57fa724 100644 (file)
@@ -105,7 +105,13 @@ static const uint64_t MSECS_PER_SEC = 1000;
  */
 static uint64_t CAGetTimeoutValue()
 {
-    return ((DEFAULT_ACK_TIMEOUT_SEC * 1000) + ((1000 * OCGetRandomByte()) >> 8)) *
+    uint8_t randomValue = 0;
+    if (!OCGetRandomBytes(&randomValue, sizeof(randomValue)))
+    {
+        OIC_LOG(ERROR, TAG, "OCGetRandomBytes failed");
+    }
+
+    return ((DEFAULT_ACK_TIMEOUT_SEC * 1000) + ((1000 * randomValue) >> 8)) *
             (uint64_t) 1000;
 }
 
index 9f87d2f..2edb143 100644 (file)
@@ -141,11 +141,19 @@ OCStackResult RMSendNotificationToAll(const OCRepPayload *payload);
  */
 void RMSendDeleteToNeighbourNodes();
 
-void RMGenerateGatewayID(uint8_t *id, size_t idLen)
+OCStackResult RMGenerateGatewayID(uint8_t *id, size_t idLen)
 {
     OIC_LOG(DEBUG, TAG, "RMGenerateGatewayID IN");
-    OCFillRandomMem(id, idLen);
+
+    if (!OCGetRandomBytes(id, idLen))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to generate random gateway ID");
+        return OC_STACK_ERROR;
+    }
+
     OIC_LOG(DEBUG, TAG, "RMGenerateGatewayID OUT");
+
+    return OC_STACK_OK;
 }
 OCStackResult RMInitialize()
 {
@@ -165,7 +173,12 @@ OCStackResult RMInitialize()
     }
 
     // Generates a 4 byte Gateway ID.
-    RMGenerateGatewayID((uint8_t *)&g_GatewayID, sizeof(g_GatewayID));
+    result = RMGenerateGatewayID((uint8_t *)&g_GatewayID, sizeof(g_GatewayID));
+    if (OC_STACK_OK != result)
+    {
+        OIC_LOG_V(ERROR, TAG, "RMGenerateGatewayID failed[%d]", result);
+        return result;
+    }
 
     OIC_LOG_V(INFO, RM_TAG, "Gateway ID: %u", g_GatewayID);
 
index a6ee58e..83a7300 100644 (file)
@@ -42,7 +42,7 @@ OCStackResult PMGeneratePairWiseCredentials(OicSecCredType_t type, size_t keySiz
         OIC_LOG(INFO, TAG, "Invalid params");
         return OC_STACK_INVALID_PARAM;
     }
-    if(!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
+    if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
     {
         OIC_LOG(INFO, TAG, "Invalid key size");
         return OC_STACK_INVALID_PARAM;
@@ -57,7 +57,12 @@ OCStackResult PMGeneratePairWiseCredentials(OicSecCredType_t type, size_t keySiz
     VERIFY_NON_NULL(TAG, privData, ERROR);
     OicSecKey_t privKey = {privData, keySize};
 
-    OCFillRandomMem(privData, privDataKeySize);
+    if (!OCGetRandomBytes(privData, privDataKeySize))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to generate private key");
+        res = OC_STACK_ERROR;
+        goto exit;
+    }
 
     // TODO: currently owner array is 1. only provisioning tool's id.
     tempFirstCred =  GenerateCredential(secondDeviceId, type, NULL, &privKey, ptDeviceId, NULL);
@@ -75,7 +80,7 @@ exit:
     OICClearMemory(privData, privDataKeySize);
     OICFree(privData);
 
-    if(res != OC_STACK_OK)
+    if (res != OC_STACK_OK)
     {
         OICFree(tempFirstCred);
         OICFree(tempSecondCred);
index 83e4e58..aa06514 100644 (file)
@@ -2277,8 +2277,7 @@ OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl)
     }
     else
     {
-        OCRandomUuidResult rdm = OCGenerateUuid(ownerId.id);
-        VERIFY_SUCCESS(TAG, RAND_UUID_OK == rdm, FATAL);
+        VERIFY_SUCCESS(TAG, OCGenerateUuid(ownerId.id), FATAL);
     }
 
     memcpy(&acl->rownerID, &ownerId, sizeof(OicUuid_t));
index c3256d6..2070117 100644 (file)
@@ -1555,10 +1555,10 @@ static OCStackResult CheckDeviceID()
 
     if (!validId)
     {
-        if (OCGenerateUuid(gDoxm->deviceID.id) != RAND_UUID_OK)
+        if (!OCGenerateUuid(gDoxm->deviceID.id))
         {
             OIC_LOG(FATAL, TAG, "Generate UUID for Server Instance failed!");
-            return ret;
+            return OC_STACK_ERROR;
         }
         ret = OC_STACK_OK;
 
index 26cc0b5..6fc776b 100644 (file)
@@ -315,7 +315,12 @@ int32_t GetDtlsPskForRandomPinOxm( CADtlsPskCredType_t type,
                  * At this point, The server generate random hint and
                  * provide it to client through server key exchange message.
                  */
-                OCFillRandomMem(result, result_length);
+                if (!OCGetRandomBytes(result, result_length))
+                {
+                    OIC_LOG(ERROR, TAG, "Failed to generate random PSK hint");
+                    ret = -1;
+                    break;
+                }
                 ret = result_length;
 
                 OIC_LOG(DEBUG, TAG, "PSK HINT : ");
@@ -431,7 +436,12 @@ int32_t GetDtlsPskForPreconfPinOxm( CADtlsPskCredType_t type,
                      * At this point, The server generate random hint and
                      * provide it to client through server key exchange message.
                      */
-                    OCFillRandomMem(result, result_length);
+                    if (!OCGetRandomBytes(result, result_length))
+                    {
+                        OIC_LOG(ERROR, TAG, "Failed to generate random PSK hint");
+                        ret = -1;
+                        break;
+                    }
                     ret = result_length;
 
                     OIC_LOG(DEBUG, TAG, "PSK HINT : ");
index 6263113..b1f7744 100644 (file)
@@ -140,6 +140,6 @@ exit:
 
 OCStackResult ConvertStrToUuid(const char* strUuid, OicUuid_t* uuid)
 {
-    OCRandomUuidResult result = OCConvertStringToUuid(strUuid, uuid->id);
-    return (result == RAND_UUID_OK) ? OC_STACK_OK : OC_STACK_INVALID_PARAM;
+    bool result = OCConvertStringToUuid(strUuid, uuid->id);
+    return (result) ? OC_STACK_OK : OC_STACK_INVALID_PARAM;
 }
index 5bb1a6b..1d7a48c 100644 (file)
@@ -368,7 +368,12 @@ OCStackResult GenerateObserverId (OCObservationId *observationId)
 
     do
     {
-        *observationId = OCGetRandomByte();
+        if (!OCGetRandomBytes((uint8_t*)observationId, sizeof(OCObservationId)))
+        {
+            OIC_LOG_V(ERROR, TAG, "Failed to generate random observationId");
+            goto exit;
+        }
+
         // Check if observation Id already exists
         resObs = GetObserverUsingId (*observationId);
     } while (NULL != resObs);
index 117a1ad..4cedebe 100755 (executable)
@@ -1475,7 +1475,7 @@ OCStackResult OCSetPlatformInfo(OCPlatformInfo info)
      * into one PAL API.
      */
     uint8_t uuid[UUID_SIZE];
-    if (OCConvertStringToUuid(info.platformID, uuid) != RAND_UUID_OK)
+    if (!OCConvertStringToUuid(info.platformID, uuid))
     {
         OIC_LOG(ERROR, TAG, "Platform ID is not a UUID.");
         goto exit;
index a6977fe..27eff0a 100644 (file)
@@ -4228,7 +4228,11 @@ static OCDoHandle GenerateInvocationHandle()
     handle = (OCDoHandle) OICMalloc(sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
     if (handle)
     {
-        OCFillRandomMem((uint8_t*)handle, sizeof(uint8_t[CA_MAX_TOKEN_LEN]));
+        if (!OCGetRandomBytes((uint8_t*)handle, sizeof(uint8_t[CA_MAX_TOKEN_LEN])))
+        {
+            OICFree(handle);
+            return NULL;
+        }
     }
 
     return handle;
@@ -4802,7 +4806,7 @@ const char* OCGetServerInstanceIDString(void)
     }
 
     const OicUuid_t *sid = OCGetServerInstanceID();
-    if (sid && OCConvertUuidToString(sid->id, sidStr) != RAND_UUID_OK)
+    if(sid && !OCConvertUuidToString(sid->id, sidStr))
     {
         OIC_LOG(FATAL, TAG, "Generate UUID String for Server Instance failed!");
         return NULL;
index 2789366..3256ce7 100755 (executable)
@@ -312,9 +312,9 @@ NSResult NSGenerateUUIDStr(char uuidStr[UUID_STRING_SIZE])
 {
     uint8_t uuid[UUID_SIZE] = { 0, };
 
-    if (RAND_UUID_OK == OCGenerateUuid(uuid))
+    if (OCGenerateUuid(uuid))
     {
-        if (RAND_UUID_OK == OCConvertUuidToString(uuid, uuidStr))
+        if (OCConvertUuidToString(uuid, uuidStr))
         {
             return NS_OK;
         }
index 5b1ad5f..a2330b8 100755 (executable)
@@ -35,9 +35,9 @@ namespace OIC
         {
             uint8_t uuid[UUID_SIZE] = { 0, };
             char uuidStr[UUID_STRING_SIZE] = { 0, };
-            if (RAND_UUID_OK == OCGenerateUuid(uuid))
+            if (OCGenerateUuid(uuid))
             {
-                if (RAND_UUID_OK == OCConvertUuidToString(uuid, uuidStr))
+                if (OCConvertUuidToString(uuid, uuidStr))
                 {
                     return std::string(uuidStr);
                 }