1 /*
2 * Copyright (c) 2023-2024 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 "anonymizer.h"
17
18 #include <locale.h>
19 #include <securec.h>
20 #include <stdbool.h>
21 #include <stdint.h>
22 #include <wchar.h>
23
24 #include "comm_log.h"
25 #include "softbus_error_code.h"
26
27 #define COMMON_STRING_MAX_LEN 128
28 #define WIDE_CHAR_MAX_LEN 8
29
30 typedef struct {
31 bool (*Matcher)(const char *, uint32_t);
32 int32_t (*Anonymizer)(const char *, uint32_t, char **);
33 } AnonymizeHandler;
34
35 typedef struct {
36 uint32_t plainPrefixPos;
37 uint32_t plainSuffixPos;
38 uint32_t len;
39 } AnonymizeParam;
40
41 static const char SYMBOL_ANONYMIZE = '*';
42 static const char SYMBOL_COLON = ':';
43 static const char SYMBOL_DASH = '-';
44 static const char SYMBOL_DOT = '.';
45
InRange(char chr,char left,char right)46 static inline bool InRange(char chr, char left, char right)
47 {
48 return left <= chr && chr <= right;
49 }
50
IsNum(char chr)51 static inline bool IsNum(char chr)
52 {
53 return InRange(chr, '0', '9');
54 }
55
IsHex(char chr)56 static inline bool IsHex(char chr)
57 {
58 return IsNum(chr) || InRange(chr, 'A', 'F') || InRange(chr, 'a', 'f');
59 }
60
IsAlphabet(char chr)61 static inline bool IsAlphabet(char chr)
62 {
63 return InRange(chr, 'A', 'Z') || InRange(chr, 'a', 'z');
64 }
65
IsDot(char chr)66 static inline bool IsDot(char chr)
67 {
68 return chr == SYMBOL_DOT;
69 }
70
IsColon(char chr)71 static inline bool IsColon(char chr)
72 {
73 return chr == SYMBOL_COLON;
74 }
75
IsDash(char chr)76 static inline bool IsDash(char chr)
77 {
78 return chr == SYMBOL_DASH;
79 }
80
FindChar(char chr,const char * str,uint32_t len,uint32_t startPos)81 static inline int32_t FindChar(char chr, const char *str, uint32_t len, uint32_t startPos)
82 {
83 for (uint32_t i = startPos; i < len; ++i) {
84 if (str[i] == chr) {
85 return (int32_t)i;
86 }
87 }
88 return -1; // not find
89 }
90
IsValid(const char * str,const uint32_t * positions,uint32_t positionNum,bool (* isValidFunc)(char))91 static bool IsValid(const char *str, const uint32_t *positions, uint32_t positionNum, bool(*isValidFunc)(char))
92 {
93 for (uint32_t i = 0; i < positionNum; ++i) {
94 if (!isValidFunc(str[positions[i]])) {
95 return false;
96 }
97 }
98 return true;
99 }
100
MatchEmpty(const char * str,uint32_t len)101 static bool MatchEmpty(const char *str, uint32_t len)
102 {
103 (void)str;
104 return len == 0;
105 }
106
MatchIpAddr(const char * str,uint32_t len)107 static bool MatchIpAddr(const char *str, uint32_t len)
108 {
109 static const uint32_t DOT_NUM_MAX = 3;
110 static const int32_t NUM_LEN_MAX = 3;
111 static const int32_t NUM_LEN_MIN = 1;
112 static const uint32_t IP_ADDR_MAX_LEN = 15;
113
114 if (len > IP_ADDR_MAX_LEN) {
115 return false;
116 }
117
118 for (uint32_t i = 0; i < len; ++i) {
119 if (!IsNum(str[i]) && !IsDot(str[i])) {
120 return false;
121 }
122 }
123
124 int32_t numLen = 0;
125 int32_t posPrevDot = -1;
126 int32_t posNextDot = -1;
127 for (uint32_t dotNum = 0; dotNum < DOT_NUM_MAX; ++dotNum) {
128 posNextDot = FindChar(SYMBOL_DOT, str, len, posPrevDot + 1);
129 numLen = posNextDot - posPrevDot - 1;
130 if (numLen < NUM_LEN_MIN || numLen > NUM_LEN_MAX) {
131 return false;
132 }
133 posPrevDot = posNextDot;
134 }
135 numLen = (int32_t)len - posPrevDot - 1;
136 if (numLen < NUM_LEN_MIN || numLen > NUM_LEN_MAX) {
137 return false;
138 }
139
140 return true;
141 }
142
MatchMacAddr(const char * str,uint32_t len)143 static bool MatchMacAddr(const char *str, uint32_t len)
144 {
145 static const uint32_t MAC_ADDR_LEN = 17;
146 static const uint32_t DELIMETER_POSITIONS[] = {2, 5, 8, 11, 14};
147 static const uint32_t HEX_POSITIONS[] = {0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16};
148
149 if (len != MAC_ADDR_LEN) {
150 return false;
151 }
152
153 return IsValid(str, HEX_POSITIONS, sizeof(HEX_POSITIONS) / sizeof(HEX_POSITIONS[0]), IsHex) &&
154 (IsValid(str, DELIMETER_POSITIONS, sizeof(DELIMETER_POSITIONS) / sizeof(DELIMETER_POSITIONS[0]), IsDash) ||
155 IsValid(str, DELIMETER_POSITIONS, sizeof(DELIMETER_POSITIONS) / sizeof(DELIMETER_POSITIONS[0]), IsColon));
156 }
157
MatchUdidStr(const char * str,uint32_t len)158 static bool MatchUdidStr(const char *str, uint32_t len)
159 {
160 const uint32_t UDID_LEN = 64;
161
162 if (len != UDID_LEN) {
163 return false;
164 }
165 for (uint32_t i = 0; i < len; ++i) {
166 if (!IsNum(str[i]) && !IsAlphabet(str[i])) {
167 return false;
168 }
169 }
170 return true;
171 }
172
MatchCommString(const char * str,uint32_t len)173 static bool MatchCommString(const char *str, uint32_t len)
174 {
175 return len <= COMMON_STRING_MAX_LEN;
176 }
177
MallocStr(uint32_t len)178 static char *MallocStr(uint32_t len)
179 {
180 char *str = (char *)malloc(sizeof(char) * (len + 1));
181 if (str != NULL) {
182 str[len] = '\0';
183 }
184 return str;
185 }
186
CopyStr(const char * str,char ** copy)187 static int32_t CopyStr(const char *str, char **copy)
188 {
189 uint32_t len = strlen(str);
190 *copy = MallocStr(len);
191 COMM_CHECK_AND_RETURN_RET_LOGE(*copy != NULL, SOFTBUS_MALLOC_ERR, COMM_DFX, "malloc failed");
192
193 errno_t ret = memcpy_s(*copy, len, str, len);
194 COMM_CHECK_AND_RETURN_RET_LOGE(ret == EOK, SOFTBUS_STRCPY_ERR, COMM_DFX, "memcpy failed");
195
196 return SOFTBUS_OK;
197 }
198
AnonymizeIpAddr(const char * str,uint32_t len,char ** anonymized)199 static int32_t AnonymizeIpAddr(const char *str, uint32_t len, char **anonymized)
200 {
201 int32_t ret = CopyStr(str, anonymized);
202 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_DFX, "copy ip addr failed");
203
204 for (uint32_t i = len - 1; i >= 0; --i) {
205 if (IsDot((*anonymized)[i])) {
206 break;
207 }
208 (*anonymized)[i] = SYMBOL_ANONYMIZE;
209 }
210 return SOFTBUS_OK;
211 }
212
AnonymizeMacAddr(const char * str,uint32_t len,char ** anonymized)213 static int32_t AnonymizeMacAddr(const char *str, uint32_t len, char **anonymized)
214 {
215 static const uint32_t ANONYMIZE_POSITIONS[] = {9, 10, 12, 13};
216
217 int32_t ret = CopyStr(str, anonymized);
218 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_DFX, "copy mac addr failed");
219
220 for (uint32_t i = 0; i < sizeof(ANONYMIZE_POSITIONS) / sizeof(ANONYMIZE_POSITIONS[0]); ++i) {
221 (*anonymized)[ANONYMIZE_POSITIONS[i]] = SYMBOL_ANONYMIZE;
222 }
223 return SOFTBUS_OK;
224 }
225
AnonymizeUdidStr(const char * str,uint32_t len,char ** anonymized)226 static int32_t AnonymizeUdidStr(const char *str, uint32_t len, char **anonymized)
227 {
228 static const uint32_t ANONYMIZE_UDID_LEN = 12;
229 static const uint32_t ANONYMIZE_POSITIONS[] = {5, 6};
230 static const uint32_t UNANONYMIZE_UDID_LEN = 5;
231 static const uint32_t UNANONYMIZE_SUFFIX_POS = ANONYMIZE_UDID_LEN - UNANONYMIZE_UDID_LEN;
232 static const uint32_t UNANONYMIZE_SUFFIX_OFFSET = 64 - UNANONYMIZE_UDID_LEN;
233
234 (void)len;
235 *anonymized = MallocStr(ANONYMIZE_UDID_LEN);
236 COMM_CHECK_AND_RETURN_RET_LOGE(*anonymized != NULL, SOFTBUS_MALLOC_ERR, COMM_DFX, "malloc failed");
237
238 errno_t ret = memcpy_s(*anonymized, ANONYMIZE_UDID_LEN, str, UNANONYMIZE_UDID_LEN);
239 COMM_CHECK_AND_RETURN_RET_LOGE(ret == EOK, SOFTBUS_STRCPY_ERR, COMM_DFX, "memcpy failed");
240 ret = memcpy_s(*anonymized + UNANONYMIZE_SUFFIX_POS, ANONYMIZE_UDID_LEN - UNANONYMIZE_SUFFIX_POS,
241 str + UNANONYMIZE_SUFFIX_OFFSET, UNANONYMIZE_UDID_LEN);
242 COMM_CHECK_AND_RETURN_RET_LOGE(ret == EOK, SOFTBUS_STRCPY_ERR, COMM_DFX, "memcpy failed");
243
244 for (uint32_t i = 0; i < sizeof(ANONYMIZE_POSITIONS) / sizeof(ANONYMIZE_POSITIONS[0]); ++i) {
245 (*anonymized)[ANONYMIZE_POSITIONS[i]] = SYMBOL_ANONYMIZE;
246 }
247 return SOFTBUS_OK;
248 }
249
SetLocale(char ** localeBefore)250 static int32_t SetLocale(char **localeBefore)
251 {
252 *localeBefore = setlocale(LC_CTYPE, NULL);
253 if (*localeBefore == NULL) {
254 COMM_LOGW(COMM_DFX, "get locale failed");
255 }
256
257 char *localeAfter = setlocale(LC_CTYPE, "C.UTF-8");
258 return (localeAfter != NULL) ? SOFTBUS_OK : SOFTBUS_LOCALE_ERR;
259 }
260
RestoreLocale(const char * localeBefore)261 static void RestoreLocale(const char *localeBefore)
262 {
263 if (setlocale(LC_CTYPE, localeBefore) == NULL) {
264 COMM_LOGW(COMM_DFX, "restore locale failed");
265 }
266 }
267
AnonymizeWideStrToByteStr(const wchar_t * wideStr,uint32_t wideStrLen,const AnonymizeParam * param,char ** anonymized)268 static int32_t AnonymizeWideStrToByteStr(const wchar_t *wideStr, uint32_t wideStrLen, const AnonymizeParam *param,
269 char **anonymized)
270 {
271 COMM_CHECK_AND_RETURN_RET_LOGE(wideStrLen != 0, SOFTBUS_INVALID_PARAM, COMM_DFX, "wideStrLen is 0");
272 COMM_CHECK_AND_RETURN_RET_LOGE(param->len != 0, SOFTBUS_INVALID_PARAM, COMM_DFX, "len is 0");
273 uint32_t len = param->len;
274 *anonymized = MallocStr(len);
275 COMM_CHECK_AND_RETURN_RET_LOGE(*anonymized != NULL, SOFTBUS_MALLOC_ERR, COMM_DFX, "malloc failed");
276
277 char multiByteChar[WIDE_CHAR_MAX_LEN] = {0};
278 uint32_t multiByteStrIndex = 0;
279 uint32_t wideStrIndex = 0;
280 errno_t ret = EOK;
281 for (; wideStrIndex < param->plainPrefixPos && multiByteStrIndex < len; ++wideStrIndex) {
282 int32_t multiByteCharLen = wctomb(multiByteChar, wideStr[wideStrIndex]);
283 COMM_CHECK_AND_RETURN_RET_LOGE(multiByteCharLen > 0, SOFTBUS_WIDECHAR_ERR, COMM_DFX, "convert prefix failed");
284 ret = memcpy_s(*anonymized + multiByteStrIndex, len - multiByteStrIndex, multiByteChar, multiByteCharLen);
285 COMM_CHECK_AND_RETURN_RET_LOGE(ret == EOK, SOFTBUS_MEM_ERR, COMM_DFX, "copy prefix failed");
286 multiByteStrIndex += (uint32_t)multiByteCharLen;
287 }
288
289 for (; wideStrIndex < param->plainSuffixPos && multiByteStrIndex < len; ++wideStrIndex) {
290 (*anonymized)[multiByteStrIndex++] = SYMBOL_ANONYMIZE;
291 }
292
293 for (; wideStrIndex < wideStrLen && multiByteStrIndex < len; ++wideStrIndex) {
294 int32_t multiByteCharLen = wctomb(multiByteChar, wideStr[wideStrIndex]);
295 COMM_CHECK_AND_RETURN_RET_LOGE(multiByteCharLen > 0, SOFTBUS_WIDECHAR_ERR, COMM_DFX, "convert suffix failed");
296 ret = memcpy_s(*anonymized + multiByteStrIndex, len - multiByteStrIndex, multiByteChar, multiByteCharLen);
297 COMM_CHECK_AND_RETURN_RET_LOGE(ret == EOK, SOFTBUS_MEM_ERR, COMM_DFX, "copy prefix failed");
298 multiByteStrIndex += (uint32_t)multiByteCharLen;
299 }
300
301 uint32_t endPos = multiByteStrIndex < len ? multiByteStrIndex : len;
302 (*anonymized)[endPos] = '\0';
303 return SOFTBUS_OK;
304 }
305
AnonymizeCommString(const char * str,uint32_t len,char ** anonymized)306 static int32_t AnonymizeCommString(const char *str, uint32_t len, char **anonymized)
307 {
308 static const uint32_t ANONYMIZE_LEN_RATIO = 2; // anonymize half str
309 static const uint32_t ANONYMIZE_POS_RATIO = 4; // start from 1/4 pos
310
311 char *localeBefore = NULL;
312 int32_t ret = SetLocale(&localeBefore);
313 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_DFX, "get locale failed");
314
315 wchar_t wideStr[COMMON_STRING_MAX_LEN] = {0};
316 uint32_t wideStrLen = (uint32_t)mbstowcs(wideStr, str, len);
317 if (wideStrLen == 0 || wideStrLen > len) {
318 COMM_LOGW(COMM_DFX, "convert wide str failed");
319 RestoreLocale(localeBefore);
320 return CopyStr(str, anonymized);
321 }
322 uint32_t anonymizedNum = (wideStrLen + ANONYMIZE_LEN_RATIO - 1) / ANONYMIZE_LEN_RATIO; // +ratio-1 for round up
323 uint32_t plainPrefixPos = wideStrLen / ANONYMIZE_POS_RATIO;
324 AnonymizeParam param = {
325 .plainPrefixPos = plainPrefixPos,
326 .plainSuffixPos = plainPrefixPos + anonymizedNum,
327 .len = len,
328 };
329
330 ret = AnonymizeWideStrToByteStr(wideStr, wideStrLen, ¶m, anonymized);
331 RestoreLocale(localeBefore);
332 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_DFX, "anonymize multi byte str failed");
333 return ret;
334 }
335
AnonymizeHalfStr(const char * str,uint32_t len,char ** anonymized)336 static int32_t AnonymizeHalfStr(const char *str, uint32_t len, char **anonymized)
337 {
338 uint32_t plainTextLen = len / 2;
339 uint32_t plainTextOffset = len - plainTextLen;
340 uint32_t anonymizeLen = 1 + plainTextLen;
341
342 *anonymized = MallocStr(anonymizeLen);
343 COMM_CHECK_AND_RETURN_RET_LOGE(*anonymized != NULL, SOFTBUS_MALLOC_ERR, COMM_DFX, "malloc failed");
344
345 if (plainTextLen > 0) {
346 errno_t ret = memcpy_s(*anonymized + 1, plainTextLen, str + plainTextOffset, plainTextLen);
347 COMM_CHECK_AND_RETURN_RET_LOGE(ret == EOK, SOFTBUS_STRCPY_ERR, COMM_DFX, "memcpy failed");
348 }
349
350 (*anonymized)[0] = SYMBOL_ANONYMIZE;
351 return SOFTBUS_OK;
352 }
353
AnonymizeEmpty(const char * str,uint32_t len,char ** anonymized)354 static int32_t AnonymizeEmpty(const char *str, uint32_t len, char **anonymized)
355 {
356 (void)str;
357 (void)len;
358 return CopyStr("EMPTY", anonymized);
359 }
360
AnonymizeInner(const char * str,char ** anonymized)361 static int32_t AnonymizeInner(const char *str, char **anonymized)
362 {
363 if (str == NULL) {
364 return CopyStr("NULL", anonymized);
365 }
366
367 static const AnonymizeHandler ANONYMIZE_HANDLER[] = {
368 { MatchEmpty, AnonymizeEmpty },
369 { MatchIpAddr, AnonymizeIpAddr },
370 { MatchMacAddr, AnonymizeMacAddr },
371 { MatchUdidStr, AnonymizeUdidStr },
372 { MatchCommString, AnonymizeCommString },
373 };
374
375 uint32_t len = strlen(str);
376 for (uint32_t i = 0; i < sizeof(ANONYMIZE_HANDLER) / sizeof(AnonymizeHandler); ++i) {
377 if (ANONYMIZE_HANDLER[i].Matcher(str, len)) {
378 return ANONYMIZE_HANDLER[i].Anonymizer(str, len, anonymized);
379 }
380 }
381 return AnonymizeHalfStr(str, len, anonymized);
382 }
383
AnonymizeDeviceNameInner(const char * str,char ** anonymized)384 static int32_t AnonymizeDeviceNameInner(const char *str, char **anonymized)
385 {
386 static const uint32_t DEVICE_NAME_PREFIX = 1;
387 static const uint32_t DEVICE_NAME_SUFFIX = 3;
388 static const uint32_t DEVICE_NAME_RATIO_ANONYMIZE_LEN = 8;
389
390 if (str == NULL) {
391 return CopyStr("NULL", anonymized);
392 }
393 uint32_t len = strlen(str);
394 if (len == 0) {
395 return CopyStr("EMPTY", anonymized);
396 }
397 if (len >= COMMON_STRING_MAX_LEN) {
398 COMM_LOGW(COMM_DFX, "invalid str len=%{public}u", len);
399 return CopyStr("INVALID", anonymized);
400 }
401
402 char *localeBefore = NULL;
403 int32_t ret = SetLocale(&localeBefore);
404 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_DFX, "get locale failed");
405
406 wchar_t wideStr[COMMON_STRING_MAX_LEN] = {0};
407 uint32_t wideStrLen = (uint32_t)mbstowcs(wideStr, str, len);
408 if (wideStrLen == 0 || wideStrLen > len) {
409 COMM_LOGW(COMM_DFX, "convert wide str failed");
410 /* string is garbled when the memory is abnormal*/
411 RestoreLocale(localeBefore);
412 return CopyStr(str, anonymized);
413 }
414 if (wideStrLen < DEVICE_NAME_RATIO_ANONYMIZE_LEN) {
415 RestoreLocale(localeBefore);
416 return AnonymizeCommString(str, len, anonymized);
417 }
418 uint32_t anonymizedNum = wideStrLen - DEVICE_NAME_PREFIX - DEVICE_NAME_SUFFIX;
419 AnonymizeParam param = {
420 .plainPrefixPos = DEVICE_NAME_PREFIX,
421 .plainSuffixPos = DEVICE_NAME_PREFIX + anonymizedNum,
422 .len = len,
423 };
424
425 ret = AnonymizeWideStrToByteStr(wideStr, wideStrLen, ¶m, anonymized);
426 RestoreLocale(localeBefore);
427 COMM_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, COMM_DFX, "anonymize multi byte str failed");
428 return ret;
429 }
430
Anonymize(const char * plainStr,char ** anonymizedStr)431 void Anonymize(const char *plainStr, char **anonymizedStr)
432 {
433 COMM_CHECK_AND_RETURN_LOGE(anonymizedStr != NULL, COMM_DFX, "anonymizedStr is null");
434
435 if (AnonymizeInner(plainStr, anonymizedStr) == SOFTBUS_OK) {
436 return;
437 }
438 if (*anonymizedStr != NULL) {
439 AnonymizeFree(*anonymizedStr);
440 *anonymizedStr = NULL;
441 }
442 }
443
AnonymizeFree(char * anonymizedStr)444 void AnonymizeFree(char *anonymizedStr)
445 {
446 if (anonymizedStr == NULL) {
447 return;
448 }
449 free(anonymizedStr);
450 }
451
AnonymizeWrapper(const char * anonymizedStr)452 const char *AnonymizeWrapper(const char *anonymizedStr)
453 {
454 return anonymizedStr ? anonymizedStr : "NULL";
455 }
456
AnonymizeDeviceName(const char * plainStr,char ** anonymizedStr)457 void AnonymizeDeviceName(const char *plainStr, char **anonymizedStr)
458 {
459 COMM_CHECK_AND_RETURN_LOGE(anonymizedStr != NULL, COMM_DFX, "anonymizedStr is null");
460
461 if (AnonymizeDeviceNameInner(plainStr, anonymizedStr) == SOFTBUS_OK) {
462 return;
463 }
464 if (*anonymizedStr != NULL) {
465 AnonymizeFree(*anonymizedStr);
466 *anonymizedStr = NULL;
467 }
468 }
469