Changed ServerInstanceID to UUID
[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(__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;
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(__linux__) || defined(__APPLE__)
166     // note: uuid_t is typedefed as unsigned char[16] on linux/apple
167     uuid_generate(uuid);
168     return RAND_UUID_OK;
169 #elif defined(__ANDROID__)
170     char uuidString[UUID_STRING_SIZE];
171     int8_t ret = OCGenerateUuidString(uuidString);
172
173     if(ret < 0)
174     {
175         return ret;
176     }
177
178     uuid[ 0] = parseUuidPart(&uuidString[0]);
179     uuid[ 1] = parseUuidPart(&uuidString[2]);
180     uuid[ 2] = parseUuidPart(&uuidString[4]);
181     uuid[ 3] = parseUuidPart(&uuidString[6]);
182
183     uuid[ 4] = parseUuidPart(&uuidString[9]);
184     uuid[ 5] = parseUuidPart(&uuidString[11]);
185
186     uuid[ 6] = parseUuidPart(&uuidString[14]);
187     uuid[ 7] = parseUuidPart(&uuidString[16]);
188
189     uuid[ 8] = parseUuidPart(&uuidString[19]);
190     uuid[ 9] = parseUuidPart(&uuidString[21]);
191
192     uuid[10] = parseUuidPart(&uuidString[24]);
193     uuid[11] = parseUuidPart(&uuidString[26]);
194     uuid[12] = parseUuidPart(&uuidString[28]);
195     uuid[13] = parseUuidPart(&uuidString[30]);
196     uuid[14] = parseUuidPart(&uuidString[32]);
197     uuid[15] = parseUuidPart(&uuidString[34]);
198
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(__linux__) || defined(__APPLE__)
214     uint8_t uuid[UUID_SIZE];
215     int8_t ret = OCGenerateUuid(uuid);
216
217     if(ret != 0)
218     {
219         return ret;
220     }
221
222     uuid_unparse_lower(uuid, uuidString);
223     return RAND_UUID_OK;
224
225 #elif defined(__ANDROID__)
226     int32_t fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
227     if(fd > 0)
228     {
229         ssize_t readResult = read(fd, uuidString, UUID_STRING_SIZE - 1);
230         close(fd);
231         if(readResult < 0)
232         {
233             return RAND_UUID_READ_ERROR;
234         }
235         else if(readResult < UUID_STRING_SIZE - 1)
236         {
237             uuidString[0] = '\0';
238             return RAND_UUID_READ_ERROR;
239         }
240
241         uuidString[UUID_STRING_SIZE - 1] = '\0';
242         for(char* p = uuidString; *p; ++p)
243         {
244             *p = tolower(*p);
245         }
246         return RAND_UUID_OK;
247     }
248     else
249     {
250         close(fd);
251         return RAND_UUID_READ_ERROR;
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 }