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