• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &param, 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, &param, 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