xref: /aosp_15_r20/system/update_engine/common/hash_calculator.cc (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
1*5a923131SAndroid Build Coastguard Worker //
2*5a923131SAndroid Build Coastguard Worker // Copyright (C) 2009 The Android Open Source Project
3*5a923131SAndroid Build Coastguard Worker //
4*5a923131SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*5a923131SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*5a923131SAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*5a923131SAndroid Build Coastguard Worker //
8*5a923131SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
9*5a923131SAndroid Build Coastguard Worker //
10*5a923131SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*5a923131SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*5a923131SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5a923131SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*5a923131SAndroid Build Coastguard Worker // limitations under the License.
15*5a923131SAndroid Build Coastguard Worker //
16*5a923131SAndroid Build Coastguard Worker 
17*5a923131SAndroid Build Coastguard Worker #include "update_engine/common/hash_calculator.h"
18*5a923131SAndroid Build Coastguard Worker 
19*5a923131SAndroid Build Coastguard Worker #include <fcntl.h>
20*5a923131SAndroid Build Coastguard Worker 
21*5a923131SAndroid Build Coastguard Worker #include <base/logging.h>
22*5a923131SAndroid Build Coastguard Worker #include <base/posix/eintr_wrapper.h>
23*5a923131SAndroid Build Coastguard Worker 
24*5a923131SAndroid Build Coastguard Worker #include "update_engine/common/utils.h"
25*5a923131SAndroid Build Coastguard Worker 
26*5a923131SAndroid Build Coastguard Worker using std::string;
27*5a923131SAndroid Build Coastguard Worker 
28*5a923131SAndroid Build Coastguard Worker namespace chromeos_update_engine {
29*5a923131SAndroid Build Coastguard Worker 
HashCalculator()30*5a923131SAndroid Build Coastguard Worker HashCalculator::HashCalculator() : valid_(false) {
31*5a923131SAndroid Build Coastguard Worker   valid_ = (SHA256_Init(&ctx_) == 1);
32*5a923131SAndroid Build Coastguard Worker   LOG_IF(ERROR, !valid_) << "SHA256_Init failed";
33*5a923131SAndroid Build Coastguard Worker }
34*5a923131SAndroid Build Coastguard Worker 
35*5a923131SAndroid Build Coastguard Worker // Update is called with all of the data that should be hashed in order.
36*5a923131SAndroid Build Coastguard Worker // Mostly just passes the data through to OpenSSL's SHA256_Update()
Update(const void * data,size_t length)37*5a923131SAndroid Build Coastguard Worker bool HashCalculator::Update(const void* data, size_t length) {
38*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(valid_);
39*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(raw_hash_.empty());
40*5a923131SAndroid Build Coastguard Worker   static_assert(sizeof(size_t) <= sizeof(unsigned long),  // NOLINT(runtime/int)
41*5a923131SAndroid Build Coastguard Worker                 "length param may be truncated in SHA256_Update");
42*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(SHA256_Update(&ctx_, data, length) == 1);
43*5a923131SAndroid Build Coastguard Worker   return true;
44*5a923131SAndroid Build Coastguard Worker }
45*5a923131SAndroid Build Coastguard Worker 
UpdateFile(const string & name,off_t length)46*5a923131SAndroid Build Coastguard Worker off_t HashCalculator::UpdateFile(const string& name, off_t length) {
47*5a923131SAndroid Build Coastguard Worker   int fd = HANDLE_EINTR(open(name.c_str(), O_RDONLY));
48*5a923131SAndroid Build Coastguard Worker   if (fd < 0) {
49*5a923131SAndroid Build Coastguard Worker     return -1;
50*5a923131SAndroid Build Coastguard Worker   }
51*5a923131SAndroid Build Coastguard Worker 
52*5a923131SAndroid Build Coastguard Worker   const int kBufferSize = 128 * 1024;  // 128 KiB
53*5a923131SAndroid Build Coastguard Worker   brillo::Blob buffer(kBufferSize);
54*5a923131SAndroid Build Coastguard Worker   off_t bytes_processed = 0;
55*5a923131SAndroid Build Coastguard Worker   while (length < 0 || bytes_processed < length) {
56*5a923131SAndroid Build Coastguard Worker     off_t bytes_to_read = buffer.size();
57*5a923131SAndroid Build Coastguard Worker     if (length >= 0 && bytes_to_read > length - bytes_processed) {
58*5a923131SAndroid Build Coastguard Worker       bytes_to_read = length - bytes_processed;
59*5a923131SAndroid Build Coastguard Worker     }
60*5a923131SAndroid Build Coastguard Worker     ssize_t rc = HANDLE_EINTR(read(fd, buffer.data(), bytes_to_read));
61*5a923131SAndroid Build Coastguard Worker     if (rc == 0) {  // EOF
62*5a923131SAndroid Build Coastguard Worker       break;
63*5a923131SAndroid Build Coastguard Worker     }
64*5a923131SAndroid Build Coastguard Worker     if (rc < 0 || !Update(buffer.data(), rc)) {
65*5a923131SAndroid Build Coastguard Worker       bytes_processed = -1;
66*5a923131SAndroid Build Coastguard Worker       break;
67*5a923131SAndroid Build Coastguard Worker     }
68*5a923131SAndroid Build Coastguard Worker     bytes_processed += rc;
69*5a923131SAndroid Build Coastguard Worker   }
70*5a923131SAndroid Build Coastguard Worker   IGNORE_EINTR(close(fd));
71*5a923131SAndroid Build Coastguard Worker   return bytes_processed;
72*5a923131SAndroid Build Coastguard Worker }
73*5a923131SAndroid Build Coastguard Worker 
74*5a923131SAndroid Build Coastguard Worker // Call Finalize() when all data has been passed in. This mostly just
75*5a923131SAndroid Build Coastguard Worker // calls OpenSSL's SHA256_Final().
Finalize()76*5a923131SAndroid Build Coastguard Worker bool HashCalculator::Finalize() {
77*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(raw_hash_.empty());
78*5a923131SAndroid Build Coastguard Worker   raw_hash_.resize(SHA256_DIGEST_LENGTH);
79*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(SHA256_Final(raw_hash_.data(), &ctx_) == 1);
80*5a923131SAndroid Build Coastguard Worker   return true;
81*5a923131SAndroid Build Coastguard Worker }
82*5a923131SAndroid Build Coastguard Worker 
RawHashOfBytes(const void * data,size_t length,brillo::Blob * out_hash)83*5a923131SAndroid Build Coastguard Worker bool HashCalculator::RawHashOfBytes(const void* data,
84*5a923131SAndroid Build Coastguard Worker                                     size_t length,
85*5a923131SAndroid Build Coastguard Worker                                     brillo::Blob* out_hash) {
86*5a923131SAndroid Build Coastguard Worker   HashCalculator calc;
87*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(calc.Update(data, length));
88*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(calc.Finalize());
89*5a923131SAndroid Build Coastguard Worker   *out_hash = calc.raw_hash();
90*5a923131SAndroid Build Coastguard Worker   return true;
91*5a923131SAndroid Build Coastguard Worker }
92*5a923131SAndroid Build Coastguard Worker 
RawHashOfData(const brillo::Blob & data,brillo::Blob * out_hash)93*5a923131SAndroid Build Coastguard Worker bool HashCalculator::RawHashOfData(const brillo::Blob& data,
94*5a923131SAndroid Build Coastguard Worker                                    brillo::Blob* out_hash) {
95*5a923131SAndroid Build Coastguard Worker   return RawHashOfBytes(data.data(), data.size(), out_hash);
96*5a923131SAndroid Build Coastguard Worker }
97*5a923131SAndroid Build Coastguard Worker 
RawHashOfFile(const string & name,brillo::Blob * out_hash)98*5a923131SAndroid Build Coastguard Worker bool HashCalculator::RawHashOfFile(const string& name, brillo::Blob* out_hash) {
99*5a923131SAndroid Build Coastguard Worker   const auto file_size = utils::FileSize(name);
100*5a923131SAndroid Build Coastguard Worker   return RawHashOfFile(name, file_size, out_hash) == file_size;
101*5a923131SAndroid Build Coastguard Worker }
102*5a923131SAndroid Build Coastguard Worker 
RawHashOfFile(const string & name,off_t length,brillo::Blob * out_hash)103*5a923131SAndroid Build Coastguard Worker off_t HashCalculator::RawHashOfFile(const string& name,
104*5a923131SAndroid Build Coastguard Worker                                     off_t length,
105*5a923131SAndroid Build Coastguard Worker                                     brillo::Blob* out_hash) {
106*5a923131SAndroid Build Coastguard Worker   HashCalculator calc;
107*5a923131SAndroid Build Coastguard Worker   off_t res = calc.UpdateFile(name, length);
108*5a923131SAndroid Build Coastguard Worker   if (res < 0) {
109*5a923131SAndroid Build Coastguard Worker     return res;
110*5a923131SAndroid Build Coastguard Worker   }
111*5a923131SAndroid Build Coastguard Worker   if (!calc.Finalize()) {
112*5a923131SAndroid Build Coastguard Worker     return -1;
113*5a923131SAndroid Build Coastguard Worker   }
114*5a923131SAndroid Build Coastguard Worker   *out_hash = calc.raw_hash();
115*5a923131SAndroid Build Coastguard Worker   return res;
116*5a923131SAndroid Build Coastguard Worker }
117*5a923131SAndroid Build Coastguard Worker 
GetContext() const118*5a923131SAndroid Build Coastguard Worker string HashCalculator::GetContext() const {
119*5a923131SAndroid Build Coastguard Worker   return string(reinterpret_cast<const char*>(&ctx_), sizeof(ctx_));
120*5a923131SAndroid Build Coastguard Worker }
121*5a923131SAndroid Build Coastguard Worker 
SetContext(const string & context)122*5a923131SAndroid Build Coastguard Worker bool HashCalculator::SetContext(const string& context) {
123*5a923131SAndroid Build Coastguard Worker   TEST_AND_RETURN_FALSE(context.size() == sizeof(ctx_));
124*5a923131SAndroid Build Coastguard Worker   memcpy(&ctx_, context.data(), sizeof(ctx_));
125*5a923131SAndroid Build Coastguard Worker   return true;
126*5a923131SAndroid Build Coastguard Worker }
127*5a923131SAndroid Build Coastguard Worker 
SHA256Digest(std::string_view blob)128*5a923131SAndroid Build Coastguard Worker std::string HashCalculator::SHA256Digest(std::string_view blob) {
129*5a923131SAndroid Build Coastguard Worker   std::vector<unsigned char> hash;
130*5a923131SAndroid Build Coastguard Worker   HashCalculator::RawHashOfBytes(blob.data(), blob.size(), &hash);
131*5a923131SAndroid Build Coastguard Worker   return HexEncode(hash);
132*5a923131SAndroid Build Coastguard Worker }
133*5a923131SAndroid Build Coastguard Worker 
SHA256Digest(std::vector<unsigned char> blob)134*5a923131SAndroid Build Coastguard Worker std::string HashCalculator::SHA256Digest(std::vector<unsigned char> blob) {
135*5a923131SAndroid Build Coastguard Worker   return SHA256Digest(ToStringView(blob));
136*5a923131SAndroid Build Coastguard Worker }
137*5a923131SAndroid Build Coastguard Worker 
SHA256Digest(std::vector<char> blob)138*5a923131SAndroid Build Coastguard Worker std::string HashCalculator::SHA256Digest(std::vector<char> blob) {
139*5a923131SAndroid Build Coastguard Worker   return SHA256Digest(ToStringView(blob));
140*5a923131SAndroid Build Coastguard Worker }
141*5a923131SAndroid Build Coastguard Worker 
142*5a923131SAndroid Build Coastguard Worker }  // namespace chromeos_update_engine
143