1 // Copyright 2017 The Fuchsia 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
5 #include <digest/digest.h>
6
7 #include <ctype.h>
8 #include <limits.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #include <fbl/alloc_checker.h>
13 #include <fbl/unique_ptr.h>
14 #include <zircon/assert.h>
15 #include <zircon/errors.h>
16
17 // See note in //zircon/third_party/ulib/uboringssl/rules.mk
18 #define BORINGSSL_NO_CXX
19 #include <openssl/sha.h>
20
21 #include <utility>
22
23 namespace digest {
24
25 // The previously opaque crypto implementation context.
26 struct Digest::Context {
Contextdigest::Digest::Context27 Context() {}
~Contextdigest::Digest::Context28 ~Context() {}
29 SHA256_CTX impl;
30 };
31
Digest()32 Digest::Digest() : bytes_{0} {}
33
Digest(const uint8_t * other)34 Digest::Digest(const uint8_t* other) : bytes_{0} {
35 *this = other;
36 }
37
~Digest()38 Digest::~Digest() {
39 ZX_DEBUG_ASSERT(ref_count_ == 0);
40 }
41
Digest(Digest && o)42 Digest::Digest(Digest&& o) {
43 ZX_DEBUG_ASSERT(o.ref_count_ == 0);
44 ctx_ = std::move(o.ctx_);
45 memcpy(bytes_, o.bytes_, kLength);
46 memset(o.bytes_, 0, kLength);
47 }
48
operator =(Digest && o)49 Digest& Digest::operator=(Digest&& o) {
50 ZX_DEBUG_ASSERT(o.ref_count_ == 0);
51 ZX_DEBUG_ASSERT(ref_count_ == 0);
52 memcpy(bytes_, o.bytes_, kLength);
53 return *this;
54 }
55
operator =(const uint8_t * rhs)56 Digest& Digest::operator=(const uint8_t* rhs) {
57 ZX_DEBUG_ASSERT(ref_count_ == 0);
58 memcpy(bytes_, rhs, kLength);
59 return *this;
60 }
61
Init()62 zx_status_t Digest::Init() {
63 ZX_DEBUG_ASSERT(ref_count_ == 0);
64 fbl::AllocChecker ac;
65 ctx_.reset(new (&ac) Context());
66 if (!ac.check()) {
67 return ZX_ERR_NO_MEMORY;
68 }
69 SHA256_Init(&ctx_->impl);
70 return ZX_OK;
71 }
72
Update(const void * buf,size_t len)73 void Digest::Update(const void* buf, size_t len) {
74 ZX_DEBUG_ASSERT(ref_count_ == 0);
75 ZX_DEBUG_ASSERT(len <= INT_MAX);
76 ZX_DEBUG_ASSERT(ctx_ != nullptr);
77 SHA256_Update(&ctx_->impl, buf, len);
78 }
79
Final()80 const uint8_t* Digest::Final() {
81 ZX_DEBUG_ASSERT(ref_count_ == 0);
82 ZX_DEBUG_ASSERT(ctx_ != nullptr);
83 SHA256_Final(bytes_, &ctx_->impl);
84 return bytes_;
85 }
86
Hash(const void * buf,size_t len)87 const uint8_t* Digest::Hash(const void* buf, size_t len) {
88 Init();
89 Update(buf, len);
90 return Final();
91 }
92
Parse(const char * hex,size_t len)93 zx_status_t Digest::Parse(const char* hex, size_t len) {
94 ZX_DEBUG_ASSERT(ref_count_ == 0);
95 if (len < sizeof(bytes_) * 2) {
96 return ZX_ERR_INVALID_ARGS;
97 }
98 uint8_t c = 0;
99 size_t i = 0;
100 for (size_t j = 0; j < sizeof(bytes_) * 2; ++j) {
101 c = static_cast<uint8_t>(toupper(hex[j]) & 0xFF);
102 if (!isxdigit(c)) {
103 return ZX_ERR_INVALID_ARGS;
104 }
105 c = static_cast<uint8_t>(c < 'A' ? c - '0' : c - '7'); // '7' = 'A' - 10
106 if (j % 2 == 0) {
107 bytes_[i] = static_cast<uint8_t>(c << 4);
108 } else {
109 bytes_[i++] |= c;
110 }
111 }
112 return ZX_OK;
113 }
114
ToString(char * out,size_t len) const115 zx_status_t Digest::ToString(char* out, size_t len) const {
116 if (len < sizeof(bytes_) * 2 + 1) {
117 return ZX_ERR_BUFFER_TOO_SMALL;
118 }
119 memset(out, 0, len);
120 char* p = out;
121 for (size_t i = 0; i < sizeof(bytes_); ++i) {
122 sprintf(p, "%02x", bytes_[i]);
123 p += 2;
124 }
125 return ZX_OK;
126 }
127
CopyTo(uint8_t * out,size_t len) const128 zx_status_t Digest::CopyTo(uint8_t* out, size_t len) const {
129 if (len < sizeof(bytes_)) {
130 return ZX_ERR_BUFFER_TOO_SMALL;
131 }
132 memset(out, 0, len);
133 memcpy(out, bytes_, sizeof(bytes_));
134 return ZX_OK;
135 }
136
AcquireBytes() const137 const uint8_t* Digest::AcquireBytes() const {
138 ZX_DEBUG_ASSERT(ref_count_ < SIZE_MAX);
139 ++ref_count_;
140 return bytes_;
141 }
142
ReleaseBytes() const143 void Digest::ReleaseBytes() const {
144 ZX_DEBUG_ASSERT(ref_count_ > 0);
145 --ref_count_;
146 }
147
operator ==(const Digest & rhs) const148 bool Digest::operator==(const Digest& rhs) const {
149 return memcmp(bytes_, rhs.bytes_, kLength) == 0;
150 }
151
operator !=(const Digest & rhs) const152 bool Digest::operator!=(const Digest& rhs) const {
153 return !(*this == rhs);
154 }
155
operator ==(const uint8_t * rhs) const156 bool Digest::operator==(const uint8_t* rhs) const {
157 return rhs ? memcmp(bytes_, rhs, kLength) == 0 : false;
158 }
159
operator !=(const uint8_t * rhs) const160 bool Digest::operator!=(const uint8_t* rhs) const {
161 return !(*this == rhs);
162 }
163
164 } // namespace digest
165
166 using digest::Digest;
167
168 // C-style wrapper functions
169 struct digest_t {
170 Digest obj;
171 };
172
digest_init(digest_t ** out)173 zx_status_t digest_init(digest_t** out) {
174 fbl::AllocChecker ac;
175 fbl::unique_ptr<digest_t> uptr(new (&ac) digest_t);
176 if (!ac.check()) {
177 return ZX_ERR_NO_MEMORY;
178 }
179 uptr->obj.Init();
180 *out = uptr.release();
181 return ZX_OK;
182 }
183
digest_update(digest_t * digest,const void * buf,size_t len)184 void digest_update(digest_t* digest, const void* buf, size_t len) {
185 digest->obj.Update(buf, len);
186 }
187
digest_final(digest_t * digest,void * out,size_t out_len)188 zx_status_t digest_final(digest_t* digest, void* out, size_t out_len) {
189 fbl::unique_ptr<digest_t> uptr(digest);
190 uptr->obj.Final();
191 return uptr->obj.CopyTo(static_cast<uint8_t*>(out), out_len);
192 }
193
digest_hash(const void * buf,size_t len,void * out,size_t out_len)194 zx_status_t digest_hash(const void* buf, size_t len, void* out, size_t out_len) {
195 Digest digest;
196 digest.Hash(buf, len);
197 return digest.CopyTo(static_cast<uint8_t*>(out), out_len);
198 }
199