blob: a1d64d25e5c4c139c33ace9193a270d8cdbb03c8 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <zircon/assert.h>
#include <zircon/errors.h>
#include <memory>
#include <digest/digest.h>
#include <fbl/alloc_checker.h>
#include <fbl/string.h>
// See note in //zircon/third_party/ulib/uboringssl/rules.mk
#define BORINGSSL_NO_CXX
#include <utility>
#include <openssl/sha.h>
namespace digest {
// The previously opaque crypto implementation context.
struct Digest::Context {
Context() {}
~Context() {}
SHA256_CTX impl;
};
Digest::Digest() : bytes_{0} {}
Digest::Digest(const uint8_t* other) : bytes_{0} { *this = other; }
Digest::Digest(Digest&& o) {
ctx_ = std::move(o.ctx_);
memcpy(bytes_, o.bytes_, sizeof(bytes_));
memset(o.bytes_, 0, sizeof(o.bytes_));
}
Digest::~Digest() {}
Digest& Digest::operator=(Digest&& o) {
memcpy(bytes_, o.bytes_, sizeof(bytes_));
return *this;
}
Digest& Digest::operator=(const uint8_t* rhs) {
memcpy(bytes_, rhs, sizeof(bytes_));
return *this;
}
zx_status_t Digest::Init() {
fbl::AllocChecker ac;
ctx_.reset(new (&ac) Context());
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
SHA256_Init(&ctx_->impl);
return ZX_OK;
}
void Digest::Update(const void* buf, size_t len) {
ZX_DEBUG_ASSERT(len <= INT_MAX);
ZX_DEBUG_ASSERT(ctx_ != nullptr);
SHA256_Update(&ctx_->impl, buf, len);
}
const uint8_t* Digest::Final() {
ZX_DEBUG_ASSERT(ctx_ != nullptr);
SHA256_Final(bytes_, &ctx_->impl);
return bytes_;
}
const uint8_t* Digest::Hash(const void* buf, size_t len) {
Init();
Update(buf, len);
return Final();
}
zx_status_t Digest::Parse(const char* hex, size_t len) {
if (len != sizeof(bytes_) * 2) {
return ZX_ERR_INVALID_ARGS;
}
size_t i = 0;
for (size_t j = 0; j < sizeof(bytes_) * 2; ++j) {
int c = toupper(hex[j]);
if (!isxdigit(c)) {
return ZX_ERR_INVALID_ARGS;
}
c = c < 'A' ? c - '0' : c - '7'; // '7' = 'A' - 10
if (j % 2 == 0) {
bytes_[i] = static_cast<uint8_t>(c << 4);
} else {
bytes_[i++] |= static_cast<uint8_t>(c);
}
}
return ZX_OK;
}
fbl::String Digest::ToString() const {
char hex[kSha256HexLength];
char* p = hex;
for (size_t i = 0; i < sizeof(bytes_); ++i) {
sprintf(p, "%02x", bytes_[i]);
p += 2;
}
return fbl::String(hex);
}
zx_status_t Digest::CopyTo(uint8_t* out, size_t len) const {
if (len < sizeof(bytes_)) {
return ZX_ERR_BUFFER_TOO_SMALL;
}
memset(out, 0, len);
memcpy(out, bytes_, sizeof(bytes_));
return ZX_OK;
}
bool Digest::operator==(const Digest& rhs) const {
return memcmp(bytes_, rhs.bytes_, sizeof(bytes_)) == 0;
}
bool Digest::operator!=(const Digest& rhs) const { return !(*this == rhs); }
bool Digest::operator==(const uint8_t* rhs) const {
return rhs ? memcmp(bytes_, rhs, sizeof(bytes_)) == 0 : false;
}
bool Digest::operator!=(const uint8_t* rhs) const { return !(*this == rhs); }
} // namespace digest