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