1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2009 The Android Open Source Project
3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License.
6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at
7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software
11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and
14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License.
15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
1649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com
1739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/hash_calculator.h"
18932bc4c1c271bc1b03da9a1bfe7c37017c58bffaAndrew de los Reyes
1936a582265809cbd04f611704ac9acf944282abf2Darin Petkov#include <fcntl.h>
2036a582265809cbd04f611704ac9acf944282abf2Darin Petkov
2136a582265809cbd04f611704ac9acf944282abf2Darin Petkov#include <base/logging.h>
22fc661a18c07822f1700b870d8435189d5d809f3bChris Sosa#include <base/posix/eintr_wrapper.h>
233f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko#include <brillo/data_encoding.h>
2436a582265809cbd04f611704ac9acf944282abf2Darin Petkov
2539910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/utils.h"
26932bc4c1c271bc1b03da9a1bfe7c37017c58bffaAndrew de los Reyes
27932bc4c1c271bc1b03da9a1bfe7c37017c58bffaAndrew de los Reyesusing std::string;
2849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com
2949fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.comnamespace chromeos_update_engine {
3049fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com
3139910dcd1d68987ccee7c3031dc269233a8490bbAlex DeymoHashCalculator::HashCalculator() : valid_(false) {
32d22cb29c911375cda5d8eb783e78a46680404ca8Darin Petkov  valid_ = (SHA256_Init(&ctx_) == 1);
33d22cb29c911375cda5d8eb783e78a46680404ca8Darin Petkov  LOG_IF(ERROR, !valid_) << "SHA256_Init failed";
3449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com}
3549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com
3649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com// Update is called with all of the data that should be hashed in order.
37d22cb29c911375cda5d8eb783e78a46680404ca8Darin Petkov// Mostly just passes the data through to OpenSSL's SHA256_Update()
3839910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymobool HashCalculator::Update(const void* data, size_t length) {
39932bc4c1c271bc1b03da9a1bfe7c37017c58bffaAndrew de los Reyes  TEST_AND_RETURN_FALSE(valid_);
40932bc4c1c271bc1b03da9a1bfe7c37017c58bffaAndrew de los Reyes  TEST_AND_RETURN_FALSE(hash_.empty());
41d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko  static_assert(sizeof(size_t) <= sizeof(unsigned long),  // NOLINT(runtime/int)
42d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko                "length param may be truncated in SHA256_Update");
43d22cb29c911375cda5d8eb783e78a46680404ca8Darin Petkov  TEST_AND_RETURN_FALSE(SHA256_Update(&ctx_, data, length) == 1);
44932bc4c1c271bc1b03da9a1bfe7c37017c58bffaAndrew de los Reyes  return true;
4549fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com}
4649fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com
4739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymooff_t HashCalculator::UpdateFile(const string& name, off_t length) {
4836a582265809cbd04f611704ac9acf944282abf2Darin Petkov  int fd = HANDLE_EINTR(open(name.c_str(), O_RDONLY));
4936a582265809cbd04f611704ac9acf944282abf2Darin Petkov  if (fd < 0) {
5036a582265809cbd04f611704ac9acf944282abf2Darin Petkov    return -1;
5136a582265809cbd04f611704ac9acf944282abf2Darin Petkov  }
5236a582265809cbd04f611704ac9acf944282abf2Darin Petkov
5336a582265809cbd04f611704ac9acf944282abf2Darin Petkov  const int kBufferSize = 128 * 1024;  // 128 KiB
543f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::Blob buffer(kBufferSize);
5536a582265809cbd04f611704ac9acf944282abf2Darin Petkov  off_t bytes_processed = 0;
5636a582265809cbd04f611704ac9acf944282abf2Darin Petkov  while (length < 0 || bytes_processed < length) {
5736a582265809cbd04f611704ac9acf944282abf2Darin Petkov    off_t bytes_to_read = buffer.size();
5836a582265809cbd04f611704ac9acf944282abf2Darin Petkov    if (length >= 0 && bytes_to_read > length - bytes_processed) {
5936a582265809cbd04f611704ac9acf944282abf2Darin Petkov      bytes_to_read = length - bytes_processed;
6036a582265809cbd04f611704ac9acf944282abf2Darin Petkov    }
6136a582265809cbd04f611704ac9acf944282abf2Darin Petkov    ssize_t rc = HANDLE_EINTR(read(fd, buffer.data(), bytes_to_read));
6236a582265809cbd04f611704ac9acf944282abf2Darin Petkov    if (rc == 0) {  // EOF
6336a582265809cbd04f611704ac9acf944282abf2Darin Petkov      break;
6436a582265809cbd04f611704ac9acf944282abf2Darin Petkov    }
6536a582265809cbd04f611704ac9acf944282abf2Darin Petkov    if (rc < 0 || !Update(buffer.data(), rc)) {
6636a582265809cbd04f611704ac9acf944282abf2Darin Petkov      bytes_processed = -1;
6736a582265809cbd04f611704ac9acf944282abf2Darin Petkov      break;
6836a582265809cbd04f611704ac9acf944282abf2Darin Petkov    }
6936a582265809cbd04f611704ac9acf944282abf2Darin Petkov    bytes_processed += rc;
7036a582265809cbd04f611704ac9acf944282abf2Darin Petkov  }
71bcee2ca34ebcd3b0abc7bc611370d323e55fa62cMike Frysinger  IGNORE_EINTR(close(fd));
7236a582265809cbd04f611704ac9acf944282abf2Darin Petkov  return bytes_processed;
7336a582265809cbd04f611704ac9acf944282abf2Darin Petkov}
7436a582265809cbd04f611704ac9acf944282abf2Darin Petkov
7589f17be356ca0863864552eecca0da15e6f59e2dAndrew de los Reyes// Call Finalize() when all data has been passed in. This mostly just
7689f17be356ca0863864552eecca0da15e6f59e2dAndrew de los Reyes// calls OpenSSL's SHA256_Final() and then base64 encodes the hash.
7739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymobool HashCalculator::Finalize() {
7889f17be356ca0863864552eecca0da15e6f59e2dAndrew de los Reyes  TEST_AND_RETURN_FALSE(hash_.empty());
7989f17be356ca0863864552eecca0da15e6f59e2dAndrew de los Reyes  TEST_AND_RETURN_FALSE(raw_hash_.empty());
8089f17be356ca0863864552eecca0da15e6f59e2dAndrew de los Reyes  raw_hash_.resize(SHA256_DIGEST_LENGTH);
81f68bbbc952aa9a71898e4939b5f36187fa564a50Alex Vakulenko  TEST_AND_RETURN_FALSE(SHA256_Final(raw_hash_.data(), &ctx_) == 1);
8289f17be356ca0863864552eecca0da15e6f59e2dAndrew de los Reyes
8389f17be356ca0863864552eecca0da15e6f59e2dAndrew de los Reyes  // Convert raw_hash_ to base64 encoding and store it in hash_.
843f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  hash_ = brillo::data_encoding::Base64Encode(raw_hash_.data(),
853f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko                                              raw_hash_.size());
86981a9fb68ec5fe56f57b3ecb117a0dc681bf5e83Alex Vakulenko  return true;
8789f17be356ca0863864552eecca0da15e6f59e2dAndrew de los Reyes}
8889f17be356ca0863864552eecca0da15e6f59e2dAndrew de los Reyes
8939910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymobool HashCalculator::RawHashOfBytes(const void* data,
9039910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo                                    size_t length,
9139910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo                                    brillo::Blob* out_hash) {
9239910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo  HashCalculator calc;
93adb3cefe62339cfad34b5c6738dec0bc3ab3261eDarin Petkov  TEST_AND_RETURN_FALSE(calc.Update(data, length));
94adb3cefe62339cfad34b5c6738dec0bc3ab3261eDarin Petkov  TEST_AND_RETURN_FALSE(calc.Finalize());
95adb3cefe62339cfad34b5c6738dec0bc3ab3261eDarin Petkov  *out_hash = calc.raw_hash();
96932bc4c1c271bc1b03da9a1bfe7c37017c58bffaAndrew de los Reyes  return true;
9749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com}
9849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com
9939910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymobool HashCalculator::RawHashOfData(const brillo::Blob& data,
10039910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo                                   brillo::Blob* out_hash) {
101adb3cefe62339cfad34b5c6738dec0bc3ab3261eDarin Petkov  return RawHashOfBytes(data.data(), data.size(), out_hash);
102adb3cefe62339cfad34b5c6738dec0bc3ab3261eDarin Petkov}
103adb3cefe62339cfad34b5c6738dec0bc3ab3261eDarin Petkov
10439910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymooff_t HashCalculator::RawHashOfFile(const string& name, off_t length,
10539910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo                                    brillo::Blob* out_hash) {
10639910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo  HashCalculator calc;
107698d04196deec8374ff148291db0afc7fec9cdccDarin Petkov  off_t res = calc.UpdateFile(name, length);
108698d04196deec8374ff148291db0afc7fec9cdccDarin Petkov  if (res < 0) {
109698d04196deec8374ff148291db0afc7fec9cdccDarin Petkov    return res;
110698d04196deec8374ff148291db0afc7fec9cdccDarin Petkov  }
111698d04196deec8374ff148291db0afc7fec9cdccDarin Petkov  if (!calc.Finalize()) {
112698d04196deec8374ff148291db0afc7fec9cdccDarin Petkov    return -1;
113698d04196deec8374ff148291db0afc7fec9cdccDarin Petkov  }
114698d04196deec8374ff148291db0afc7fec9cdccDarin Petkov  *out_hash = calc.raw_hash();
115698d04196deec8374ff148291db0afc7fec9cdccDarin Petkov  return res;
116698d04196deec8374ff148291db0afc7fec9cdccDarin Petkov}
117698d04196deec8374ff148291db0afc7fec9cdccDarin Petkov
11839910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymostring HashCalculator::HashOfBytes(const void* data, size_t length) {
11939910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo  HashCalculator calc;
120f68bbbc952aa9a71898e4939b5f36187fa564a50Alex Vakulenko  calc.Update(data, length);
12149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com  calc.Finalize();
12249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com  return calc.hash();
12349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com}
12449fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com
12539910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymostring HashCalculator::HashOfString(const string& str) {
12639910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo  return HashOfBytes(str.data(), str.size());
12749fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com}
12849fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com
12939910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymostring HashCalculator::HashOfData(const brillo::Blob& data) {
13039910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo  return HashOfBytes(data.data(), data.size());
13149fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com}
13249fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com
13339910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymostring HashCalculator::GetContext() const {
13473058b421f91e04cc605c2a113e0010009a63594Darin Petkov  return string(reinterpret_cast<const char*>(&ctx_), sizeof(ctx_));
13573058b421f91e04cc605c2a113e0010009a63594Darin Petkov}
13673058b421f91e04cc605c2a113e0010009a63594Darin Petkov
13739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymobool HashCalculator::SetContext(const string& context) {
13873058b421f91e04cc605c2a113e0010009a63594Darin Petkov  TEST_AND_RETURN_FALSE(context.size() == sizeof(ctx_));
13973058b421f91e04cc605c2a113e0010009a63594Darin Petkov  memcpy(&ctx_, context.data(), sizeof(ctx_));
14073058b421f91e04cc605c2a113e0010009a63594Darin Petkov  return true;
14173058b421f91e04cc605c2a113e0010009a63594Darin Petkov}
14273058b421f91e04cc605c2a113e0010009a63594Darin Petkov
14349fdf1889b965be25f929eeebc5b60cd40b9043rspangler@google.com}  // namespace chromeos_update_engine
144