blob: de70d10631bc07852fe815b45e4f136d7fb77a8a [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
Andrew de los Reyes89f17be2010-10-22 13:39:09 -070066bool OmahaHashCalculator::Base64Encode(const void* data,
67 size_t size,
68 string* out) {
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070069 bool success = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000070 BIO *b64 = BIO_new(BIO_f_base64());
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070071 if (!b64)
72 LOG(INFO) << "BIO_new(BIO_f_base64()) failed";
rspangler@google.com49fdf182009-10-10 00:57:34 +000073 BIO *bmem = BIO_new(BIO_s_mem());
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070074 if (!bmem)
75 LOG(INFO) << "BIO_new(BIO_s_mem()) failed";
76 if (b64 && bmem) {
77 b64 = BIO_push(b64, bmem);
Darin Petkovd7061ab2010-10-06 14:37:09 -070078 success =
Andrew de los Reyes89f17be2010-10-22 13:39:09 -070079 (BIO_write(b64, data, size) == static_cast<int>(size));
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070080 if (success)
81 success = (BIO_flush(b64) == 1);
rspangler@google.com49fdf182009-10-10 00:57:34 +000082
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070083 BUF_MEM *bptr = NULL;
84 BIO_get_mem_ptr(b64, &bptr);
Andrew de los Reyes89f17be2010-10-22 13:39:09 -070085 out->assign(bptr->data, bptr->length - 1);
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -070086 }
87 if (b64) {
88 BIO_free_all(b64);
89 b64 = NULL;
90 }
91 return success;
rspangler@google.com49fdf182009-10-10 00:57:34 +000092}
93
Andrew de los Reyes89f17be2010-10-22 13:39:09 -070094// Call Finalize() when all data has been passed in. This mostly just
95// calls OpenSSL's SHA256_Final() and then base64 encodes the hash.
96bool OmahaHashCalculator::Finalize() {
97 TEST_AND_RETURN_FALSE(hash_.empty());
98 TEST_AND_RETURN_FALSE(raw_hash_.empty());
99 raw_hash_.resize(SHA256_DIGEST_LENGTH);
100 TEST_AND_RETURN_FALSE(
101 SHA256_Final(reinterpret_cast<unsigned char*>(&raw_hash_[0]),
102 &ctx_) == 1);
103
104 // Convert raw_hash_ to base64 encoding and store it in hash_.
105 return Base64Encode(&raw_hash_[0], raw_hash_.size(), &hash_);;
106}
107
Darin Petkovadb3cef2011-01-13 16:16:08 -0800108bool OmahaHashCalculator::RawHashOfBytes(const char* data,
109 size_t length,
110 vector<char>* out_hash) {
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700111 OmahaHashCalculator calc;
Darin Petkovadb3cef2011-01-13 16:16:08 -0800112 TEST_AND_RETURN_FALSE(calc.Update(data, length));
113 TEST_AND_RETURN_FALSE(calc.Finalize());
114 *out_hash = calc.raw_hash();
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700115 return true;
116}
117
Darin Petkovadb3cef2011-01-13 16:16:08 -0800118bool OmahaHashCalculator::RawHashOfData(const vector<char>& data,
119 vector<char>* out_hash) {
120 return RawHashOfBytes(data.data(), data.size(), out_hash);
121}
122
123off_t OmahaHashCalculator::RawHashOfFile(const string& name, off_t length,
124 vector<char>* out_hash) {
Darin Petkov698d0412010-10-13 10:59:44 -0700125 OmahaHashCalculator calc;
126 off_t res = calc.UpdateFile(name, length);
127 if (res < 0) {
128 return res;
129 }
130 if (!calc.Finalize()) {
131 return -1;
132 }
133 *out_hash = calc.raw_hash();
134 return res;
135}
136
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700137string OmahaHashCalculator::OmahaHashOfBytes(
rspangler@google.com49fdf182009-10-10 00:57:34 +0000138 const void* data, size_t length) {
139 OmahaHashCalculator calc;
140 calc.Update(reinterpret_cast<const char*>(data), length);
141 calc.Finalize();
142 return calc.hash();
143}
144
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700145string OmahaHashCalculator::OmahaHashOfString(const string& str) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000146 return OmahaHashOfBytes(str.data(), str.size());
147}
148
Andrew de los Reyes932bc4c2010-08-23 18:14:09 -0700149string OmahaHashCalculator::OmahaHashOfData(const vector<char>& data) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000150 return OmahaHashOfBytes(&data[0], data.size());
151}
152
Darin Petkov73058b42010-10-06 16:32:19 -0700153string OmahaHashCalculator::GetContext() const {
154 return string(reinterpret_cast<const char*>(&ctx_), sizeof(ctx_));
155}
156
157bool OmahaHashCalculator::SetContext(const std::string& context) {
158 TEST_AND_RETURN_FALSE(context.size() == sizeof(ctx_));
159 memcpy(&ctx_, context.data(), sizeof(ctx_));
160 return true;
161}
162
rspangler@google.com49fdf182009-10-10 00:57:34 +0000163} // namespace chromeos_update_engine