1 /*
2 * Copyright (c) 2023 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 "sha256_utils.h"
17
18 #include <cstdlib>
19 #include <openssl/sha.h>
20 #include <sys/stat.h>
21 #include <sys/statfs.h>
22 #include <unistd.h>
23
24 #include "file_utils.h"
25
26 namespace OHOS {
27 namespace UpdateService {
28 constexpr int OPENSSL_SUCCESS = 1;
29 constexpr unsigned int SHA256_STRING_LEN = 65;
30 constexpr unsigned int SHA256_LENGTH = 32;
31 constexpr unsigned int MAX_BUFFER_LENGTH = 1024;
32 constexpr unsigned int SHA256_TO_STRING_STEP = 2;
33
CalculateHashCode(std::string inputStr)34 std::string Sha256Utils::CalculateHashCode(std::string inputStr)
35 {
36 char result[SHA256_STRING_LEN] = {0};
37 if (!Sha256Calculate(reinterpret_cast<const unsigned char *>(inputStr.c_str()), inputStr.length(),
38 result, SHA256_STRING_LEN)) {
39 ENGINE_LOGE("CalculateHashCode fail, src = %s", inputStr.c_str());
40 return "";
41 }
42 return result;
43 }
44
CheckFileSha256String(const std::string & fileName,const std::string & sha256String)45 bool Sha256Utils::CheckFileSha256String(const std::string &fileName, const std::string &sha256String)
46 {
47 if (!FileUtils::IsFileExist(fileName)) {
48 ENGINE_LOGE("check file sha256 failed, file not exist");
49 return false;
50 }
51 char sha256Result[SHA256_STRING_LEN] = {0}; // sha256Result len is 65
52 if (!GetFileSha256Str(fileName, sha256Result, sizeof(sha256Result))) {
53 ENGINE_LOGE("get file sha256 failed");
54 return false;
55 }
56 if (strcasecmp(sha256Result, sha256String.c_str()) != 0) {
57 ENGINE_LOGE("sha256 not same! input=%{public}s, cal=%{public}s", sha256Result, sha256String.c_str());
58 return false;
59 }
60 return true;
61 }
62
FreeBuffer(char * buffer,std::ifstream & file)63 void Sha256Utils::FreeBuffer(char *buffer, std::ifstream &file)
64 {
65 if (buffer != nullptr) {
66 free(buffer);
67 }
68
69 if (file.is_open()) {
70 file.close();
71 }
72 }
73
GetDigestFromFile(const char * fileName,unsigned char digest[])74 bool Sha256Utils::GetDigestFromFile(const char *fileName, unsigned char digest[])
75 {
76 char realPath[PATH_MAX] = {};
77 if (realpath(fileName, realPath) == NULL) {
78 ENGINE_LOGI("file not exist or invalid");
79 return false;
80 }
81
82 std::ifstream file(realPath, std::ios::binary);
83 if (!file.is_open()) {
84 ENGINE_LOGI("%{private}s Unable to open file", realPath);
85 return false;
86 }
87
88 char *buffer = (char *)malloc(MAX_BUFFER_LENGTH); /* buffer len 1024 */
89 if (buffer == nullptr) {
90 ENGINE_LOGI("failed to allocate memory");
91 file.close();
92 return false;
93 }
94 SHA256_CTX sha256;
95 int32_t startRet = SHA256_Init(&sha256);
96 if (startRet != OPENSSL_SUCCESS) {
97 ENGINE_LOGE("SHA256_init_ret failed, startRet = %{public}d", startRet);
98 FreeBuffer(buffer, file);
99 return false;
100 }
101
102 while (!file.eof()) {
103 file.read(buffer, MAX_BUFFER_LENGTH);
104 int32_t updateRet = SHA256_Update(&sha256, buffer, file.gcount());
105 if (updateRet != OPENSSL_SUCCESS) {
106 ENGINE_LOGE("SHA256_update_ret failed, updateRet = %{public}d", updateRet);
107 FreeBuffer(buffer, file);
108 return false;
109 }
110 }
111 int32_t finishRet = SHA256_Final(digest, &sha256);
112 if (finishRet != OPENSSL_SUCCESS) {
113 ENGINE_LOGE("SHA256_finish_ret failed, finishRet = %{public}d", finishRet);
114 FreeBuffer(buffer, file);
115 return false;
116 }
117 FreeBuffer(buffer, file);
118 return true;
119 }
120
GetFileSha256Str(const std::string & fileName,char * sha256Result,uint32_t len)121 bool Sha256Utils::GetFileSha256Str(const std::string &fileName, char *sha256Result, uint32_t len)
122 {
123 unsigned char digest[SHA256_LENGTH] = {0};
124 GetDigestFromFile(fileName.c_str(), digest);
125 return TransDigestToSha256Result(sha256Result, len, digest);
126 }
127
Sha256Calculate(const unsigned char * input,size_t len,char * componentId,unsigned int componentIdLen)128 bool Sha256Utils::Sha256Calculate(const unsigned char *input, size_t len, char *componentId,
129 unsigned int componentIdLen)
130 {
131 unsigned char digest[SHA256_LENGTH] = {0};
132 SHA256_CTX ctx;
133 int ret = memset_s(&ctx, sizeof(ctx), 0, sizeof(ctx));
134 if (ret != 0) {
135 ENGINE_LOGE("init sha256_context failed");
136 return false;
137 }
138 int startRet = SHA256_Init(&ctx);
139 if (startRet != OPENSSL_SUCCESS) {
140 ENGINE_LOGE("SHA256_Init failed, startRet = %{public}d", startRet);
141 return false;
142 }
143
144 int updateRet = SHA256_Update(&ctx, input, len);
145 if (updateRet != OPENSSL_SUCCESS) {
146 ENGINE_LOGE("SHA256_Update failed, updateRet = %{public}d", updateRet);
147 return false;
148 }
149
150 int finishRet = SHA256_Final(digest, &ctx);
151 if (finishRet != OPENSSL_SUCCESS) {
152 ENGINE_LOGE("SHA256_Final failed, finishRet = %{public}d", finishRet);
153 return false;
154 }
155
156 return TransDigestToSha256Result(componentId, componentIdLen, digest);
157 }
158
TransDigestToSha256Result(char * sha256Result,uint32_t componentIdLen,const unsigned char * digest)159 bool Sha256Utils::TransDigestToSha256Result(char *sha256Result, uint32_t componentIdLen, const unsigned char *digest)
160 {
161 for (unsigned int i = 0; i < SHA256_LENGTH; i++) {
162 unsigned int deviation = i * SHA256_TO_STRING_STEP;
163 if (deviation >= componentIdLen) {
164 ENGINE_LOGE("deviation len illegal");
165 return false;
166 }
167 int result = sprintf_s(sha256Result + deviation, (componentIdLen - deviation), "%02x", digest[i]);
168 if (result <= 0) {
169 ENGINE_LOGE("generated sha256 failed");
170 return false;
171 }
172 }
173 return true;
174 }
175 } // namespace UpdateService
176 } // namespace OHOS