Cut a release.

This commit is contained in:
Kyle Isom 2023-10-18 03:39:27 -07:00
parent ad07da5a39
commit 4a2c18751a
16 changed files with 593 additions and 543 deletions

View File

@ -1,7 +1,8 @@
HeaderFilterRegex: \./.+
Checks: >- Checks: >-
bugprone-*, bugprone-*,
cppcoreguidelines-*, cppcoreguidelines-*,
google-*,
misc-*, misc-*,
modernize-*, modernize-*,
performance-*, performance-*,
@ -15,6 +16,7 @@ Checks: >-
-cppcoreguidelines-pro-type-vararg, -cppcoreguidelines-pro-type-vararg,
-google-readability-braces-around-statements, -google-readability-braces-around-statements,
-google-readability-function-size, -google-readability-function-size,
-google-readability-namespace-comments,
-misc-no-recursion, -misc-no-recursion,
-modernize-return-braced-init-list, -modernize-return-braced-init-list,
-modernize-use-nodiscard, -modernize-use-nodiscard,

View File

@ -2,8 +2,8 @@
<profile version="1.0"> <profile version="1.0">
<option name="myName" value="Project Default" /> <option name="myName" value="Project Default" />
<inspection_tool class="ClangTidy" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="ClangTidy" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="Misra" enabled="false" level="WARNING" enabled_by_default="false"> <inspection_tool class="Misra" enabled="true" level="WARNING" enabled_by_default="false">
<scope name="ProjectSources" level="WARNING" enabled="false" /> <scope name="ProjectSources" level="WARNING" enabled="true" />
</inspection_tool> </inspection_tool>
</profile> </profile>
</component> </component>

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.22) cmake_minimum_required(VERSION 3.22)
project(emsha project(emsha
VERSION 1.0.3 VERSION 1.1.0
LANGUAGES CXX LANGUAGES CXX
DESCRIPTION "A compact HMAC-SHA-256 C++11 library.") DESCRIPTION "A compact HMAC-SHA-256 C++11 library.")
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
@ -9,8 +9,14 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(EMSHA_NO_HEXSTRING OFF CACHE BOOL set(EMSHA_NO_HEXSTRING OFF CACHE BOOL
"Don't include support for hex strings.") "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).") "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) include(CTest)
enable_testing() enable_testing()

View File

@ -24,13 +24,13 @@ if (${DOXYGEN_FOUND})
set(DOXYGEN_GENERATE_LATEX YES) set(DOXYGEN_GENERATE_LATEX YES)
set(DOXYGEN_EXTRACT_ALL YES) set(DOXYGEN_EXTRACT_ALL YES)
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE "${CMAKE_CURRENT_SOURCE_DIR}/docs/mainpage.md") 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.") message(STATUS "Doxygen found, building docs.")
doxygen_add_docs(${PROJECT_NAME}_docs doxygen_add_docs(${PROJECT_NAME}_docs
${HEADER_FILES} ${HEADER_FILES}
${SOURCE_FILES} ALL
USE_STAMP_FILE) USE_STAMP_FILE)
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_docs)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html
${CMAKE_CURRENT_BINARY_DIR}/latex ${CMAKE_CURRENT_BINARY_DIR}/latex
DESTINATION share/doc/${PROJECT_NAME}/doxygen) DESTINATION share/doc/${PROJECT_NAME}/doxygen)

View File

@ -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` All functionality provided by this library is found under the `emsha`
namespace. 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: The possible values are:
// All operations have completed successfully so far. // All operations have completed successfully so far.
EMSHA_ROK = 0, EMSHAResult::OK = 0,
// A self test or unit test failed. // 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 // A null pointer was passed in as a buffer where it
// shouldn't have been. // shouldn't have been.
EMSHA_NULLPTR = 2, EMSHAResult::NullPointer = 2,
// The Hash is in an invalid state. // The Hash is in an invalid state.
EMSHA_INVALID_STATE = 3, EMSHAResult::InvalidState = 3,
// The input to SHA256::update is too large. // 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 // The self tests have been disabled, but a self test
// function was called. // function was called.
EMSHA_SELFTEST_DISABLED = 5 EMSHAResult::SelfTestDisabled = 5
As a convenience, the following `typedef` is also provided. 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"} > role="type"}
## The Hash interface ## The Hash interface
In general, a [Hash]{.title-ref} is used along the lines of: : 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) hash_single_pass(uint8_t *m, uint32_t ml, uint8_t *digest)
{ {
// Depending on the implementation, the constructor may need // Depending on the implementation, the constructor may need
// arguments. // arguments.
emsha::Hash h; emsha::Hash h;
emsha::EMSHA_RESULT res; emsha::EMSHAResult res;
res = h.write(m, ml); res = h.write(m, ml);
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
return res; return res;
} }

View File

@ -55,10 +55,13 @@ HashEqual(const uint8_t *a, const uint8_t *b)
#ifndef EMSHA_NO_HEXSTRING #ifndef EMSHA_NO_HEXSTRING
namespace {
#ifndef EMSHA_NO_HEXLUT #ifndef EMSHA_NO_HEXLUT
// If using a lookup table is permitted, then the faster way to do this // If using a lookup table is permitted, then the faster way to do this
// is to use one. // is to use one.
static void void
writeHexChar(uint8_t *dest, uint8_t src) writeHexChar(uint8_t *dest, uint8_t src)
{ {
static constexpr uint8_t lut[256][3] = { 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) // memory constraints, we'll work around this using a small (16-byte)
// lookup table and some bit shifting. On platforms where even this is // lookup table and some bit shifting. On platforms where even this is
// too much, the HexString functionality will just be disabled. // too much, the HexString functionality will just be disabled.
static void void
writeHexChar(uint8_t *dest, uint8_t src) writeHexChar(uint8_t *dest, uint8_t src)
{ {
static constexpr uint8_t lut[] = { static constexpr uint8_t lut[] = {
@ -118,6 +121,7 @@ writeHexChar(uint8_t *dest, uint8_t src)
*(dest + 1) = lut[(src & 0xF)]; *(dest + 1) = lut[(src & 0xF)];
} }
#endif // #ifndef EMSHA_NO_HEXLUT #endif // #ifndef EMSHA_NO_HEXLUT
} // anonymous namespace for writeHexChar
void void

View File

@ -35,11 +35,10 @@
#include <cstdint> #include <cstdint>
// Emsha is an EMbedded Secure HAshing interface. // emsha is an EMbedded Secure HAshing interface.
namespace emsha { namespace emsha {
/// EMSHA_CHECK is used for sanity checks in certain parts of the code.
#ifdef NDEBUG #ifdef NDEBUG
/// EMSHA_CHECK is used for sanity checks in certain parts of /// EMSHA_CHECK is used for sanity checks in certain parts of
/// the code. If asserts are turned off, expand the check to an /// 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; const std::uint32_t SHA256_HASH_SIZE = 32;
/// The EMSHA_RESULT type is used to indicate whether an /// \brief Describe the result of an EMSHA operation.
/// operation succeeded, and if not, what the general fault type ///
/// was. /// The EMSHAResult type is used to indicate whether an operation
typedef enum _EMSHA_RESULT_ : std::uint8_t { /// succeeded, and if not, what the general fault type was.
/// All operations have completed successfully so far. typedef enum class EMSHAResult : std::uint8_t {
EMSHA_ROK = 0, /// An unknown fault occurred. This is a serious bug in the
/// program.
Unknown = 0,
/// A self test or unit test failed. /// All operations have completed successfully so far.
EMSHA_TEST_FAILURE = 1, OK = 1,
/// The self-test failed.
TestFailure = 2,
/// A null pointer was passed in as a buffer where it shouldn't /// A null pointer was passed in as a buffer where it shouldn't
/// have been. /// have been.
EMSHA_NULLPTR = 2, NullPointer = 3,
/// The Hash is in an invalid state. /// The Hash is in an invalid state.
EMSHA_INVALID_STATE = 3, InvalidState = 4,
/// The input to SHA256::update is too large. /// 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 /// The self tests have been disabled, but a self-test function
/// was called. /// was called.
EMSHA_SELFTEST_DISABLED = 5 SelfTestDisabled = 6
} EMSHA_RESULT; } ;
// A Hash is generalised superclass supporting concrete classes /// A Hash is an abstract base class supporting concrete classes
// that produce digests of data. /// that produce digests of data.
class Hash { class Hash {
public: public:
virtual ~Hash() = default; virtual ~Hash() = default;
/// Reset should bring the Hash back into its /// \brief Bring the Hash back to its initial state.
/// initial state. That is, the idea is that
/// ///
/// hash->reset(); hash->update(...)... ; /// That is, the idea is that
/// hash->result(...) ; ///
/// ```
/// hash->reset();
/// hash->update(...);
/// hash->result(...);
/// ```
/// ///
/// is idempotent, assuming the inputs to update /// is idempotent, assuming the inputs to update
/// and result are constant. The implications of /// and result are constant. The implications of
@ -103,34 +111,54 @@ public:
/// in general, it has the effect of preserving /// in general, it has the effect of preserving
/// any initial state while removing any data /// any initial state while removing any data
/// written to the Hash via the update method. /// 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. /// \brief Write message data into the Hash.
virtual EMSHA_RESULT Update(const std::uint8_t *m, ///
std::uint32_t ml) = 0; /// \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 /// \brief Carry out any final operations on the Hash.
/// on the Hash; after a call to finalize, no ///
/// more data can be written. Additionally, it /// After a call to finalize, no more data can be written.
/// transfers out the resulting hash into its /// Additionally, it transfers out the resulting hash into its
/// argument. /// 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 /// \brief Result transfers out the hash to the argument.
/// argument. The Hash must keep enough state ///
/// for repeated calls to result to work. /// The Hash must keep enough state for repeated calls to
virtual EMSHA_RESULT Result(std::uint8_t *d) = 0; /// 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 /// \brief Return the output size of the Hash.
/// Hash; this is, how large the buffers written ///
/// to by result should be. /// This is how large the buffers written to by result should
/// be.
virtual std::uint32_t Size() = 0; virtual std::uint32_t Size() = 0;
}; };
/// HashEqual provides a constant time function for comparing /// \brief Constant-time function for comparing two digests.
/// two hashes. The caller *must* ensure that both a and b are ///
/// the same size. The recommended approach is to use fixed-size /// HashEqual provides a constant time function for comparing two
/// buffers of emsha::SHA256_HASH_SIZE length: /// 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++ /// ```c++
/// uint8_t expected[emsha::SHA256_HASH_SIZE]; /// uint8_t expected[emsha::SHA256_HASH_SIZE];
@ -146,21 +174,21 @@ public:
/// \param a A byte buffer of size Hash::Size(). /// \param a A byte buffer of size Hash::Size().
/// \param b A byte buffer of size Hash::Size(). /// \param b A byte buffer of size Hash::Size().
/// \return True if both byte arrays match. /// \return True if both byte arrays match.
bool bool HashEqual(const std::uint8_t *a, const std::uint8_t *b);
HashEqual(const std::uint8_t *a, const std::uint8_t *b);
#ifndef EMSHA_NO_HEXSTRING #ifndef EMSHA_NO_HEXSTRING
/// HexString writes a hex-encoded version of the src byte /// \brief Write a hex-encoded version of a byte string.
/// array into dest. The caller *must* ensure that dest is
/// srclen * 2 bytes or longer.
/// ///
/// 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. /// 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. /// \param srclen The size in bytes of src.
void void HexString(std::uint8_t *dest, std::uint8_t *src, std::uint32_t srclen);
HexString(std::uint8_t *dest, std::uint8_t *src, std::uint32_t srclen);
#endif // EMSHA_NO_HEXSTRING #endif // EMSHA_NO_HEXSTRING

