diff --git a/configure.ac b/configure.ac index 556b6db..e7f0d6b 100644 --- a/configure.ac +++ b/configure.ac @@ -9,7 +9,7 @@ AC_INIT([libemsha], AM_INIT_AUTOMAKE([1.11 foreign]) AC_CONFIG_SRCDIR([src/emsha/sha256.hh]) -AC_CONFIG_FILES([Makefile src/Makefile doc/source/conf.py]) +AC_CONFIG_FILES([Makefile src/Makefile doc/source/conf.py doc/source/header.rst]) AC_CONFIG_FILES([do-release], [chmod +x do-release]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/do-release.in b/do-release.in index 47f1b5c..d9929f8 100755 --- a/do-release.in +++ b/do-release.in @@ -5,8 +5,10 @@ set -e VERSION="@PACKAGE_VERSION@" TARBALL="@PACKAGE_NAME@-$VERSION" -echo "[+] building release tarballs" make clean +echo "[+] rebuilding single ReST doc" +cd doc && make singlerst && cd .. +echo "[+] building release tarballs" make dist-gzip if [ ! -e "$TARBALL.tar.gz" ] then diff --git a/doc/Makefile b/doc/Makefile index 6d665bc..a6f9e61 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -51,6 +51,9 @@ all: check: distclean: clean + rm -f source/header*.rst + rm -f source/conf.py + clean: rm -rf $(BUILDDIR)/* @@ -182,3 +185,20 @@ pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +singlerst: + sed -e "s/@BUILD_DATE@/$$(date +'%Y-%m-%d')/" \ + source/header.rst > source/header.dated.rst + cat source/header.dated.rst \ + source/intro.rst \ + source/building.rst \ + source/overview.rst \ + source/hash.rst \ + source/sha256.rst \ + source/hmac.rst \ + source/misc.rst \ + source/tests.rst \ + source/refs.rst \ + > libemsha.rst + + diff --git a/doc/Makefile.bak b/doc/Makefile.bak deleted file mode 100644 index 45592e5..0000000 --- a/doc/Makefile.bak +++ /dev/null @@ -1,5 +0,0 @@ -if HAVE_SPHINX - -sphinx-html: - cd sphinx/ && make html -endif diff --git a/doc/libemsha.rst b/doc/libemsha.rst new file mode 100644 index 0000000..1a04292 --- /dev/null +++ b/doc/libemsha.rst @@ -0,0 +1,597 @@ +======== +libemsha +======== + +Version: 1.0.0-RC3 +Date: 2015-12-22 + +Table of Contents: + ++ Introduction ++ Getting and Building the Source ++ Library Overview ++ The Hash interface ++ The SHA256 class ++ The HMAC class ++ Miscellaneous functions ++ Test Programs ++ References + + +------------- +Introduction +------------- + +This library is an MIT-licensed compact HMAC-SHA-256 C++11 library +designed for embedded systems. It is built following the JPL `Power of +Ten `_ rules. + +This library came about as a result of a need for a standalone +SHA-256 library for an embedded system. The original goal was +to implement a wrapper around the code extracted from `RFC 6234 +`_; instead a standalone +implementation was decided on. + +Additional resources: + ++ `Github page `_ ++ `Travis CI status `_ ++ `Coverity Scan page `_ + + +------------------------------- +Getting and Building the Source +------------------------------- + +The source code is available via `Github +`_; each version should be git tagged. :: + + git clone https://github.com/kisom/libemsha + git clone git@github.com:kisom/libemsha + +The current release is `1.0.0 `_. + +The project is built using Autotools and ``make``. + +When building from a git checkout, the `autobuild` script will bootstrap +the project from the autotools sources (e.g. via ``autoreconf -i``), +run ``configurei`` (by default to use clang), and attempt to build the library +and run the unit tests. + +Once the autotools infrastructure has been bootstrapped, the following +should work: :: + + ./configure && make && make check && make install + +There are three flags to ``configure`` that might be useful: + ++ ``--disable-hexstring`` disables the provided ``hexstring`` function; + while this might be useful in many cases, it also adds extra size to + the code. + ++ ``--disable-hexlut`` disables the larger lookup table used by + ``hexstring``, which can save around a kilobyte of program space. If + the ``hexstring`` function is disabled, this option has no effect. + ++ ``--disable-selftest`` disables the internal self-tests, which can + reclaim some additional program space. + +---------------- +Library Overview +---------------- + +.. cpp:namespace:: emsha + +The package provides a pair of classes, :cpp:class:`SHA256` and +:cpp:class:`HMAC`, that both satisfy a common interface :cpp:class:`Hash`. All +functionality provided by this library is found under the ``emsha`` namespace. + + +``EMSHA_RESULT`` +^^^^^^^^^^^^^^^^^ + +The ``EMSHA_RESULT`` enum is used to convey the result of an +operation. The possible values are: + +.. cpp:enum:: _EMSHA_RESULT_ : uint8_t + +:: + + // All operations have completed successfully so far. + EMSHA_ROK = 0, + + // A self test or unit test failed. + EMSHA_TEST_FAILURE = 1, + + // A null pointer was passed in as a buffer where it + // shouldn't have been. + EMSHA_NULLPTR = 2, + + // The Hash is in an invalid state. + EMSHA_INVALID_STATE = 3, + + // The input to SHA256::update is too large. + SHA256_INPUT_TOO_LONG = 4, + + // The self tests have been disabled, but a self test + // function was called. + EMSHA_SELFTEST_DISABLED = 5 + +As a convenience, the following ``typedef`` is also provided. + + ``typedef enum _EMSHA_RESULT_`` :cpp:type:`EMSHA_RESULT` + + +------------------ +The Hash interface +------------------ + +.. cpp:class:: emsha::Hash + + The ``Hash`` class contains a top-level interface for the objects in + this library. + +In general, a `Hash` is used along the lines of: :: + + emsha::EMSHA_RESULT + 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; + + res = h.write(m, ml); + if (emsha::EMSHA_ROK != res) { + return res; + } + + // digest will contain the output of the Hash, and the + // caller MUST ensure that there is enough space in + // the buffer. + return h.result(d); + } + +Methods +^^^^^^^ + +.. cpp:function:: emsha::EMSHA_RESULT reset(void) + + reset should bring the Hash back into its initial state. That is, + the idea is that:: + + hash->reset(); + hash->update(...); // possibly many of these... + hash->result(...); // should always return the same hash. + + is idempotent, assuming the inputs to ``update`` and ``result`` + are constant. The implications of this for a given concrete class + should be described in that class's documentation, but in general, + it has the effect of preserving any initial state while removing any + data written to the Hash via the update method. + +.. cpp:function:: emsha::EMSHA_RESULT update(const uint8_t *m, uint32_t ml) + + ``update`` is used to write message data into + the Hash. + +.. cpp:function:: emsha::EMSHA_RESULT finalize(uint8_t *d) + + ``finalize`` should 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. + + Note that this library does not allocate memory, and therefore the + caller *must* ensure that ``d`` is a valid buffer containing at least + ``this->size()`` bytes. + +.. cpp:function:: emsha::EMSHA_RESULT result(uint8_t *d) + + ``result`` is used to transfer out the hash to the argument. This implies + that the `Hash` must keep enough state for repeated calls to ``result`` + to work. + +.. cpp:function:: uint32_t size(void) + + ``size`` should return the output size of the `Hash`; this is, how large + the buffers written to by ``result`` should be. + +----------------- +The SHA256 class +----------------- + +.. cpp:class:: emsha::SHA256 + + SHA256 is an implementation of the :cpp:class:`emsha::Hash` interface + implementing the SHA-256 cryptographic hash algorithm + +.. cpp:function:: SHA256::SHA256() + + A SHA256 context does not need any special construction. It can be + declared and immediately start being used. + + +.. cpp:function:: SHA256::~SHA256() + + The SHA256 destructor will clear out its internal message buffer; + all of the members are local and not resource handles, so cleanup + is minimal. + + +.. cpp:function:: emsha::EMSHA_RESULT SHA256::reset(void) + + reset clears the internal state of the `SHA256` context and returns + it to its initial state. It should always return ``EMSHA_ROK``. + +.. cpp:function:: emsha::EMSHA_RESULT SHA256::update(const uint8_t *m, uint32_t ml) + + 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. + + **Return values**: + + * ``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. + + +.. cpp:function:: emsha::EMSHA_RESULT SHA256::finalize(uint8_t *d) + + ``finalize`` 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``. + + +.. cpp:function:: emsha::EMSHA_RESULT SHA256::result(uint8_t *d) + + ``result`` copies the result from the SHA-256 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 ``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``. + +.. cpp:function:: uint32_t SHA256::size(void) + + ``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``. + + +-------------- +The HMAC class +-------------- + + +.. cpp:class:: emsha::HMAC + + HMAC is an implementation of the :cpp:class:`emsha::Hash` interface + implementing the HMAC keyed-hash message authentication code as + defined in FIPS 198-1, using SHA-256 internally. + +.. cpp:function:: HMAC::HMAC(const uint8_t *key, uint32_t keylen) + + An HMAC context must be initialised with a key. + + +.. cpp:function:: HMAc::~HMAC() + + The HMAC destructor will attempt to wipe the key and reset the + underlying SHA-256 context. + + +.. cpp:function:: emsha::EMSHA_RESULT HMAC::reset(void) + + reset clears the internal state of the `HMAC` context and returns + it to its initial state. It should always return ``EMSHA_ROK``. + This function will **not** wipe the key; an `HMAC` object that has + `reset` called it can be used immediately after. + + +.. cpp:function:: emsha::EMSHA_RESULT HMAC::update(const uint8_t *m, uint32_t ml) + + update writes data into the context. While there is an upper limit on + the size of data that the underlying SHA-256 context 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. + + **Return values**: + + * ``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 HMAC context. + + +.. cpp:function:: emsha::EMSHA_RESULT SHA256::finalize(uint8_t *d) + + ``finalize`` 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 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``. + + +.. cpp:function:: emsha::EMSHA_RESULT SHA256::result(uint8_t *d) + + ``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``. + +.. cpp:function:: uint32_t SHA256::size(void) + + ``size`` returns the output size of HMAC, 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``. + +----------------------- +Miscellaneous functions +----------------------- + +.. cpp:function:: emsha::EMSHA_RESULT sha256_self_test(void) + + If the library was `compiled with support for self tests + <./building.html>`_ (the default), this function will run a few self + tests on the SHA-256 functions to validate that they are working + correctly. + + **Outputs**: + + * ``EMSHA_ROK`` if the self-test completed successfully. + + * ``EMSHA_TEST_FAILURE`` if the SHA-256 functions did not produce + the expected value. + + * ``EMSHA_SELFTEST_DISABLED`` if the library was built without + support for the self test. + + * If an error occurs in the SHA-256 code, the resulting error code + will be returned. + + +.. cpp:function:: emsha::EMSHA_RESULT sha256_digest(const uint8_t *m, uint32_t ml, uint8_t *d) + + The ``sha256_digest`` function will compute the digest on the + ``ml``-byte octet string stored in ``m``, returning the result + in ``d``. This is a convenience function implemented as: :: + + EMSHA_RESULT + sha256_digest(const uint8_t *m, uint32_t ml, uint8_t *d) + { + SHA256 h; + EMSHA_RESULT ret; + + if (EMSHA_ROK != (ret = h.update(m, ml))) { + return ret; + } + + return h.finalize(d); + } + +.. cpp:function:: emsha::EMSHA_RESULT compute_hmac(const uint8_t *k, uint32_t kl, const uint8_t *m, uint32_t ml, uint8_t *d) + + The ``compute_hmac`` function computes the MAC on the ``ml``-byte + octet string stored in``m``, using the ``kl``-length key ``k``. The + result is stored in ``d``. This is a convenience function implemented + as: :: + + EMSHA_RESULT + compute_hmac(const uint8_t *k, uint32_t kl, const uint8_t *m, uint32_t ml, + uint8_t *d) + { + EMSHA_RESULT 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; + } + + return res; + } + +.. cpp:function:: bool hash_equal(const uint8_t *a, const uint8_t *b) + + ``hash_equal`` performs a constant-time comparison of the first + ``emsha::SHA256_HASH_SIZE`` bytes in the two byte array arguments. + + **Inputs**: + + * ``a``, ``b``: byte arrays at least ``emsha::SHA256_HASH_SIZE`` + bytes in length. + + ** Outputs**: + + * true *iff* the first ``emsha::SHA256_HASH_SIZE`` bytes match in + both arrays. + + * false otherwise. + + +.. cpp:function:: void hexstring(uint8_t *dest, uint8_t *src, uint32_t srclen) + + **Note**: this function is only present if the library was + `built with support <./building.html>`_ for the hexstring functionality. + + **Inputs**: + + * dest: a byte array that is 2 * ``srclen``. + + * src: a byte array containing the data to process. + + * srclen: the size of ``src``. + + **Outputs**: + + When the function returns, the hex-encoded string will be placed in + ``dest``. + +------------- +Test Programs +------------- + +Running ``make check`` builds and runs the test programs. These are: + +* ``emsha_core_test`` runs the core tests. +* ``emsha_sha256_test`` runs test vectors on the SHA-256 code. +* ``emsha_hmac_test`` runs test vectors on the HMAC code. + +Additionally, the following test programs are built but not run. These +programs do not link with the library as the above programs do; instead, +they compile the object files in to avoid the libtool dance before the +library is installed. + +* ``emsha_mem_test`` and ``emsha_static_mem_test`` are for memory + profiling (e.g., with `Valgrind `_ during + development. + +* ``emsha_static_sha256_test`` and ``emsha_static_hmac_test`` are used + to facilitate testing and debugging the library. These programs run + the same tests as the ``emsha_sha256_test`` and ``emsha_hmac_test`` + programs. + + +Core Tests +^^^^^^^^^^ + +There are three tests run in the core tests: a hexstring test (if +`support is built in <./building.html>`_) and the constant time +check. The constant time test does not validate that the function +is constant time, only that it correctly verifies that two byte +arrays are equal. + + +SHA-256 Tests +^^^^^^^^^^^^^ + +The SHA-256 checks take a number of test vectors from the Go standard +library's SHA-256 library. + + +HMAC Tests +^^^^^^^^^^ + +The HMAC checks apply the `RFC 4231 `_ +test vectors to the HMAC code. + + + +---------- +References +---------- + +* `FIPS 180-4, the Secure Hash Standard `_ +* `FIPS 198-1, The Keyed-Hash Message Authentication Code (HMAC) `_ +* `RFC 2014, HMAC: Keyed-Hashing for Message Authentication `_ +* `RFC 6234, US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF) `_\ [#f1]_ +* The behaviour of this package was cross-checked using the Go 1.5.1 + linux/amd64 standard library's `crypto/sha256 `_ + package. + +.. rubric:: Footnotes + +.. [#f1] This library came about after extracting the relevant C code + from RFC 6234, and needing a C++ version. It draws heavy + inspiration from that code base. diff --git a/doc/source/conf.py.in b/doc/source/conf.py.in index 717367a..581a6eb 100644 --- a/doc/source/conf.py.in +++ b/doc/source/conf.py.in @@ -216,10 +216,10 @@ latex_documents = [ #latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +latex_show_pagerefs = True # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = True # Documents to append as an appendix to all manuals. #latex_appendices = [] @@ -238,7 +238,7 @@ man_pages = [ ] # If true, show URL addresses after external links. -#man_show_urls = False +man_show_urls = True # -- Options for Texinfo output ------------------------------------------- diff --git a/doc/source/header.rst.in b/doc/source/header.rst.in new file mode 100644 index 0000000..d28e725 --- /dev/null +++ b/doc/source/header.rst.in @@ -0,0 +1,22 @@ +======== +libemsha +======== + +Version: @PACKAGE_VERSION@ +Date: @BUILD_DATE@ + +------------------ +Table of Contents: +------------------ + ++ Introduction ++ Getting and Building the Source ++ Library Overview ++ The Hash interface ++ The SHA256 class ++ The HMAC class ++ Miscellaneous functions ++ Test Programs ++ References + +