Merge "Remove unused openssl-devel dependency" into tizen
[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     if (!location)
191     {
192         return;
193     }
194     uint16_t i, rand_idx;
195     uint8_t *loc;
196     i = len;
197     loc = location;
198     for (; i--;)
199     {
200         *loc++ = OCGetRandomByte();
201     }
202     uint8_t temp;
203     i = len;
204     while(i > 1)
205     {
206         rand_idx = lrand48() % i;
207         temp = location[i - 1];
208         location[i - 1] = location[rand_idx];
209         location[rand_idx] = temp;
210         i--;
211     }
212 }
213
214 uint32_t OCGetRandom()
215 {
216     uint32_t result = 0;
217     OCFillRandomMem((uint8_t*) &result, 4);
218     return result;
219 }
220
221 uint8_t OCGetRandomByte(void)
222 {
223 #ifdef HAVE_SRANDOM
224     return random() & 0x00FF;
225 #else
226     return rand() & 0x00FF;
227 #endif
228 }
229
230 uint16_t OCGetRandomTwoByte(void)
231 {
232 #ifdef HAVE_SRANDOM
233     return random() & 0x00FFFF;
234 #else
235     return rand() & 0x00FFFF;
236 #endif
237 }
238
239
240 uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound)
241 {
242     uint32_t base;
243     uint32_t diff;
244     uint32_t result;
245     if (firstBound > secondBound)
246     {
247         base = secondBound;
248         diff = firstBound - secondBound;
249     }
250     else if (firstBound < secondBound)
251     {
252         base = firstBound;
253         diff = secondBound - firstBound;
254     }
255     else
256     {
257         return secondBound;
258     }
259     result = ((float)OCGetRandom()/((float)(0xFFFFFFFF))*(float)diff) + (float) base;
260     return result;
261 }
262
263 #if defined(__ANDROID__)
264 uint8_t parseUuidChar(char c)
265 {
266     if (isdigit(c))
267     {
268         return c - '0';
269     }
270     else
271     {
272         return c - 'a' + 10;
273     }
274 }
275 uint8_t parseUuidPart(const char *c)
276 {
277     return (parseUuidChar(c[0])<<4) + parseUuidChar(c[1]);
278 }
279 #endif
280
281 OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE])
282 {
283     if (!uuid)
284     {
285         return RAND_UUID_INVALID_PARAM;
286     }
287 #if defined(__ANDROID__)
288     char uuidString[UUID_STRING_SIZE];
289     int8_t ret = OCGenerateUuidString(uuidString);
290
291     if (RAND_UUID_OK == ret)
292     {
293         uuid[ 0] = parseUuidPart(&uuidString[0]);
294         uuid[ 1] = parseUuidPart(&uuidString[2]);
295         uuid[ 2] = parseUuidPart(&uuidString[4]);
296         uuid[ 3] = parseUuidPart(&uuidString[6]);
297
298         uuid[ 4] = parseUuidPart(&uuidString[9]);
299         uuid[ 5] = parseUuidPart(&uuidString[11]);
300
301         uuid[ 6] = parseUuidPart(&uuidString[14]);
302         uuid[ 7] = parseUuidPart(&uuidString[16]);
303
304         uuid[ 8] = parseUuidPart(&uuidString[19]);
305         uuid[ 9] = parseUuidPart(&uuidString[21]);
306
307         uuid[10] = parseUuidPart(&uuidString[24]);
308         uuid[11] = parseUuidPart(&uuidString[26]);
309         uuid[12] = parseUuidPart(&uuidString[28]);
310         uuid[13] = parseUuidPart(&uuidString[30]);
311         uuid[14] = parseUuidPart(&uuidString[32]);
312         uuid[15] = parseUuidPart(&uuidString[34]);
313
314         return RAND_UUID_OK;
315     }
316 #endif
317 #if defined(HAVE_UUID_UUID_H)
318     // note: uuid_t is typedefed as unsigned char[16] on linux/apple
319     uuid_generate(uuid);
320     return RAND_UUID_OK;
321 #else
322     // Fallback for all platforms is filling the array with random data
323     OCFillRandomMem(uuid, UUID_SIZE);
324     return RAND_UUID_OK;
325 #endif
326 }
327
328 OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE])
329 {
330     if (!uuidString)
331     {
332         return RAND_UUID_INVALID_PARAM;
333     }
334 #if defined(__ANDROID__)
335     int32_t fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
336     if (fd > 0)
337     {
338         ssize_t readResult = read(fd, uuidString, UUID_STRING_SIZE - 1);
339         close(fd);
340         if (readResult < 0)
341         {
342             return RAND_UUID_READ_ERROR;
343         }
344         else if (readResult < UUID_STRING_SIZE - 1)
345         {
346             uuidString[0] = '\0';
347             return RAND_UUID_READ_ERROR;
348         }
349
350         uuidString[UUID_STRING_SIZE - 1] = '\0';
351         for (char* p = uuidString; *p; ++p)
352         {
353             *p = tolower(*p);
354         }
355         return RAND_UUID_OK;
356     }
357     else
358     {
359         return RAND_UUID_READ_ERROR;
360     }
361 #elif defined(HAVE_UUID_UUID_H)
362     uint8_t uuid[UUID_SIZE];
363     int8_t ret = OCGenerateUuid(uuid);
364
365     if (ret != 0)
366     {
367         return ret;
368     }
369
370     uuid_unparse_lower(uuid, uuidString);
371     return RAND_UUID_OK;
372
373 #else
374     uint8_t uuid[UUID_SIZE];
375     OCGenerateUuid(uuid);
376
377     return OCConvertUuidToString(uuid, uuidString);
378 #endif
379 }
380
381 OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
382                                          char uuidString[UUID_STRING_SIZE])
383 {
384     if (uuid == NULL || uuidString == NULL)
385     {
386         return RAND_UUID_INVALID_PARAM;
387     }
388
389
390     int ret = snprintf(uuidString, UUID_STRING_SIZE,
391             "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
392             uuid[0], uuid[1], uuid[2], uuid[3],
393             uuid[4], uuid[5], uuid[6], uuid[7],
394             uuid[8], uuid[9], uuid[10], uuid[11],
395             uuid[12], uuid[13], uuid[14], uuid[15]
396             );
397
398     if (ret != UUID_STRING_SIZE - 1)
399     {
400         return RAND_UUID_CONVERT_ERROR;
401     }
402
403     return RAND_UUID_OK;
404 }
405
406 OCRandomUuidResult OCConvertStringToUuid(const char uuidString[UUID_STRING_SIZE],
407                                          uint8_t uuid[UUID_SIZE])
408 {
409     if(NULL == uuidString || NULL == uuid)
410     {
411         return RAND_UUID_INVALID_PARAM;
412     }
413
414     size_t urnIdx = 0;
415     size_t uuidIdx = 0;
416     size_t strUuidLen = 0;
417     char convertedUuid[UUID_SIZE * 2] = {0};
418
419     strUuidLen = strlen(uuidString);
420     if((UUID_STRING_SIZE - 1) == strUuidLen)
421     {
422         for(uuidIdx=0, urnIdx=0; uuidIdx < UUID_SIZE ; uuidIdx++, urnIdx+=2)
423         {
424             if(*(uuidString + urnIdx) == '-')
425             {
426                 urnIdx++;
427             }
428             sscanf(uuidString + urnIdx, "%2hhx", &convertedUuid[uuidIdx]);
429         }
430     }
431     else
432     {
433         return RAND_UUID_CONVERT_ERROR;
434     }
435
436     memcpy(uuid, convertedUuid, UUID_SIZE);
437
438     return RAND_UUID_OK;
439 }
440