View File

@ -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 /// HMAC is a keyed hash that can be used to produce an
/// authenticated hash of some data. The HMAC is built on /// 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 /// note that faults that occur in the SHA-256 code will be
/// propagated up as the return value from many of the HMAC /// propagated up as the return value from many of the HMAC
/// functions. /// functions.
class HMAC : Hash { class HMAC : Hash {
public: public:
/// An HMAC is constructed with a key and the /// \brief Construct an HMAC with its initial key.
/// length of the key. This key is stored in ///
/// the HMAC context, and is wiped by the HMAC /// An HMAC is constructed with a key and the length of the
/// destructor. /// key. This key is stored in the HMAC context, and is wiped
/// by the HMAC destructor.
/// ///
/// \param k The HMAC key. /// \param k The HMAC key.
/// \param kl THe length of the HMAC key. /// \param kl THe length of the HMAC key.
HMAC(const uint8_t *k, uint32_t kl); HMAC(const uint8_t *k, uint32_t kl);
/// Reset clears any data written to the HMAC; /// \brief Clear any data written to the HMAC.
/// this is equivalent to constructing a new HMAC,
/// but it preserves the keys.
/// ///
/// \return EMSHA_ROK is returned if the reset /// This is equivalent to constructing a new HMAC, but it
/// occurred without (detected) fault. /// preserves the keys.
/// If a fault occurs with the under- ///
/// lying SHA-256 context, the error /// \return EMSHAResult::OK is returned if the reset occurred
/// code is returned. /// without (detected) fault. If a fault occurs with
EMSHA_RESULT Reset() override; /// the underlying SHA256 context, the error code is
/// returned.
EMSHAResult Reset() override;
/// Update writes data into the context. While /// \brief Write data into the context.
/// 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.
/// ///
/// \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. /// to be written.
/// \param ml The message length, in bytes. /// \param messageLength The message length, in bytes.
/// \return /// \return An ::EMSHAResult describing the result of the
/// - EMSHA_NULLPTR is returned if m is NULL and ml is /// operation.
/// 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.
/// ///
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 /// \brief Complete the HMAC computation.
// method is called, the context cannot be updated ///
// unless the context is reset. /// \note Once #Finalise is called, the context cannot be
// /// updated unless the context is reset.
// Inputs: ///
// d: a byte buffer that must be at least /// \param digest A byte buffer that must be at least #HMAC.Size()
// HMAC.size() in length. /// in length.
// /// \return An EMSHAResult describing the result of this
// Outputs: /// method:
// EMSHA_NULLPTR is returned if d is the null ///
// pointer. /// - EMSHAResult::NullPointer is returned if d is a
// /// null pointer.
// EMSHA_INVALID_STATE is returned if the HMAC /// - EMSHAResult::InvalidState is returned if the HMAC
// context is in an invalid state, such as if there /// context is in an invalid state, such as if there
// were errors in previous updates. /// were errors in previous updates.
// /// - EMSHAResult::OK is returned if the context was
// EMSHA_ROK is returned if the context was /// successfully finalised and the digest copied to d.
// successfully finalised and the digest copied to ///
// d. EMSHAResult Finalise(std::uint8_t *digest) override;
//
EMSHA_RESULT Finalise(uint8_t *) override;
// Result copies the result from the HMAC context into /// \brief Copy the current digest into a destination buffer.
// the buffer pointed to by d, running finalize if ///
// needed. Once called, the context cannot be updated /// Copy the current digest from the HMAC context into
// until the context is reset. /// `digest`, 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 /// \param digest A byte buffer that must be at least #HMAC.size()
// HMAC.size() in length. /// in length.
// /// \return An ::EMSHAResult describing the result of this
// Outputs: /// method:
// EMSHA_NULLPTR is returned if d is the null ///
// pointer. /// - EMSHAResult::NullPointer is returned if d is a
// /// null pointer.
// EMSHA_INVALID_STATE is returned if the HMAC /// - EMSHAResult::InvalidState is returned if the HMAC
// context is in an invalid state, such as if there /// context is in an invalid state, such as if there
// were errors in previous updates. /// were errors in previous updates.
// /// - EMSHAResult::OK is returned if the context was
// EMSHA_ROK is returned if the context was /// successfully finalised and the digest copied to d.
// successfully finalised and the digest copied to EMSHAResult Result(std::uint8_t *digest) override;
// d.
//
EMSHA_RESULT Result(uint8_t *) override;
// size returns the output size of HMAC-SHA-256, e.g. /// \brief Returns the output size of HMAC-SHA-256.
// the size that the buffers passed to finalize and ///
// result should be. /// The buffers passed to #Update and #Finalise should be at
// /// least this size.
// Outputs: ///
// A uint32_t representing the expected size /// \return The expected size of buffers passed to result and
// of buffers passed to result and finalize. /// finalize.
std::uint32_t Size() override; std::uint32_t Size() override;
// When an HMAC context is destroyed, it is reset and /// When an HMAC context is destroyed, it is reset and
// the key material is zeroised using the STL fill /// the key material is zeroised using the STL `fill`
// function. /// function.
~HMAC(void); ~HMAC();
private: private:
uint8_t hstate; uint8_t hstate;
SHA256 ctx; SHA256 ctx;
uint8_t k[HMAC_KEY_LENGTH]; uint8_t k[HMAC_KEY_LENGTH];
uint8_t buf[SHA256_HASH_SIZE]; uint8_t buf[SHA256_HASH_SIZE];
EMSHA_RESULT reset(); EMSHAResult reset();
inline EMSHA_RESULT inline EMSHAResult finalResult(uint8_t *d);
finalResult(uint8_t *d);
}; };
// compute_hmac performs a single-pass HMAC computation over
// a message. /// \brief Perform a single-pass HMAC computation over a message.
// ///
// Inputs: /// \param k A byte buffer containing the HMAC key.
// 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.
// kl: the length of the HMAC key. /// \param ml The length of the message.
// /// \param d Byte buffer that will be used to store the resulting
// m: the message data over which the HMAC is to be computed. /// HMAC. It should be emsha::SHA256_HASH_SIZE bytes in size.
// /// \return An ::EMSHAResult describing the result of the HMAC operation.
// ml: the length of the message. EMSHAResult
// ComputeHMAC(const uint8_t *k, const uint32_t kl,
// d: a byte buffer that will be used to store the resulting const uint8_t *m, const uint32_t ml,
// 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,
uint8_t *d); uint8_t *d);
} // end of namespace emsha } // end of namespace emsha

