1 /*
2  * Copyright (c) 2021 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 "hash_file.h"
17 
18 #include <fstream>
19 #include <functional>
20 #include <iomanip>
21 #include <memory>
22 #include <openssl/md5.h>
23 #include <openssl/sha.h>
24 #include <sstream>
25 #include <unistd.h>
26 
27 namespace OHOS {
28 namespace DistributedFS {
29 using namespace std;
30 
HashFinal(int err,const unique_ptr<unsigned char[]> & hashBuf,size_t hashLen)31 static tuple<int, string> HashFinal(int err, const unique_ptr<unsigned char[]> &hashBuf, size_t hashLen)
32 {
33     if (err) {
34         return { err, "" };
35     }
36 
37     stringstream ss;
38     for (size_t i = 0; i < hashLen; ++i) {
39         const int hexPerByte = 2;
40         ss << std::uppercase << std::setfill('0') << std::setw(hexPerByte) << std::hex <<
41             static_cast<uint32_t>(hashBuf[i]);
42     }
43 
44     return { err, ss.str() };
45 }
46 
ForEachFileSegment(const string & fpath,function<void (char *,size_t)> executor)47 static int ForEachFileSegment(const string &fpath, function<void(char *, size_t)> executor)
48 {
49     unique_ptr<FILE, decltype(&fclose)> filp = { fopen(fpath.c_str(), "r"), fclose };
50     if (!filp) {
51         return errno;
52     }
53 
54     const size_t pageSize { getpagesize() };
55     auto buf = make_unique<char[]>(pageSize);
56     size_t actLen;
57     do {
58         actLen = fread(buf.get(), 1, pageSize, filp.get());
59         if (actLen > 0) {
60             executor(buf.get(), actLen);
61         }
62     } while (actLen == pageSize);
63 
64     return ferror(filp.get()) ? errno : 0;
65 }
66 
HashWithMD5(const string & fpath)67 tuple<int, string> HashFile::HashWithMD5(const string &fpath)
68 {
69     auto res = make_unique<unsigned char[]>(MD5_DIGEST_LENGTH);
70     MD5_CTX ctx;
71     MD5_Init(&ctx);
72     auto md5Update = [ctx = &ctx](char *buf, size_t len) {
73         MD5_Update(ctx, buf, len);
74     };
75     int err = ForEachFileSegment(fpath, md5Update);
76     MD5_Final(res.get(), &ctx);
77     return HashFinal(err, res, MD5_DIGEST_LENGTH);
78 }
79 
HashWithSHA1(const string & fpath)80 tuple<int, string> HashFile::HashWithSHA1(const string &fpath)
81 {
82     auto res = make_unique<unsigned char[]>(SHA_DIGEST_LENGTH);
83     SHA_CTX ctx;
84     SHA1_Init(&ctx);
85     auto sha1Update = [ctx = &ctx](char *buf, size_t len) {
86         SHA1_Update(ctx, buf, len);
87     };
88     int err = ForEachFileSegment(fpath, sha1Update);
89     SHA1_Final(res.get(), &ctx);
90     return HashFinal(err, res, SHA_DIGEST_LENGTH);
91 }
92 
HashWithSHA256(const string & fpath)93 tuple<int, string> HashFile::HashWithSHA256(const string &fpath)
94 {
95     auto res = make_unique<unsigned char[]>(SHA256_DIGEST_LENGTH);
96     SHA256_CTX ctx;
97     SHA256_Init(&ctx);
98     auto sha256Update = [ctx = &ctx](char *buf, size_t len) {
99         SHA256_Update(ctx, buf, len);
100     };
101     int err = ForEachFileSegment(fpath, sha256Update);
102     SHA256_Final(res.get(), &ctx);
103     return HashFinal(err, res, SHA256_DIGEST_LENGTH);
104 }
105 } // namespace DistributedFS
106 } // namespace OHOS