diff --git a/.clang-tidy b/.clang-tidy
index 183b1d8..1fe1cd5 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,7 +1,8 @@
+HeaderFilterRegex: \./.+
+
Checks: >-
bugprone-*,
cppcoreguidelines-*,
- google-*,
misc-*,
modernize-*,
performance-*,
@@ -15,6 +16,7 @@ Checks: >-
-cppcoreguidelines-pro-type-vararg,
-google-readability-braces-around-statements,
-google-readability-function-size,
+ -google-readability-namespace-comments,
-misc-no-recursion,
-modernize-return-braced-init-list,
-modernize-use-nodiscard,
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 536a3da..41d7934 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -2,8 +2,8 @@
-
-
+
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 90f2778..8be2ab0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.22)
project(emsha
- VERSION 1.0.3
+ VERSION 1.1.0
LANGUAGES CXX
DESCRIPTION "A compact HMAC-SHA-256 C++11 library.")
set(CMAKE_CXX_STANDARD 11)
@@ -9,8 +9,14 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(EMSHA_NO_HEXSTRING OFF CACHE BOOL
"Don't include support for hex strings.")
-set(EMSHA_NO_HEXLUT OFF CACHE BOOL
+if (EMSHA_NO_HEXSTRING)
+ add_definitions(EMSHA_NO_HEXSTRING)
+endif ()
+set(SET_EMSHA_NO_HEXLUT OFF CACHE BOOL
"Don't use a LUT for hex strings (saves ~256B of memory).")
+if (SET_EMSHA_NO_HEXLUT)
+ add_definitions("-DEMSHA_NO_HEXLUT")
+endif ()
include(CTest)
enable_testing()
diff --git a/cmake/docs.cmake b/cmake/docs.cmake
index af153ff..309530e 100644
--- a/cmake/docs.cmake
+++ b/cmake/docs.cmake
@@ -24,13 +24,13 @@ if (${DOXYGEN_FOUND})
set(DOXYGEN_GENERATE_LATEX YES)
set(DOXYGEN_EXTRACT_ALL YES)
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE "${CMAKE_CURRENT_SOURCE_DIR}/docs/mainpage.md")
+ set(DOXYGEN_EXCLUDE_PATTERNS "test_*" "*.cc" )
message(STATUS "Doxygen found, building docs.")
doxygen_add_docs(${PROJECT_NAME}_docs
${HEADER_FILES}
- ${SOURCE_FILES}
+ ALL
USE_STAMP_FILE)
- add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_docs)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html
${CMAKE_CURRENT_BINARY_DIR}/latex
DESTINATION share/doc/${PROJECT_NAME}/doxygen)
diff --git a/docs/mainpage.md b/docs/mainpage.md
index 12194cd..ca088a5 100644
--- a/docs/mainpage.md
+++ b/docs/mainpage.md
@@ -77,50 +77,50 @@ satisfy a common interface :cpp`Hash`{.interpreted-text role="class"}.
All functionality provided by this library is found under the `emsha`
namespace.
-### `EMSHA_RESULT`
+### `EMSHAResult`
-The `EMSHA_RESULT` enum is used to convey the result of an operation.
+The `EMSHAResult` enum is used to convey the result of an operation.
The possible values are:
// All operations have completed successfully so far.
- EMSHA_ROK = 0,
+ EMSHAResult::OK = 0,
// A self test or unit test failed.
- EMSHA_TEST_FAILURE = 1,
+ EMSHAResult::TestFailure = 1,
// A null pointer was passed in as a buffer where it
// shouldn't have been.
- EMSHA_NULLPTR = 2,
+ EMSHAResult::NullPointer = 2,
// The Hash is in an invalid state.
- EMSHA_INVALID_STATE = 3,
+ EMSHAResult::InvalidState = 3,
// The input to SHA256::update is too large.
- SHA256_INPUT_TOO_LONG = 4,
+ EMSHAResult::InputTooLong = 4,
// The self tests have been disabled, but a self test
// function was called.
- EMSHA_SELFTEST_DISABLED = 5
+ EMSHAResult::SelfTestDisabled = 5
As a convenience, the following `typedef` is also provided.
-> `typedef enum _EMSHA_RESULT_` :cpp`EMSHA_RESULT`{.interpreted-text
+> `typedef enum _EMSHA_RESULT_` :cpp`EMSHAResult`{.interpreted-text
> role="type"}
## The Hash interface
In general, a [Hash]{.title-ref} is used along the lines of: :
- emsha::EMSHA_RESULT
+ emsha::EMSHAResult
hash_single_pass(uint8_t *m, uint32_t ml, uint8_t *digest)
{
// Depending on the implementation, the constructor may need
// arguments.
emsha::Hash h;
- emsha::EMSHA_RESULT res;
+ emsha::EMSHAResult res;
res = h.write(m, ml);
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
return res;
}
diff --git a/emsha.cc b/emsha.cc
index b590b07..f89c581 100644
--- a/emsha.cc
+++ b/emsha.cc
@@ -55,10 +55,13 @@ HashEqual(const uint8_t *a, const uint8_t *b)
#ifndef EMSHA_NO_HEXSTRING
+
+
+namespace {
#ifndef EMSHA_NO_HEXLUT
// If using a lookup table is permitted, then the faster way to do this
// is to use one.
-static void
+void
writeHexChar(uint8_t *dest, uint8_t src)
{
static constexpr uint8_t lut[256][3] = {
@@ -106,7 +109,7 @@ writeHexChar(uint8_t *dest, uint8_t src)
// memory constraints, we'll work around this using a small (16-byte)
// lookup table and some bit shifting. On platforms where even this is
// too much, the HexString functionality will just be disabled.
-static void
+void
writeHexChar(uint8_t *dest, uint8_t src)
{
static constexpr uint8_t lut[] = {
@@ -118,6 +121,7 @@ writeHexChar(uint8_t *dest, uint8_t src)
*(dest + 1) = lut[(src & 0xF)];
}
#endif // #ifndef EMSHA_NO_HEXLUT
+} // anonymous namespace for writeHexChar
void
diff --git a/emsha/emsha.h b/emsha/emsha.h
index 5587ebb..a4a2b3a 100644
--- a/emsha/emsha.h
+++ b/emsha/emsha.h
@@ -35,11 +35,10 @@
#include
-// Emsha is an EMbedded Secure HAshing interface.
+// emsha is an EMbedded Secure HAshing interface.
namespace emsha {
-/// EMSHA_CHECK is used for sanity checks in certain parts of the code.
#ifdef NDEBUG
/// EMSHA_CHECK is used for sanity checks in certain parts of
/// the code. If asserts are turned off, expand the check to an
@@ -58,43 +57,52 @@ namespace emsha {
const std::uint32_t SHA256_HASH_SIZE = 32;
-/// The EMSHA_RESULT type is used to indicate whether an
-/// operation succeeded, and if not, what the general fault type
-/// was.
-typedef enum _EMSHA_RESULT_ : std::uint8_t {
- /// All operations have completed successfully so far.
- EMSHA_ROK = 0,
+/// \brief Describe the result of an EMSHA operation.
+///
+/// The EMSHAResult type is used to indicate whether an operation
+/// succeeded, and if not, what the general fault type was.
+typedef enum class EMSHAResult : std::uint8_t {
+ /// An unknown fault occurred. This is a serious bug in the
+ /// program.
+ Unknown = 0,
- /// A self test or unit test failed.
- EMSHA_TEST_FAILURE = 1,
+ /// All operations have completed successfully so far.
+ OK = 1,
+
+ /// The self-test failed.
+ TestFailure = 2,
/// A null pointer was passed in as a buffer where it shouldn't
/// have been.
- EMSHA_NULLPTR = 2,
+ NullPointer = 3,
/// The Hash is in an invalid state.
- EMSHA_INVALID_STATE = 3,
+ InvalidState = 4,
/// The input to SHA256::update is too large.
- SHA256_INPUT_TOO_LONG = 4,
+ InputTooLong = 5,
/// The self tests have been disabled, but a self-test function
/// was called.
- EMSHA_SELFTEST_DISABLED = 5
-} EMSHA_RESULT;
+ SelfTestDisabled = 6
+} ;
-// A Hash is generalised superclass supporting concrete classes
-// that produce digests of data.
+/// A Hash is an abstract base class supporting concrete classes
+/// that produce digests of data.
class Hash {
public:
virtual ~Hash() = default;
- /// Reset should bring the Hash back into its
- /// initial state. That is, the idea is that
+ /// \brief Bring the Hash back to its initial state.
///
- /// hash->reset(); hash->update(...)... ;
- /// hash->result(...) ;
+ /// That is, the idea is that
+ ///
+ /// ```
+ /// hash->reset();
+ /// hash->update(...);
+ /// hash->result(...);
+ /// ```
///
/// is idempotent, assuming the inputs to update
/// and result are constant. The implications of
@@ -103,34 +111,54 @@ public:
/// in general, it has the effect of preserving
/// any initial state while removing any data
/// written to the Hash via the update method.
- virtual EMSHA_RESULT Reset() = 0;
+ ///
+ /// \return An ::EMSHAResult describing the status of the
+ /// operation.
+ virtual EMSHAResult Reset() = 0;
- // Update is writes message data into the Hash.
- virtual EMSHA_RESULT Update(const std::uint8_t *m,
- std::uint32_t ml) = 0;
+ /// \brief Write message data into the Hash.
+ ///
+ /// \param message The message data to write into the Hash.
+ /// \param messageLength The length of the message data.
+ /// \return An ::EMSHAResult describing the status of the
+ /// operation.
+ virtual EMSHAResult Update(const std::uint8_t *message,
+ std::uint32_t messageLength) = 0;
- /// Finalise carries out any final operations
- /// on the Hash; after a call to finalize, no
- /// more data can be written. Additionally, it
- /// transfers out the resulting hash into its
+ /// \brief Carry out any final operations on the Hash.
+ ///
+ /// After a call to finalize, no more data can be written.
+ /// Additionally, it transfers out the resulting hash into its
/// argument.
- virtual EMSHA_RESULT Finalise(std::uint8_t *d) = 0;
+ ///
+ /// \param digest The buffer to store the hash in.
+ /// \return An ::EMSHAResult describing the status of the
+ /// operation.
+ virtual EMSHAResult Finalise(std::uint8_t *digest) = 0;
- /// Result transfers out the hash to the
- /// argument. The Hash must keep enough state
- /// for repeated calls to result to work.
- virtual EMSHA_RESULT Result(std::uint8_t *d) = 0;
+ /// \brief Result transfers out the hash to the argument.
+ ///
+ /// The Hash must keep enough state for repeated calls to
+ /// result to work.
+ ///
+ /// \param digest The buffer to store the hash in.
+ /// \return An ::EMSHAResult describing the status of the
+ /// operation.
+ virtual EMSHAResult Result(std::uint8_t *digest) = 0;
- /// Size should return the output size of the
- /// Hash; this is, how large the buffers written
- /// to by result should be.
+ /// \brief Return the output size of the Hash.
+ ///
+ /// This is how large the buffers written to by result should
+ /// be.
virtual std::uint32_t Size() = 0;
};
-/// HashEqual provides a constant time function for comparing
-/// two hashes. The caller *must* ensure that both a and b are
-/// the same size. The recommended approach is to use fixed-size
-/// buffers of emsha::SHA256_HASH_SIZE length:
+/// \brief Constant-time function for comparing two digests.
+///
+/// HashEqual provides a constant time function for comparing two
+/// digests. The caller *must* ensure that both a and b are the same
+/// size. The recommended approach is to use fixed-size buffers of
+/// emsha::SHA256_HASH_SIZE length:
///
/// ```c++
/// uint8_t expected[emsha::SHA256_HASH_SIZE];
@@ -146,21 +174,21 @@ public:
/// \param a A byte buffer of size Hash::Size().
/// \param b A byte buffer of size Hash::Size().
/// \return True if both byte arrays match.
-bool
-HashEqual(const std::uint8_t *a, const std::uint8_t *b);
+bool HashEqual(const std::uint8_t *a, const std::uint8_t *b);
+
#ifndef EMSHA_NO_HEXSTRING
-/// HexString writes a hex-encoded version of the src byte
-/// array into dest. The caller *must* ensure that dest is
-/// srclen * 2 bytes or longer.
+/// \brief Write a hex-encoded version of a byte string.
///
+/// HexString writes a hex-encoded version of the src byte array into
+/// dest. The caller **must** ensure that dest is `srclen * 2` bytes
+/// or longer.
///
-/// \param dest The destination byte array at least (2*srclen)
+/// \param dest The destination byte array at least (`2*srclen`)
/// bytes in length.
-/// \param src A byte array containing the data to hexify..
+/// \param src A byte array containing the data to hexify.
/// \param srclen The size in bytes of src.
-void
-HexString(std::uint8_t *dest, std::uint8_t *src, std::uint32_t srclen);
+void HexString(std::uint8_t *dest, std::uint8_t *src, std::uint32_t srclen);
#endif // EMSHA_NO_HEXSTRING
diff --git a/emsha/hmac.h b/emsha/hmac.h
index b8d540b..06f30db 100644
--- a/emsha/hmac.h
+++ b/emsha/hmac.h
@@ -43,151 +43,137 @@ const uint32_t HMAC_KEY_LENGTH = SHA256_MB_SIZE;
/// HMAC is a keyed hash that can be used to produce an
/// authenticated hash of some data. The HMAC is built on
-/// (and uses internally) the SHA-256 class; it's helpful to
+/// (and uses internally) the SHA256 class; it's helpful to
/// note that faults that occur in the SHA-256 code will be
/// propagated up as the return value from many of the HMAC
/// functions.
class HMAC : Hash {
public:
- /// An HMAC is constructed with a key and the
- /// length of the key. This key is stored in
- /// the HMAC context, and is wiped by the HMAC
- /// destructor.
+ /// \brief Construct an HMAC with its initial key.
+ ///
+ /// An HMAC is constructed with a key and the length of the
+ /// key. This key is stored in the HMAC context, and is wiped
+ /// by the HMAC destructor.
///
/// \param k The HMAC key.
/// \param kl THe length of the HMAC key.
HMAC(const uint8_t *k, uint32_t kl);
- /// Reset clears any data written to the HMAC;
- /// this is equivalent to constructing a new HMAC,
- /// but it preserves the keys.
+ /// \brief Clear any data written to the HMAC.
///
- /// \return EMSHA_ROK is returned if the reset
- /// occurred without (detected) fault.
- /// If a fault occurs with the under-
- /// lying SHA-256 context, the error
- /// code is returned.
- EMSHA_RESULT Reset() override;
+ /// This is equivalent to constructing a new HMAC, but it
+ /// preserves the keys.
+ ///
+ /// \return EMSHAResult::OK is returned if the reset occurred
+ /// without (detected) fault. If a fault occurs with
+ /// the underlying SHA256 context, the error code is
+ /// returned.
+ EMSHAResult Reset() override;
- /// Update writes data into the context. While
- /// there is an upper limit on the size of data
- /// that the underlying hash can operate on,
- /// this package is designed for small systems
- /// that will not approach that level of data
- /// (which is on the order of 2 exabytes), so it
- /// is not thought to be a concern.
+ /// \brief Write data into the context.
///
- /// \param m A byte array containing the message
+ /// While there is an upper limit on the size of data that the
+ /// underlying hash can operate on, this package is designed
+ /// for small systems that will not approach that level of data
+ /// (which is on the order of 2 exabytes), so it is not a
+ /// concern for this library.
+ ///
+ /// \param message A byte array containing the message
/// to be written.
- /// \param ml The message length, in bytes.
- /// \return
- /// - EMSHA_NULLPTR is returned if m is NULL and ml is
- /// nonzero.
- /// - EMSHA_INVALID_STATE is returned if the update
- /// is called after a call to finalize.
- /// - SHA256_INPUT_TOO_LONG is returned if too much
- /// data has been written to the context.
- /// - EMSHA_ROK is returned if the data was
- /// successfully written into the HMAC context.
+ /// \param messageLength The message length, in bytes.
+ /// \return An ::EMSHAResult describing the result of the
+ /// operation.
///
- EMSHA_RESULT Update(const uint8_t *, uint32_t) override;
+ /// - EMSHAResult::NullPointer is returned if m is NULL
+ /// and ml is nonzero.
+ /// - EMSHAResult::InvalidState is returned if the
+ /// update is called after a call to finalize.
+ /// - EMSHAResult::InputTooLong is returned if too much
+ /// data has been written to the context.
+ /// - EMSHAResult::OK is returned if the data was
+ /// successfully written into the HMAC context.
+ EMSHAResult Update(const std::uint8_t *message, std::uint32_t messageLength) override;
- // Finalise completes the HMAC computation. Once this
- // method is called, the context cannot be updated
- // unless the context is reset.
- //
- // Inputs:
- // d: a byte buffer that must be at least
- // HMAC.size() in length.
- //
- // Outputs:
- // EMSHA_NULLPTR is returned if d is the null
- // pointer.
- //
- // EMSHA_INVALID_STATE is returned if the HMAC
- // context is in an invalid state, such as if there
- // were errors in previous updates.
- //
- // EMSHA_ROK is returned if the context was
- // successfully finalised and the digest copied to
- // d.
- //
- EMSHA_RESULT Finalise(uint8_t *) override;
+ /// \brief Complete the HMAC computation.
+ ///
+ /// \note Once #Finalise is called, the context cannot be
+ /// updated unless the context is reset.
+ ///
+ /// \param digest A byte buffer that must be at least #HMAC.Size()
+ /// in length.
+ /// \return An EMSHAResult describing the result of this
+ /// method:
+ ///
+ /// - EMSHAResult::NullPointer is returned if d is a
+ /// null pointer.
+ /// - EMSHAResult::InvalidState is returned if the HMAC
+ /// context is in an invalid state, such as if there
+ /// were errors in previous updates.
+ /// - EMSHAResult::OK is returned if the context was
+ /// successfully finalised and the digest copied to d.
+ ///
+ EMSHAResult Finalise(std::uint8_t *digest) override;
- // Result copies the result from the HMAC context into
- // the buffer pointed to by d, running finalize if
- // needed. Once called, the context cannot be updated
- // until the context is reset.
- //
- // Inputs:
- // d: a byte buffer that must be at least
- // HMAC.size() in length.
- //
- // Outputs:
- // EMSHA_NULLPTR is returned if d is the null
- // pointer.
- //
- // EMSHA_INVALID_STATE is returned if the HMAC
- // context is in an invalid state, such as if there
- // were errors in previous updates.
- //
- // EMSHA_ROK is returned if the context was
- // successfully finalised and the digest copied to
- // d.
- //
- EMSHA_RESULT Result(uint8_t *) override;
+ /// \brief Copy the current digest into a destination buffer.
+ ///
+ /// Copy the current digest from the HMAC context into
+ /// `digest`, running #Finalise if needed. Once called, the
+ /// context cannot be updated until the context is reset.
+ ///
+ /// \param digest A byte buffer that must be at least #HMAC.size()
+ /// in length.
+ /// \return An ::EMSHAResult describing the result of this
+ /// method:
+ ///
+ /// - EMSHAResult::NullPointer is returned if d is a
+ /// null pointer.
+ /// - EMSHAResult::InvalidState is returned if the HMAC
+ /// context is in an invalid state, such as if there
+ /// were errors in previous updates.
+ /// - EMSHAResult::OK is returned if the context was
+ /// successfully finalised and the digest copied to d.
+ EMSHAResult Result(std::uint8_t *digest) override;
- // size returns the output size of HMAC-SHA-256, e.g.
- // the size that the buffers passed to finalize and
- // result should be.
- //
- // Outputs:
- // A uint32_t representing the expected size
- // of buffers passed to result and finalize.
+ /// \brief Returns the output size of HMAC-SHA-256.
+ ///
+ /// The buffers passed to #Update and #Finalise should be at
+ /// least this size.
+ ///
+ /// \return The expected size of buffers passed to result and
+ /// finalize.
std::uint32_t Size() override;
- // When an HMAC context is destroyed, it is reset and
- // the key material is zeroised using the STL fill
- // function.
- ~HMAC(void);
+ /// When an HMAC context is destroyed, it is reset and
+ /// the key material is zeroised using the STL `fill`
+ /// function.
+ ~HMAC();
private:
uint8_t hstate;
SHA256 ctx;
uint8_t k[HMAC_KEY_LENGTH];
- uint8_t buf[SHA256_HASH_SIZE];
+ uint8_t buf[SHA256_HASH_SIZE];
- EMSHA_RESULT reset();
- inline EMSHA_RESULT
- finalResult(uint8_t *d);
+ EMSHAResult reset();
+ inline EMSHAResult finalResult(uint8_t *d);
};
-// compute_hmac performs a single-pass HMAC computation over
-// a message.
-//
-// Inputs:
-// k: a byte buffer containing the HMAC key.
-//
-// kl: the length of the HMAC key.
-//
-// m: the message data over which the HMAC is to be computed.
-//
-// ml: the length of the message.
-//
-// d: a byte buffer that will be used to store the resulting
-// HMAC. It should be SHA256_HASH_SIZE bytes in size.
-//
-// Outputs:
-// This function handles setting up the HMAC context with
-// the given key, calling update with the message data, and
-// then calling finalize to place the result in the output
-// buffer. Any of the faults that can occur in these functions
-// can be returned here, or EMSHA_ROK if the HMAC was
-// successfully computed.
-EMSHA_RESULT
-ComputeHMAC(const uint8_t *k, uint32_t kl,
- const uint8_t *m, uint32_t ml,
+
+/// \brief Perform a single-pass HMAC computation over a message.
+///
+/// \param k A byte buffer containing the HMAC key.
+/// \param kl The length of the HMAC key.
+/// \param m The message data over which the HMAC is to be computed.
+/// \param ml The length of the message.
+/// \param d Byte buffer that will be used to store the resulting
+/// HMAC. It should be emsha::SHA256_HASH_SIZE bytes in size.
+/// \return An ::EMSHAResult describing the result of the HMAC operation.
+EMSHAResult
+ComputeHMAC(const uint8_t *k, const uint32_t kl,
+ const uint8_t *m, const uint32_t ml,
uint8_t *d);
+
+
} // end of namespace emsha
diff --git a/emsha/sha256.h b/emsha/sha256.h
index e9e796d..b781909 100644
--- a/emsha/sha256.h
+++ b/emsha/sha256.h
@@ -34,184 +34,160 @@
#include
#include
+#include
namespace emsha {
-// SHA256_MB_SIZE is the size of a message block.
+/// SHA256_MB_SIZE is the size of a message block.
const uint32_t SHA256_MB_SIZE = 64;
class SHA256 : Hash {
public:
- // A SHA256 context does not need any special
- // construction. It can be declared and
- // immediately start being used.
+ /// \brief A SHA256 context does not need any special
+ /// construction.
+ ///
+ /// It can be declared and immediately start being used.
SHA256();
- // The SHA256 destructor will clear out its internal
- // message buffer; all the members are local and
- // not resource handles, so cleanup is minimal.
+ /// The SHA256 destructor will clear out its internal
+ /// message buffer; all the members are local and
+ /// not resource handles, so cleanup is minimal.
~SHA256();
- // reset clears the internal state of the SHA256
- // context and returns it to its initial state.
- // It should always return EMSHA_ROK.
- EMSHA_RESULT Reset() override;
+ /// \brief Clear the internal state of the SHA256 context,
+ /// returning it to its initial state.
+ ///
+ /// \return This should always return EMSHAResult::OK.
+ EMSHAResult Reset() override;
- // update writes data into the context. While
- // there is an upper limit on the size of data
- // that SHA-256 can operate on, this package is
- // designed for small systems that will not
- // approach that level of data (which is on the
- // order of 2 exabytes), so it is not thought
- // to be a concern.
- //
- // Inputs:
- // m: a byte array containing the message to
- // be written. It must not be NULL (unless
- // the message length is zero).
- //
- // ml: the message length, in bytes.
- //
- // Outputs:
- // EMSHA_NULLPTR is returned if m is NULL
- // and ml is nonzero.
- //
- // EMSHA_INVALID_STATE is returned if the
- // update is called after a call to
- // finalize.
- //
- // SHA256_INPUT_TOO_LONG is returned if too
- // much data has been written to the
- // context.
- //
- // EMSHA_ROK is returned if the data was
- // successfully added to the SHA-256
- // context.
- //
- EMSHA_RESULT Update(const uint8_t *m, uint32_t ml) override;
+ /// \brief Writes data into the SHA256.
+ ///
+ /// While there is an upper limit on the size of data that
+ /// SHA-256 can operate on, this package is designed for small
+ /// systems that will not approach that level of data (which is
+ /// on the order of 2 exabytes), so it is not thought to be a
+ /// concern.
+ ///
+ /// \param message A byte array containing the message to be
+ /// written. It must not be NULL (unless the
+ /// message length is zero).
+ /// \param messageLength The message length, in bytes.
+ /// \return An ::EMSHAResult describing the result of the
+ /// operation.
+ ///
+ /// - EMSHAResult::NullPointer is returned if m is a
+ /// nullptr and ml is nonzero.
+ /// - EMSHAResult::InvalidState is returned if the
+ /// update is called after a call to finalize.
+ /// - EMSHAResult::InputTooLong is returned if too much
+ /// data has been written to the context.
+ /// - EMSHAResult::OK is returned if the data was
+ /// successfully added to the SHA-256 context.
+ EMSHAResult Update(const std::uint8_t *message, std::uint32_t messageLength) override;
- // Finalise completes the digest. Once this
- // method is called, the context cannot be
- // updated unless the context is reset.
- //
- // Inputs:
- // d: a byte buffer that must be at least
- // SHA256.size() in length.
- //
- // Outputs:
- // EMSHA_NULLPTR is returned if d is the
- // null pointer.
- //
- // EMSHA_INVALID_STATE is returned if the
- // SHA-256 context is in an invalid state,
- // such as if there were errors in previous
- // updates.
- //
- // EMSHA_ROK is returned if the context was
- // successfully finalised and the digest
- // copied to d.
- //
- EMSHA_RESULT Finalise(uint8_t *d) override;
+ /// \brief Complete the digest.
+ ///
+ /// Once this method is called, the context cannot be updated
+ /// unless the context is reset.
+ ///
+ /// \param digest byte buffer that must be at least
+ /// SHA256.size() in length.
+ /// \return An ::EMSHAResult describing the result of the
+ /// operation.
+ ///
+ /// - EMSHAResult::NullPointer is returned if a nullptr
+ /// is passed in.
+ /// - EMSHAResult::InvalidState is returned if the
+ /// SHA-256 context is in an invalid state, such as
+ /// if there were errors in previous updates.
+ /// - EMSHAResult::OK is returned if the context was
+ /// successfully finalised and the digest copied to
+ /// digest.
+ EMSHAResult Finalise(std::uint8_t *digest) override;
- // result copies the result from the SHA-256
- // context into the buffer pointed to by d,
- // running Finalise if needed. Once called,
- // the context cannot be updated until the
- // context is reset.
- //
- // Inputs:
- // d: a byte buffer that must be at least
- // SHA256.size() in length.
- //
- // Outputs:
- // EMSHA_NULLPTR is returned if d is the
- // null pointer.
- //
- // EMSHA_INVALID_STATE is returned if the
- // SHA-256 context is in an invalid state,
- // such as if there were errors in previous
- // updates.
- //
- // EMSHA_ROK is returned if the context was
- // successfully finalised and the digest
- // copied to d.
- //
- EMSHA_RESULT Result(uint8_t *d) override;
+ /// \brief Copy the result from the SHA-256
+ /// context into the buffer pointed to by d,
+ /// running #Finalise if needed. Once called,
+ /// the context cannot be updated until the
+ /// context is reset.
+ ///
+ /// \param digest A byte buffer that must be at least
+ /// SHA256.size() in length.
+ /// \return An ::EMSHAResult describing the result of the
+ /// operation.
+ ///
+ /// - EMSHAResult::NullPointer is returned if a nullptr
+ /// is passed in.
+ /// - EMSHAResult::InvalidState is returned if the
+ /// SHA-256 context is in an invalid state, such as
+ /// if there were errors in previous updates.
+ /// - EMSHAResult::OK is returned if the context was
+ /// successfully finalised and the digest copied to
+ /// digest.
+ EMSHAResult Result(std::uint8_t *digest) override;
- // size returns the output size of SHA256, e.g.
- // the size that the buffers passed to finalize
- // and result should be.
- //
- // Outputs:
- // a uint32_t representing the expected size
- // of buffers passed to result and finalize.
+ /// \brief Returns the output size of SHA-256.
+ ///
+ /// The buffers passed to #Update and #Finalise should be at
+ /// least this size.
+ ///
+ /// \return The expected size of buffers passed to result and
+ /// finalize.
std::uint32_t Size() override;
private:
- // mlen stores the current message length.
- uint64_t mlen;
-
- // The intermediate hash is 8x 32-bit blocks.
- uint32_t i_hash[8];
+ uint64_t mlen; // Current message length.
+ uint32_t i_hash[8]; // The intermediate hash is 8x 32-bit blocks.
// hStatus is the hash status, and hComplete indicates
// whether the hash has been finalised.
- EMSHA_RESULT hStatus;
- uint8_t hComplete;
+ EMSHAResult hStatus;
+ uint8_t hComplete;
// mb is the message block, and mbi is the message
// block index.
uint8_t mbi;
- uint8_t mb[SHA256_MB_SIZE];
+ std::array mb;
- inline EMSHA_RESULT addLength(const uint32_t);
- inline void updateMessageBlock(void);
- inline void padMessage(uint8_t pc);
- EMSHA_RESULT reset();
+ inline EMSHAResult addLength(const uint32_t);
+ inline void updateMessageBlock(void);
+ inline void padMessage(uint8_t pc);
+ uint32_t chunkToUint32(uint32_t offset);
+ uint32_t uint32ToChunk(uint32_t offset);
+ EMSHAResult reset();
}; // end class SHA256
-// sha256Digest performs a single pass hashing of the message
-// passed in.
-//
-// Inputs:
-// m: byte buffer containing the message to hash.
-//
-// ml: the length of m.
-//
-// d: byte buffer that will be used to store the resulting
-// hash; it should have at least emsha::SHA256_HASH_SIZE
-// bytes available.
-//
-// Outputs:
-// This function handles setting up a SHA256 context, calling
-// update using the message data, and then calling finalize. Any
-// of the errors that can occur in those functions can be
-// returned here, or EMSHA_ROK if the digest was computed
-// successfully.
-//
-EMSHA_RESULT
-sha256Digest(const uint8_t *m, uint32_t ml, uint8_t *d);
-// sha256SelfTest runs through two test cases to ensure that the
-// SHA-256 functions are working correctly.
-//
-// Outputs:
-// EMSHA_ROK is returned if the self tests pass.
-//
-// EMSHA_SELFTEST_DISABLED is returned if the self tests
-// have been disabled (e.g., libemsha was compiled with the
-// EMSHA_NO_SELFTEST #define).
-//
-// If a fault occurred inside the SHA-256 code, the error
-// code from one of the update, finalize, result, or reset
-// methods is returned.
-//
-// If the fault is that the output does not match the test
-// vector, EMSHA_TEST_FAILURE is returned.
-EMSHA_RESULT
-sha256SelfTest(void);
+/// \brief SHA256Digest performs a single pass hashing of the message
+/// passed in.
+///
+/// \param m Byte buffer containing the message to hash.
+/// \param ml The length of m.
+/// \param d Byte buffer that will be used to store the resulting hash;
+/// it should have at least emsha::SHA256_HASH_SIZE bytes
+/// available.
+/// \return An ::EMSHAResult describing the result of the operation.
+EMSHAResult SHA256Digest(const uint8_t *m, uint32_t ml, uint8_t *d);
+
+/// \brief SHA256SelfTest runs through two test cases to ensure that the
+/// SHA-256 functions are working correctly.
+///
+/// \return The result of the self-test.
+///
+/// - EMSHAResult::OK is returned if the self tests pass.
+/// - EMSHAResult::SelfTestDisabled is returned if the self
+/// tests have been disabled (e.g., libemsha was compiled
+/// with the EMSHA_NO_SELFTEST #define).
+/// - If a fault occurred inside the SHA-256 code, the error
+/// code from one of the update, finalize, result, or reset
+/// methods is returned.
+/// - If the fault is that the output does not match the test
+/// vector, EMSHAResult::TestFailure is returned.
+EMSHAResult SHA256SelfTest();
+
+
} // end of namespace emsha
diff --git a/hmac.cc b/hmac.cc
index 7e8b347..c672e34 100644
--- a/hmac.cc
+++ b/hmac.cc
@@ -63,11 +63,12 @@ static constexpr uint8_t opad = 0x5c;
HMAC::HMAC(const uint8_t *ik, uint32_t ikl)
: hstate(HMAC_INIT), k{0}, buf{0}
{
-
- std::fill(this->k, this->k + emsha::HMAC_KEY_LENGTH, 0);
+ std::fill(this->k, this->k+HMAC_KEY_LENGTH, 0);
if (ikl < HMAC_KEY_LENGTH) {
- std::copy(ik, ik + ikl, this->k);
+ for (uint32_t i = 0; i < ikl; i++) {
+ this->k[i] = ik[i];
+ }
while (ikl < HMAC_KEY_LENGTH) {
this->k[ikl++] = 0;
}
@@ -76,7 +77,9 @@ HMAC::HMAC(const uint8_t *ik, uint32_t ikl)
this->ctx.Result(this->k);
this->ctx.Reset();
} else {
- std::copy(ik, ik + ikl, this->k);
+ for (uint32_t i = 0; i < ikl; i++) {
+ this->k[i] = ik[i];
+ }
}
this->reset();
@@ -93,17 +96,17 @@ HMAC::~HMAC()
}
-EMSHA_RESULT
+EMSHAResult
HMAC::Reset()
{
return this->reset();
}
-EMSHA_RESULT
+EMSHAResult
HMAC::reset()
{
- EMSHA_RESULT res;
+ EMSHAResult res;
// Following a reset, both SHA-256 contexts and result buffer should be
// zero'd out for a clean slate. The HMAC state should be reset
@@ -119,7 +122,7 @@ HMAC::reset()
}
res = this->ctx.Update(key, HMAC_KEY_LENGTH);
- if (EMSHA_ROK != res) {
+ if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID;
return res;
}
@@ -128,55 +131,56 @@ HMAC::reset()
std::fill(key, key + HMAC_KEY_LENGTH, 0);
this->hstate = HMAC_IPAD;
- return EMSHA_ROK;
+ return EMSHAResult::OK;
}
-EMSHA_RESULT
-HMAC::Update(const uint8_t *m, uint32_t ml)
+EMSHAResult
+HMAC::Update(const std::uint8_t *message, std::uint32_t messageLength)
{
- EMSHA_RESULT res;
- SHA256 &hctx = this->ctx;
+ EMSHAResult res;
+ SHA256 &hctx = this->ctx;
- EMSHA_CHECK(m != nullptr, EMSHA_NULLPTR);
- EMSHA_CHECK(HMAC_IPAD == this->hstate, EMSHA_INVALID_STATE);
+ EMSHA_CHECK(message != nullptr, EMSHAResult::NullPointer);
+ EMSHA_CHECK(HMAC_IPAD == this->hstate, EMSHAResult::InvalidState);
// Write the message to the SHA-256 context.
- res = hctx.Update(m, ml);
- if (EMSHA_ROK != res) {
+ res = hctx.Update(message, messageLength);
+ if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID;
return res;
}
assert(HMAC_IPAD == this->hstate);
- return EMSHA_ROK;
+ return EMSHAResult::OK;
}
-inline EMSHA_RESULT
+inline EMSHAResult
HMAC::finalResult(uint8_t *d)
{
if (nullptr == d) {
- return EMSHA_NULLPTR;
+ return EMSHAResult::NullPointer;
}
// If the HMAC has already been finalised, skip straight to
// copying the result.
- if (HMAC_FIN == this->hstate) {
- std::copy(this->buf, this->buf + SHA256_HASH_SIZE, d);
- return EMSHA_ROK;
+ if (this->hstate == HMAC_FIN) {
+ std::copy(this->buf, this->buf+SHA256_HASH_SIZE, d);
+
+ return EMSHAResult::OK;
}
- EMSHA_CHECK(HMAC_IPAD == this->hstate, EMSHA_INVALID_STATE);
+ EMSHA_CHECK(HMAC_IPAD == this->hstate, EMSHAResult::InvalidState);
- EMSHA_RESULT res;
+ EMSHAResult res;
// Use the result buffer as an intermediate buffer to store the result
// of the inner hash.
res = this->ctx.Result(this->buf);
- if (EMSHA_ROK != res) {
+ if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID;
- return EMSHA_INVALID_STATE;
+ return EMSHAResult::InvalidState;
}
assert(HMAC_IPAD == this->hstate);
@@ -192,7 +196,7 @@ HMAC::finalResult(uint8_t *d)
}
res = this->ctx.Update(key, HMAC_KEY_LENGTH);
- if (EMSHA_ROK != res) {
+ if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID;
return res;
}
@@ -203,14 +207,14 @@ HMAC::finalResult(uint8_t *d)
// Write the inner hash result into the outer hash.
res = this->ctx.Update(this->buf, SHA256_HASH_SIZE);
- if (EMSHA_ROK != res) {
+ if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID;
return res;
}
// Write the outer hash result into the working buffer.
res = this->ctx.Finalise(this->buf);
- if (EMSHA_ROK != res) {
+ if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID;
return res;
}
@@ -218,21 +222,21 @@ HMAC::finalResult(uint8_t *d)
std::copy(this->buf, this->buf + SHA256_HASH_SIZE, d);
this->hstate = HMAC_FIN;
- return EMSHA_ROK;
+ return EMSHAResult::OK;
}
-EMSHA_RESULT
-HMAC::Finalise(uint8_t *d)
+EMSHAResult
+HMAC::Finalise(std::uint8_t *digest)
{
- return this->finalResult(d);
+ return this->finalResult(digest);
}
-EMSHA_RESULT
-HMAC::Result(uint8_t *d)
+EMSHAResult
+HMAC::Result(std::uint8_t *digest)
{
- return this->finalResult(d);
+ return this->finalResult(digest);
}
@@ -243,21 +247,17 @@ HMAC::Size()
}
-EMSHA_RESULT
-ComputeHMAC(const uint8_t *k, uint32_t kl, const uint8_t *m, uint32_t ml,
+EMSHAResult
+ComputeHMAC(const uint8_t *k, const uint32_t kl,
+ const uint8_t *m, const uint32_t ml,
uint8_t *d)
{
- EMSHA_RESULT res;
- HMAC h(k, kl);
+ EMSHAResult res;
+ HMAC h(k, kl);
res = h.Update(m, ml);
- if (EMSHA_ROK != res) {
- return res;
- }
-
- res = h.Result(d);
- if (EMSHA_ROK != res) {
- return res;
+ if (res == EMSHAResult::OK) {
+ res = h.Result(d);
}
return res;
diff --git a/sha256.cc b/sha256.cc
index 5612dab..4381efe 100644
--- a/sha256.cc
+++ b/sha256.cc
@@ -69,13 +69,13 @@ static constexpr uint32_t emsha256H0[] = {
};
-EMSHA_RESULT
-sha256Digest(const uint8_t *m, uint32_t ml, uint8_t *d)
+EMSHAResult
+SHA256Digest(const uint8_t *m, uint32_t ml, uint8_t *d)
{
- SHA256 h;
- EMSHA_RESULT ret;
+ SHA256 h;
+ EMSHAResult ret = EMSHAResult::Unknown;
- if (EMSHA_ROK != (ret = h.Update(m, ml))) {
+ if (EMSHAResult::OK != (ret = h.Update(m, ml))) {
return ret;
}
@@ -92,33 +92,35 @@ SHA256::SHA256()
SHA256::~SHA256()
{
- memset(this->mb, 0, SHA256_MB_SIZE);
+ for (auto i = static_cast(0); i < SHA256_MB_SIZE; i++) {
+ this->mb[i] = static_cast(0);
+ }
}
-EMSHA_RESULT
+EMSHAResult
SHA256::addLength(const uint32_t l)
{
- uint32_t tmp = this->mlen + l;
+ EMSHAResult res = EMSHAResult::InputTooLong;;
- if (tmp < this->mlen) {
- return SHA256_INPUT_TOO_LONG;
+ uint32_t const tmp = static_cast(this->mlen) + l;
+ if (tmp >= this->mlen) {
+ this->mlen = tmp;
+ assert(this->mlen > 0);
+ res = EMSHAResult::OK;
}
- this->mlen = tmp;
- assert(this->mlen > 0);
-
- return EMSHA_ROK;
+ return res;
}
-EMSHA_RESULT
+EMSHAResult
SHA256::Reset()
{
return this->reset();
}
-EMSHA_RESULT
+EMSHAResult
SHA256::reset()
{
// The message block is set to the initial hash vector.
@@ -132,29 +134,47 @@ SHA256::reset()
this->i_hash[7] = emsha256H0[7];
this->mbi = 0;
- this->hStatus = EMSHA_ROK;
+ this->hStatus = EMSHAResult::OK;
this->hComplete = 0;
this->mlen = 0;
- memset(this->mb, 0, SHA256_MB_SIZE);
+
+ std::fill(this->mb.begin(), this->mb.end(), 0);
return this->hStatus;
}
-// Read 32 bits from the byte buffer chunk as an unsigned 32-bit integer.
-static uint32_t
-chunkToUint32(const uint8_t *chunk)
+uint32_t
+SHA256::chunkToUint32(uint32_t offset)
{
- return ((*chunk) << 24) |
- ((*(chunk + 1)) << 16) |
- ((*(chunk + 2)) << 8) |
- (*(chunk + 3));
+ uint32_t chunk = 0;
+
+ for (uint32_t i = offset; i < offset+4; i++) {
+ chunk <<= 8;
+ chunk += static_cast(this->mb[i]);
+ }
+
+ return chunk;
+}
+
+
+uint32_t
+SHA256::uint32ToChunk(uint32_t offset)
+{
+ uint32_t chunk = 0;
+
+ for (uint32_t i = offset; i < offset+4; i++) {
+ chunk <<= 8;
+ chunk += static_cast(this->mb[i]);
+ }
+
+ return chunk;
+
}
-// Copy an unsigned 32-bit integer into the start of the byte buffer chunk.
static void
-uint32ToChunk(uint32_t x, uint8_t *chunk)
+uint32ToChunkInPlace(uint32_t x, uint8_t *chunk)
{
chunk[0] = (x & 0xff000000) >> 24;
chunk[1] = (x & 0x00ff0000) >> 16;
@@ -180,7 +200,7 @@ SHA256::updateMessageBlock()
uint32_t h = 0;
while (i < 16) {
- w[i++] = chunkToUint32(this->mb + chunk);
+ w[i++] = this->chunkToUint32(chunk);
chunk += 4;
}
this->mbi = 0;
@@ -225,36 +245,36 @@ SHA256::updateMessageBlock()
}
-EMSHA_RESULT
-SHA256::Update(const uint8_t *m, uint32_t ml)
+EMSHAResult
+SHA256::Update(const std::uint8_t *message, std::uint32_t messageLength)
{
// Checking invariants:
// If the message length is zero, there's nothing to be done.
- if (0 == ml) { return EMSHA_ROK; }
+ if (0 == messageLength) { return EMSHAResult::OK; }
// The message passed in cannot be the null pointer if the
// message length is greater than 0.
- if (nullptr == m) { return EMSHA_NULLPTR; }
+ if (message == nullptr) { return EMSHAResult::NullPointer; }
// If the SHA256 object is in a bad state, don't proceed.
- if (EMSHA_ROK != this->hStatus) { return this->hStatus; }
+ if (this->hStatus != EMSHAResult::OK) { return this->hStatus; }
// If the hash has been finalised, don't proceed.
- if (0 != this->hComplete) { return EMSHA_INVALID_STATE; }
+ if (this->hComplete != static_cast(0)) { return EMSHAResult::InvalidState; }
// Invariants satisfied by here.
- for (uint32_t i = 0; i < ml; i++) {
- this->mb[this->mbi] = *(m + i);
+ for (uint32_t i = 0; i < messageLength; i++) {
+ this->mb[this->mbi] = *(message + i);
mbi++;
- if (EMSHA_ROK == this->addLength(8)) {
+ if (EMSHAResult::OK == this->addLength(8)) {
if (SHA256_MB_SIZE == this->mbi) {
this->updateMessageBlock();
// Assumption: following the message block
// write, the context should still be in a good
// state.
- assert(EMSHA_ROK == this->hStatus);
+ assert(EMSHAResult::OK == this->hStatus);
}
}
}
@@ -267,7 +287,7 @@ inline void
SHA256::padMessage(uint8_t pc)
{
// Assumption: the context is not in a corrupted state.
- assert(EMSHA_ROK == this->hStatus);
+ assert(EMSHAResult::OK == this->hStatus);
if (this->mbi < (SHA256_MB_SIZE - 8)) {
this->mb[this->mbi++] = pc;
@@ -290,7 +310,7 @@ SHA256::padMessage(uint8_t pc)
// Assumption: updating the message block has not left the
// context in a corrupted state.
- assert(EMSHA_ROK == this->hStatus);
+ assert(EMSHAResult::OK == this->hStatus);
}
while (this->mbi < (SHA256_MB_SIZE - 8)) {
@@ -320,76 +340,76 @@ SHA256::padMessage(uint8_t pc)
// Assumption: updating the message block has not left the context in a
// corrupted state.
- assert(EMSHA_ROK == this->hStatus);
+ assert(EMSHAResult::OK == this->hStatus);
}
-EMSHA_RESULT
-SHA256::Finalise(uint8_t *d)
+EMSHAResult
+SHA256::Finalise(std::uint8_t *digest)
{
// Check invariants.
// The digest cannot be a null pointer; this library allocates
// no memory of its own.
- if (nullptr == d) { return EMSHA_NULLPTR; }
+ if (nullptr == digest) { return EMSHAResult::NullPointer; }
// If the SHA256 object is in a bad state, don't proceed.
- if (EMSHA_ROK != this->hStatus) { return this->hStatus; }
+ if (EMSHAResult::OK != this->hStatus) { return this->hStatus; }
// If the hash has been finalised, don't proceed.
- if (0 != this->hComplete) { return EMSHA_INVALID_STATE; }
+ if (0 != this->hComplete) { return EMSHAResult::InvalidState; }
// Invariants satisfied by here.
this->padMessage(0x80);
// Assumption: padding the message block has not left the context in a
// corrupted state.
- assert(EMSHA_ROK == this->hStatus);
- std::fill(this->mb, this->mb + SHA256_MB_SIZE, 0);
+ assert(EMSHAResult::OK == this->hStatus);
+ std::fill(this->mb.begin(), this->mb.end(), 0);
this->hComplete = 1;
this->mlen = 0;
- uint32ToChunk(this->i_hash[0], d);
- uint32ToChunk(this->i_hash[1], d + 4);
- uint32ToChunk(this->i_hash[2], d + 8);
- uint32ToChunk(this->i_hash[3], d + 12);
- uint32ToChunk(this->i_hash[4], d + 16);
- uint32ToChunk(this->i_hash[5], d + 20);
- uint32ToChunk(this->i_hash[6], d + 24);
- uint32ToChunk(this->i_hash[7], d + 28);
+ uint32ToChunkInPlace(this->i_hash[0], digest);
+ uint32ToChunkInPlace(this->i_hash[1], digest + 4);
+ uint32ToChunkInPlace(this->i_hash[2], digest + 8);
+ uint32ToChunkInPlace(this->i_hash[3], digest + 12);
+ uint32ToChunkInPlace(this->i_hash[4], digest + 16);
+ uint32ToChunkInPlace(this->i_hash[5], digest + 20);
+ uint32ToChunkInPlace(this->i_hash[6], digest + 24);
+ uint32ToChunkInPlace(this->i_hash[7], digest + 28);
- return EMSHA_ROK;
+ return EMSHAResult::OK;
}
-EMSHA_RESULT
-SHA256::Result(uint8_t *d)
+EMSHAResult
+SHA256::Result(std::uint8_t *digest)
{
// Check invariants.
// The digest cannot be a null pointer; this library allocates
// no memory of its own.
- if (nullptr == d) { return EMSHA_NULLPTR; }
+ if (nullptr == digest) { return EMSHAResult::NullPointer; }
// If the SHA256 object is in a bad state, don't proceed.
- if (EMSHA_ROK != this->hStatus) { return this->hStatus; }
+ if (EMSHAResult::OK != this->hStatus) { return this->hStatus; }
// Invariants satisfied by here.
if (this->hComplete == 0U) {
- return this->Finalise(d);
+ return this->Finalise(digest);
}
- uint32ToChunk(this->i_hash[0], d);
- uint32ToChunk(this->i_hash[1], d + 4);
- uint32ToChunk(this->i_hash[2], d + 8);
- uint32ToChunk(this->i_hash[3], d + 12);
- uint32ToChunk(this->i_hash[4], d + 16);
- uint32ToChunk(this->i_hash[5], d + 20);
- uint32ToChunk(this->i_hash[6], d + 24);
- uint32ToChunk(this->i_hash[7], d + 28);
+ uint32ToChunkInPlace(this->i_hash[0], digest);
+ uint32ToChunkInPlace(this->i_hash[1], digest + 4);
+ uint32ToChunkInPlace(this->i_hash[2], digest + 8);
+ uint32ToChunkInPlace(this->i_hash[3], digest + 12);
+ uint32ToChunkInPlace(this->i_hash[4], digest + 16);
+ uint32ToChunkInPlace(this->i_hash[5], digest + 20);
+ uint32ToChunkInPlace(this->i_hash[6], digest + 24);
+ uint32ToChunkInPlace(this->i_hash[7], digest + 28);
- return EMSHA_ROK;
+ return EMSHAResult::OK;
}
@@ -426,22 +446,22 @@ static const uint8_t helloWorld[] = {
constexpr uint32_t EMSHA_SELF_TEST_ITERS = 4;
-static EMSHA_RESULT
+static EMSHAResult
runTest(const uint8_t *input, uint32_t input_len, const uint8_t *expected)
{
- uint8_t hexString[65]{0};
- uint8_t d[SHA256_HASH_SIZE]{0};
- emsha::SHA256 ctx;
- emsha::EMSHA_RESULT res;
+ uint8_t hexString[65]{0};
+ uint8_t d[SHA256_HASH_SIZE]{0};
+ emsha::SHA256 ctx;
+ emsha::EMSHAResult res;
res = ctx.Update(input, input_len);
- if (EMSHA_ROK != res) {
+ if (EMSHAResult::OK != res) {
return res;
}
for (uint32_t n = 0; n < EMSHA_SELF_TEST_ITERS; n++) {
res = ctx.Result(d);
- if (EMSHA_ROK != res) {
+ if (EMSHAResult::OK != res) {
return res;
}
@@ -451,24 +471,24 @@ runTest(const uint8_t *input, uint32_t input_len, const uint8_t *expected)
std::cerr << "[!] have: " << hexString << "\n";
HexString(hexString, const_cast(helloWorld), 32);
std::cerr << "[!] want: " << hexString << "\n";
- return EMSHA_TEST_FAILURE;
+ return EMSHAResult::TestFailure;
}
}
}
- return EMSHA_ROK;
+ return EMSHAResult::OK;
}
-EMSHA_RESULT
-sha256SelfTest()
+EMSHAResult
+SHA256SelfTest()
{
- EMSHA_RESULT res;
+ EMSHAResult res;
res = runTest(reinterpret_cast(""), 0, emptyVector);
- if (EMSHA_ROK == res) {
+ if (EMSHAResult::OK == res) {
res = runTest(reinterpret_cast("hello, world"), 12, helloWorld);
- if (res != EMSHA_ROK) {
+ if (res != EMSHAResult::OK) {
std::cerr << "[!] failed on hello, world.\n";
}
} else {
@@ -480,10 +500,10 @@ sha256SelfTest()
#else // #ifdef EMSHA_NO_SELFTEST
-EMSHA_RESULT
+EMSHAResult
sha256_self_test()
{
- return EMSHA_SELFTEST_DISABLED;
+ return EMSHAResult::SelfTestDisabled;
}
diff --git a/test_emsha.cc b/test_emsha.cc
index 34b09eb..34f4dda 100644
--- a/test_emsha.cc
+++ b/test_emsha.cc
@@ -23,8 +23,8 @@
*/
+#include
#include
-
#include
#include "test_utils.h"
@@ -33,6 +33,10 @@
using namespace std;
+// how many test runs to benchmark hex strings?
+static constexpr auto testIterations = 32768;
+
+
#ifndef EMSHA_NO_HEXSTRING
static void
hexStringTest()
@@ -49,19 +53,11 @@ hexStringTest()
emsha::HexString(out, buf, emsha::SHA256_HASH_SIZE);
string const outs(reinterpret_cast(out));
if (outs != expected) {
- cerr << "FAILED: HexString" << endl;
- cerr << "\twanted: " << expected << endl;
- cerr << "\thave: " << out << endl;
+ cerr << "FAILED: HexString\n";
+ cerr << "\twanted: " << expected << "\n";
+ cerr << "\thave: " << out << "\n";
exit(1);
}
-
- cout << "PASSED: HexString ";
-#ifdef EMSHA_NO_HEXLUT
- cout << "(small LUT)";
-#else // #ifdef EMSHA_NO_HEXLUT
- cout << "(large LUT)";
-#endif // #ifdef EMSHA_NO_HEXLUT
- cout << endl;
}
#endif // #ifndef EMSHA_NO_HEXSTRING
@@ -84,9 +80,9 @@ hashEqualTest()
cerr << "FAILED: HashEqual\n";
cerr << "\tHashEqual should have succeeded comparing a and b.\n";
DumpHexString(s, a, emsha::SHA256_HASH_SIZE);
- cerr << "\ta <- " << s << std::endl;
+ cerr << "\ta <- " << s << "\n";
DumpHexString(s, b, emsha::SHA256_HASH_SIZE);
- cerr << "\tb <- " << s << std::endl;
+ cerr << "\tb <- " << s << "\n";
exit(1);
}
@@ -100,9 +96,9 @@ hashEqualTest()
cerr << "FAILED: HashEqual\n";
cerr << "\tHashEqual should not have succeeded comparing a and b.\n";
DumpHexString(s, a, emsha::SHA256_HASH_SIZE);
- cerr << "\ta <- " << s << std::endl;
+ cerr << "\ta <- " << s << "\n";
DumpHexString(s, b, emsha::SHA256_HASH_SIZE);
- cerr << "\tb <- " << s << std::endl;
+ cerr << "\tb <- " << s << "\n";
exit(1);
}
@@ -126,17 +122,33 @@ hashEqualTest()
cerr << "\tb <- " << s << std::endl;
exit(1);
}
-
-
- cout << "PASSED: HashEqual\n";
}
int
main()
{
+ auto start = std::chrono::steady_clock::now();
+ std::string testLabel;
+
+ for (auto i = 0; i < testIterations; i++) {
#ifndef EMSHA_NO_HEXSTRING
- hexStringTest();
+#ifndef EMSHA_NO_HEXLUT
+ testLabel = "(large LUT) ";
#endif
- hashEqualTest();
+ hexStringTest();
+#endif
+ hashEqualTest();
+ }
+
+ auto end = std::chrono::steady_clock::now();
+ auto delta = (end - start);
+
+ std::cout << "Passed HexString " << testLabel << "tests.\n";
+ std::cout << "Total time: "
+ << std::chrono::duration(delta).count()
+ << " ms\n";
+ std::cout << "Average over " << testIterations << " tests: "
+ << std::chrono::duration(delta).count() / testIterations
+ << " ns\n";
}
diff --git a/test_mem.cc b/test_mem.cc
index 70edd39..047f0c6 100644
--- a/test_mem.cc
+++ b/test_mem.cc
@@ -41,7 +41,7 @@
// Number of test iterations.
-static constexpr std::uint32_t ITERS = 8192;
+static constexpr std::uint32_t ITERS = 32768;
// The key used for HMAC.
static constexpr std::uint8_t k[] = {
@@ -111,13 +111,13 @@ static void
iterateSHA()
{
emsha::SHA256 ctx;
- int cmp = 0;
- emsha::EMSHA_RESULT res;
+ int cmp = 0;
+ emsha::EMSHAResult res;
res = ctx.Update(m, sizeof(m));
- assert(emsha::EMSHA_ROK == res);
+ assert(emsha::EMSHAResult::OK == res);
res = ctx.Result(dig);
- assert(emsha::EMSHA_ROK == res);
+ assert(emsha::EMSHAResult::OK == res);
cmp = std::memcmp(dig, d, emsha::SHA256_HASH_SIZE);
assert(0 == cmp);
@@ -128,13 +128,13 @@ static void
iterateHMAC()
{
emsha::HMAC ctx(k, kl);
- int cmp = 0;
- emsha::EMSHA_RESULT res;
+ int cmp = 0;
+ emsha::EMSHAResult res;
res = ctx.Update(m, sizeof(m));
- assert(emsha::EMSHA_ROK == res);
+ assert(emsha::EMSHAResult::OK == res);
res = ctx.Result(dig);
- assert(emsha::EMSHA_ROK == res);
+ assert(emsha::EMSHAResult::OK == res);
cmp = std::memcmp(dig, t, emsha::SHA256_HASH_SIZE);
assert(0 == cmp);
@@ -146,7 +146,7 @@ iterateSHASP()
{
int cmp = 0;
- assert(emsha::EMSHA_ROK == emsha::sha256Digest(m, sizeof(m), dig));
+ assert(emsha::EMSHAResult::OK == emsha::SHA256Digest(m, sizeof(m), dig));
cmp = std::memcmp(dig, d, emsha::SHA256_HASH_SIZE);
assert(0 == cmp);
}
@@ -155,11 +155,11 @@ iterateSHASP()
static void
iterateHMACSP()
{
- int cmp = 0;
- emsha::EMSHA_RESULT res;
+ int cmp = 0;
+ emsha::EMSHAResult res;
res = emsha::ComputeHMAC(k, kl, m, sizeof(m), dig);
- assert(emsha::EMSHA_ROK == res);
+ assert(emsha::EMSHAResult::OK == res);
cmp = std::memcmp(dig, t, emsha::SHA256_HASH_SIZE);
assert(0 == cmp);
diff --git a/test_sha256.cc b/test_sha256.cc
index 5436248..badfffb 100644
--- a/test_sha256.cc
+++ b/test_sha256.cc
@@ -76,18 +76,34 @@ main()
#ifdef EMSHA_NO_SELFTEST
cout << "[NOTICE] internal self-tests have been disabled.\n";
#else
- auto selfTestStatus = emsha::sha256SelfTest();
+ auto selfTestStatus = emsha::SHA256SelfTest();
switch (selfTestStatus) {
- case emsha::EMSHA_ROK:
+ case emsha::EMSHAResult::OK:
cout << "PASSED: SHA-256 self test\n";
break;
- case emsha::EMSHA_TEST_FAILURE:
- cout << "FAILED: SHA-256 self test (test failure)\n";
+ case emsha::EMSHAResult::TestFailure:
+ cout << "FAILED: SHA-256 self-test\n";
+ break;
+ case emsha::EMSHAResult::Unknown:
+ cout << "FAILED: SHA-256 self test (fault: Unknown)\n";
+ break;
+ case emsha::EMSHAResult::NullPointer:
+ cout << "FAILED: SHA-256 self test (fault: NullPointer)\n";
+ break;
+ case emsha::EMSHAResult::InvalidState:
+ cout << "FAILED: SHA-256 self test (fault: InvalidState)\n";
+ break;
+ case emsha::EMSHAResult::InputTooLong:
+ cout << "FAILED: SHA-256 self test (fault: InputTooLong)\n";
+ break;
+ case emsha::EMSHAResult::SelfTestDisabled:
+ cout << "FAILED: SHA-256 self test (fault: SelfTestDisabled)\n";
break;
default:
- cout << "FAILED: SHA-256 self test (fault " << selfTestStatus << ")\n";
+ cout << "FAILED: SHA-256 self test (fault: internal system failure)\n";
+ abort();
}
- assert(selfTestStatus == emsha::EMSHA_ROK);
+ assert(selfTestStatus == emsha::EMSHAResult::OK);
#endif
diff --git a/test_utils.cc b/test_utils.cc
index 39dd2e6..4f1e35d 100644
--- a/test_utils.cc
+++ b/test_utils.cc
@@ -53,28 +53,28 @@ DumpHexString(std::string& hs, uint8_t *s, uint32_t sl)
}
-emsha::EMSHA_RESULT
-runHMACTest(const struct hmacTest test, const string& label)
+emsha::EMSHAResult
+runHMACTest(const struct hmacTest& test, const string& label)
{
- emsha::HMAC h(test.key, test.keylen);
- emsha::EMSHA_RESULT res;
- uint8_t dig[emsha::SHA256_HASH_SIZE];
+ emsha::HMAC h(test.key, test.keylen);
+ emsha::EMSHAResult res;
+ uint8_t dig[emsha::SHA256_HASH_SIZE];
string hs;
res = h.Update((uint8_t *)test.input.c_str(), test.input.size());
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
goto exit;
}
for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) {
res = h.Result(dig);
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
goto exit;
}
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) {
- res = emsha::EMSHA_TEST_FAILURE;
+ res = emsha::EMSHAResult::TestFailure;
goto exit;
}
memset(dig, 0, emsha::SHA256_HASH_SIZE);
@@ -84,19 +84,19 @@ runHMACTest(const struct hmacTest test, const string& label)
h.Reset();
res = h.Update((uint8_t *)test.input.c_str(), test.input.size());
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
goto exit;
}
for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) {
res = h.Result(dig);
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
goto exit;
}
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) {
- res = emsha::EMSHA_TEST_FAILURE;
+ res = emsha::EMSHAResult::TestFailure;
goto exit;
}
memset(dig, 0, emsha::SHA256_HASH_SIZE);
@@ -106,7 +106,7 @@ runHMACTest(const struct hmacTest test, const string& label)
res = emsha::ComputeHMAC(test.key, test.keylen,
(uint8_t *)test.input.c_str(), test.input.size(),
dig);
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
cerr << "(running single pass function test)\n";
goto exit;
}
@@ -114,15 +114,15 @@ runHMACTest(const struct hmacTest test, const string& label)
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) {
cerr << "(comparing single pass function output)\n";
- res = emsha::EMSHA_TEST_FAILURE;
+ res = emsha::EMSHAResult::TestFailure;
goto exit;
}
memset(dig, 0, emsha::SHA256_HASH_SIZE);
- res = emsha::EMSHA_ROK;
+ res = emsha::EMSHAResult::OK;
exit:
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
cerr << "FAILED: " << label << endl;
cerr << "\tinput: " << test.input << endl;
cerr << "\twanted: " << test.output << endl;
@@ -137,7 +137,7 @@ int
runHMACTests(const struct hmacTest *tests, size_t nTests, const string& label)
{
for (uint32_t i = 0; i < nTests; i++) {
- if (emsha::EMSHA_ROK != runHMACTest(*(tests + i), label)) {
+ if (emsha::EMSHAResult::OK != runHMACTest(*(tests + i), label)) {
return -1;
}
}
@@ -146,28 +146,28 @@ runHMACTests(const struct hmacTest *tests, size_t nTests, const string& label)
}
-emsha::EMSHA_RESULT
+emsha::EMSHAResult
runHashTest(const struct hashTest& test, const string& label)
{
- emsha::SHA256 ctx;
- emsha::EMSHA_RESULT res;
- uint8_t dig[emsha::SHA256_HASH_SIZE];
+ emsha::SHA256 ctx;
+ emsha::EMSHAResult res;
+ uint8_t dig[emsha::SHA256_HASH_SIZE];
string hs;
res = ctx.Update((uint8_t *)test.input.c_str(), test.input.size());
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
goto exit;
}
for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) {
res = ctx.Result(dig);
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
goto exit;
}
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) {
- res = emsha::EMSHA_TEST_FAILURE;
+ res = emsha::EMSHAResult::TestFailure;
goto exit;
}
memset(dig, 0, emsha::SHA256_HASH_SIZE);
@@ -177,28 +177,28 @@ runHashTest(const struct hashTest& test, const string& label)
ctx.Reset();
res = ctx.Update((uint8_t *)test.input.c_str(), test.input.size());
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
goto exit;
}
for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) {
res = ctx.Result(dig);
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
goto exit;
}
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) {
- res = emsha::EMSHA_TEST_FAILURE;
+ res = emsha::EMSHAResult::TestFailure;
goto exit;
}
memset(dig, 0, emsha::SHA256_HASH_SIZE);
}
// Test that the single-pass function works.
- res = emsha::sha256Digest((uint8_t *) test.input.c_str(),
+ res = emsha::SHA256Digest((uint8_t *) test.input.c_str(),
test.input.size(), dig);
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
cerr << "(running single pass function test)\n";
goto exit;
}
@@ -206,14 +206,14 @@ runHashTest(const struct hashTest& test, const string& label)
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) {
cerr << "(comparing single pass function output)\n";
- res = emsha::EMSHA_TEST_FAILURE;
+ res = emsha::EMSHAResult::TestFailure;
goto exit;
}
memset(dig, 0, emsha::SHA256_HASH_SIZE);
- res = emsha::EMSHA_ROK;
+ res = emsha::EMSHAResult::OK;
exit:
- if (emsha::EMSHA_ROK != res) {
+ if (emsha::EMSHAResult::OK != res) {
cerr << "FAILED: " << label << endl;
cerr << "\tinput: '" << test.input << "'" << endl;
cerr << "\twanted: " << test.output << endl;
@@ -227,7 +227,7 @@ int
runHashTests(const struct hashTest *tests, const size_t ntests, const string& label)
{
for (uint32_t i = 0; i < ntests; i++) {
- if (emsha::EMSHA_ROK != runHashTest(*(tests + i), label)) {
+ if (emsha::EMSHAResult::OK != runHashTest(*(tests + i), label)) {
return -1;
}
}
diff --git a/test_utils.h b/test_utils.h
index 52a40dc..74783c7 100644
--- a/test_utils.h
+++ b/test_utils.h
@@ -64,13 +64,13 @@ void dump_pair(std::uint8_t *, std::uint8_t *);
// SHA-256 testing functions.
-emsha::EMSHA_RESULT runHashTest(const struct hashTest& test, const std::string& label);
+emsha::EMSHAResult runHashTest(const struct hashTest& test, const std::string& label);
int runHashTests(const struct hashTest *tests, const std::size_t nTests,
const std::string& label);
// HMAC-SHA-256 testery.
-emsha::EMSHA_RESULT runHMACTest(struct hmacTest test, const std::string& label);
+emsha::EMSHAResult runHMACTest(struct hmacTest& test, const std::string& label);
int runHMACTests(const struct hmacTest *tests, std::size_t nTests,
const std::string& label);