View File

@ -34,184 +34,160 @@
#include <cstdint> #include <cstdint>
#include <emsha/emsha.h> #include <emsha/emsha.h>
#include <array>
namespace emsha { 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; const uint32_t SHA256_MB_SIZE = 64;
class SHA256 : Hash { class SHA256 : Hash {
public: public:
// A SHA256 context does not need any special /// \brief A SHA256 context does not need any special
// construction. It can be declared and /// construction.
// immediately start being used. ///
/// It can be declared and immediately start being used.
SHA256(); SHA256();
// The SHA256 destructor will clear out its internal /// The SHA256 destructor will clear out its internal
// message buffer; all the members are local and /// message buffer; all the members are local and
// not resource handles, so cleanup is minimal. /// not resource handles, so cleanup is minimal.
~SHA256(); ~SHA256();
// reset clears the internal state of the SHA256 /// \brief Clear the internal state of the SHA256 context,
// context and returns it to its initial state. /// returning it to its initial state.
// It should always return EMSHA_ROK. ///
EMSHA_RESULT Reset() override; /// \return This should always return EMSHAResult::OK.
EMSHAResult Reset() override;
// update writes data into the context. While /// \brief Writes data into the SHA256.
// there is an upper limit on the size of data ///
// that SHA-256 can operate on, this package is /// While there is an upper limit on the size of data that
// designed for small systems that will not /// SHA-256 can operate on, this package is designed for small
// approach that level of data (which is on the /// systems that will not approach that level of data (which is
// order of 2 exabytes), so it is not thought /// on the order of 2 exabytes), so it is not thought to be a
// to be a concern. /// concern.
// ///
// Inputs: /// \param message A byte array containing the message to be
// m: a byte array containing the message to /// written. It must not be NULL (unless the
// be written. It must not be NULL (unless /// message length is zero).
// the message length is zero). /// \param messageLength The message length, in bytes.
// /// \return An ::EMSHAResult describing the result of the
// ml: the message length, in bytes. /// operation.
// ///
// Outputs: /// - EMSHAResult::NullPointer is returned if m is a
// EMSHA_NULLPTR is returned if m is NULL /// nullptr and ml is nonzero.
// and ml is nonzero. /// - EMSHAResult::InvalidState is returned if the
// /// update is called after a call to finalize.
// EMSHA_INVALID_STATE is returned if the /// - EMSHAResult::InputTooLong is returned if too much
// update is called after a call to /// data has been written to the context.
// finalize. /// - EMSHAResult::OK is returned if the data was
// /// successfully added to the SHA-256 context.
// SHA256_INPUT_TOO_LONG is returned if too EMSHAResult Update(const std::uint8_t *message, std::uint32_t messageLength) override;
// 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;
// Finalise completes the digest. Once this /// \brief Complete the digest.
// method is called, the context cannot be ///
// updated unless the context is reset. /// 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 /// \param digest byte buffer that must be at least
// SHA256.size() in length. /// SHA256.size() in length.
// /// \return An ::EMSHAResult describing the result of the
// Outputs: /// operation.
// EMSHA_NULLPTR is returned if d is the ///
// null pointer. /// - EMSHAResult::NullPointer is returned if a nullptr
// /// is passed in.
// EMSHA_INVALID_STATE is returned if the /// - EMSHAResult::InvalidState is returned if the
// SHA-256 context is in an invalid state, /// SHA-256 context is in an invalid state, such as
// such as if there were errors in previous /// if there were errors in previous updates.
// updates. /// - EMSHAResult::OK is returned if the context was
// /// successfully finalised and the digest copied to
// EMSHA_ROK is returned if the context was /// digest.
// successfully finalised and the digest EMSHAResult Finalise(std::uint8_t *digest) override;
// copied to d.
//
EMSHA_RESULT Finalise(uint8_t *d) override;
// result copies the result from the SHA-256 /// \brief Copy the result from the SHA-256
// context into the buffer pointed to by d, /// context into the buffer pointed to by d,
// running Finalise if needed. Once called, /// running #Finalise if needed. Once called,
// the context cannot be updated until the /// the context cannot be updated until the
// context is reset. /// context is reset.
// ///
// Inputs: /// \param digest A byte buffer that must be at least
// d: a byte buffer that must be at least /// SHA256.size() in length.
// SHA256.size() in length. /// \return An ::EMSHAResult describing the result of the
// /// operation.
// Outputs: ///
// EMSHA_NULLPTR is returned if d is the /// - EMSHAResult::NullPointer is returned if a nullptr
// null pointer. /// is passed in.
// /// - EMSHAResult::InvalidState is returned if the
// EMSHA_INVALID_STATE is returned if the /// SHA-256 context is in an invalid state, such as
// SHA-256 context is in an invalid state, /// if there were errors in previous updates.
// such as if there were errors in previous /// - EMSHAResult::OK is returned if the context was
// updates. /// successfully finalised and the digest copied to
// /// digest.
// EMSHA_ROK is returned if the context was EMSHAResult Result(std::uint8_t *digest) override;
// successfully finalised and the digest
// copied to d.
//
EMSHA_RESULT Result(uint8_t *d) override;
// size returns the output size of SHA256, e.g. /// \brief Returns the output size of SHA-256.
// the size that the buffers passed to finalize ///
// and result should be. /// The buffers passed to #Update and #Finalise should be at
// /// least this size.
// Outputs: ///
// a uint32_t representing the expected size /// \return The expected size of buffers passed to result and
// of buffers passed to result and finalize. /// finalize.
std::uint32_t Size() override; std::uint32_t Size() override;
private: private:
// mlen stores the current message length. uint64_t mlen; // Current message length.
uint64_t mlen; uint32_t i_hash[8]; // The intermediate hash is 8x 32-bit blocks.
// The intermediate hash is 8x 32-bit blocks.
uint32_t i_hash[8];
// hStatus is the hash status, and hComplete indicates // hStatus is the hash status, and hComplete indicates
// whether the hash has been finalised. // whether the hash has been finalised.
EMSHA_RESULT hStatus; EMSHAResult hStatus;
uint8_t hComplete; uint8_t hComplete;
// mb is the message block, and mbi is the message // mb is the message block, and mbi is the message
// block index. // block index.
uint8_t mbi; uint8_t mbi;
uint8_t mb[SHA256_MB_SIZE]; std::array<uint8_t, SHA256_MB_SIZE> mb;
inline EMSHA_RESULT addLength(const uint32_t); inline EMSHAResult addLength(const uint32_t);
inline void updateMessageBlock(void); inline void updateMessageBlock(void);
inline void padMessage(uint8_t pc); inline void padMessage(uint8_t pc);
EMSHA_RESULT reset(); uint32_t chunkToUint32(uint32_t offset);
uint32_t uint32ToChunk(uint32_t offset);
EMSHAResult reset();
}; // end class SHA256 }; // 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 /// \brief SHA256Digest performs a single pass hashing of the message
// SHA-256 functions are working correctly. /// passed in.
// ///
// Outputs: /// \param m Byte buffer containing the message to hash.
// EMSHA_ROK is returned if the self tests pass. /// \param ml The length of m.
// /// \param d Byte buffer that will be used to store the resulting hash;
// EMSHA_SELFTEST_DISABLED is returned if the self tests /// it should have at least emsha::SHA256_HASH_SIZE bytes
// have been disabled (e.g., libemsha was compiled with the /// available.
// EMSHA_NO_SELFTEST #define). /// \return An ::EMSHAResult describing the result of the operation.
// EMSHAResult SHA256Digest(const uint8_t *m, uint32_t ml, uint8_t *d);
// If a fault occurred inside the SHA-256 code, the error
// code from one of the update, finalize, result, or reset /// \brief SHA256SelfTest runs through two test cases to ensure that the
// methods is returned. /// SHA-256 functions are working correctly.
// ///
// If the fault is that the output does not match the test /// \return The result of the self-test.
// vector, EMSHA_TEST_FAILURE is returned. ///
EMSHA_RESULT /// - EMSHAResult::OK is returned if the self tests pass.
sha256SelfTest(void); /// - 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 } // end of namespace emsha

96
hmac.cc
View File

@ -63,11 +63,12 @@ static constexpr uint8_t opad = 0x5c;
HMAC::HMAC(const uint8_t *ik, uint32_t ikl) HMAC::HMAC(const uint8_t *ik, uint32_t ikl)
: hstate(HMAC_INIT), k{0}, buf{0} : hstate(HMAC_INIT), k{0}, buf{0}
{ {
std::fill(this->k, this->k+HMAC_KEY_LENGTH, 0);
std::fill(this->k, this->k + emsha::HMAC_KEY_LENGTH, 0);
if (ikl < HMAC_KEY_LENGTH) { 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) { while (ikl < HMAC_KEY_LENGTH) {
this->k[ikl++] = 0; this->k[ikl++] = 0;
} }
@ -76,7 +77,9 @@ HMAC::HMAC(const uint8_t *ik, uint32_t ikl)
this->ctx.Result(this->k); this->ctx.Result(this->k);
this->ctx.Reset(); this->ctx.Reset();
} else { } else {
std::copy(ik, ik + ikl, this->k); for (uint32_t i = 0; i < ikl; i++) {
this->k[i] = ik[i];
}
} }
this->reset(); this->reset();
@ -93,17 +96,17 @@ HMAC::~HMAC()
} }
EMSHA_RESULT EMSHAResult
HMAC::Reset() HMAC::Reset()
{ {
return this->reset(); return this->reset();
} }
EMSHA_RESULT EMSHAResult
HMAC::reset() HMAC::reset()
{ {
EMSHA_RESULT res; EMSHAResult res;
// Following a reset, both SHA-256 contexts and result buffer should be // 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 // 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); res = this->ctx.Update(key, HMAC_KEY_LENGTH);
if (EMSHA_ROK != res) { if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID; this->hstate = HMAC_INVALID;
return res; return res;
} }
@ -128,55 +131,56 @@ HMAC::reset()
std::fill(key, key + HMAC_KEY_LENGTH, 0); std::fill(key, key + HMAC_KEY_LENGTH, 0);
this->hstate = HMAC_IPAD; this->hstate = HMAC_IPAD;
return EMSHA_ROK; return EMSHAResult::OK;
} }
EMSHA_RESULT EMSHAResult
HMAC::Update(const uint8_t *m, uint32_t ml) HMAC::Update(const std::uint8_t *message, std::uint32_t messageLength)
{ {
EMSHA_RESULT res; EMSHAResult res;
SHA256 &hctx = this->ctx; SHA256 &hctx = this->ctx;
EMSHA_CHECK(m != nullptr, EMSHA_NULLPTR); EMSHA_CHECK(message != nullptr, EMSHAResult::NullPointer);
EMSHA_CHECK(HMAC_IPAD == this->hstate, EMSHA_INVALID_STATE); EMSHA_CHECK(HMAC_IPAD == this->hstate, EMSHAResult::InvalidState);
// Write the message to the SHA-256 context. // Write the message to the SHA-256 context.
res = hctx.Update(m, ml); res = hctx.Update(message, messageLength);
if (EMSHA_ROK != res) { if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID; this->hstate = HMAC_INVALID;
return res; return res;
} }
assert(HMAC_IPAD == this->hstate); assert(HMAC_IPAD == this->hstate);
return EMSHA_ROK; return EMSHAResult::OK;
} }
inline EMSHA_RESULT inline EMSHAResult
HMAC::finalResult(uint8_t *d) HMAC::finalResult(uint8_t *d)
{ {
if (nullptr == d) { if (nullptr == d) {
return EMSHA_NULLPTR; return EMSHAResult::NullPointer;
} }
// If the HMAC has already been finalised, skip straight to // If the HMAC has already been finalised, skip straight to
// copying the result. // copying the result.
if (HMAC_FIN == this->hstate) { if (this->hstate == HMAC_FIN) {
std::copy(this->buf, this->buf + SHA256_HASH_SIZE, d); std::copy(this->buf, this->buf+SHA256_HASH_SIZE, d);
return EMSHA_ROK;
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 // Use the result buffer as an intermediate buffer to store the result
// of the inner hash. // of the inner hash.
res = this->ctx.Result(this->buf); res = this->ctx.Result(this->buf);
if (EMSHA_ROK != res) { if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID; this->hstate = HMAC_INVALID;
return EMSHA_INVALID_STATE; return EMSHAResult::InvalidState;
} }
assert(HMAC_IPAD == this->hstate); assert(HMAC_IPAD == this->hstate);
@ -192,7 +196,7 @@ HMAC::finalResult(uint8_t *d)
} }
res = this->ctx.Update(key, HMAC_KEY_LENGTH); res = this->ctx.Update(key, HMAC_KEY_LENGTH);
if (EMSHA_ROK != res) { if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID; this->hstate = HMAC_INVALID;
return res; return res;
} }
@ -203,14 +207,14 @@ HMAC::finalResult(uint8_t *d)
// Write the inner hash result into the outer hash. // Write the inner hash result into the outer hash.
res = this->ctx.Update(this->buf, SHA256_HASH_SIZE); res = this->ctx.Update(this->buf, SHA256_HASH_SIZE);
if (EMSHA_ROK != res) { if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID; this->hstate = HMAC_INVALID;
return res; return res;
} }
// Write the outer hash result into the working buffer. // Write the outer hash result into the working buffer.
res = this->ctx.Finalise(this->buf); res = this->ctx.Finalise(this->buf);
if (EMSHA_ROK != res) { if (EMSHAResult::OK != res) {
this->hstate = HMAC_INVALID; this->hstate = HMAC_INVALID;
return res; return res;
} }
@ -218,21 +222,21 @@ HMAC::finalResult(uint8_t *d)
std::copy(this->buf, this->buf + SHA256_HASH_SIZE, d); std::copy(this->buf, this->buf + SHA256_HASH_SIZE, d);
this->hstate = HMAC_FIN; this->hstate = HMAC_FIN;
return EMSHA_ROK; return EMSHAResult::OK;
} }
EMSHA_RESULT EMSHAResult
HMAC::Finalise(uint8_t *d) HMAC::Finalise(std::uint8_t *digest)
{ {
return this->finalResult(d); return this->finalResult(digest);
} }
EMSHA_RESULT EMSHAResult
HMAC::Result(uint8_t *d) HMAC::Result(std::uint8_t *digest)
{ {
return this->finalResult(d); return this->finalResult(digest);
} }
@ -243,21 +247,17 @@ HMAC::Size()
} }
EMSHA_RESULT EMSHAResult
ComputeHMAC(const uint8_t *k, uint32_t kl, const uint8_t *m, uint32_t ml, ComputeHMAC(const uint8_t *k, const uint32_t kl,
const uint8_t *m, const uint32_t ml,
uint8_t *d) uint8_t *d)
{ {
EMSHA_RESULT res; EMSHAResult res;
HMAC h(k, kl); HMAC h(k, kl);
res = h.Update(m, ml); res = h.Update(m, ml);
if (EMSHA_ROK != res) { if (res == EMSHAResult::OK) {
return res; res = h.Result(d);
}
res = h.Result(d);
if (EMSHA_ROK != res) {
return res;
} }
return res; return res;

194
sha256.cc
View File

@ -69,13 +69,13 @@ static constexpr uint32_t emsha256H0[] = {
}; };
EMSHA_RESULT EMSHAResult
sha256Digest(const uint8_t *m, uint32_t ml, uint8_t *d) SHA256Digest(const uint8_t *m, uint32_t ml, uint8_t *d)
{ {
SHA256 h; SHA256 h;
EMSHA_RESULT ret; EMSHAResult ret = EMSHAResult::Unknown;
if (EMSHA_ROK != (ret = h.Update(m, ml))) { if (EMSHAResult::OK != (ret = h.Update(m, ml))) {
return ret; return ret;
} }
@ -92,33 +92,35 @@ SHA256::SHA256()
SHA256::~SHA256() SHA256::~SHA256()
{ {
memset(this->mb, 0, SHA256_MB_SIZE); for (auto i = static_cast<uint32_t>(0); i < SHA256_MB_SIZE; i++) {
this->mb[i] = static_cast<uint8_t>(0);
}
} }
EMSHA_RESULT EMSHAResult
SHA256::addLength(const uint32_t l) SHA256::addLength(const uint32_t l)
{ {
uint32_t tmp = this->mlen + l; EMSHAResult res = EMSHAResult::InputTooLong;;
if (tmp < this->mlen) { uint32_t const tmp = static_cast<uint32_t>(this->mlen) + l;
return SHA256_INPUT_TOO_LONG; if (tmp >= this->mlen) {
this->mlen = tmp;
assert(this->mlen > 0);
res = EMSHAResult::OK;
} }
this->mlen = tmp; return res;
assert(this->mlen > 0);
return EMSHA_ROK;
} }
EMSHA_RESULT EMSHAResult
SHA256::Reset() SHA256::Reset()
{ {
return this->reset(); return this->reset();
} }
EMSHA_RESULT EMSHAResult
SHA256::reset() SHA256::reset()
{ {
// The message block is set to the initial hash vector. // The message block is set to the initial hash vector.
@ -132,29 +134,47 @@ SHA256::reset()
this->i_hash[7] = emsha256H0[7]; this->i_hash[7] = emsha256H0[7];
this->mbi = 0; this->mbi = 0;
this->hStatus = EMSHA_ROK; this->hStatus = EMSHAResult::OK;
this->hComplete = 0; this->hComplete = 0;
this->mlen = 0; this->mlen = 0;
memset(this->mb, 0, SHA256_MB_SIZE);
std::fill(this->mb.begin(), this->mb.end(), 0);
return this->hStatus; return this->hStatus;
} }
// Read 32 bits from the byte buffer chunk as an unsigned 32-bit integer. uint32_t
static uint32_t SHA256::chunkToUint32(uint32_t offset)
chunkToUint32(const uint8_t *chunk)
{ {
return ((*chunk) << 24) | uint32_t chunk = 0;
((*(chunk + 1)) << 16) |
((*(chunk + 2)) << 8) | for (uint32_t i = offset; i < offset+4; i++) {
(*(chunk + 3)); chunk <<= 8;
chunk += static_cast<uint32_t>(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<uint32_t>(this->mb[i]);
}
return chunk;
} }
// Copy an unsigned 32-bit integer into the start of the byte buffer chunk.
static void static void
uint32ToChunk(uint32_t x, uint8_t *chunk) uint32ToChunkInPlace(uint32_t x, uint8_t *chunk)
{ {
chunk[0] = (x & 0xff000000) >> 24; chunk[0] = (x & 0xff000000) >> 24;
chunk[1] = (x & 0x00ff0000) >> 16; chunk[1] = (x & 0x00ff0000) >> 16;
@ -180,7 +200,7 @@ SHA256::updateMessageBlock()
uint32_t h = 0; uint32_t h = 0;
while (i < 16) { while (i < 16) {
w[i++] = chunkToUint32(this->mb + chunk); w[i++] = this->chunkToUint32(chunk);
chunk += 4; chunk += 4;
} }
this->mbi = 0; this->mbi = 0;
@ -225,36 +245,36 @@ SHA256::updateMessageBlock()
} }
EMSHA_RESULT EMSHAResult
SHA256::Update(const uint8_t *m, uint32_t ml) SHA256::Update(const std::uint8_t *message, std::uint32_t messageLength)
{ {
// Checking invariants: // Checking invariants:
// If the message length is zero, there's nothing to be done. // 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 // The message passed in cannot be the null pointer if the
// message length is greater than 0. // 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 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 the hash has been finalised, don't proceed.
if (0 != this->hComplete) { return EMSHA_INVALID_STATE; } if (this->hComplete != static_cast<uint8_t>(0)) { return EMSHAResult::InvalidState; }
// Invariants satisfied by here. // Invariants satisfied by here.
for (uint32_t i = 0; i < ml; i++) { for (uint32_t i = 0; i < messageLength; i++) {
this->mb[this->mbi] = *(m + i); this->mb[this->mbi] = *(message + i);
mbi++; mbi++;
if (EMSHA_ROK == this->addLength(8)) { if (EMSHAResult::OK == this->addLength(8)) {
if (SHA256_MB_SIZE == this->mbi) { if (SHA256_MB_SIZE == this->mbi) {
this->updateMessageBlock(); this->updateMessageBlock();
// Assumption: following the message block // Assumption: following the message block
// write, the context should still be in a good // write, the context should still be in a good
// state. // state.
assert(EMSHA_ROK == this->hStatus); assert(EMSHAResult::OK == this->hStatus);
} }
} }
} }
@ -267,7 +287,7 @@ inline void
SHA256::padMessage(uint8_t pc) SHA256::padMessage(uint8_t pc)
{ {
// Assumption: the context is not in a corrupted state. // 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)) { if (this->mbi < (SHA256_MB_SIZE - 8)) {
this->mb[this->mbi++] = pc; this->mb[this->mbi++] = pc;
@ -290,7 +310,7 @@ SHA256::padMessage(uint8_t pc)
// Assumption: updating the message block has not left the // Assumption: updating the message block has not left the
// context in a corrupted state. // context in a corrupted state.
assert(EMSHA_ROK == this->hStatus); assert(EMSHAResult::OK == this->hStatus);
} }
while (this->mbi < (SHA256_MB_SIZE - 8)) { 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 // Assumption: updating the message block has not left the context in a
// corrupted state. // corrupted state.
assert(EMSHA_ROK == this->hStatus); assert(EMSHAResult::OK == this->hStatus);
} }
EMSHA_RESULT EMSHAResult
SHA256::Finalise(uint8_t *d) SHA256::Finalise(std::uint8_t *digest)
{ {
// Check invariants. // Check invariants.
// The digest cannot be a null pointer; this library allocates // The digest cannot be a null pointer; this library allocates
// no memory of its own. // 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 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 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. // Invariants satisfied by here.
this->padMessage(0x80); this->padMessage(0x80);
// Assumption: padding the message block has not left the context in a // Assumption: padding the message block has not left the context in a
// corrupted state. // corrupted state.
assert(EMSHA_ROK == this->hStatus); assert(EMSHAResult::OK == this->hStatus);
std::fill(this->mb, this->mb + SHA256_MB_SIZE, 0); std::fill(this->mb.begin(), this->mb.end(), 0);
this->hComplete = 1; this->hComplete = 1;
this->mlen = 0; this->mlen = 0;
uint32ToChunk(this->i_hash[0], d); uint32ToChunkInPlace(this->i_hash[0], digest);
uint32ToChunk(this->i_hash[1], d + 4); uint32ToChunkInPlace(this->i_hash[1], digest + 4);
uint32ToChunk(this->i_hash[2], d + 8); uint32ToChunkInPlace(this->i_hash[2], digest + 8);
uint32ToChunk(this->i_hash[3], d + 12); uint32ToChunkInPlace(this->i_hash[3], digest + 12);
uint32ToChunk(this->i_hash[4], d + 16); uint32ToChunkInPlace(this->i_hash[4], digest + 16);
uint32ToChunk(this->i_hash[5], d + 20); uint32ToChunkInPlace(this->i_hash[5], digest + 20);
uint32ToChunk(this->i_hash[6], d + 24); uint32ToChunkInPlace(this->i_hash[6], digest + 24);
uint32ToChunk(this->i_hash[7], d + 28); uint32ToChunkInPlace(this->i_hash[7], digest + 28);
return EMSHA_ROK; return EMSHAResult::OK;
} }
EMSHA_RESULT EMSHAResult
SHA256::Result(uint8_t *d) SHA256::Result(std::uint8_t *digest)
{ {
// Check invariants. // Check invariants.
// The digest cannot be a null pointer; this library allocates // The digest cannot be a null pointer; this library allocates
// no memory of its own. // 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 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. // Invariants satisfied by here.
if (this->hComplete == 0U) { if (this->hComplete == 0U) {
return this->Finalise(d); return this->Finalise(digest);
} }
uint32ToChunk(this->i_hash[0], d); uint32ToChunkInPlace(this->i_hash[0], digest);
uint32ToChunk(this->i_hash[1], d + 4); uint32ToChunkInPlace(this->i_hash[1], digest + 4);
uint32ToChunk(this->i_hash[2], d + 8); uint32ToChunkInPlace(this->i_hash[2], digest + 8);
uint32ToChunk(this->i_hash[3], d + 12); uint32ToChunkInPlace(this->i_hash[3], digest + 12);
uint32ToChunk(this->i_hash[4], d + 16); uint32ToChunkInPlace(this->i_hash[4], digest + 16);
uint32ToChunk(this->i_hash[5], d + 20); uint32ToChunkInPlace(this->i_hash[5], digest + 20);
uint32ToChunk(this->i_hash[6], d + 24); uint32ToChunkInPlace(this->i_hash[6], digest + 24);
uint32ToChunk(this->i_hash[7], d + 28); 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; 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) runTest(const uint8_t *input, uint32_t input_len, const uint8_t *expected)
{ {
uint8_t hexString[65]{0}; uint8_t hexString[65]{0};
uint8_t d[SHA256_HASH_SIZE]{0}; uint8_t d[SHA256_HASH_SIZE]{0};
emsha::SHA256 ctx; emsha::SHA256 ctx;
emsha::EMSHA_RESULT res; emsha::EMSHAResult res;
res = ctx.Update(input, input_len); res = ctx.Update(input, input_len);
if (EMSHA_ROK != res) { if (EMSHAResult::OK != res) {
return res; return res;
} }
for (uint32_t n = 0; n < EMSHA_SELF_TEST_ITERS; n++) { for (uint32_t n = 0; n < EMSHA_SELF_TEST_ITERS; n++) {
res = ctx.Result(d); res = ctx.Result(d);
if (EMSHA_ROK != res) { if (EMSHAResult::OK != res) {
return 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"; std::cerr << "[!] have: " << hexString << "\n";
HexString(hexString, const_cast<uint8_t *>(helloWorld), 32); HexString(hexString, const_cast<uint8_t *>(helloWorld), 32);
std::cerr << "[!] want: " << hexString << "\n"; std::cerr << "[!] want: " << hexString << "\n";
return EMSHA_TEST_FAILURE; return EMSHAResult::TestFailure;
} }
} }
} }
return EMSHA_ROK; return EMSHAResult::OK;
} }
EMSHA_RESULT EMSHAResult
sha256SelfTest() SHA256SelfTest()
{ {
EMSHA_RESULT res; EMSHAResult res;
res = runTest(reinterpret_cast<const uint8_t *>(""), 0, emptyVector); res = runTest(reinterpret_cast<const uint8_t *>(""), 0, emptyVector);
if (EMSHA_ROK == res) { if (EMSHAResult::OK == res) {
res = runTest(reinterpret_cast<const uint8_t *>("hello, world"), 12, helloWorld); res = runTest(reinterpret_cast<const uint8_t *>("hello, world"), 12, helloWorld);
if (res != EMSHA_ROK) { if (res != EMSHAResult::OK) {
std::cerr << "[!] failed on hello, world.\n"; std::cerr << "[!] failed on hello, world.\n";
} }
} else { } else {
@ -480,10 +500,10 @@ sha256SelfTest()
#else // #ifdef EMSHA_NO_SELFTEST #else // #ifdef EMSHA_NO_SELFTEST
EMSHA_RESULT EMSHAResult
sha256_self_test() sha256_self_test()
{ {
return EMSHA_SELFTEST_DISABLED; return EMSHAResult::SelfTestDisabled;
} }

View File

@ -23,8 +23,8 @@
*/ */
#include <chrono>
#include <iostream> #include <iostream>
#include <emsha/emsha.h> #include <emsha/emsha.h>
#include "test_utils.h" #include "test_utils.h"
@ -33,6 +33,10 @@
using namespace std; using namespace std;
// how many test runs to benchmark hex strings?
static constexpr auto testIterations = 32768;
#ifndef EMSHA_NO_HEXSTRING #ifndef EMSHA_NO_HEXSTRING
static void static void
hexStringTest() hexStringTest()
@ -49,19 +53,11 @@ hexStringTest()
emsha::HexString(out, buf, emsha::SHA256_HASH_SIZE); emsha::HexString(out, buf, emsha::SHA256_HASH_SIZE);
string const outs(reinterpret_cast<const char *>(out)); string const outs(reinterpret_cast<const char *>(out));
if (outs != expected) { if (outs != expected) {
cerr << "FAILED: HexString" << endl; cerr << "FAILED: HexString\n";
cerr << "\twanted: " << expected << endl; cerr << "\twanted: " << expected << "\n";
cerr << "\thave: " << out << endl; cerr << "\thave: " << out << "\n";
exit(1); 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 #endif // #ifndef EMSHA_NO_HEXSTRING
@ -84,9 +80,9 @@ hashEqualTest()
cerr << "FAILED: HashEqual\n"; cerr << "FAILED: HashEqual\n";
cerr << "\tHashEqual should have succeeded comparing a and b.\n"; cerr << "\tHashEqual should have succeeded comparing a and b.\n";
DumpHexString(s, a, emsha::SHA256_HASH_SIZE); DumpHexString(s, a, emsha::SHA256_HASH_SIZE);
cerr << "\ta <- " << s << std::endl; cerr << "\ta <- " << s << "\n";
DumpHexString(s, b, emsha::SHA256_HASH_SIZE); DumpHexString(s, b, emsha::SHA256_HASH_SIZE);
cerr << "\tb <- " << s << std::endl; cerr << "\tb <- " << s << "\n";
exit(1); exit(1);
} }
@ -100,9 +96,9 @@ hashEqualTest()
cerr << "FAILED: HashEqual\n"; cerr << "FAILED: HashEqual\n";
cerr << "\tHashEqual should not have succeeded comparing a and b.\n"; cerr << "\tHashEqual should not have succeeded comparing a and b.\n";
DumpHexString(s, a, emsha::SHA256_HASH_SIZE); DumpHexString(s, a, emsha::SHA256_HASH_SIZE);
cerr << "\ta <- " << s << std::endl; cerr << "\ta <- " << s << "\n";
DumpHexString(s, b, emsha::SHA256_HASH_SIZE); DumpHexString(s, b, emsha::SHA256_HASH_SIZE);
cerr << "\tb <- " << s << std::endl; cerr << "\tb <- " << s << "\n";
exit(1); exit(1);
} }
@ -126,17 +122,33 @@ hashEqualTest()
cerr << "\tb <- " << s << std::endl; cerr << "\tb <- " << s << std::endl;
exit(1); exit(1);
} }
cout << "PASSED: HashEqual\n";
} }
int int
main() main()
{ {
auto start = std::chrono::steady_clock::now();
std::string testLabel;
for (auto i = 0; i < testIterations; i++) {
#ifndef EMSHA_NO_HEXSTRING #ifndef EMSHA_NO_HEXSTRING
hexStringTest(); #ifndef EMSHA_NO_HEXLUT
testLabel = "(large LUT) ";
#endif #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<double, std::milli>(delta).count()
<< " ms\n";
std::cout << "Average over " << testIterations << " tests: "
<< std::chrono::duration<double, std::nano>(delta).count() / testIterations
<< " ns\n";
} }

View File

@ -41,7 +41,7 @@
// Number of test iterations. // Number of test iterations.
static constexpr std::uint32_t ITERS = 8192; static constexpr std::uint32_t ITERS = 32768;
// The key used for HMAC. // The key used for HMAC.
static constexpr std::uint8_t k[] = { static constexpr std::uint8_t k[] = {
@ -111,13 +111,13 @@ static void
iterateSHA() iterateSHA()
{ {
emsha::SHA256 ctx; emsha::SHA256 ctx;
int cmp = 0; int cmp = 0;
emsha::EMSHA_RESULT res; emsha::EMSHAResult res;
res = ctx.Update(m, sizeof(m)); res = ctx.Update(m, sizeof(m));
assert(emsha::EMSHA_ROK == res); assert(emsha::EMSHAResult::OK == res);
res = ctx.Result(dig); res = ctx.Result(dig);
assert(emsha::EMSHA_ROK == res); assert(emsha::EMSHAResult::OK == res);
cmp = std::memcmp(dig, d, emsha::SHA256_HASH_SIZE); cmp = std::memcmp(dig, d, emsha::SHA256_HASH_SIZE);
assert(0 == cmp); assert(0 == cmp);
@ -128,13 +128,13 @@ static void
iterateHMAC() iterateHMAC()
{ {
emsha::HMAC ctx(k, kl); emsha::HMAC ctx(k, kl);
int cmp = 0; int cmp = 0;
emsha::EMSHA_RESULT res; emsha::EMSHAResult res;
res = ctx.Update(m, sizeof(m)); res = ctx.Update(m, sizeof(m));
assert(emsha::EMSHA_ROK == res); assert(emsha::EMSHAResult::OK == res);
res = ctx.Result(dig); res = ctx.Result(dig);
assert(emsha::EMSHA_ROK == res); assert(emsha::EMSHAResult::OK == res);
cmp = std::memcmp(dig, t, emsha::SHA256_HASH_SIZE); cmp = std::memcmp(dig, t, emsha::SHA256_HASH_SIZE);
assert(0 == cmp); assert(0 == cmp);
@ -146,7 +146,7 @@ iterateSHASP()
{ {
int cmp = 0; 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); cmp = std::memcmp(dig, d, emsha::SHA256_HASH_SIZE);
assert(0 == cmp); assert(0 == cmp);
} }
@ -155,11 +155,11 @@ iterateSHASP()
static void static void
iterateHMACSP() iterateHMACSP()
{ {
int cmp = 0; int cmp = 0;
emsha::EMSHA_RESULT res; emsha::EMSHAResult res;
res = emsha::ComputeHMAC(k, kl, m, sizeof(m), dig); 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); cmp = std::memcmp(dig, t, emsha::SHA256_HASH_SIZE);
assert(0 == cmp); assert(0 == cmp);

View File

@ -76,18 +76,34 @@ main()
#ifdef EMSHA_NO_SELFTEST #ifdef EMSHA_NO_SELFTEST
cout << "[NOTICE] internal self-tests have been disabled.\n"; cout << "[NOTICE] internal self-tests have been disabled.\n";
#else #else
auto selfTestStatus = emsha::sha256SelfTest(); auto selfTestStatus = emsha::SHA256SelfTest();
switch (selfTestStatus) { switch (selfTestStatus) {
case emsha::EMSHA_ROK: case emsha::EMSHAResult::OK:
cout << "PASSED: SHA-256 self test\n"; cout << "PASSED: SHA-256 self test\n";
break; break;
case emsha::EMSHA_TEST_FAILURE: case emsha::EMSHAResult::TestFailure:
cout << "FAILED: SHA-256 self test (test failure)\n"; 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; break;
default: 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 #endif

View File

@ -53,28 +53,28 @@ DumpHexString(std::string& hs, uint8_t *s, uint32_t sl)
} }
emsha::EMSHA_RESULT emsha::EMSHAResult
runHMACTest(const struct hmacTest test, const string& label) runHMACTest(const struct hmacTest& test, const string& label)
{ {
emsha::HMAC h(test.key, test.keylen); emsha::HMAC h(test.key, test.keylen);
emsha::EMSHA_RESULT res; emsha::EMSHAResult res;
uint8_t dig[emsha::SHA256_HASH_SIZE]; uint8_t dig[emsha::SHA256_HASH_SIZE];
string hs; string hs;
res = h.Update((uint8_t *)test.input.c_str(), test.input.size()); res = h.Update((uint8_t *)test.input.c_str(), test.input.size());
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
goto exit; goto exit;
} }
for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) { for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) {
res = h.Result(dig); res = h.Result(dig);
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
goto exit; goto exit;
} }
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) { if (hs != test.output) {
res = emsha::EMSHA_TEST_FAILURE; res = emsha::EMSHAResult::TestFailure;
goto exit; goto exit;
} }
memset(dig, 0, emsha::SHA256_HASH_SIZE); memset(dig, 0, emsha::SHA256_HASH_SIZE);
@ -84,19 +84,19 @@ runHMACTest(const struct hmacTest test, const string& label)
h.Reset(); h.Reset();
res = h.Update((uint8_t *)test.input.c_str(), test.input.size()); res = h.Update((uint8_t *)test.input.c_str(), test.input.size());
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
goto exit; goto exit;
} }
for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) { for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) {
res = h.Result(dig); res = h.Result(dig);
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
goto exit; goto exit;
} }
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) { if (hs != test.output) {
res = emsha::EMSHA_TEST_FAILURE; res = emsha::EMSHAResult::TestFailure;
goto exit; goto exit;
} }
memset(dig, 0, emsha::SHA256_HASH_SIZE); 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, res = emsha::ComputeHMAC(test.key, test.keylen,
(uint8_t *)test.input.c_str(), test.input.size(), (uint8_t *)test.input.c_str(), test.input.size(),
dig); dig);
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
cerr << "(running single pass function test)\n"; cerr << "(running single pass function test)\n";
goto exit; goto exit;
} }
@ -114,15 +114,15 @@ runHMACTest(const struct hmacTest test, const string& label)
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) { if (hs != test.output) {
cerr << "(comparing single pass function output)\n"; cerr << "(comparing single pass function output)\n";
res = emsha::EMSHA_TEST_FAILURE; res = emsha::EMSHAResult::TestFailure;
goto exit; goto exit;
} }
memset(dig, 0, emsha::SHA256_HASH_SIZE); memset(dig, 0, emsha::SHA256_HASH_SIZE);
res = emsha::EMSHA_ROK; res = emsha::EMSHAResult::OK;
exit: exit:
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
cerr << "FAILED: " << label << endl; cerr << "FAILED: " << label << endl;
cerr << "\tinput: " << test.input << endl; cerr << "\tinput: " << test.input << endl;
cerr << "\twanted: " << test.output << endl; cerr << "\twanted: " << test.output << endl;
@ -137,7 +137,7 @@ int
runHMACTests(const struct hmacTest *tests, size_t nTests, const string& label) runHMACTests(const struct hmacTest *tests, size_t nTests, const string& label)
{ {
for (uint32_t i = 0; i < nTests; i++) { 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; 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) runHashTest(const struct hashTest& test, const string& label)
{ {
emsha::SHA256 ctx; emsha::SHA256 ctx;
emsha::EMSHA_RESULT res; emsha::EMSHAResult res;
uint8_t dig[emsha::SHA256_HASH_SIZE]; uint8_t dig[emsha::SHA256_HASH_SIZE];
string hs; string hs;
res = ctx.Update((uint8_t *)test.input.c_str(), test.input.size()); res = ctx.Update((uint8_t *)test.input.c_str(), test.input.size());
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
goto exit; goto exit;
} }
for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) { for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) {
res = ctx.Result(dig); res = ctx.Result(dig);
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
goto exit; goto exit;
} }
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) { if (hs != test.output) {
res = emsha::EMSHA_TEST_FAILURE; res = emsha::EMSHAResult::TestFailure;
goto exit; goto exit;
} }
memset(dig, 0, emsha::SHA256_HASH_SIZE); memset(dig, 0, emsha::SHA256_HASH_SIZE);
@ -177,28 +177,28 @@ runHashTest(const struct hashTest& test, const string& label)
ctx.Reset(); ctx.Reset();
res = ctx.Update((uint8_t *)test.input.c_str(), test.input.size()); res = ctx.Update((uint8_t *)test.input.c_str(), test.input.size());
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
goto exit; goto exit;
} }
for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) { for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) {
res = ctx.Result(dig); res = ctx.Result(dig);
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
goto exit; goto exit;
} }
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) { if (hs != test.output) {
res = emsha::EMSHA_TEST_FAILURE; res = emsha::EMSHAResult::TestFailure;
goto exit; goto exit;
} }
memset(dig, 0, emsha::SHA256_HASH_SIZE); memset(dig, 0, emsha::SHA256_HASH_SIZE);
} }
// Test that the single-pass function works. // 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); test.input.size(), dig);
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
cerr << "(running single pass function test)\n"; cerr << "(running single pass function test)\n";
goto exit; goto exit;
} }
@ -206,14 +206,14 @@ runHashTest(const struct hashTest& test, const string& label)
DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE);
if (hs != test.output) { if (hs != test.output) {
cerr << "(comparing single pass function output)\n"; cerr << "(comparing single pass function output)\n";
res = emsha::EMSHA_TEST_FAILURE; res = emsha::EMSHAResult::TestFailure;
goto exit; goto exit;
} }
memset(dig, 0, emsha::SHA256_HASH_SIZE); memset(dig, 0, emsha::SHA256_HASH_SIZE);
res = emsha::EMSHA_ROK; res = emsha::EMSHAResult::OK;
exit: exit:
if (emsha::EMSHA_ROK != res) { if (emsha::EMSHAResult::OK != res) {
cerr << "FAILED: " << label << endl; cerr << "FAILED: " << label << endl;
cerr << "\tinput: '" << test.input << "'" << endl; cerr << "\tinput: '" << test.input << "'" << endl;
cerr << "\twanted: " << test.output << endl; cerr << "\twanted: " << test.output << endl;
@ -227,7 +227,7 @@ int
runHashTests(const struct hashTest *tests, const size_t ntests, const string& label) runHashTests(const struct hashTest *tests, const size_t ntests, const string& label)
{ {
for (uint32_t i = 0; i < ntests; i++) { 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; return -1;
} }
} }

View File

@ -64,13 +64,13 @@ void dump_pair(std::uint8_t *, std::uint8_t *);
// SHA-256 testing functions. // 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, int runHashTests(const struct hashTest *tests, const std::size_t nTests,
const std::string& label); const std::string& label);
// HMAC-SHA-256 testery. // 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, int runHMACTests(const struct hmacTest *tests, std::size_t nTests,
const std::string& label); const std::string& label);