1/*
2 * Copyright (c) 2022 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#include "calc_fingerprint.h"
16
17#include <securec.h>
18
19#include "common_defines.h"
20#include "file_util.h"
21
22using namespace std;
23namespace OHOS {
24namespace HiviewDFX {
25DEFINE_LOG_TAG("CalcFingerprint");
26int CalcFingerprint::ConvertToString(const unsigned char hash[SHA256_DIGEST_LENGTH], char *outstr, size_t len)
27{
28    uint32_t i;
29    char *outHash = outstr;
30
31    if (hash == nullptr || outHash == nullptr) {
32        return EINVAL;
33    }
34    constexpr int charsEachHex = 2;
35    if (len < (SHA256_DIGEST_LENGTH * charsEachHex + 1)) { // 1: add '\0'
36        return ENOMEM;
37    }
38    for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
39        int err = snprintf_s(outHash, charsEachHex + 1, charsEachHex, "%02x", hash[i]);
40        if (err < 0) {
41            return err;
42        }
43        outHash += charsEachHex;
44    }
45    *outHash = '\0';
46    return 0;
47}
48
49/*
50 * API name : calc_file_sha1
51 * Description : calculate a file sha1 hash for given file
52 * Input parameters
53 * filePath : path of the file to be calculated
54 * hash      : buffer to store output sha1 string
55 * Return
56 * 0 : successful
57 * x : fail
58 */
59int CalcFingerprint::CalcFileSha(const string& filePath, char *hash, size_t len)
60{
61    if (filePath.empty() || hash == nullptr || !FileUtil::IsLegalPath(filePath)) {
62        HIVIEW_LOGE("invalid param.");
63        return EINVAL;
64    }
65    unsigned char value[SHA256_DIGEST_LENGTH] = {0};
66    int ret = CalcFileShaOriginal(filePath, value, len);
67    if (ret != 0) {
68        HIVIEW_LOGE("CalcFileShaOriginal failed.");
69        return ret;
70    }
71    return ConvertToString(value, hash, len);
72}
73
74int CalcFingerprint::CalcFileShaOriginal(const string& filePath, unsigned char *hash, size_t len)
75{
76    if (filePath.empty() || hash == nullptr || !FileUtil::IsLegalPath(filePath)) {
77        HIVIEW_LOGE("file is invalid.");
78        return EINVAL;
79    }
80
81    if (len < SHA256_DIGEST_LENGTH) {
82        HIVIEW_LOGE("hash buf len error.");
83        return ENOMEM;
84    }
85
86    FILE *fp = nullptr;
87    fp = fopen(filePath.c_str(), "rb");
88    if (fp == nullptr) {
89        HIVIEW_LOGE("open file failed.");
90        return errno; // if file not exist, errno will be ENOENT
91    }
92
93    size_t n;
94    char buffer[HASH_BUFFER_SIZE] = {0};
95    SHA256_CTX ctx;
96    SHA256_Init(&ctx);
97    while ((n = fread(buffer, 1, sizeof(buffer), fp))) {
98        SHA256_Update(&ctx, (unsigned char *)buffer, n);
99    }
100    if (fclose(fp)) {
101        HIVIEW_LOGE("fclose is failed");
102    }
103    fp = nullptr;
104    SHA256_Final(hash, &ctx);
105    return 0;
106}
107
108/*
109 * API name : calc_buffer_sha1
110 * Description : calculate a buffer sha1 hash for given buffer
111 * Input parameters
112 * buffer : buffer to store the content which needed to be calculated
113 * hash_str   : buffer to store output sha1 string
114 * Return
115 * 0 : successful
116 * x : fail
117 */
118int CalcFingerprint::CalcBufferSha(const string& buffer, size_t bufSize, char *hash, size_t len)
119{
120    if (buffer.empty()) {
121        return EINVAL;
122    }
123    return CalcBufferSha((unsigned char *)buffer.c_str(), bufSize, hash, len);
124}
125
126/*
127 * API name : calc_buffer_sha1
128 * Description : calculate a buffer sha1 hash for given buffer
129 * Input parameters
130 * source : buffer to store the content which needed to be calculated
131 * sourceLen : input buffer len
132 * hash : buffer to store output sha1 string
133 * hashLen : output buff len
134 * Return
135 * 0 : successful
136 * x : fail
137 */
138int CalcFingerprint::CalcBufferSha(unsigned char* source, size_t sourceLen, char *hash, size_t hashLen)
139{
140    if (source == nullptr || hash == nullptr || sourceLen == 0) {
141        return EINVAL;
142    }
143    unsigned char value[SHA256_DIGEST_LENGTH] = {0};
144    SHA256(source, sourceLen, value);
145    return ConvertToString(value, hash, hashLen);
146}
147}
148}
149