Fixing crash in OCFillRandomMem (#512)
[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 "iotivity_config.h"
34
35 #ifdef HAVE_FCNTL_H
36 #include <fcntl.h>
37 #endif
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #ifdef HAVE_STDLIB_H
42 #include <stdlib.h>
43 #endif
44 #ifdef HAVE_STRING_H
45 #include <string.h>
46 #elif defined(HAVE_STRINGS_H)
47 #include <strings.h>
48 #endif
49 #ifdef HAVE_SYS_TIME_H
50 #include <sys/time.h>
51 #endif
52 #ifdef HAVE_TIME_H
53 #include <time.h>
54 #endif
55 #if defined(__ANDROID__)
56 #include <ctype.h>
57 #include <linux/time.h>
58 #endif
59 #ifdef HAVE_WINDOWS_H
60 #include <windows.h>
61 #endif
62 #include "ocrandom.h"
63 #include <stdio.h>
64
65 #ifdef HAVE_UUID_UUID_H
66 #include <uuid/uuid.h>
67 #endif
68
69 #define NANO_SEC 1000000000
70
71 #ifdef ARDUINO
72 #include "Arduino.h"
73
74 // ARM GCC compiler doesnt define srandom function.
75 #if defined(ARDUINO) && !defined(ARDUINO_ARCH_SAM)
76 #define HAVE_SRANDOM 1
77 #endif
78
79 uint8_t GetRandomBitRaw()
80 {
81     return analogRead((uint8_t)ANALOG_IN) & 0x1;
82 }
83
84 uint8_t GetRandomBitRaw2()
85 {
86     int a = 0;
87     for (;;)
88     {
89         a = GetRandomBitRaw() | (GetRandomBitRaw()<<1);
90         if (a==1)
91         {
92             return 0; // 1 to 0 transition: log a zero bit
93         }
94         if (a==2)
95         {
96             return 1;// 0 to 1 transition: log a one bit
97         }
98         // For other cases, try again.
99     }
100 }
101
102 uint8_t GetRandomBit()
103 {
104     int a = 0;
105     for (;;)
106     {
107         a = GetRandomBitRaw2() | (GetRandomBitRaw2()<<1);
108         if (a==1)
109         {
110             return 0; // 1 to 0 transition: log a zero bit
111         }
112         if (a==2)
113         {
114             return 1;// 0 to 1 transition: log a one bit
115         }
116         // For other cases, try again.
117     }
118 }
119 #endif
120
121 int8_t OCSeedRandom()
122 {
123 #ifndef ARDUINO
124     // Get current time to Seed.
125     uint64_t currentTime = 0;
126 #ifdef __ANDROID__
127     struct timespec getTs;
128     clock_gettime(CLOCK_MONOTONIC, &getTs);
129     currentTime = (getTs.tv_sec * (uint64_t)NANO_SEC + getTs.tv_nsec)/1000;
130 #elif _WIN32
131     LARGE_INTEGER count;
132     if (QueryPerformanceCounter(&count)) {
133         currentTime = count.QuadPart;
134     }
135 #elif  _POSIX_TIMERS > 0
136     struct timespec ts;
137     clock_gettime(CLOCK_MONOTONIC, &ts);
138     currentTime = (ts.tv_sec * (uint64_t)NANO_SEC + ts.tv_nsec)/ 1000;
139 #else
140     struct timeval tv;
141     gettimeofday(&tv, NULL);
142     currentTime = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec;
143 #endif
144 #if defined(__unix__) || defined(__APPLE__) || defined(__TIZENRT__)
145     int32_t fd = open("/dev/urandom", O_RDONLY);
146     if (fd >= 0)
147     {
148         uint32_t randomSeed = 0;
149         uint32_t totalRead = 0; //how many integers were read
150         int32_t currentRead = 0;
151         while (totalRead < sizeof(randomSeed))
152         {
153             currentRead = read(fd, (uint8_t*) &randomSeed + totalRead,
154                     sizeof(randomSeed) - totalRead);
155             if (currentRead > 0)
156             {
157                 totalRead += currentRead;
158             }
159         }
160         close(fd);
161         srand(randomSeed | currentTime);
162     }
163     else
164 #endif
165     {
166         // Do time based seed when problem in accessing "/dev/urandom"
167         srand(currentTime);
168     }
169
170     return 0;
171 #elif defined ARDUINO
172     uint32_t result =0;
173     uint8_t i;
174     for (i=32; i--;)
175     {
176         result += result + GetRandomBit();
177     }
178 #if HAVE_SRANDOM
179     srandom(result);
180 #else
181     srand(result);
182 #endif
183     return 0;
184 #endif
185
186 }
187
188 void OCFillRandomMem(uint8_t * location, uint16_t len)
189 {
190     int i, j, rand_idx;
191     i = len;
192     if (!location)
193     {
194         return;
195     }
196     for (; i--;)
197     {
198         *location++ = OCGetRandomByte();
199     }
200     uint8_t *temp = (char *) OICCalloc(len, sizeof(char));
201     int *mask = (int *) OICCalloc(len, sizeof(int));
202     for (i = 0; i < len; i++)
203     {
204         mask[i] = 0;
205     }
206     j = 0;
207     for (i = 0; i < len; i++)
208     {
209         rand_idx = lrand48() % len;
210         while((rand_idx < len) && (mask[rand_idx] != 0))
211         {
212             rand_idx++;
213         }
214         if(rand_idx == len)
215         {
216             rand_idx = 0;
217             while(mask[rand_idx] != 0)
218             {
219                 rand_idx++;
220             }
221         }
222         temp[rand_idx] = location[j];
223         mask[rand_idx] = 1;
224         j++;
225     }
226     for (i = 0; i < len; i++)
227     {
228         location[i] = temp[i];
229     }
230     OICFree(temp);
231     OICFree(mask);
232 }
233
234 uint32_t OCGetRandom()
235 {
236     uint32_t result = 0;
237     OCFillRandomMem((uint8_t*) &result, 4);
238     return result;
239 }
240
241 uint8_t OCGetRandomByte(void)
242 {
243 #ifdef HAVE_SRANDOM
244     return random() & 0x00FF;
245 #else
246     return rand() & 0x00FF;
247 #endif
248 }
249
250 uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound)
251 {
252     uint32_t base;
253     uint32_t diff;
254     uint32_t result;
255     if (firstBound > secondBound)
256     {
257         base = secondBound;
258         diff = firstBound - secondBound;
259     }
260     else if (firstBound < secondBound)
261     {
262         base = firstBound;
263         diff = secondBound - firstBound;
264     }
265     else
266     {
267         return secondBound;
268     }
269     result = ((float)OCGetRandom()/((float)(0xFFFFFFFF))*(float)diff) + (float) base;
270     return result;
271 }
272
273 #if defined(__ANDROID__)
274 uint8_t parseUuidChar(char c)
275 {
276     if (isdigit(c))
277     {
278         return c - '0';
279     }
280     else
281     {
282         return c - 'a' + 10;
283     }
284 }
285 uint8_t parseUuidPart(const char *c)
286 {
287     return (parseUuidChar(c[0])<<4) + parseUuidChar(c[1]);
288 }
289 #endif
290
291 OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE])
292 {
293     if (!uuid)
294     {
295         return RAND_UUID_INVALID_PARAM;
296     }
297 #if defined(__ANDROID__)
298     char uuidString[UUID_STRING_SIZE];
299     int8_t ret = OCGenerateUuidString(uuidString);
300
301     if (RAND_UUID_OK == ret)
302     {
303         uuid[ 0] = parseUuidPart(&uuidString[0]);
304         uuid[ 1] = parseUuidPart(&uuidString[2]);
305         uuid[ 2] = parseUuidPart(&uuidString[4]);
306         uuid[ 3] = parseUuidPart(&uuidString[6]);
307
308         uuid[ 4] = parseUuidPart(&uuidString[9]);
309         uuid[ 5] = parseUuidPart(&uuidString[11]);
310
311         uuid[ 6] = parseUuidPart(&uuidString[14]);
312         uuid[ 7] = parseUuidPart(&uuidString[16]);
313
314         uuid[ 8] = parseUuidPart(&uuidString[19]);
315         uuid[ 9] = parseUuidPart(&uuidString[21]);
316
317         uuid[10] = parseUuidPart(&uuidString[24]);
318         uuid[11] = parseUuidPart(&uuidString[26]);
319         uuid[12] = parseUuidPart(&uuidString[28]);
320         uuid[13] = parseUuidPart(&uuidString[30]);
321         uuid[14] = parseUuidPart(&uuidString[32]);
322         uuid[15] = parseUuidPart(&uuidString[34]);
323
324         return RAND_UUID_OK;
325     }
326 #endif
327 #if defined(HAVE_UUID_UUID_H)
328     // note: uuid_t is typedefed as unsigned char[16] on linux/apple
329     uuid_generate(uuid);
330     return RAND_UUID_OK;
331 #else
332     // Fallback for all platforms is filling the array with random data
333     OCFillRandomMem(uuid, UUID_SIZE);
334     return RAND_UUID_OK;
335 #endif
336 }
337
338 OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE])
339 {
340     if (!uuidString)
341     {
342         return RAND_UUID_INVALID_PARAM;
343     }
344 #if defined(__ANDROID__)
345     int32_t fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
346     if (fd > 0)
347     {
348         ssize_t readResult = read(fd, uuidString, UUID_STRING_SIZE - 1);
349         close(fd);
350         if (readResult < 0)
351         {
352             return RAND_UUID_READ_ERROR;
353         }
354         else if (readResult < UUID_STRING_SIZE - 1)
355         {
356             uuidString[0] = '\0';
357             return RAND_UUID_READ_ERROR;
358         }
359
360         uuidString[UUID_STRING_SIZE - 1] = '\0';
361         for (char* p = uuidString; *p; ++p)
362         {
363             *p = tolower(*p);
364         }
365         return RAND_UUID_OK;
366     }
367     else
368     {
369         return RAND_UUID_READ_ERROR;
370     }
371 #elif defined(HAVE_UUID_UUID_H)
372     uint8_t uuid[UUID_SIZE];
373     int8_t ret = OCGenerateUuid(uuid);
374
375     if (ret != 0)
376     {
377         return ret;
378     }
379
380     uuid_unparse_lower(uuid, uuidString);
381     return RAND_UUID_OK;
382
383 #else
384     uint8_t uuid[UUID_SIZE];
385     OCGenerateUuid(uuid);
386
387     return OCConvertUuidToString(uuid, uuidString);
388 #endif
389 }
390
391 OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
392                                          char uuidString[UUID_STRING_SIZE])
393 {
394     if (uuid == NULL || uuidString == NULL)
395     {
396         return RAND_UUID_INVALID_PARAM;
397     }
398
399
400     int ret = snprintf(uuidString, UUID_STRING_SIZE,
401             "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
402             uuid[0], uuid[1], uuid[2], uuid[3],
403             uuid[4], uuid[5], uuid[6], uuid[7],
404             uuid[8], uuid[9], uuid[10], uuid[11],
405             uuid[12], uuid[13], uuid[14], uuid[15]
406             );
407
408     if (ret != UUID_STRING_SIZE - 1)
409     {
410         return RAND_UUID_CONVERT_ERROR;
411     }
412
413     return RAND_UUID_OK;
414 }
415
416 OCRandomUuidResult OCConvertStringToUuid(const char uuidString[UUID_STRING_SIZE],
417                                          uint8_t uuid[UUID_SIZE])
418 {
419     if(NULL == uuidString || NULL == uuid)
420     {
421         return RAND_UUID_INVALID_PARAM;
422     }
423
424     size_t urnIdx = 0;
425     size_t uuidIdx = 0;
426     size_t strUuidLen = 0;
427     char convertedUuid[UUID_SIZE * 2] = {0};
428
429     strUuidLen = strlen(uuidString);
430     if((UUID_STRING_SIZE - 1) == strUuidLen)
431     {
432         for(uuidIdx=0, urnIdx=0; uuidIdx < UUID_SIZE ; uuidIdx++, urnIdx+=2)
433         {
434             if(*(uuidString + urnIdx) == '-')
435             {
436                 urnIdx++;
437             }
438             sscanf(uuidString + urnIdx, "%2hhx", &convertedUuid[uuidIdx]);
439         }
440     }
441     else
442     {
443         return RAND_UUID_CONVERT_ERROR;
444     }
445
446     memcpy(uuid, convertedUuid, UUID_SIZE);
447
448     return RAND_UUID_OK;
449 }
450