0d0f0c1b08f9004ba5afe34eb62f0a43b6deddc0
[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
22 #if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__)
23 #include "fcntl.h"
24 #include "unistd.h"
25 #endif
26 #include "ocrandom.h"
27 #include <stdio.h>
28
29 #if !defined(__ANDROID__) && (defined(__linux__) || defined(__APPLE__))
30 #include <uuid/uuid.h>
31 #endif
32
33 #ifdef ARDUINO
34 #include "Arduino.h"
35
36 uint8_t GetRandomBitRaw() {
37     return analogRead((uint8_t)ANALOG_IN) & 0x1;
38 }
39
40 uint8_t GetRandomBitRaw2() {
41     int a = 0;
42     for(;;) {
43         a = GetRandomBitRaw() | (GetRandomBitRaw()<<1);
44         if (a==1){
45             return 0; // 1 to 0 transition: log a zero bit
46         }
47         if (a==2){
48             return 1;// 0 to 1 transition: log a one bit
49         }
50         // For other cases, try again.
51     }
52 }
53
54 uint8_t GetRandomBit() {
55     int a = 0;
56     for(;;) {
57         a = GetRandomBitRaw2() | (GetRandomBitRaw2()<<1);
58         if (a==1){
59             return 0; // 1 to 0 transition: log a zero bit
60         }
61         if (a==2){
62             return 1;// 0 to 1 transition: log a one bit
63         }
64         // For other cases, try again.
65     }
66 }
67 #endif
68
69 int8_t OCSeedRandom() {
70 #if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__)
71     int32_t fd = open("/dev/urandom", O_RDONLY);
72     if (fd > 0) {
73         uint32_t randomSeed = 0;
74         uint32_t totalRead = 0; //how many integers were read
75         int32_t currentRead = 0;
76         while (totalRead < sizeof(randomSeed)) {
77             currentRead = read(fd, (uint8_t*) &randomSeed + totalRead,
78                     sizeof(randomSeed) - totalRead);
79             if(currentRead > 0){
80                 totalRead += currentRead;
81             }
82         }
83         close(fd);
84         srand(randomSeed);
85         return 0;
86     }
87     close(fd);
88     return -1;
89 #elif defined ARDUINO
90     uint32_t result =0;
91     uint8_t i;
92     for (i=32; i--;){
93         result += result + GetRandomBit();
94     }
95     randomSeed(result);
96     return 0;
97 #endif
98
99 }
100
101 void OCFillRandomMem(uint8_t * location, uint16_t len) {
102     if(!location){
103         return;
104     }
105     for (; len--;){
106         *location++ = OCGetRandomByte();
107     }
108 }
109
110 uint32_t OCGetRandom() {
111     uint32_t result = 0;
112     OCFillRandomMem((uint8_t*) &result, 4);
113     return result;
114 }
115
116 uint8_t OCGetRandomByte(void) {
117 #if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__)
118     return rand() & 0x00FF;
119 #elif defined ARDUINO
120     return random(256) & 0x00FF;
121 #endif
122 }
123
124 uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound){
125     uint32_t base;
126     uint32_t diff;
127     uint32_t result;
128     if(firstBound > secondBound){
129         base = secondBound;
130         diff = firstBound - secondBound;
131     }else if(firstBound < secondBound){
132         base = firstBound;
133         diff = secondBound - firstBound;
134     }else{
135         return secondBound;
136     }
137     result = ((float)OCGetRandom()/((float)(0xFFFFFFFF))*(float)diff) + (float) base;
138     return result;
139 }
140
141 #if defined(__ANDROID__)
142 uint8_t parseUuidChar(char c)
143 {
144     if(isdigit(c))
145     {
146         return c - '0';
147     }
148     else
149     {
150         return c - 'a' + 10;
151     }
152 }
153 uint8_t parseUuidPart(const char *c)
154 {
155     return (parseUuidChar(c[0])<<4) + parseUuidChar(c[1]);
156 }
157 #endif
158
159 OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE])
160 {
161     if(!uuid)
162     {
163         return RAND_UUID_INVALID_PARAM;
164     }
165 #if defined(__ANDROID__)
166     char uuidString[UUID_STRING_SIZE];
167     int8_t ret = OCGenerateUuidString(uuidString);
168
169     if(ret < 0)
170     {
171         return ret;
172     }
173
174     uuid[ 0] = parseUuidPart(&uuidString[0]);
175     uuid[ 1] = parseUuidPart(&uuidString[2]);
176     uuid[ 2] = parseUuidPart(&uuidString[4]);
177     uuid[ 3] = parseUuidPart(&uuidString[6]);
178
179     uuid[ 4] = parseUuidPart(&uuidString[9]);
180     uuid[ 5] = parseUuidPart(&uuidString[11]);
181
182     uuid[ 6] = parseUuidPart(&uuidString[14]);
183     uuid[ 7] = parseUuidPart(&uuidString[16]);
184
185     uuid[ 8] = parseUuidPart(&uuidString[19]);
186     uuid[ 9] = parseUuidPart(&uuidString[21]);
187
188     uuid[10] = parseUuidPart(&uuidString[24]);
189     uuid[11] = parseUuidPart(&uuidString[26]);
190     uuid[12] = parseUuidPart(&uuidString[28]);
191     uuid[13] = parseUuidPart(&uuidString[30]);
192     uuid[14] = parseUuidPart(&uuidString[32]);
193     uuid[15] = parseUuidPart(&uuidString[34]);
194
195     return RAND_UUID_OK;
196 #elif !defined(__ANDROID__) && (defined(__linux__) || defined(__APPLE__))
197     // note: uuid_t is typedefed as unsigned char[16] on linux/apple
198     uuid_generate(uuid);
199     return RAND_UUID_OK;
200 #else
201     // Fallback for all platforms is filling the array with random data
202     OCFillRandomMem(uuid, UUID_SIZE);
203     return RAND_UUID_OK;
204 #endif
205 }
206
207 OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE])
208 {
209     if(!uuidString)
210     {
211         return RAND_UUID_INVALID_PARAM;
212     }
213 #if defined(__ANDROID__)
214     int32_t fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
215     if(fd > 0)
216     {
217         ssize_t readResult = read(fd, uuidString, UUID_STRING_SIZE - 1);
218         close(fd);
219         if(readResult < 0)
220         {
221             return RAND_UUID_READ_ERROR;
222         }
223         else if(readResult < UUID_STRING_SIZE - 1)
224         {
225             uuidString[0] = '\0';
226             return RAND_UUID_READ_ERROR;
227         }
228
229         uuidString[UUID_STRING_SIZE - 1] = '\0';
230         for(char* p = uuidString; *p; ++p)
231         {
232             *p = tolower(*p);
233         }
234         return RAND_UUID_OK;
235     }
236     else
237     {
238         close(fd);
239         return RAND_UUID_READ_ERROR;
240     }
241 #elif !defined(__ANDROID__) && (defined(__linux__) || defined(__APPLE__))
242     uint8_t uuid[UUID_SIZE];
243     int8_t ret = OCGenerateUuid(uuid);
244
245     if(ret != 0)
246     {
247         return ret;
248     }
249
250     uuid_unparse_lower(uuid, uuidString);
251     return RAND_UUID_OK;
252
253 #else
254     uint8_t uuid[UUID_SIZE];
255     OCGenerateUuid(uuid);
256
257     return OCConvertUuidToString(uuid, uuidString);
258 #endif
259 }
260
261 OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
262                                          char uuidString[UUID_STRING_SIZE])
263 {
264     if (uuid == NULL || uuidString == NULL)
265     {
266         return RAND_UUID_INVALID_PARAM;
267     }
268
269
270     int ret = snprintf(uuidString, UUID_STRING_SIZE,
271             "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
272             uuid[0], uuid[1], uuid[2], uuid[3],
273             uuid[4], uuid[5], uuid[6], uuid[7],
274             uuid[8], uuid[9], uuid[10], uuid[11],
275             uuid[12], uuid[13], uuid[14], uuid[15]
276             );
277
278     if (ret != UUID_STRING_SIZE - 1)
279     {
280         return RAND_UUID_CONVERT_ERROR;
281     }
282
283     return RAND_UUID_OK;
284 }