* Copyright (C) 2025-2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "antifraud_cloud_service.h"
#include <chrono>
#include <cJSON.h>
#include "hitrace/tracechain.h"
#include <iomanip>
#include <limits>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <parameter.h>
#include <random>
#include <sstream>
#include "base64.h"
#include "call_manager_utils.h"
#include "telephony_log_wrapper.h"
namespace OHOS {
namespace Telephony {
constexpr size_t BOUNDARY_LENGTH = 32;
constexpr size_t SERIAL_NUM_LEN = 16;
constexpr int BASE64_NUMBER2 = 2;
constexpr int COMMON_TIME_OUT = 5000;
const std::string RANDOM_CHAR_SET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
const std::string UPLOAD_MODEL_PATH = "/rms/v1/antiFraud/upload-model-result";
const std::string CLOUD_CONNECT_SERVICE_NAME = "com.cloud.afs.ROOT";
const std::string UCS_SERVICE_NAME = "com.hmos.hsdr.antifraud";
AntiFraudCloudService::AntiFraudCloudService(const std::string &phoneNum) : phoneNum_(phoneNum) {}
bool AntiFraudCloudService::UploadPostRequest(const OHOS::AntiFraudService::AntiFraudResult &antiFraudResult)
{
auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
std::string metaData = GeneratePayload(antiFraudResult);
if (metaData.empty()) {
TELEPHONY_LOGE("Failed to generate payload.");
return false;
}
auto auth = std::make_shared<std::string>();
if (!GetAuthAsync(metaData, auth)) {
TELEPHONY_LOGE("Failed to get auth.");
helper.DisconnectHsdr();
return false;
}
if (auth->empty()) {
TELEPHONY_LOGE("Auth is empty.");
helper.DisconnectHsdr();
return false;
}
return UploadToCloudAsync(metaData, *auth, antiFraudResult);
}
bool AntiFraudCloudService::GetAuthAsync(const std::string &metaData, std::shared_ptr<std::string> &auth)
{
std::weak_ptr<AntiFraudCloudService> weakPtr = shared_from_this();
std::unique_lock<ffrt::mutex> lock(mutex_);
isSettled_ = false;
auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
helper.ConnectHsdr([weakPtr, metaData, wqAuth =
std::weak_ptr<std::string>(auth)](sptr<IRemoteObject> remoteObject) {
auto ptr = weakPtr.lock();
auto sqAuth = wqAuth.lock();
if (ptr == nullptr || sqAuth == nullptr) {
auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
helper.DisconnectHsdr();
if (ptr != nullptr) {
ptr->isSettled_ = true;
ptr->cv_.notify_all();
}
return;
}
std::lock_guard<ffrt::mutex> lock(ptr->mutex_);
auto pair = ptr->EncryptSync(metaData, remoteObject);
auto ak = pair.first;
if (ak.empty()) {
TELEPHONY_LOGE("Failed to get ak.");
ptr->isSettled_ = true;
ptr->cv_.notify_all();
return;
}
*sqAuth = ptr->GetAuthSync(metaData, ak, remoteObject);
ptr->isSettled_ = true;
ptr->cv_.notify_all();
});
while (!isSettled_) {
if (cv_.wait_for(lock, std::chrono::milliseconds(COMMON_TIME_OUT)) == ffrt::cv_status::timeout) {
TELEPHONY_LOGE("Get auth timeout.");
return false;
}
}
return true;
}
bool AntiFraudCloudService::UploadToCloudAsync(const std::string &metaData, const std::string &auth,
const OHOS::AntiFraudService::AntiFraudResult &antiFraudResult)
{
std::weak_ptr<AntiFraudCloudService> weakPtr = shared_from_this();
auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
helper.ConnectHsdr([metaData, auth, antiFraudResult, weakPtr](sptr<IRemoteObject> remoteObject) {
auto ptr = weakPtr.lock();
if (ptr == nullptr) {
auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
helper.DisconnectHsdr();
return;
}
ptr->ConnectCloudAsync(metaData, auth, antiFraudResult, remoteObject);
});
return true;
}
std::string AntiFraudCloudService::GeneratePayload(const OHOS::AntiFraudService::AntiFraudResult &antiFraudResult)
{
cJSON *root = cJSON_CreateObject();
if (root == nullptr) {
TELEPHONY_LOGE("Failed to create json object");
return "";
}
OHOS::HiviewDFX::HiTraceId chainId = OHOS::HiviewDFX::HiTraceChain::GetId();
cJSON_AddStringToObject(root, "modelCaller", "com.hsdr");
cJSON_AddStringToObject(root, "reqNo", std::to_string(chainId.GetChainId()).c_str());
cJSON_AddStringToObject(root, "calleeId", "15564984");
cJSON_AddStringToObject(root, "osType", "1");
cJSON_AddStringToObject(root, "serviceType", "00000002");
cJSON_AddStringToObject(root, "callerNum", phoneNum_.c_str());
cJSON_AddStringToObject(root, "markerId", "11");
cJSON_AddStringToObject(root, "romVer", GetRomVersion().c_str());
cJSON_AddStringToObject(root, "modelVer", std::to_string(antiFraudResult.modelVersion).c_str());
cJSON_AddNumberToObject(root, "modelScore", antiFraudResult.pvalue);
cJSON_AddStringToObject(root, "modelDecision", std::to_string(antiFraudResult.fraudType).c_str());
char *jsonString = cJSON_Print(root);
if (jsonString == nullptr) {
TELEPHONY_LOGE("Failed to generate json string.");
cJSON_Delete(root);
return "";
}
std::string payload(jsonString);
cJSON_Delete(root);
free(jsonString);
return payload;
}
std::pair<std::string, std::string> AntiFraudCloudService::EncryptSync(const std::string &metaData,
sptr<IRemoteObject> remoteObject)
{
if (remoteObject == nullptr) {
TELEPHONY_LOGE("remoteObject is nullptr.");
return {"", ""};
}
HsdrProxy service(remoteObject);
std::string encryptResult;
HsdrRequest encryptReq = { std::to_string(GenerateRandomLong()), UCS_SERVICE_NAME,
HsdrCommands::COMMAND_UCS_REQUEST, GenerateUcsRequestBody(UcsMethod::Encrypt, metaData) };
auto ret = service.RequestHsdrServiceSync(encryptReq, encryptResult);
TELEPHONY_LOGI("RequestHsdrServiceSync ret = %{public}d", ret);
auto pair = ProcessEncryptResult(encryptResult);
return pair;
}
std::pair<std::string, std::string> AntiFraudCloudService::ProcessEncryptResult(const std::string &encryptResult)
{
cJSON *root = cJSON_Parse(encryptResult.c_str());
if (root == nullptr) {
TELEPHONY_LOGE("cJSON_Parse failed");
return {"", ""};
}
cJSON *ak = cJSON_GetObjectItem(root, "ak");
if (ak == nullptr || ak->type != cJSON_String) {
TELEPHONY_LOGE("ak is not string.");
cJSON_Delete(root);
return {"", ""};
}
std::string akString(ak->valuestring);
cJSON *encrypt = cJSON_GetObjectItem(root, "data");
if (encrypt == nullptr || encrypt->type != cJSON_String) {
TELEPHONY_LOGE("encrypt is not string.");
cJSON_Delete(root);
return {akString, ""};
}
std::string encryptString(encrypt->valuestring);
cJSON_Delete(root);
return {akString, encryptString};
}
std::string AntiFraudCloudService::GetAuthSync(const std::string &metaData, const std::string &ak,
sptr<IRemoteObject> remoteObject)
{
if (remoteObject == nullptr) {
TELEPHONY_LOGE("remoteObject is nullptr.");
return "";
}
HsdrProxy service(remoteObject);
auto timestamp = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count());
std::string toSign = "POST&" + UPLOAD_MODEL_PATH + "&&";
toSign += metaData + "&";
toSign += "ak=" + ak + "&";
toSign += "timestamp=" + timestamp;
std::string signResult;
HsdrRequest signReq = { std::to_string(GenerateRandomLong()), UCS_SERVICE_NAME, HsdrCommands::COMMAND_UCS_REQUEST,
GenerateUcsRequestBody(UcsMethod::Sign, toSign) };
auto ret = service.RequestHsdrServiceSync(signReq, signResult);
TELEPHONY_LOGI("RequestHsdrServiceSync ret = %{public}d", ret);
std::string signature = ProcessSignResult(signResult);
std::string auth = "EXT-CLOUDSOA-HMAC-SHA256 ak=\"" + ak + "\",timestamp=" + timestamp +
",signature=\"" + signature + "\"";
return auth;
}
std::string AntiFraudCloudService::ProcessSignResult(const std::string &signResult)
{
cJSON *root = cJSON_Parse(signResult.c_str());
if (root == nullptr) {
TELEPHONY_LOGE("cJSON_Parse failed");
return "";
}
cJSON *data = cJSON_GetObjectItem(root, "data");
if (data == nullptr || data->type != cJSON_String) {
TELEPHONY_LOGE("signature data is not string.");
cJSON_Delete(root);
return "";
}
std::string signature(data->valuestring);
cJSON_Delete(root);
return signature;
}
std::string AntiFraudCloudService::GenerateUcsRequestBody(UcsMethod code, const std::string &requestData)
{
cJSON *root = cJSON_CreateObject();
if (root == nullptr) {
TELEPHONY_LOGE("Failed to create json object.");
return "";
}
cJSON_AddNumberToObject(root, "method", static_cast<int>(code));
cJSON_AddStringToObject(root, "data", EncodeBase64(requestData).c_str());
char *jsonString = cJSON_Print(root);
if (jsonString == nullptr) {
TELEPHONY_LOGE("Failed to generate json string.");
cJSON_Delete(root);
return "";
}
std::string requestBody(jsonString);
free(jsonString);
cJSON_Delete(root);
return requestBody;
}
std::string AntiFraudCloudService::EncodeBase64(const std::string &src)
{
auto results = Base64::Encode(std::vector<unsigned char>(src.begin(), src.end()));
std::string res = (results != nullptr) ? *results : "";
return res;
}
bool AntiFraudCloudService::ConnectCloudAsync(const std::string &metaData, const std::string &auth,
const OHOS::AntiFraudService::AntiFraudResult &antiFraudResult, sptr<IRemoteObject> remoteObject)
{
if (remoteObject == nullptr) {
TELEPHONY_LOGE("remoteObject is nullptr.");
auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
helper.DisconnectHsdr();
return false;
}
HsdrProxy service(remoteObject);
std::string boundary = GenerateRandomString(BOUNDARY_LENGTH);
std::map<std::string, std::string> headers = GenerateHeadersMap(auth, antiFraudResult.voiceText, boundary);
std::ostringstream bodyStream;
bodyStream << "--" << boundary << "\r\n" <<
"Content-Disposition: form-data; name=\"meta-data\"\r\n" <<
"Content-Type: application/json\r\n" <<
"\r\n" <<
metaData << "\r\n" <<
"--" << boundary << "\r\n" <<
"Content-Disposition: form-data; name=\"file-data\"; filename=\"file.txt\"\r\n" <<
"Content-Type: text/plain\r\n" <<
"\r\n" <<
antiFraudResult.voiceText << "\r\n" <<
"--" << boundary << "--";
std::string body = bodyStream.str();
std::string requestJson = GenerateRequestJson(headers, body);
OnResponse onResponse = [](const HsdrResponse &response) {
TELEPHONY_LOGI("Onresponse, body: %{public}s", response.body_.c_str());
auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
helper.DisconnectHsdr();
};
OnError onError = [](int errCode) {
TELEPHONY_LOGE("error code = %{public}d", errCode);
auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
helper.DisconnectHsdr();
};
std::string requestId = std::to_string(GenerateRandomLong());
sptr<HsdrCallbackStub> callbackStub =
new (std::nothrow) HsdrCallbackStub(requestId, onResponse, onError);
if (callbackStub == nullptr) {
TELEPHONY_LOGE("callbackStub is nullptr.");
auto &helper = DelayedRefSingleton<HsdrHelper>().GetInstance();
helper.DisconnectHsdr();
return false;
}
HsdrRequest request = { requestId, CLOUD_CONNECT_SERVICE_NAME, HsdrCommands::COMMAND_CLOUD_CONNECT,
requestJson };
int ret = service.RequestHsdrServiceAsync(callbackStub, request);
TELEPHONY_LOGI("RequestHsdrServiceAsync ret = %{public}d", ret);
return ret == 0;
}
std::map<std::string, std::string> AntiFraudCloudService::GenerateHeadersMap(const std::string &auth,
const std::string &fileContent, const std::string &boundary)
{
std::map<std::string, std::string> headers;
headers["Authorization"] = auth;
headers["X-Request-ID"] = GetDeviceSerial();
headers["Content-Digest"] = CalculateDigest(fileContent);
headers["down-algo"] = "AES-GCM";
headers["X-OS-Version"] = GetOsVersion();
std::string contentType = "multipart/form-data; boundary=" + boundary;
headers["Content-Type"] = contentType;
return headers;
}
std::string AntiFraudCloudService::CalculateDigest(const std::string &payload)
{
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, payload.c_str(), payload.size());
SHA256_Final(hash, &sha256);
std::stringstream ss;
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
ss << std::hex << std::setw(BASE64_NUMBER2) << std::setfill('0') << (int)hash[i];
}
return ss.str();
}
std::string AntiFraudCloudService::GenerateRequestJson(const std::map<std::string, std::string> &headersMap,
const std::string &body)
{
cJSON *root = cJSON_CreateObject();
if (root == nullptr) {
TELEPHONY_LOGE("Failed to create json object.");
return "";
}
cJSON_AddStringToObject(root, "method", "POST");
cJSON_AddStringToObject(root, "path", UPLOAD_MODEL_PATH.c_str());
cJSON *headers = cJSON_CreateObject();
if (headers == nullptr) {
TELEPHONY_LOGE("Failed to create json object.");
cJSON_Delete(root);
return "";
}
cJSON *params = cJSON_CreateArray();
if (params == nullptr) {
TELEPHONY_LOGE("Failed to create json object.");
cJSON_Delete(root);
cJSON_Delete(headers);
return "";
}
for (auto header : headersMap) {
cJSON *param = cJSON_CreateObject();
if (param == nullptr) {
TELEPHONY_LOGE("Failed to create json object.");
cJSON_Delete(root);
cJSON_Delete(headers);
cJSON_Delete(params);
return "";
}
cJSON_AddStringToObject(param, "name", header.first.c_str());
cJSON_AddStringToObject(param, "value", header.second.c_str());
cJSON_AddItemToArray(params, param);
}
cJSON_AddItemToObject(headers, "params", params);
cJSON_AddItemToObject(root, "headers", headers);
cJSON_AddStringToObject(root, "body", body.c_str());
cJSON_AddNumberToObject(root, "connectTimeout", COMMON_TIME_OUT);
cJSON_AddNumberToObject(root, "readTimeout", COMMON_TIME_OUT);
char *str = cJSON_Print(root);
if (str == nullptr) {
TELEPHONY_LOGE("Failed to generate json string.");
cJSON_Delete(root);
return "";
}
std::string requestJson(str);
cJSON_Delete(root);
cJSON_free(str);
return requestJson;
}
std::string AntiFraudCloudService::GenerateRandomString(size_t length)
{
std::string randomString;
randomString.reserve(length);
for (size_t i = 0; i < length; i++) {
std::random_device rd;
std::uniform_int_distribution<size_t> dist(0, RANDOM_CHAR_SET.size() - 1);
size_t randomNum = dist(rd);
randomString += RANDOM_CHAR_SET[randomNum];
}
return randomString;
}
uint64_t AntiFraudCloudService::GenerateRandomLong()
{
std::random_device seed;
std::mt19937_64 gen(seed());
std::uniform_int_distribution<uint64_t> dis(std::numeric_limits<uint64_t>::min(),
std::numeric_limits<uint64_t>::max());
return dis(gen);
}
std::string AntiFraudCloudService::GetOsVersion()
{
return CallManagerUtils::GetSystemParameter("const.ohos.fullname", "");
}
std::string AntiFraudCloudService::GetDeviceSerial()
{
const char *serial = GetSerial();
if (serial == nullptr) {
TELEPHONY_LOGE("GetSerial failed.");
return GenerateRandomString(SERIAL_NUM_LEN);
}
std::string deviceSerial(serial);
return deviceSerial;
}
std::string AntiFraudCloudService::GetRomVersion()
{
std::string fullVersion = CallManagerUtils::GetSystemParameter("const.product.software.version", "");
return GetSubstringBeforeSymbol(fullVersion, "(");
}
std::string AntiFraudCloudService::GetSubstringBeforeSymbol(const std::string &str, const std::string &symbol)
{
size_t pos = str.rfind(symbol);
if (pos != std::string::npos) {
return str.substr(0, pos);
} else {
return str;
}
}
}
}