blob: 1523286000305df6c33d3b6981bd7a9b1da12af4 [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 <stddef.h>
#include <stdint.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <memory>
#include <ostream>
#include <fbl/string.h>
namespace digest {
// The length (in bytes) of a SHA256 hash.
constexpr size_t kSha256Length = 32;
// The length (in characters) of a stringified SHA256 hash. Does not include room for a
// null-terminator character.
constexpr size_t kSha256HexLength = (kSha256Length * 2);
// This class represents a digest produced by a hash algorithm.
// This class is not thread safe.
class Digest final {
explicit Digest(const uint8_t (&bytes)[kSha256Length]);
Digest(Digest&& other);
Digest& operator=(const uint8_t (&bytes)[kSha256Length]);
Digest& operator=(Digest&& other);
// Copying a digest copies the digest bytes but can not be used for incrementally adding to
// the digest. The copy constructor/assignment code will assert if the source object is not
// finalized.
Digest(const Digest& other);
Digest& operator=(const Digest& other);
const uint8_t* get() const { return bytes_; }
constexpr size_t len() const { return sizeof(bytes_); }
// Initializes the hash algorithm context. It must be called before Update,
// and after Final when reusing the Digest object.
void Init();
// Adds data to be hashed. This may be called multiple times between calls
// to |Init| and |Final|. If A and B are byte sequences of length A_len and
// B_len, respectively, and AB is the concatenation of A and B, then
// "Update(A, A_len); Update(B, B_len);" and "Update(AB, A_len + B_len)"
// yield the same internal state and will produce the same digest when
// |Final| is called.
void Update(const void* data, size_t len);
// Completes the hash algorithm and returns the digest. This must only be
// called after a call to |Init|; intervening calls to |Update| are
// optional.
const uint8_t* Final();
// This convenience method performs the hash algorithm in "one shot": It
// calls |Init| and |Update(data, len)| before returning the result of
// calling |Final|.
const uint8_t* Hash(const void* data, size_t len);
// Converts a null-terminated |hex| string to binary and stores it in this
// object. |hex| must represent |kLength| bytes, that is, it must have
// |kLength| * 2 characters.
zx_status_t Parse(const char* hex, size_t len);
zx_status_t Parse(const char* hex) { return Parse(hex, strlen(hex)); }
zx_status_t Parse(const fbl::String& hex) { return Parse(hex.c_str(), hex.length()); }
// Returns the current digest as a hex string.
fbl::String ToString() const;
// Writes digest to |out|.
void CopyTo(uint8_t (&out)[kSha256Length]) const { CopyTo(out, kSha256Length); }
// Write digest to |out|. |len| must be at least |kSha256Length|; if it is
// greater, the remainder of |out| is filled with zeros.
void CopyTo(uint8_t* out, size_t len) const;
// Like |CopyTo(out, len)|, but only writes the first |len| bytes of the digest to |out| if |len|
// is less than |kSha256Length|.
void CopyTruncatedTo(uint8_t* out, size_t len) const;
// Equality operators. Those that take |const uint8_t *| arguments will
// read |kLength| bytes; callers MUST ensure there are sufficient bytes
// present.
bool Equals(const uint8_t* rhs, size_t rhs_len) const;
bool operator==(const Digest& rhs) const { return Equals(rhs.bytes_, kSha256Length); }
bool operator!=(const Digest& rhs) const { return !Equals(rhs.bytes_, kSha256Length); }
bool operator==(const uint8_t (&rhs)[kSha256Length]) const { return Equals(rhs, kSha256Length); }
bool operator!=(const uint8_t (&rhs)[kSha256Length]) const { return !Equals(rhs, kSha256Length); }
// Allow a digest to be used in a map.
bool operator<(const Digest& rhs) const { return memcmp(bytes_, rhs.bytes_, kSha256Length) < 0; }
// Opaque crypto implementation context.
struct Context;
friend std::ostream& operator<<(std::ostream&, const Digest&);
// Opaque pointer to the crypto implementation context.
std::unique_ptr<Context> ctx_;
// The raw bytes of the current digest. This is filled in either by the
// assignment operators or the Parse and Final methods.
uint8_t bytes_[kSha256Length];
std::ostream& operator<<(std::ostream&, const Digest&);
} // namespace digest