blob: d061455f6fcfe0daebc66552564860d064a5417e [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.
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#define SHA256_DIGEST_LENGTH 32
#ifdef __cplusplus
#include <fbl/unique_ptr.h>
namespace digest {
// This class represents a digest produced by a hash algorithm.
// This class is not thread safe.
class Digest final {
// The length of a digest in bytes; this matches sizeof(this->data).
static constexpr size_t kLength = DIGEST_LENGTH;
explicit Digest(const uint8_t* other);
Digest(Digest&& o);
Digest& operator=(Digest&& o);
Digest& operator=(const uint8_t* rhs);
// Initializes the hash algorithm context. It must be called before Update,
// and after Final when reusing the Digest object.
zx_status_t 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 |hex| string to binary and stores it in this->data. The
// string must contain at least |kLength| * 2 valid hex characters.
zx_status_t Parse(const char* hex, size_t len);
// Writes the current digest to |out| as a null-terminated, hex-encoded
// string. |out| must have room for (kLength * 2) + 1 characters to
// succeed.
zx_status_t ToString(char* out, size_t len) const;
// Write the current digest to |out|. |len| must be at least kLength to
// succeed.
zx_status_t CopyTo(uint8_t* out, size_t len) const;
// Returns a pointer to a buffer containing the current digest value. This
// will always have |kLength| bytes. Each call to |AcquireBytes| must have
// a corresponding call to |ReleaseBytes| before calling any other non-const
// method.
const uint8_t* AcquireBytes() const;
// Indicates to this object that the caller is finished using the pointer
// returned by |AcquireBytes|. It is an error to call any other non-const
// method after |AcquireBytes| without first calling |ReleaseBytes|.
void ReleaseBytes() const;
// Equality operators. Those that take |const uint8_t *| arguments will
// read |kLength| bytes; callers MUST ensure there are sufficient bytes
// present.
bool operator==(const Digest& rhs) const;
bool operator!=(const Digest& rhs) const;
bool operator==(const uint8_t* rhs) const;
bool operator!=(const uint8_t* rhs) const;
// Check to see if this digest is currently valid. A digest is defined as
// valid when it has a valid crypto context; so any time after a successful
// call to Init, but before the call to Final. The following operations
// require a valid digest in order to execute.
// ++ Update
// ++ Final
bool is_valid() const { return ctx_ != nullptr; }
// Opaque crypto implementation context.
struct Context;
// Opaque pointer to the crypto implementation context.
fbl::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_[kLength];
// The number of outstanding calls to |AcquireBytes| without matching calls
// to |ReleaseBytes|.
mutable size_t ref_count_ = 0;
} // namespace digest
#endif // __cplusplus
typedef struct digest_t digest_t;
// C API for Digest. It's called in a similar manner as the corresponding C++
// code, namely, the caller should do roughly the following (with additional
// error checking):
// digest_t *digest = NULL;
// digest_init(&digest);
// while(true) {
// // Fill buf with len bytes somehow or break if no more data
// digest_update(digest, buf, len);
// }
// uint8_t result[DIGEST_LENGTH];
// digest_final(digest, result, sizeof(result));
// Then |result| will have the result of the hashing the data.
// C wrapper for |Digest::Init|. On success this function allocates memory and
// returns it in |out|. The caller must make a call to |digest_final| to free
// this memory.
zx_status_t digest_init(digest_t** out);
// C wrapper for |Digest::Update|.
void digest_update(digest_t* digest, const void* buf, size_t len);
// C wrapper for |Digest::Final|. |out| must point to a buffer with room for at
// least |DIGEST_LENGTH| bytes. This method frees |digest|, which must not be
// used again after this call.
zx_status_t digest_final(digest_t* digest, void* out, size_t out_len);
// C wrapper for |Digest::Hash|. |out| must point to a buffer with room for at
// least |DIGEST_LENGTH| bytes.
zx_status_t digest_hash(const void* buf, size_t len, void* out, size_t out_len);