1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "commonlibrary/ets_utils/js_util_module/util/js_uuid.h"
17 
18 #include <map>
19 #include "securec.h"
20 #include "tools/log.h"
21 
22 #include "napi/native_api.h"
23 #include "napi/native_node_api.h"
24 
25 namespace OHOS::Util {
26 static thread_local unsigned char g_uuidCache[MAX_CACHE_MASK * UUID_SIZE];
27 static thread_local uint32_t uuidCachedIndex = 0;
28 
CharToHex(char in)29 unsigned char CharToHex(char in)
30 {
31     unsigned char res = 0;  // 0: initialization
32     static const std::map<char, unsigned char> hexMap = {
33         {'0', HEX_ZERO_FLG},
34         {'1', HEX_ONE_FLG},
35         {'2', HEX_TWO_FLG},
36         {'3', HEX_THREE_FLG},
37         {'4', HEX_FOUR_FLG},
38         {'5', HEX_FIVE_FLG},
39         {'6', HEX_SIX_FLG},
40         {'7', HEX_SEVEN_FLG},
41         {'8', HEX_EIGHT_FLG},
42         {'9', HEX_NINE_FLG},
43         {'a', HEX_TEN_FLG},
44         {'b', HEX_ELEVEN_FLG},
45         {'c', HEX_TWELVE_FLG},
46         {'d', HEX_THIRTEEN_FLG},
47         {'e', HEX_FOURTEEN_FLG},
48         {'f', HEX_FIFTEEN_FLG},
49         {'A', HEX_TEN_FLG},
50         {'B', HEX_ELEVEN_FLG},
51         {'C', HEX_TWELVE_FLG},
52         {'D', HEX_THIRTEEN_FLG},
53         {'E', HEX_FOURTEEN_FLG},
54         {'F', HEX_FIFTEEN_FLG}
55     };
56 
57     auto it = hexMap.find(in);
58     if (it != hexMap.end()) {
59         res = it->second;
60     } else {
61         res = HEX_ZERO_FLG;
62     }
63     return res;
64 }
65 
HexToChar(unsigned char in)66 unsigned char HexToChar(unsigned char in)
67 {
68     unsigned char res = '0';
69     switch (in) {
70         case HEX_ZERO_FLG: res = '0'; break;
71         case HEX_ONE_FLG: res = '1'; break;
72         case HEX_TWO_FLG: res = '2'; break;
73         case HEX_THREE_FLG: res = '3'; break;
74         case HEX_FOUR_FLG: res = '4'; break;
75         case HEX_FIVE_FLG: res = '5'; break;
76         case HEX_SIX_FLG: res = '6'; break;
77         case HEX_SEVEN_FLG: res = '7'; break;
78         case HEX_EIGHT_FLG: res = '8'; break;
79         case HEX_NINE_FLG: res = '9'; break;
80         case HEX_TEN_FLG: res = 'a'; break;
81         case HEX_ELEVEN_FLG: res = 'b'; break;
82         case HEX_TWELVE_FLG: res = 'c'; break;
83         case HEX_THIRTEEN_FLG: res = 'd'; break;
84         case HEX_FOURTEEN_FLG: res = 'e'; break;
85         case HEX_FIFTEEN_FLG: res = 'f'; break;
86         default : res = 'x';
87     }
88     return res;
89 }
90 
ConvertBits(std::string &input)91 unsigned char ConvertBits(std::string &input)
92 {
93     unsigned char temp = 0; // 0: initialization
94     if (input[0] == '-') {
95         input.erase(0, 1);
96     }
97     temp = CharToHex(input[0]);
98     temp *= HEX_SIXTEEN_FLG;
99     input.erase(0, 1);
100     temp += CharToHex(input[0]);
101     input.erase(0, 1);
102     return temp;
103 }
104 
GenerateUUID(unsigned char *data, int32_t size)105 bool GenerateUUID(unsigned char *data, int32_t size)
106 {
107     RAND_priv_bytes(data, size);
108     return true;
109 }
110 
ProcessUUID(unsigned char *data)111 void ProcessUUID(unsigned char *data)
112 {
113     data[HEX_SIX_FLG] = (data[HEX_SIX_FLG] & 0x0F) | 0x40; // 0x0F,0x40 Operate the mark
114     int m = 0x8;    // Upper of numerical range
115     int n = 0xb;    // down of numerical range
116     int r = static_cast<int>(data[HEX_EIGHT_FLG]);
117     unsigned char num = static_cast<unsigned char>(r % (n - m + 1) + m);
118     data[HEX_EIGHT_FLG] = (data[HEX_EIGHT_FLG] & 0x0F) | (num << 4);  // 0x0F,4 Operate the mark
119 }
120 
GetBufferedUUID(napi_env env, UUID &uuid)121 bool GetBufferedUUID(napi_env env, UUID &uuid)
122 {
123     if (uuidCachedIndex == 0) {
124         if (!GenerateUUID(g_uuidCache, MAX_CACHE_MASK * UUID_SIZE)) {
125             napi_throw_error(env, "-1", "uuid generate failed");
126             return false;
127         }
128     }
129     if (memcpy_s(uuid.elements, UUID_SIZE, g_uuidCache + uuidCachedIndex * UUID_SIZE, UUID_SIZE) != EOK) {
130         napi_throw_error(env, "-1", "uuid generate failed");
131         return false;
132     }
133     ProcessUUID(uuid.elements);
134     uuidCachedIndex = (uuidCachedIndex + 1) % MAX_CACHE_MASK;
135     return true;
136 }
137 
GetUnBufferedUUID(napi_env env, UUID &uuid)138 bool GetUnBufferedUUID(napi_env env, UUID &uuid)
139 {
140     if (!GenerateUUID(uuid.elements, UUID_SIZE)) {
141         napi_throw_error(env, "-1", "uuid generate failed");
142         return false;
143     }
144     ProcessUUID(uuid.elements);
145     return true;
146 }
147 
GetUUID(napi_env env, bool entropyCache, UUID &uuid)148 bool GetUUID(napi_env env, bool entropyCache, UUID &uuid)
149 {
150     return entropyCache ? GetBufferedUUID(env, uuid) : GetUnBufferedUUID(env, uuid);
151 }
152 
GetStringUUID(napi_env env, bool entropyCache)153 std::string GetStringUUID(napi_env env, bool entropyCache)
154 {
155     UUID uuid;
156     std::string uuidString = "";
157     if (!GetUUID(env, entropyCache, uuid)) {
158         uuidString = '0';
159     } else {
160         uuidString = GetFormatUUID(uuid);
161     }
162     return uuidString;
163 }
164 
GetFormatUUID(const UUID &uuid)165 std::string GetFormatUUID(const UUID &uuid)
166 {
167     std::string format = "";
168     for (size_t i = 0; i < sizeof(uuid.elements); i++) {
169         unsigned char value = uuid.elements[i];
170         if (i >= HEX_FOUR_FLG && i % 2 == 0 && i <= HEX_TEN_FLG) {  // 2: step value
171             format += "-";
172         }
173         format += HexToChar(value >> HEX_FOUR_FLG);
174         unsigned char high = value & 0xF0;  // Operate the mark
175         if (high == 0) {
176             format += HexToChar(value);
177         } else {
178             format += HexToChar(value % (value & high));
179         }
180     }
181     return format;
182 }
183 
GetBinaryUUID(napi_env env, bool entropyCache)184 napi_value GetBinaryUUID(napi_env env, bool entropyCache)
185 {
186     UUID uuid;
187     if (!GetUUID(env, entropyCache, uuid)) {
188         return nullptr;
189     }
190     void *data = nullptr;
191     napi_value arrayBuffer = nullptr;
192     size_t bufferSize = sizeof(uuid.elements);
193     napi_create_arraybuffer(env, bufferSize, &data, &arrayBuffer);
194     if (memcpy_s(data, bufferSize, uuid.elements, bufferSize) != EOK) {
195         HILOG_ERROR("get uuid memcpy_s failed");
196         return nullptr;
197     }
198     napi_value result = nullptr;
199     napi_create_typedarray(env, napi_uint8_array, bufferSize, arrayBuffer, 0, &result);
200     return result;
201 }
202 
DoParseUUID(napi_env env, napi_value src)203 napi_value DoParseUUID(napi_env env, napi_value src)
204 {
205     size_t outLen = 16; // 16: the length of UUID
206     std::string buffer = "";
207     size_t bufferSize = 0;  // 0: initialization
208     napi_status status = napi_ok;
209     status = napi_get_value_string_utf8(env, src, nullptr, 0, &bufferSize);
210     if (status != napi_ok) {
211         HILOG_ERROR("can not get src size");
212         return nullptr;
213     }
214     buffer.resize(bufferSize);
215     status = napi_get_value_string_utf8(env, src, buffer.data(), bufferSize + 1, &bufferSize);
216     if (status != napi_ok) {
217         HILOG_ERROR("can not get src value");
218         return nullptr;
219     }
220     void *data = nullptr;
221     napi_value arrayBuffer = nullptr;
222     napi_create_arraybuffer(env, outLen, &data, &arrayBuffer);
223     unsigned char *count = static_cast<unsigned char*>(data);
224     for (size_t i = 0; !buffer.empty() && i < outLen; i++) {
225         *count = ConvertBits(buffer);
226         count++;
227     }
228     napi_value result = nullptr;
229     napi_create_typedarray(env, napi_uint8_array, outLen, arrayBuffer, 0, &result);
230     return result;
231 }
232 }
233