1 /*
2 * Copyright (C) 2025-2025 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 "antifraud_cloud_service.h"
17
18 #include <chrono>
19 #include <cJSON.h>
20 #include <limits>
21 #include <openssl/sha.h>
22 #include <openssl/hmac.h>
23 #include <parameter.h>
24 #include <parameters.h>
25 #include <random>
26 #include <sstream>
27 #include "telephony_log_wrapper.h"
28
29 namespace OHOS {
30 namespace Telephony {
31 constexpr size_t BOUNDARY_LENGTH = 32;
32 constexpr size_t REQUEST_NO_LENGTH = 10;
33 constexpr size_t SERIAL_NUM_LEN = 16;
34 constexpr int BASE64_NUMBER2 = 2;
35 constexpr int BASE64_NUMBER3 = 3;
36 constexpr int BASE64_NUMBER4 = 4;
37 constexpr int BASE64_NUMBER6 = 6;
38 constexpr int COMMON_TIME_OUT = 5000;
39 const std::string BASE_64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
40 const std::string RANDOM_CHAR_SET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
41 const std::string UPLOAD_MODEL_PATH = "/rms/v1/antiFraud/upload-model-result";
42 const std::string CLOUD_CONNECT_SERVICE_NAME = "com.cloud.afs.ROOT";
43 const std::string UCS_SERVICE_NAME = "com.hmos.hsdr.antifraud";
44
AntiFraudCloudService(const std::string & phoneNum)45 AntiFraudCloudService::AntiFraudCloudService(const std::string &phoneNum) : phoneNum_(phoneNum) {}
46
UploadPostRequest(const OHOS::AntiFraudService::AntiFraudResult & antiFraudResult)47 bool AntiFraudCloudService::UploadPostRequest(const OHOS::AntiFraudService::AntiFraudResult &antiFraudResult)
48 {
49 auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
50 std::string metaData = GeneratePayload(antiFraudResult);
51 std::weak_ptr<AntiFraudCloudService> weakPtr = shared_from_this();
52 std::unique_lock<std::mutex> lock(mutex_);
53 isSettled_ = false;
54 std::string auth;
55 helper.ConnectHsdr([weakPtr, metaData, &auth](sptr<IRemoteObject> remoteObject) {
56 auto ptr = weakPtr.lock();
57 if (ptr == nullptr) {
58 auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
59 helper.DisconnectHsdr();
60 return;
61 }
62 std::lock_guard<std::mutex> lock(ptr->mutex_);
63 auto pair = ptr->EncryptSync(metaData, remoteObject);
64 auto ak = pair.first;
65 if (ak.empty()) {
66 TELEPHONY_LOGE("Failed to get ak.");
67 ptr->isSettled_ = true;
68 ptr->cv_.notify_all();
69 return;
70 }
71 auth = ptr->GetAuthSync(metaData, ak, remoteObject);
72 ptr->isSettled_ = true;
73 ptr->cv_.notify_all();
74 });
75
76 while (!isSettled_) {
77 if (cv_.wait_for(lock, std::chrono::milliseconds(COMMON_TIME_OUT)) == std::cv_status::timeout) {
78 TELEPHONY_LOGE("get auth timeout.");
79 helper.DisconnectHsdr();
80 return false;
81 }
82 }
83
84 if (auth.empty()) {
85 TELEPHONY_LOGE("Failed to get auth.");
86 helper.DisconnectHsdr();
87 return false;
88 }
89
90 helper.ConnectHsdr([metaData, auth, antiFraudResult, weakPtr](sptr<IRemoteObject> remoteObject) {
91 auto ptr = weakPtr.lock();
92 if (ptr == nullptr) {
93 auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
94 helper.DisconnectHsdr();
95 return;
96 }
97 ptr->ConnectCloudAsync(metaData, auth, antiFraudResult, remoteObject);
98 });
99 return true;
100 }
101
GeneratePayload(const OHOS::AntiFraudService::AntiFraudResult & antiFraudResult)102 std::string AntiFraudCloudService::GeneratePayload(const OHOS::AntiFraudService::AntiFraudResult &antiFraudResult)
103 {
104 cJSON *root = cJSON_CreateObject();
105 if (root == nullptr) {
106 TELEPHONY_LOGE("Failed to create json object");
107 return "";
108 }
109 cJSON_AddStringToObject(root, "modelCaller", "com.hsdr");
110 cJSON_AddStringToObject(root, "reqNo", GenerateRandomString(REQUEST_NO_LENGTH).c_str());
111 cJSON_AddStringToObject(root, "calleeId", "15564984");
112 cJSON_AddStringToObject(root, "osType", "1");
113 cJSON_AddStringToObject(root, "serviceType", "00000002");
114 cJSON_AddStringToObject(root, "callerNum", phoneNum_.c_str());
115 cJSON_AddStringToObject(root, "markerId", "11");
116 cJSON_AddStringToObject(root, "romVer", GetRomVersion().c_str());
117 cJSON_AddStringToObject(root, "modelVer", std::to_string(antiFraudResult.modelVersion).c_str());
118 cJSON_AddNumberToObject(root, "modelScore", antiFraudResult.pvalue);
119 cJSON_AddStringToObject(root, "modelDecision", std::to_string(antiFraudResult.fraudType).c_str());
120 char *jsonString = cJSON_Print(root);
121 if (jsonString == nullptr) {
122 TELEPHONY_LOGE("Failed to generate json string.");
123 cJSON_Delete(root);
124 return "";
125 }
126 std::string payload(jsonString);
127 cJSON_Delete(root);
128 free(jsonString);
129 return payload;
130 }
131
EncryptSync(const std::string & metaData,sptr<IRemoteObject> remoteObject)132 std::pair<std::string, std::string> AntiFraudCloudService::EncryptSync(const std::string &metaData,
133 sptr<IRemoteObject> remoteObject)
134 {
135 if (remoteObject == nullptr) {
136 TELEPHONY_LOGE("remoteObject is nullptr.");
137 return {"", ""};
138 }
139 HsdrProxy service(remoteObject);
140 std::string encryptResult;
141 HsdrRequest encryptReq = { std::to_string(GenerateRandomLong()), UCS_SERVICE_NAME,
142 HsdrCommands::COMMAND_UCS_REQUEST, GenerateUcsRequestBody(UcsMethod::Encrypt, metaData) };
143 auto ret = service.RequestHsdrServiceSync(encryptReq, encryptResult);
144 TELEPHONY_LOGI("RequestHsdrServiceSync ret = %{public}d", ret);
145
146 auto pair = ProcessEncryptResult(encryptResult);
147 return pair;
148 }
149
ProcessEncryptResult(const std::string & encryptResult)150 std::pair<std::string, std::string> AntiFraudCloudService::ProcessEncryptResult(const std::string &encryptResult)
151 {
152 cJSON *root = cJSON_Parse(encryptResult.c_str());
153 if (root == nullptr) {
154 TELEPHONY_LOGE("cJSON_Parse failed");
155 return {"", ""};
156 }
157 cJSON *ak = cJSON_GetObjectItem(root, "ak");
158 if (ak == nullptr || ak->type != cJSON_String) {
159 TELEPHONY_LOGE("ak is not string.");
160 cJSON_Delete(root);
161 return {"", ""};
162 }
163 std::string akString(ak->valuestring);
164 cJSON *encrypt = cJSON_GetObjectItem(root, "data");
165 if (encrypt == nullptr || encrypt->type != cJSON_String) {
166 TELEPHONY_LOGE("encrypt is not string.");
167 cJSON_Delete(root);
168 return {akString, ""};
169 }
170 std::string encryptString(encrypt->valuestring);
171 cJSON_Delete(root);
172 return {akString, encryptString};
173 }
174
GetAuthSync(const std::string & metaData,const std::string & ak,sptr<IRemoteObject> remoteObject)175 std::string AntiFraudCloudService::GetAuthSync(const std::string &metaData, const std::string &ak,
176 sptr<IRemoteObject> remoteObject)
177 {
178 if (remoteObject == nullptr) {
179 TELEPHONY_LOGE("remoteObject is nullptr.");
180 return "";
181 }
182 HsdrProxy service(remoteObject);
183 auto timestamp = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
184 std::chrono::system_clock::now().time_since_epoch()).count());
185 std::string toSign = "POST&" + UPLOAD_MODEL_PATH + "&&";
186 toSign += metaData + "&";
187 toSign += "ak=" + ak + "&";
188 toSign += "timestamp=" + timestamp;
189 std::string signResult;
190 HsdrRequest signReq = { std::to_string(GenerateRandomLong()), UCS_SERVICE_NAME, HsdrCommands::COMMAND_UCS_REQUEST,
191 GenerateUcsRequestBody(UcsMethod::Sign, toSign) };
192 auto ret = service.RequestHsdrServiceSync(signReq, signResult);
193 TELEPHONY_LOGI("RequestHsdrServiceSync ret = %{public}d", ret);
194 std::string signature = ProcessSignResult(signResult);
195 std::string auth = "EXT-CLOUDSOA-HMAC-SHA256 ak=\"" + ak + "\",timestamp=" + timestamp +
196 ",signature=\"" + signature + "\"";
197 return auth;
198 }
199
ProcessSignResult(const std::string & signResult)200 std::string AntiFraudCloudService::ProcessSignResult(const std::string &signResult)
201 {
202 cJSON *root = cJSON_Parse(signResult.c_str());
203 if (root == nullptr) {
204 TELEPHONY_LOGE("cJSON_Parse failed");
205 return "";
206 }
207 cJSON *data = cJSON_GetObjectItem(root, "data");
208 if (data == nullptr || data->type != cJSON_String) {
209 TELEPHONY_LOGE("signature data is not string.");
210 cJSON_Delete(root);
211 return "";
212 }
213 std::string signature(data->valuestring);
214 cJSON_Delete(root);
215 return signature;
216 }
217
GenerateUcsRequestBody(UcsMethod code,const std::string & requestData)218 std::string AntiFraudCloudService::GenerateUcsRequestBody(UcsMethod code, const std::string &requestData)
219 {
220 cJSON *root = cJSON_CreateObject();
221 if (root == nullptr) {
222 TELEPHONY_LOGE("Failed to create json object.");
223 return "";
224 }
225 cJSON_AddNumberToObject(root, "method", static_cast<int>(code));
226 cJSON_AddStringToObject(root, "data", EncodeBase64(requestData.c_str(), requestData.size()).c_str());
227 char *jsonString = cJSON_Print(root);
228 if (jsonString == nullptr) {
229 TELEPHONY_LOGE("Failed to generate json string.");
230 cJSON_Delete(root);
231 return "";
232 }
233 std::string requestBody(jsonString);
234 free(jsonString);
235 cJSON_Delete(root);
236 return requestBody;
237 }
238
EncodeBase64(const char * bytes,unsigned int size)239 std::string AntiFraudCloudService::EncodeBase64(const char *bytes, unsigned int size)
240 {
241 std::string result;
242 int i = 0;
243 int j = 0;
244 uint8_t charArray3[BASE64_NUMBER3] = { 0 }; // store 3 byte of bytes_to_encode
245 uint8_t charArray4[BASE64_NUMBER4] = { 0 }; // store encoded character to 4 bytes
246
247 while (size--) {
248 charArray3[i++] = *(bytes++); // get three bytes (24 bits)
249 if (i == BASE64_NUMBER3) {
250 // eg. we have 3 bytes as ( 0100 1101, 0110 0001, 0110 1110) --> (010011, 010110, 000101, 101110)
251 charArray4[0] = (charArray3[0] & 0xfc) >> BASE64_NUMBER2; // get first 6 bits of first byte
252 // get last 2 bits of first byte and first 4 bit of second byte
253 charArray4[1] = ((charArray3[0] & 0x03) << BASE64_NUMBER4) + ((charArray3[1] & 0xf0) >> BASE64_NUMBER4);
254 // get last 4 bits of second byte and first 2 bits of third byte
255 charArray4[BASE64_NUMBER2] = ((charArray3[1] & 0x0f) << BASE64_NUMBER2) +
256 ((charArray3[BASE64_NUMBER2] & 0xc0) >> BASE64_NUMBER6);
257 charArray4[BASE64_NUMBER3] = charArray3[BASE64_NUMBER2] & 0x3f; // get last 6 bits of third byte
258
259 for (i = 0; (i < BASE64_NUMBER4); i++) {
260 result += BASE_64_CHARS[charArray4[i]];
261 }
262 i = 0;
263 }
264 }
265
266 if (i) {
267 for (j = i; j < BASE64_NUMBER3; j++) {
268 charArray3[j] = '\0';
269 }
270
271 charArray4[0] = (charArray3[0] & 0xfc) >> BASE64_NUMBER2;
272 charArray4[1] = ((charArray3[0] & 0x03) << BASE64_NUMBER4) + ((charArray3[1] & 0xf0) >> BASE64_NUMBER4);
273 charArray4[BASE64_NUMBER2] = ((charArray3[1] & 0x0f) << BASE64_NUMBER2) +
274 ((charArray3[BASE64_NUMBER2] & 0xc0) >> BASE64_NUMBER6);
275
276 for (j = 0; (j < i + 1); j++) {
277 result += BASE_64_CHARS[charArray4[j]];
278 }
279
280 while ((i++ < BASE64_NUMBER3)) {
281 result += '=';
282 }
283 }
284
285 return result;
286 }
287
ConnectCloudAsync(const std::string & metaData,const std::string & auth,const OHOS::AntiFraudService::AntiFraudResult & antiFraudResult,sptr<IRemoteObject> remoteObject)288 bool AntiFraudCloudService::ConnectCloudAsync(const std::string &metaData, const std::string &auth,
289 const OHOS::AntiFraudService::AntiFraudResult &antiFraudResult, sptr<IRemoteObject> remoteObject)
290 {
291 if (remoteObject == nullptr) {
292 TELEPHONY_LOGE("remoteObject is nullptr.");
293 auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
294 helper.DisconnectHsdr();
295 return false;
296 }
297 HsdrProxy service(remoteObject);
298 std::string boundary = GenerateRandomString(BOUNDARY_LENGTH);
299 std::map<std::string, std::string> headers = GenerateHeadersMap(auth, antiFraudResult.text, boundary);
300 std::ostringstream bodyStream;
301 bodyStream << "--" << boundary << "\r\n" <<
302 "Content-Disposition: form-data; name=\"meta-data\"\r\n" <<
303 "Content-Type: application/json\r\n" <<
304 "\r\n" <<
305 metaData << "\r\n" <<
306 "--" << boundary << "\r\n" <<
307 "Content-Disposition: form-data; name=\"file-data\"; filename=\"file.txt\"\r\n" <<
308 "Content-Type: text/plain\r\n" <<
309 "\r\n" <<
310 antiFraudResult.text << "\r\n" <<
311 "--" << boundary << "--";
312 std::string body = bodyStream.str();
313 std::string requestJson = GenerateRequestJson(headers, body);
314 OnResponse onResponse = [](const HsdrResponse &response) {
315 TELEPHONY_LOGI("Onresponse, body: %{public}s", response.body_.c_str());
316 auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
317 helper.DisconnectHsdr();
318 };
319 OnError onError = [](int errCode) {
320 TELEPHONY_LOGE("error code = %{public}d", errCode);
321 auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
322 helper.DisconnectHsdr();
323 };
324 std::string requestId = std::to_string(GenerateRandomLong());
325 sptr<HsdrCallbackStub> callbackStub =
326 new (std::nothrow) HsdrCallbackStub(requestId, onResponse, onError);
327 if (callbackStub == nullptr) {
328 TELEPHONY_LOGE("callbackStub is nullptr.");
329 auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
330 helper.DisconnectHsdr();
331 return false;
332 }
333 HsdrRequest request = { requestId, CLOUD_CONNECT_SERVICE_NAME, HsdrCommands::COMMAND_CLOUD_CONNECT,
334 requestJson };
335 int ret = service.RequestHsdrServiceAsync(callbackStub, request);
336 TELEPHONY_LOGI("RequestHsdrServiceAsync ret = %{public}d", ret);
337 return ret == 0;
338 }
339
GenerateHeadersMap(const std::string & auth,const std::string & fileContent,const std::string & boundary)340 std::map<std::string, std::string> AntiFraudCloudService::GenerateHeadersMap(const std::string &auth,
341 const std::string &fileContent, const std::string &boundary)
342 {
343 std::map<std::string, std::string> headers;
344 headers["Authorization"] = auth;
345 headers["X-Request-ID"] = GetDeviceSerial();
346 headers["Content-Digest"] = CalculateDigest(fileContent);
347 headers["down-algo"] = "AES-GCM";
348 headers["X-OS-Version"] = GetOsVersion();
349 std::string contentType = "multipart/form-data; boundary=" + boundary;
350 headers["Content-Type"] = contentType;
351 return headers;
352 }
353
CalculateDigest(const std::string & payload)354 std::string AntiFraudCloudService::CalculateDigest(const std::string &payload)
355 {
356 unsigned char hash[SHA256_DIGEST_LENGTH];
357 SHA256_CTX sha256;
358 SHA256_Init(&sha256);
359 SHA256_Update(&sha256, payload.c_str(), payload.size());
360 SHA256_Final(hash, &sha256);
361
362 std::stringstream ss;
363 for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
364 ss << std::hex << std::setw(BASE64_NUMBER2) << std::setfill('0') << (int)hash[i];
365 }
366 return ss.str();
367 }
368
GenerateRequestJson(const std::map<std::string,std::string> & headersMap,const std::string & body)369 std::string AntiFraudCloudService::GenerateRequestJson(const std::map<std::string, std::string> &headersMap,
370 const std::string &body)
371 {
372 cJSON *root = cJSON_CreateObject();
373 if (root == nullptr) {
374 TELEPHONY_LOGE("Failed to create json object.");
375 return "";
376 }
377 cJSON_AddStringToObject(root, "method", "POST");
378 cJSON_AddStringToObject(root, "path", UPLOAD_MODEL_PATH.c_str());
379
380 cJSON *headers = cJSON_CreateObject();
381 if (headers == nullptr) {
382 TELEPHONY_LOGE("Failed to create json object.");
383 cJSON_Delete(root);
384 return "";
385 }
386 cJSON *params = cJSON_CreateArray();
387 if (params == nullptr) {
388 TELEPHONY_LOGE("Failed to create json object.");
389 cJSON_Delete(root);
390 cJSON_Delete(headers);
391 return "";
392 }
393 for (auto header : headersMap) {
394 cJSON *param = cJSON_CreateObject();
395 if (param == nullptr) {
396 TELEPHONY_LOGE("Failed to create json object.");
397 cJSON_Delete(root);
398 cJSON_Delete(headers);
399 cJSON_Delete(params);
400 return "";
401 }
402 cJSON_AddStringToObject(param, "name", header.first.c_str());
403 cJSON_AddStringToObject(param, "value", header.second.c_str());
404 cJSON_AddItemToArray(params, param);
405 }
406 cJSON_AddItemToObject(headers, "params", params);
407 cJSON_AddItemToObject(root, "headers", headers);
408
409 cJSON_AddStringToObject(root, "body", body.c_str());
410 cJSON_AddNumberToObject(root, "connectTimeout", COMMON_TIME_OUT);
411 cJSON_AddNumberToObject(root, "readTimeout", COMMON_TIME_OUT);
412 char *str = cJSON_Print(root);
413 if (str == nullptr) {
414 TELEPHONY_LOGE("Failed to generate json string.");
415 cJSON_Delete(root);
416 return "";
417 }
418 std::string requestJson(str);
419 cJSON_Delete(root);
420 free(str);
421 return requestJson;
422 }
423
GenerateRandomString(size_t length)424 std::string AntiFraudCloudService::GenerateRandomString(size_t length)
425 {
426 std::string randomString;
427 randomString.reserve(length);
428 for (size_t i = 0; i < length; i++) {
429 std::random_device rd;
430 std::uniform_int_distribution<size_t> dist(0, RANDOM_CHAR_SET.size() - 1);
431 size_t randomNum = dist(rd);
432 randomString += RANDOM_CHAR_SET[randomNum];
433 }
434
435 return randomString;
436 }
437
GenerateRandomLong()438 uint64_t AntiFraudCloudService::GenerateRandomLong()
439 {
440 std::random_device seed;
441 std::mt19937_64 gen(seed());
442 std::uniform_int_distribution<uint64_t> dis(std::numeric_limits<uint64_t>::min(),
443 std::numeric_limits<uint64_t>::max());
444 return dis(gen);
445 }
446
GetOsVersion()447 std::string AntiFraudCloudService::GetOsVersion()
448 {
449 return system::GetParameter("const.ohos.fullname", "");
450 }
451
GetDeviceSerial()452 std::string AntiFraudCloudService::GetDeviceSerial()
453 {
454 const char *serial = GetSerial();
455 if (serial == nullptr) {
456 TELEPHONY_LOGE("GetSerial failed.");
457 return GenerateRandomString(SERIAL_NUM_LEN);
458 }
459 std::string deviceSerial(serial);
460 return deviceSerial;
461 }
462
GetRomVersion()463 std::string AntiFraudCloudService::GetRomVersion()
464 {
465 std::string fullVersion = system::GetParameter("const.product.software.version", "");
466 return GetSubstringBeforeSymbol(fullVersion, "(");
467 }
468
GetSubstringBeforeSymbol(const std::string & str,const std::string & symbol)469 std::string AntiFraudCloudService::GetSubstringBeforeSymbol(const std::string &str, const std::string &symbol)
470 {
471 size_t pos = str.rfind(symbol);
472 if (pos != std::string::npos) {
473 return str.substr(0, pos);
474 } else {
475 return str;
476 }
477 }
478 } // namespace Telephony
479 } // namsespace OHOS