1020a203aSopenharmony_ci/*
2020a203aSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3020a203aSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4020a203aSopenharmony_ci * you may not use this file except in compliance with the License.
5020a203aSopenharmony_ci * You may obtain a copy of the License at
6020a203aSopenharmony_ci *
7020a203aSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8020a203aSopenharmony_ci *
9020a203aSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10020a203aSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11020a203aSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12020a203aSopenharmony_ci * See the License for the specific language governing permissions and
13020a203aSopenharmony_ci * limitations under the License.
14020a203aSopenharmony_ci */
15020a203aSopenharmony_ci#include "calc_fingerprint.h"
16020a203aSopenharmony_ci
17020a203aSopenharmony_ci#include <securec.h>
18020a203aSopenharmony_ci
19020a203aSopenharmony_ci#include "common_defines.h"
20020a203aSopenharmony_ci#include "file_util.h"
21020a203aSopenharmony_ci
22020a203aSopenharmony_ciusing namespace std;
23020a203aSopenharmony_cinamespace OHOS {
24020a203aSopenharmony_cinamespace HiviewDFX {
25020a203aSopenharmony_ciDEFINE_LOG_TAG("CalcFingerprint");
26020a203aSopenharmony_ciint CalcFingerprint::ConvertToString(const unsigned char hash[SHA256_DIGEST_LENGTH], char *outstr, size_t len)
27020a203aSopenharmony_ci{
28020a203aSopenharmony_ci    uint32_t i;
29020a203aSopenharmony_ci    char *outHash = outstr;
30020a203aSopenharmony_ci
31020a203aSopenharmony_ci    if (hash == nullptr || outHash == nullptr) {
32020a203aSopenharmony_ci        return EINVAL;
33020a203aSopenharmony_ci    }
34020a203aSopenharmony_ci    constexpr int charsEachHex = 2;
35020a203aSopenharmony_ci    if (len < (SHA256_DIGEST_LENGTH * charsEachHex + 1)) { // 1: add '\0'
36020a203aSopenharmony_ci        return ENOMEM;
37020a203aSopenharmony_ci    }
38020a203aSopenharmony_ci    for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
39020a203aSopenharmony_ci        int err = snprintf_s(outHash, charsEachHex + 1, charsEachHex, "%02x", hash[i]);
40020a203aSopenharmony_ci        if (err < 0) {
41020a203aSopenharmony_ci            return err;
42020a203aSopenharmony_ci        }
43020a203aSopenharmony_ci        outHash += charsEachHex;
44020a203aSopenharmony_ci    }
45020a203aSopenharmony_ci    *outHash = '\0';
46020a203aSopenharmony_ci    return 0;
47020a203aSopenharmony_ci}
48020a203aSopenharmony_ci
49020a203aSopenharmony_ci/*
50020a203aSopenharmony_ci * API name : calc_file_sha1
51020a203aSopenharmony_ci * Description : calculate a file sha1 hash for given file
52020a203aSopenharmony_ci * Input parameters
53020a203aSopenharmony_ci * filePath : path of the file to be calculated
54020a203aSopenharmony_ci * hash      : buffer to store output sha1 string
55020a203aSopenharmony_ci * Return
56020a203aSopenharmony_ci * 0 : successful
57020a203aSopenharmony_ci * x : fail
58020a203aSopenharmony_ci */
59020a203aSopenharmony_ciint CalcFingerprint::CalcFileSha(const string& filePath, char *hash, size_t len)
60020a203aSopenharmony_ci{
61020a203aSopenharmony_ci    if (filePath.empty() || hash == nullptr || !FileUtil::IsLegalPath(filePath)) {
62020a203aSopenharmony_ci        HIVIEW_LOGE("invalid param.");
63020a203aSopenharmony_ci        return EINVAL;
64020a203aSopenharmony_ci    }
65020a203aSopenharmony_ci    unsigned char value[SHA256_DIGEST_LENGTH] = {0};
66020a203aSopenharmony_ci    int ret = CalcFileShaOriginal(filePath, value, len);
67020a203aSopenharmony_ci    if (ret != 0) {
68020a203aSopenharmony_ci        HIVIEW_LOGE("CalcFileShaOriginal failed.");
69020a203aSopenharmony_ci        return ret;
70020a203aSopenharmony_ci    }
71020a203aSopenharmony_ci    return ConvertToString(value, hash, len);
72020a203aSopenharmony_ci}
73020a203aSopenharmony_ci
74020a203aSopenharmony_ciint CalcFingerprint::CalcFileShaOriginal(const string& filePath, unsigned char *hash, size_t len)
75020a203aSopenharmony_ci{
76020a203aSopenharmony_ci    if (filePath.empty() || hash == nullptr || !FileUtil::IsLegalPath(filePath)) {
77020a203aSopenharmony_ci        HIVIEW_LOGE("file is invalid.");
78020a203aSopenharmony_ci        return EINVAL;
79020a203aSopenharmony_ci    }
80020a203aSopenharmony_ci
81020a203aSopenharmony_ci    if (len < SHA256_DIGEST_LENGTH) {
82020a203aSopenharmony_ci        HIVIEW_LOGE("hash buf len error.");
83020a203aSopenharmony_ci        return ENOMEM;
84020a203aSopenharmony_ci    }
85020a203aSopenharmony_ci
86020a203aSopenharmony_ci    FILE *fp = nullptr;
87020a203aSopenharmony_ci    fp = fopen(filePath.c_str(), "rb");
88020a203aSopenharmony_ci    if (fp == nullptr) {
89020a203aSopenharmony_ci        HIVIEW_LOGE("open file failed.");
90020a203aSopenharmony_ci        return errno; // if file not exist, errno will be ENOENT
91020a203aSopenharmony_ci    }
92020a203aSopenharmony_ci
93020a203aSopenharmony_ci    size_t n;
94020a203aSopenharmony_ci    char buffer[HASH_BUFFER_SIZE] = {0};
95020a203aSopenharmony_ci    SHA256_CTX ctx;
96020a203aSopenharmony_ci    SHA256_Init(&ctx);
97020a203aSopenharmony_ci    while ((n = fread(buffer, 1, sizeof(buffer), fp))) {
98020a203aSopenharmony_ci        SHA256_Update(&ctx, (unsigned char *)buffer, n);
99020a203aSopenharmony_ci    }
100020a203aSopenharmony_ci    if (fclose(fp)) {
101020a203aSopenharmony_ci        HIVIEW_LOGE("fclose is failed");
102020a203aSopenharmony_ci    }
103020a203aSopenharmony_ci    fp = nullptr;
104020a203aSopenharmony_ci    SHA256_Final(hash, &ctx);
105020a203aSopenharmony_ci    return 0;
106020a203aSopenharmony_ci}
107020a203aSopenharmony_ci
108020a203aSopenharmony_ci/*
109020a203aSopenharmony_ci * API name : calc_buffer_sha1
110020a203aSopenharmony_ci * Description : calculate a buffer sha1 hash for given buffer
111020a203aSopenharmony_ci * Input parameters
112020a203aSopenharmony_ci * buffer : buffer to store the content which needed to be calculated
113020a203aSopenharmony_ci * hash_str   : buffer to store output sha1 string
114020a203aSopenharmony_ci * Return
115020a203aSopenharmony_ci * 0 : successful
116020a203aSopenharmony_ci * x : fail
117020a203aSopenharmony_ci */
118020a203aSopenharmony_ciint CalcFingerprint::CalcBufferSha(const string& buffer, size_t bufSize, char *hash, size_t len)
119020a203aSopenharmony_ci{
120020a203aSopenharmony_ci    if (buffer.empty()) {
121020a203aSopenharmony_ci        return EINVAL;
122020a203aSopenharmony_ci    }
123020a203aSopenharmony_ci    return CalcBufferSha((unsigned char *)buffer.c_str(), bufSize, hash, len);
124020a203aSopenharmony_ci}
125020a203aSopenharmony_ci
126020a203aSopenharmony_ci/*
127020a203aSopenharmony_ci * API name : calc_buffer_sha1
128020a203aSopenharmony_ci * Description : calculate a buffer sha1 hash for given buffer
129020a203aSopenharmony_ci * Input parameters
130020a203aSopenharmony_ci * source : buffer to store the content which needed to be calculated
131020a203aSopenharmony_ci * sourceLen : input buffer len
132020a203aSopenharmony_ci * hash : buffer to store output sha1 string
133020a203aSopenharmony_ci * hashLen : output buff len
134020a203aSopenharmony_ci * Return
135020a203aSopenharmony_ci * 0 : successful
136020a203aSopenharmony_ci * x : fail
137020a203aSopenharmony_ci */
138020a203aSopenharmony_ciint CalcFingerprint::CalcBufferSha(unsigned char* source, size_t sourceLen, char *hash, size_t hashLen)
139020a203aSopenharmony_ci{
140020a203aSopenharmony_ci    if (source == nullptr || hash == nullptr || sourceLen == 0) {
141020a203aSopenharmony_ci        return EINVAL;
142020a203aSopenharmony_ci    }
143020a203aSopenharmony_ci    unsigned char value[SHA256_DIGEST_LENGTH] = {0};
144020a203aSopenharmony_ci    SHA256(source, sourceLen, value);
145020a203aSopenharmony_ci    return ConvertToString(value, hash, hashLen);
146020a203aSopenharmony_ci}
147020a203aSopenharmony_ci}
148020a203aSopenharmony_ci}
149