Merge branch 'master' into windows-port
[platform/upstream/iotivity.git] / resource / c_common / ocrandom / src / ocrandom.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 // Defining _POSIX_C_SOURCE macro with 199309L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1b, Real-time extensions
24 // (IEEE Std 1003.1b-1993) specification
25 //
26 // For this specific file, see use of clock_gettime,
27 // Refer to http://pubs.opengroup.org/stage7tc1/functions/clock_gettime.html
28 // and to http://man7.org/linux/man-pages/man2/clock_gettime.2.html
29 #ifndef _POSIX_C_SOURCE
30 #define _POSIX_C_SOURCE 200809L
31 #endif
32
33 #include "platform_features.h"
34 #ifdef HAVE_FCNTL_H
35 #include <fcntl.h>
36 #endif
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #ifdef HAVE_STDLIB_H
41 #include <stdlib.h>
42 #endif
43 #ifdef HAVE_SYS_TIME_H
44 #include <sys/time.h>
45 #endif
46 #ifdef HAVE_TIME_H
47 #include <time.h>
48 #endif
49 #if defined(__ANDROID__)
50 #include <ctype.h>
51 #include <linux/time.h>
52 #endif
53 #ifdef HAVE_WINDOWS_H
54 #include <windows.h>
55 #endif
56 #include "ocrandom.h"
57 #include <stdio.h>
58
59 #ifdef HAVE_UUID_UUID_H
60 #include <uuid/uuid.h>
61 #endif
62
63 #define NANO_SEC 1000000000
64
65 #ifdef ARDUINO
66 #include "Arduino.h"
67
68 // ARM GCC compiler doesnt define srandom function.
69 #if defined(ARDUINO) && !defined(ARDUINO_ARCH_SAM)
70 #define HAVE_SRANDOM 1
71 #endif
72
73 uint8_t GetRandomBitRaw()
74 {
75     return analogRead((uint8_t)ANALOG_IN) & 0x1;
76 }
77
78 uint8_t GetRandomBitRaw2()
79 {
80     int a = 0;
81     for (;;)
82     {
83         a = GetRandomBitRaw() | (GetRandomBitRaw()<<1);
84         if (a==1)
85         {
86             return 0; // 1 to 0 transition: log a zero bit
87         }
88         if (a==2)
89         {
90             return 1;// 0 to 1 transition: log a one bit
91         }
92         // For other cases, try again.
93     }
94 }
95
96 uint8_t GetRandomBit()
97 {
98     int a = 0;
99     for (;;)
100     {
101         a = GetRandomBitRaw2() | (GetRandomBitRaw2()<<1);
102         if (a==1)
103         {
104             return 0; // 1 to 0 transition: log a zero bit
105         }
106         if (a==2)
107         {
108             return 1;// 0 to 1 transition: log a one bit
109         }
110         // For other cases, try again.
111     }
112 }
113 #endif
114
115 int8_t OCSeedRandom()
116 {
117 #ifndef ARDUINO
118     // Get current time to Seed.
119     uint64_t currentTime = 0;
120 #ifdef __ANDROID__
121     struct timespec getTs;
122     clock_gettime(CLOCK_MONOTONIC, &getTs);
123     currentTime = (getTs.tv_sec * (uint64_t)NANO_SEC + getTs.tv_nsec)/1000;
124 #elif _WIN32
125     LARGE_INTEGER count;
126     if (QueryPerformanceCounter(&count)) {
127         currentTime = count.QuadPart;
128     }
129 #elif  _POSIX_TIMERS > 0
130     struct timespec ts;
131     clock_gettime(CLOCK_MONOTONIC, &ts);
132     currentTime = (ts.tv_sec * (uint64_t)NANO_SEC + ts.tv_nsec)/ 1000;
133 #else
134     struct timeval tv;
135     gettimeofday(&tv, NULL);
136     currentTime = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec;
137 #endif
138 #if defined(__unix__) || defined(__APPLE__)
139     int32_t fd = open("/dev/urandom", O_RDONLY);
140     if (fd >= 0)
141     {
142         uint32_t randomSeed = 0;
143         uint32_t totalRead = 0; //how many integers were read
144         int32_t currentRead = 0;
145         while (totalRead < sizeof(randomSeed))
146         {
147             currentRead = read(fd, (uint8_t*) &randomSeed + totalRead,
148                     sizeof(randomSeed) - totalRead);
149             if (currentRead > 0)
150             {
151                 totalRead += currentRead;
152             }
153         }
154         close(fd);
155         srand(randomSeed | currentTime);
156     }
157     else
158 #endif
159     {
160         // Do time based seed when problem in accessing "/dev/urandom"
161         srand(currentTime);
162     }
163
164     return 0;
165 #elif defined ARDUINO
166     uint32_t result =0;
167     uint8_t i;
168     for (i=32; i--;)
169     {
170         result += result + GetRandomBit();
171     }
172 #if HAVE_SRANDOM
173     srandom(result);
174 #else
175     srand(result);
176 #endif
177     return 0;
178 #endif
179
180 }
181
182 void OCFillRandomMem(uint8_t * location, uint16_t len)
183 {
184     if (!location)
185     {
186         return;
187     }
188     for (; len--;)
189     {
190         *location++ = OCGetRandomByte();
191     }
192 }
193
194 uint32_t OCGetRandom()
195 {
196     uint32_t result = 0;
197     OCFillRandomMem((uint8_t*) &result, 4);
198     return result;
199 }
200
201 uint8_t OCGetRandomByte(void)
202 {
203 #ifdef HAVE_SRANDOM
204     return random() & 0x00FF;
205 #else
206     return rand() & 0x00FF;
207 #endif
208 }
209
210 uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound)
211 {
212     uint32_t base;
213     uint32_t diff;
214     uint32_t result;
215     if (firstBound > secondBound)
216     {
217         base = secondBound;
218         diff = firstBound - secondBound;
219     }
220     else if (firstBound < secondBound)
221     {
222         base = firstBound;
223         diff = secondBound - firstBound;
224     }
225     else
226     {
227         return secondBound;
228     }
229     result = ((float)OCGetRandom()/((float)(0xFFFFFFFF))*(float)diff) + (float) base;
230     return result;
231 }
232
233 #if defined(__ANDROID__)
234 uint8_t parseUuidChar(char c)
235 {
236     if (isdigit(c))
237     {
238         return c - '0';
239     }
240     else
241     {
242         return c - 'a' + 10;
243     }
244 }
245 uint8_t parseUuidPart(const char *c)
246 {
247     return (parseUuidChar(c[0])<<4) + parseUuidChar(c[1]);
248 }
249 #endif
250
251 OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE])
252 {
253     if (!uuid)
254     {
255         return RAND_UUID_INVALID_PARAM;
256     }
257 #if defined(__ANDROID__)
258     char uuidString[UUID_STRING_SIZE];
259     int8_t ret = OCGenerateUuidString(uuidString);
260
261     if (ret < 0)
262     {
263         return ret;
264     }
265
266     uuid[ 0] = parseUuidPart(&uuidString[0]);
267     uuid[ 1] = parseUuidPart(&uuidString[2]);
268     uuid[ 2] = parseUuidPart(&uuidString[4]);
269     uuid[ 3] = parseUuidPart(&uuidString[6]);
270
271     uuid[ 4] = parseUuidPart(&uuidString[9]);
272     uuid[ 5] = parseUuidPart(&uuidString[11]);
273
274     uuid[ 6] = parseUuidPart(&uuidString[14]);
275     uuid[ 7] = parseUuidPart(&uuidString[16]);
276
277     uuid[ 8] = parseUuidPart(&uuidString[19]);
278     uuid[ 9] = parseUuidPart(&uuidString[21]);
279
280     uuid[10] = parseUuidPart(&uuidString[24]);
281     uuid[11] = parseUuidPart(&uuidString[26]);
282     uuid[12] = parseUuidPart(&uuidString[28]);
283     uuid[13] = parseUuidPart(&uuidString[30]);
284     uuid[14] = parseUuidPart(&uuidString[32]);
285     uuid[15] = parseUuidPart(&uuidString[34]);
286
287     return RAND_UUID_OK;
288 #elif defined(HAVE_UUID_UUID_H)
289     // note: uuid_t is typedefed as unsigned char[16] on linux/apple
290     uuid_generate(uuid);
291     return RAND_UUID_OK;
292 #else
293     // Fallback for all platforms is filling the array with random data
294     OCFillRandomMem(uuid, UUID_SIZE);
295     return RAND_UUID_OK;
296 #endif
297 }
298
299 OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE])
300 {
301     if (!uuidString)
302     {
303         return RAND_UUID_INVALID_PARAM;
304     }
305 #if defined(__ANDROID__)
306     int32_t fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
307     if (fd > 0)
308     {
309         ssize_t readResult = read(fd, uuidString, UUID_STRING_SIZE - 1);
310         close(fd);
311         if (readResult < 0)
312         {
313             return RAND_UUID_READ_ERROR;
314         }
315         else if (readResult < UUID_STRING_SIZE - 1)
316         {
317             uuidString[0] = '\0';
318             return RAND_UUID_READ_ERROR;
319         }
320
321         uuidString[UUID_STRING_SIZE - 1] = '\0';
322         for (char* p = uuidString; *p; ++p)
323         {
324             *p = tolower(*p);
325         }
326         return RAND_UUID_OK;
327     }
328     else
329     {
330         close(fd);
331         return RAND_UUID_READ_ERROR;
332     }
333 #elif defined(HAVE_UUID_UUID_H)
334     uint8_t uuid[UUID_SIZE];
335     int8_t ret = OCGenerateUuid(uuid);
336
337     if (ret != 0)
338     {
339         return ret;
340     }
341
342     uuid_unparse_lower(uuid, uuidString);
343     return RAND_UUID_OK;
344
345 #else
346     uint8_t uuid[UUID_SIZE];
347     OCGenerateUuid(uuid);
348
349     return OCConvertUuidToString(uuid, uuidString);
350 #endif
351 }
352
353 OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
354                                          char uuidString[UUID_STRING_SIZE])
355 {
356     if (uuid == NULL || uuidString == NULL)
357     {
358         return RAND_UUID_INVALID_PARAM;
359     }
360
361
362     int ret = snprintf(uuidString, UUID_STRING_SIZE,
363             "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
364             uuid[0], uuid[1], uuid[2], uuid[3],
365             uuid[4], uuid[5], uuid[6], uuid[7],
366             uuid[8], uuid[9], uuid[10], uuid[11],
367             uuid[12], uuid[13], uuid[14], uuid[15]
368             );
369
370     if (ret != UUID_STRING_SIZE - 1)
371     {
372         return RAND_UUID_CONVERT_ERROR;
373     }
374
375     return RAND_UUID_OK;
376 }