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