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