Merge remote-tracking branch 'origin/routing-manager'
[platform/upstream/iotivity.git] / resource / csdk / 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 #if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__)
34 #include "fcntl.h"
35 #include "unistd.h"
36 #include <stdlib.h>
37 #include <sys/time.h>
38 #include <time.h>
39 #if defined(__ANDROID__)
40 #include <linux/time.h>
41 #endif
42 #endif
43 #include "ocrandom.h"
44 #include <stdio.h>
45
46 #if !defined(__ANDROID__) && (defined(__linux__) || defined(__APPLE__))
47 #include <uuid/uuid.h>
48 #endif
49
50 #ifdef ARDUINO
51 #include "Arduino.h"
52
53 uint8_t GetRandomBitRaw()
54 {
55     return analogRead((uint8_t)ANALOG_IN) & 0x1;
56 }
57
58 uint8_t GetRandomBitRaw2()
59 {
60     int a = 0;
61     for (;;)
62     {
63         a = GetRandomBitRaw() | (GetRandomBitRaw()<<1);
64         if (a==1)
65         {
66             return 0; // 1 to 0 transition: log a zero bit
67         }
68         if (a==2)
69         {
70             return 1;// 0 to 1 transition: log a one bit
71         }
72         // For other cases, try again.
73     }
74 }
75
76 uint8_t GetRandomBit()
77 {
78     int a = 0;
79     for (;;)
80     {
81         a = GetRandomBitRaw2() | (GetRandomBitRaw2()<<1);
82         if (a==1)
83         {
84             return 0; // 1 to 0 transition: log a zero bit
85         }
86         if (a==2)
87         {
88             return 1;// 0 to 1 transition: log a one bit
89         }
90         // For other cases, try again.
91     }
92 }
93 #endif
94
95 int8_t OCSeedRandom()
96 {
97 #if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__) || defined(__TIZEN__)
98     // Get current time to Seed.
99     uint64_t currentTime = 0;
100 #ifdef __ANDROID__
101     struct timespec getTs;
102     clock_gettime(CLOCK_MONOTONIC, &getTs);
103     currentTime = (getTs.tv_sec * (uint64_t)1000000000 + getTs.tv_nsec)/1000;
104 #elif  _POSIX_TIMERS > 0
105     struct timespec ts;
106     clock_gettime(CLOCK_MONOTONIC, &ts);
107     currentTime = ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
108 #else
109     struct timeval tv;
110     gettimeofday(&tv, NULL);
111     currentTime = tv.tv_sec * 1000000 + tv.tv_usec;
112 #endif
113
114     int32_t fd = open("/dev/urandom", O_RDONLY);
115     if (fd >= 0)
116     {
117         uint32_t randomSeed = 0;
118         uint32_t totalRead = 0; //how many integers were read
119         int32_t currentRead = 0;
120         while (totalRead < sizeof(randomSeed))
121         {
122             currentRead = read(fd, (uint8_t*) &randomSeed + totalRead,
123                     sizeof(randomSeed) - totalRead);
124             if (currentRead > 0)
125             {
126                 totalRead += currentRead;
127             }
128         }
129         close(fd);
130         srand(randomSeed | currentTime);
131     }
132     else
133     {
134         // Do time based seed when problem in accessing "/dev/urandom"
135         srand(currentTime);
136     }
137
138     return 0;
139 #elif defined ARDUINO
140     uint32_t result =0;
141     uint8_t i;
142     for (i=32; i--;)
143     {
144         result += result + GetRandomBit();
145     }
146     randomSeed(result);
147     return 0;
148 #endif
149
150 }
151
152 void OCFillRandomMem(uint8_t * location, uint16_t len)
153 {
154     if (!location)
155     {
156         return;
157     }
158     for (; len--;)
159     {
160         *location++ = OCGetRandomByte();
161     }
162 }
163
164 uint32_t OCGetRandom()
165 {
166     uint32_t result = 0;
167     OCFillRandomMem((uint8_t*) &result, 4);
168     return result;
169 }
170
171 uint8_t OCGetRandomByte(void)
172 {
173 #if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__)
174     return rand() & 0x00FF;
175 #elif defined ARDUINO
176     return random(256) & 0x00FF;
177 #endif
178 }
179
180 uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound)
181 {
182     uint32_t base;
183     uint32_t diff;
184     uint32_t result;
185     if (firstBound > secondBound)
186     {
187         base = secondBound;
188         diff = firstBound - secondBound;
189     }
190     else if (firstBound < secondBound)
191     {
192         base = firstBound;
193         diff = secondBound - firstBound;
194     }
195     else
196     {
197         return secondBound;
198     }
199     result = ((float)OCGetRandom()/((float)(0xFFFFFFFF))*(float)diff) + (float) base;
200     return result;
201 }
202
203 #if defined(__ANDROID__)
204 uint8_t parseUuidChar(char c)
205 {
206     if (isdigit(c))
207     {
208         return c - '0';
209     }
210     else
211     {
212         return c - 'a' + 10;
213     }
214 }
215 uint8_t parseUuidPart(const char *c)
216 {
217     return (parseUuidChar(c[0])<<4) + parseUuidChar(c[1]);
218 }
219 #endif
220
221 OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE])
222 {
223     if (!uuid)
224     {
225         return RAND_UUID_INVALID_PARAM;
226     }
227 #if defined(__ANDROID__)
228     char uuidString[UUID_STRING_SIZE];
229     int8_t ret = OCGenerateUuidString(uuidString);
230
231     if (ret < 0)
232     {
233         return ret;
234     }
235
236     uuid[ 0] = parseUuidPart(&uuidString[0]);
237     uuid[ 1] = parseUuidPart(&uuidString[2]);
238     uuid[ 2] = parseUuidPart(&uuidString[4]);
239     uuid[ 3] = parseUuidPart(&uuidString[6]);
240
241     uuid[ 4] = parseUuidPart(&uuidString[9]);
242     uuid[ 5] = parseUuidPart(&uuidString[11]);
243
244     uuid[ 6] = parseUuidPart(&uuidString[14]);
245     uuid[ 7] = parseUuidPart(&uuidString[16]);
246
247     uuid[ 8] = parseUuidPart(&uuidString[19]);
248     uuid[ 9] = parseUuidPart(&uuidString[21]);
249
250     uuid[10] = parseUuidPart(&uuidString[24]);
251     uuid[11] = parseUuidPart(&uuidString[26]);
252     uuid[12] = parseUuidPart(&uuidString[28]);
253     uuid[13] = parseUuidPart(&uuidString[30]);
254     uuid[14] = parseUuidPart(&uuidString[32]);
255     uuid[15] = parseUuidPart(&uuidString[34]);
256
257     return RAND_UUID_OK;
258 #elif !defined(__ANDROID__) && (defined(__linux__) || defined(__APPLE__))
259     // note: uuid_t is typedefed as unsigned char[16] on linux/apple
260     uuid_generate(uuid);
261     return RAND_UUID_OK;
262 #else
263     // Fallback for all platforms is filling the array with random data
264     OCFillRandomMem(uuid, UUID_SIZE);
265     return RAND_UUID_OK;
266 #endif
267 }
268
269 OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE])
270 {
271     if (!uuidString)
272     {
273         return RAND_UUID_INVALID_PARAM;
274     }
275 #if defined(__ANDROID__)
276     int32_t fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
277     if (fd > 0)
278     {
279         ssize_t readResult = read(fd, uuidString, UUID_STRING_SIZE - 1);
280         close(fd);
281         if (readResult < 0)
282         {
283             return RAND_UUID_READ_ERROR;
284         }
285         else if (readResult < UUID_STRING_SIZE - 1)
286         {
287             uuidString[0] = '\0';
288             return RAND_UUID_READ_ERROR;
289         }
290
291         uuidString[UUID_STRING_SIZE - 1] = '\0';
292         for (char* p = uuidString; *p; ++p)
293         {
294             *p = tolower(*p);
295         }
296         return RAND_UUID_OK;
297     }
298     else
299     {
300         close(fd);
301         return RAND_UUID_READ_ERROR;
302     }
303 #elif !defined(__ANDROID__) && (defined(__linux__) || defined(__APPLE__))
304     uint8_t uuid[UUID_SIZE];
305     int8_t ret = OCGenerateUuid(uuid);
306
307     if (ret != 0)
308     {
309         return ret;
310     }
311
312     uuid_unparse_lower(uuid, uuidString);
313     return RAND_UUID_OK;
314
315 #else
316     uint8_t uuid[UUID_SIZE];
317     OCGenerateUuid(uuid);
318
319     return OCConvertUuidToString(uuid, uuidString);
320 #endif
321 }
322
323 OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
324                                          char uuidString[UUID_STRING_SIZE])
325 {
326     if (uuid == NULL || uuidString == NULL)
327     {
328         return RAND_UUID_INVALID_PARAM;
329     }
330
331
332     int ret = snprintf(uuidString, UUID_STRING_SIZE,
333             "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
334             uuid[0], uuid[1], uuid[2], uuid[3],
335             uuid[4], uuid[5], uuid[6], uuid[7],
336             uuid[8], uuid[9], uuid[10], uuid[11],
337             uuid[12], uuid[13], uuid[14], uuid[15]
338             );
339
340     if (ret != UUID_STRING_SIZE - 1)
341     {
342         return RAND_UUID_CONVERT_ERROR;
343     }
344
345     return RAND_UUID_OK;
346 }