blob: ac4edf480d6589846192cd70318a538a76fa2f8e [file] [log] [blame]
rspangler@google.com49fdf182009-10-10 00:57:34 +00001// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -07005#include "update_engine/omaha_hash_calculator.h"
6
Darin Petkov36a58222010-10-07 22:00:09 -07007#include <fcntl.h>
8
9#include <base/eintr_wrapper.h>
10#include <base/logging.h>
rspangler@google.com49fdf182009-10-10 00:57:34 +000011#include <openssl/bio.h>
12#include <openssl/buffer.h>
13#include <openssl/evp.h>
Darin Petkov36a58222010-10-07 22:00:09 -070014
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070015#include "update_engine/utils.h"
16
17using std::string;
18using std::vector;
rspangler@google.com49fdf182009-10-10 00:57:34 +000019
20namespace chromeos_update_engine {
21
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070022OmahaHashCalculator::OmahaHashCalculator() : valid_(false) {
Darin Petkovd22cb292010-09-29 10:02:29 -070023 valid_ = (SHA256_Init(&ctx_) == 1);
24 LOG_IF(ERROR, !valid_) << "SHA256_Init failed";
rspangler@google.com49fdf182009-10-10 00:57:34 +000025}
26
27// Update is called with all of the data that should be hashed in order.
Darin Petkovd22cb292010-09-29 10:02:29 -070028// Mostly just passes the data through to OpenSSL's SHA256_Update()
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070029bool OmahaHashCalculator::Update(const char* data, size_t length) {
30 TEST_AND_RETURN_FALSE(valid_);
31 TEST_AND_RETURN_FALSE(hash_.empty());
rspangler@google.com49fdf182009-10-10 00:57:34 +000032 COMPILE_ASSERT(sizeof(size_t) <= sizeof(unsigned long),
Darin Petkovd22cb292010-09-29 10:02:29 -070033 length_param_may_be_truncated_in_SHA256_Update);
34 TEST_AND_RETURN_FALSE(SHA256_Update(&ctx_, data, length) == 1);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070035 return true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000036}
37
Darin Petkov36a58222010-10-07 22:00:09 -070038off_t OmahaHashCalculator::UpdateFile(const string& name, off_t length) {
39 int fd = HANDLE_EINTR(open(name.c_str(), O_RDONLY));
40 if (fd < 0) {
41 return -1;
42 }
43
44 const int kBufferSize = 128 * 1024; // 128 KiB
45 vector<char> buffer(kBufferSize);
46 off_t bytes_processed = 0;
47 while (length < 0 || bytes_processed < length) {
48 off_t bytes_to_read = buffer.size();
49 if (length >= 0 && bytes_to_read > length - bytes_processed) {
50 bytes_to_read = length - bytes_processed;
51 }
52 ssize_t rc = HANDLE_EINTR(read(fd, buffer.data(), bytes_to_read));
53 if (rc == 0) { // EOF
54 break;
55 }
56 if (rc < 0 || !Update(buffer.data(), rc)) {
57 bytes_processed = -1;
58 break;
59 }
60 bytes_processed += rc;
61 }
62 HANDLE_EINTR(close(fd));
63 return bytes_processed;
64}
65
rspangler@google.com49fdf182009-10-10 00:57:34 +000066// Call Finalize() when all data has been passed in. This mostly just
Darin Petkovd22cb292010-09-29 10:02:29 -070067// calls OpenSSL's SHA256_Final() and then base64 encodes the hash.
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070068bool OmahaHashCalculator::Finalize() {
69 bool success = true;
70 TEST_AND_RETURN_FALSE(hash_.empty());
Darin Petkovd7061ab2010-10-06 14:37:09 -070071 TEST_AND_RETURN_FALSE(raw_hash_.empty());
72 raw_hash_.resize(SHA256_DIGEST_LENGTH);
73 TEST_AND_RETURN_FALSE(
74 SHA256_Final(reinterpret_cast<unsigned char*>(&raw_hash_[0]),
75 &ctx_) == 1);
rspangler@google.com49fdf182009-10-10 00:57:34 +000076
Darin Petkovd7061ab2010-10-06 14:37:09 -070077 // Convert raw_hash_ to base64 encoding and store it in hash_.
rspangler@google.com49fdf182009-10-10 00:57:34 +000078 BIO *b64 = BIO_new(BIO_f_base64());
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070079 if (!b64)
80 LOG(INFO) << "BIO_new(BIO_f_base64()) failed";
rspangler@google.com49fdf182009-10-10 00:57:34 +000081 BIO *bmem = BIO_new(BIO_s_mem());
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070082 if (!bmem)
83 LOG(INFO) << "BIO_new(BIO_s_mem()) failed";
84 if (b64 && bmem) {
85 b64 = BIO_push(b64, bmem);
Darin Petkovd7061ab2010-10-06 14:37:09 -070086 success =
87 (BIO_write(b64, &raw_hash_[0], raw_hash_.size()) ==
88 static_cast<int>(raw_hash_.size()));
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070089 if (success)
90 success = (BIO_flush(b64) == 1);
rspangler@google.com49fdf182009-10-10 00:57:34 +000091
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070092 BUF_MEM *bptr = NULL;
93 BIO_get_mem_ptr(b64, &bptr);
94 hash_.assign(bptr->data, bptr->length - 1);
95 }
96 if (b64) {
97 BIO_free_all(b64);
98 b64 = NULL;
99 }
100 return success;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000101}
102
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700103bool OmahaHashCalculator::RawHashOfData(const vector<char>& data,
104 vector<char>* out_hash) {
105 OmahaHashCalculator calc;
106 calc.Update(&data[0], data.size());
Darin Petkovd22cb292010-09-29 10:02:29 -0700107
108 out_hash->resize(out_hash->size() + SHA256_DIGEST_LENGTH);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700109 TEST_AND_RETURN_FALSE(
Darin Petkovd22cb292010-09-29 10:02:29 -0700110 SHA256_Final(reinterpret_cast<unsigned char*>(&(*(out_hash->end() -
111 SHA256_DIGEST_LENGTH))),
112 &calc.ctx_) == 1);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700113 return true;
114}
115
Darin Petkov698d0412010-10-13 10:59:44 -0700116off_t OmahaHashCalculator::RawHashOfFile(const std::string& name, off_t length,
117 std::vector<char>* out_hash) {
118 OmahaHashCalculator calc;
119 off_t res = calc.UpdateFile(name, length);
120 if (res < 0) {
121 return res;
122 }
123 if (!calc.Finalize()) {
124 return -1;
125 }
126 *out_hash = calc.raw_hash();
127 return res;
128}
129
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700130string OmahaHashCalculator::OmahaHashOfBytes(
rspangler@google.com49fdf182009-10-10 00:57:34 +0000131 const void* data, size_t length) {
132 OmahaHashCalculator calc;
133 calc.Update(reinterpret_cast<const char*>(data), length);
134 calc.Finalize();
135 return calc.hash();
136}
137
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700138string OmahaHashCalculator::OmahaHashOfString(const string& str) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000139 return OmahaHashOfBytes(str.data(), str.size());
140}
141
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700142string OmahaHashCalculator::OmahaHashOfData(const vector<char>& data) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000143 return OmahaHashOfBytes(&data[0], data.size());
144}
145
Darin Petkov73058b42010-10-06 16:32:19 -0700146string OmahaHashCalculator::GetContext() const {
147 return string(reinterpret_cast<const char*>(&ctx_), sizeof(ctx_));
148}
149
150bool OmahaHashCalculator::SetContext(const std::string& context) {
151 TEST_AND_RETURN_FALSE(context.size() == sizeof(ctx_));
152 memcpy(&ctx_, context.data(), sizeof(ctx_));
153 return true;
154}
155
rspangler@google.com49fdf182009-10-10 00:57:34 +0000156} // namespace chromeos_update_engine