diff --git a/headers/private/kernel/util/Random.h b/headers/private/kernel/util/Random.h index 26d1ee0059..d30976d198 100644 --- a/headers/private/kernel/util/Random.h +++ b/headers/private/kernel/util/Random.h @@ -15,9 +15,11 @@ #define MAX_FAST_RANDOM_VALUE 0x7fff #define MAX_RANDOM_VALUE 0x7fffffffu +#define MAX_SECURE_RANDOM_VALUE 0xffffffffu static const int kFastRandomShift = 15; static const int kRandomShift = 31; +static const int kSecureRandomShift = 32; #ifdef __cplusplus extern "C" { @@ -25,6 +27,7 @@ extern "C" { unsigned int fast_random_value(void); unsigned int random_value(void); +unsigned int secure_random_value(void); #ifdef __cplusplus } @@ -63,6 +66,21 @@ get_random() } +template +T +secure_get_random() +{ + size_t shift = 0; + T random = 0; + while (shift < sizeof(T) * 8) { + random |= (T)secure_random_value() << shift; + shift += kSecureRandomShift; + } + + return random; +} + + #endif // __cplusplus #endif // KERNEL_UTIL_RANDOM_H diff --git a/src/system/kernel/util/Random.cpp b/src/system/kernel/util/Random.cpp index 57c724de4f..46ad125ff7 100644 --- a/src/system/kernel/util/Random.cpp +++ b/src/system/kernel/util/Random.cpp @@ -14,6 +14,59 @@ static uint32 sFastLast = 0; static uint32 sLast = 0; +static uint32 sSecureLast = 0; + +// MD4 helper definitions, based on RFC 1320 +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +#define STEP(f, a, b, c, d, xk, s) \ + (a += f((b), (c), (d)) + (xk), a = (a << (s)) | (a >> (32 - (s)))) + + +// MD4 based hash function. Simplified in order to improve performance. +static uint32 +hash(uint32* data) +{ + const uint32 kMD4Round2 = 0x5a827999; + const uint32 kMD4Round3 = 0x6ed9eba1; + + uint32 a = 0x67452301; + uint32 b = 0xefcdab89; + uint32 c = 0x98badcfe; + uint32 d = 0x10325476; + + STEP(F, a, b, c, d, data[0], 3); + STEP(F, d, a, b, c, data[1], 7); + STEP(F, c, d, a, b, data[2], 11); + STEP(F, b, c, d, a, data[3], 19); + STEP(F, a, b, c, d, data[4], 3); + STEP(F, d, a, b, c, data[5], 7); + STEP(F, c, d, a, b, data[6], 11); + STEP(F, b, c, d, a, data[7], 19); + + STEP(G, a, b, c, d, data[1] + kMD4Round2, 3); + STEP(G, d, a, b, c, data[5] + kMD4Round2, 5); + STEP(G, c, d, a, b, data[6] + kMD4Round2, 9); + STEP(G, b, c, d, a, data[2] + kMD4Round2, 13); + STEP(G, a, b, c, d, data[3] + kMD4Round2, 3); + STEP(G, d, a, b, c, data[7] + kMD4Round2, 5); + STEP(G, c, d, a, b, data[4] + kMD4Round2, 9); + STEP(G, b, c, d, a, data[0] + kMD4Round2, 13); + + STEP(H, a, b, c, d, data[1] + kMD4Round3, 3); + STEP(H, d, a, b, c, data[6] + kMD4Round3, 9); + STEP(H, c, d, a, b, data[5] + kMD4Round3, 11); + STEP(H, b, c, d, a, data[2] + kMD4Round3, 15); + STEP(H, a, b, c, d, data[3] + kMD4Round3, 3); + STEP(H, d, a, b, c, data[4] + kMD4Round3, 9); + STEP(H, c, d, a, b, data[7] + kMD4Round3, 11); + STEP(H, b, c, d, a, data[0] + kMD4Round3, 15); + + return b; +} + // In the following functions there are race conditions when many threads // attempt to update static variable last. However, since such conflicts @@ -52,3 +105,24 @@ random_value() return random % (MAX_RANDOM_VALUE + 1); } + +unsigned int +secure_random_value() +{ + static vint32 count = 0; + + uint32 data[8]; + data[0] = atomic_add(&count, 1); + data[1] = system_time(); + data[2] = find_thread(NULL); + data[3] = smp_get_current_cpu(); + data[4] = smp_get_num_cpus(); + data[5] = sFastLast; + data[6] = sLast; + data[7] = sSecureLast; + + uint32 random = hash(data); + sSecureLast = random; + return random; +} +