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