diff --git a/Makefile.am b/Makefile.am index 1d595f5..641d117 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,3 +25,5 @@ cloc-report: coverity-scan: cd src && make $@ +epub: + cd doc && make $@ diff --git a/README.rst b/README.rst index 22d3579..df9e7c1 100644 --- a/README.rst +++ b/README.rst @@ -4,6 +4,9 @@ libemsha .. image:: https://travis-ci.org/kisom/libemsha.svg?branch=master :target: https://travis-ci.org/kisom/libemsha +.. image:: https://scan.coverity.com/projects/7318/badge.svg + :target: https://scan.coverity.com/projects/libemsha-52f2a5fd-e759-43c2-9073-cf6c2ed9abdb + This library is an MIT-licensed HMAC-SHA-256 C++11 library designed for embedded systems. It is built following the JPL `Power of Ten `_ rules. It was written in @@ -54,11 +57,22 @@ Documentation ------------- Documentation is currently done with `Sphinx `_. -See ``doc/sphinx/``. +See ``doc/``. See also -------- -+ `FIPS 180-4, FIPS 198-1 `_ +* `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/configure.ac b/configure.ac index bfd9ad3..556b6db 100644 --- a/configure.ac +++ b/configure.ac @@ -2,14 +2,14 @@ # versions that can be used with Travis right now. AC_PREREQ([2.68]) AC_INIT([libemsha], - [1.0.0-RC2], + [1.0.0-RC3], [coder@kyleisom.net], [libemsha], [https://kyleisom.net/projects/libemsha/]) AM_INIT_AUTOMAKE([1.11 foreign]) AC_CONFIG_SRCDIR([src/emsha/sha256.hh]) -AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile doc/sphinx/source/conf.py]) +AC_CONFIG_FILES([Makefile src/Makefile doc/source/conf.py]) AC_CONFIG_FILES([do-release], [chmod +x do-release]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/doc/sphinx/Makefile b/doc/Makefile similarity index 98% rename from doc/sphinx/Makefile rename to doc/Makefile index dd28a95..e8a3ce1 100644 --- a/doc/sphinx/Makefile +++ b/doc/Makefile @@ -19,7 +19,7 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) sou # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex pdf latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @@ -110,6 +110,8 @@ latex: @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." +pdf: latexpdf + latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." diff --git a/doc/Makefile.am b/doc/Makefile.bak similarity index 100% rename from doc/Makefile.am rename to doc/Makefile.bak diff --git a/doc/sphinx/build/.gitkeep b/doc/build/.gitkeep similarity index 100% rename from doc/sphinx/build/.gitkeep rename to doc/build/.gitkeep diff --git a/doc/sphinx/source/_static/.gitkeep b/doc/source/_static/.gitkeep similarity index 100% rename from doc/sphinx/source/_static/.gitkeep rename to doc/source/_static/.gitkeep diff --git a/doc/sphinx/source/_templates/.gitkeep b/doc/source/_templates/.gitkeep similarity index 100% rename from doc/sphinx/source/_templates/.gitkeep rename to doc/source/_templates/.gitkeep diff --git a/doc/sphinx/source/building.rst b/doc/source/building.rst similarity index 100% rename from doc/sphinx/source/building.rst rename to doc/source/building.rst diff --git a/doc/sphinx/source/conf.py.in b/doc/source/conf.py.in similarity index 94% rename from doc/sphinx/source/conf.py.in rename to doc/source/conf.py.in index 07e2dc7..717367a 100644 --- a/doc/sphinx/source/conf.py.in +++ b/doc/source/conf.py.in @@ -48,7 +48,7 @@ master_doc = 'index' # General information about the project. project = u'@PACKAGE_NAME@' -copyright = u'2015, @PACKAGE_AUTHOR@' +copyright = u'2015, K. Isom ' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -183,7 +183,7 @@ html_static_path = ['_static'] #html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'PACKAGE_NAMEdoc' +htmlhelp_basename = '@PACKAGE_NAME@doc' # -- Options for LaTeX output --------------------------------------------- @@ -203,8 +203,8 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'PACKAGE_NAME.tex', u'@PACKAGE\\_NAME@ Documentation', - u'@PACKAGE\\_AUTHOR@', 'manual'), + ('index', '@PACKAGE_NAME@.tex', u'@PACKAGE_NAME@ Documentation', + u'K. Isom ', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -234,7 +234,7 @@ latex_documents = [ # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'package_name', u'@PACKAGE_NAME@ Documentation', - [u'@PACKAGE_AUTHOR@'], 1) + [u'K. Isom '], 1) ] # If true, show URL addresses after external links. @@ -247,9 +247,9 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'PACKAGE_NAME', u'@PACKAGE_NAME@ Documentation', - u'@PACKAGE_AUTHOR@', 'PACKAGE_NAME', 'One line description of project.', - 'Miscellaneous'), + ('index', '@PACKAGE_NAME@', u'@PACKAGE_NAME@ Documentation', + u'K. Isom ', '@PACKAGE_NAME@', 'HMAC-SHA-256 C++11 library designed for embedded systems.', + 'Development'), ] # Documents to append as an appendix to all manuals. @@ -269,9 +269,9 @@ texinfo_documents = [ # Bibliographic Dublin Core info. epub_title = u'@PACKAGE_NAME@' -epub_author = u'@PACKAGE_AUTHOR@' -epub_publisher = u'@PACKAGE_AUTHOR@' -epub_copyright = u'2015, @PACKAGE_AUTHOR@' +epub_author = u'K. Isom ' +epub_publisher = u'K. Isom ' +epub_copyright = u'2015, K. Isom ' # The basename for the epub file. It defaults to the project name. #epub_basename = u'@PACKAGE_NAME@' diff --git a/doc/sphinx/source/hash.rst b/doc/source/hash.rst similarity index 100% rename from doc/sphinx/source/hash.rst rename to doc/source/hash.rst diff --git a/doc/source/hmac.rst b/doc/source/hmac.rst new file mode 100644 index 0000000..615a2df --- /dev/null +++ b/doc/source/hmac.rst @@ -0,0 +1,113 @@ +-------------- +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``. + diff --git a/doc/sphinx/source/index.rst b/doc/source/index.rst similarity index 61% rename from doc/sphinx/source/index.rst rename to doc/source/index.rst index a322d9f..3408366 100644 --- a/doc/sphinx/source/index.rst +++ b/doc/source/index.rst @@ -6,29 +6,22 @@ libemsha ======== -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. - -Contents: - .. toctree:: :maxdepth: 2 - building intro + building + overview hash sha256 hmac misc - - + tests + refs Indices and tables ================== * :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/doc/source/intro.rst b/doc/source/intro.rst new file mode 100644 index 0000000..d269820 --- /dev/null +++ b/doc/source/intro.rst @@ -0,0 +1,21 @@ +------------- +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 `_ + + diff --git a/doc/source/misc.rst b/doc/source/misc.rst new file mode 100644 index 0000000..b526385 --- /dev/null +++ b/doc/source/misc.rst @@ -0,0 +1,107 @@ +----------------------- +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``. + diff --git a/doc/sphinx/source/intro.rst b/doc/source/overview.rst similarity index 96% rename from doc/sphinx/source/intro.rst rename to doc/source/overview.rst index fe2ab97..35e17f0 100644 --- a/doc/sphinx/source/intro.rst +++ b/doc/source/overview.rst @@ -1,6 +1,6 @@ -------------- -Introduction -------------- +---------------- +Library Overview +---------------- .. cpp:namespace:: emsha diff --git a/doc/source/refs.rst b/doc/source/refs.rst new file mode 100644 index 0000000..a696dde --- /dev/null +++ b/doc/source/refs.rst @@ -0,0 +1,17 @@ +---------- +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/sphinx/source/sha256.rst b/doc/source/sha256.rst similarity index 96% rename from doc/sphinx/source/sha256.rst rename to doc/source/sha256.rst index 6d5f2b5..5d65b4f 100644 --- a/doc/sphinx/source/sha256.rst +++ b/doc/source/sha256.rst @@ -4,8 +4,8 @@ The SHA256 class .. cpp:class:: emsha::SHA256 - SHA256 is an implementation of the :cpp:class:`emsha::Hash` - interface. + SHA256 is an implementation of the :cpp:class:`emsha::Hash` interface + implementing the SHA-256 cryptographic hash algorithm .. cpp:function:: SHA256::SHA256() @@ -109,3 +109,4 @@ The SHA256 class * a ``uint32_t`` representing the expected size of buffers passed to ``result`` and ``finalize``. + diff --git a/doc/source/tests.rst b/doc/source/tests.rst new file mode 100644 index 0000000..9a152a1 --- /dev/null +++ b/doc/source/tests.rst @@ -0,0 +1,50 @@ +------------- +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. + + + diff --git a/doc/sphinx/source/hmac.rst b/doc/sphinx/source/hmac.rst deleted file mode 100644 index 32aee82..0000000 --- a/doc/sphinx/source/hmac.rst +++ /dev/null @@ -1,3 +0,0 @@ --------------- -The HMAC class --------------- diff --git a/doc/sphinx/source/misc.rst b/doc/sphinx/source/misc.rst deleted file mode 100644 index d0b5d1b..0000000 --- a/doc/sphinx/source/misc.rst +++ /dev/null @@ -1,4 +0,0 @@ ------------------------ -Miscellaneous functions ------------------------ - diff --git a/src/Makefile.am b/src/Makefile.am index 76cf9a3..c1232a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,7 +16,8 @@ libemsha_li_CPPFLAGS = $(AM_CPPFLAGS) -Winline check_PROGRAMS = emsha_sha256_test emsha_hmac_test \ emsha_core_test emsha_mem_test \ emsha_static_mem_test \ - emsha_static_sha_test + emsha_static_sha_test \ + emsha_static_hmac_test check_CPPFLAGS = $(AM_CPPFLAGS) -Wnoinline # emsha_sha256_test runs through some SHA-256 test vectors, ensuring @@ -40,22 +41,22 @@ emsha_core_test_LDADD = libemsha.la emsha_mem_test_SOURCES = test_mem.cc $(TEST_UTILS) emsha_mem_test_LDADD = libemsha.la -# emsha_static_mem_test is a statically compiled (e.g. not libtool'd) -# test program whose stack can be more accurately measured. emsha_static_mem_test_SOURCES = test_mem.cc emsha.cc sha256.cc hmac.cc $(TEST_UTILS) emsha_static_mem_test_CPPFLAGS = $(AM_CPPFLAGS) -static emsha_static_mem_test_LDFLAGS = $(AM_LDFLAGS) -static -# emsha_static_mem_test is a statically compiled (e.g. not libtool'd) -# test program whose stack can be more accurately measured. emsha_static_sha_test_SOURCES = test_sha256.cc emsha.cc sha256.cc hmac.cc $(TEST_UTILS) emsha_static_sha_test_CPPFLAGS = $(AM_CPPFLAGS) -static emsha_static_sha_test_LDFLAGS = $(AM_LDFLAGS) -static +emsha_static_hmac_test_SOURCES = test_hmac.cc emsha.cc sha256.cc hmac.cc $(TEST_UTILS) +emsha_static_hmac_test_CPPFLAGS = $(AM_CPPFLAGS) -static +emsha_static_hmac_test_LDFLAGS = $(AM_LDFLAGS) -static + .PHONY: valgrind-check valgrind-check: emsha_static_mem_test - valgrind --tool=massif -v emsha_mem_test ms_print + valgrind --tool=massif -v emsha_static_mem_test ms_print .PHONY: cloc-report cloc-report: diff --git a/src/emsha/emsha.hh b/src/emsha/emsha.hh index fec1033..aaa57c3 100644 --- a/src/emsha/emsha.hh +++ b/src/emsha/emsha.hh @@ -148,6 +148,19 @@ namespace emsha { // 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. + // + // Inputs: + // + // dest: a byte array that is 2 * srclen. + // + // src: a byte array containing the data to process. + // + // srclen: the size of src. + // + // Outputs: + // + // The hex-encoded string will be placed into dest. + // void hexstring(std::uint8_t *dest, std::uint8_t *src, std::uint32_t srclen); #endif // EMSHA_NO_HEXSTRING } // end of namespace emsha diff --git a/src/test_emsha.cc b/src/test_emsha.cc index 81cb90e..f6cb9ea 100644 --- a/src/test_emsha.cc +++ b/src/test_emsha.cc @@ -66,6 +66,8 @@ hexstring_test(void) #endif // #ifndef EMSHA_NO_HEXSTRING +// TODO(kyle): build a test harness around this to verify times between +// runs. static void hash_equal_test(void) {