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