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