diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..0451da0 --- /dev/null +++ b/.clang-format @@ -0,0 +1,67 @@ +# Generated from CLion C/C++ Code Style settings +BasedOnStyle: LLVM +AccessModifierOffset: -8 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: Consecutive +AlignOperands: Align +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterReturnType: TopLevel +AlwaysBreakTemplateDeclarations: Yes +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: true +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 0 +CompactNamespaces: false +ContinuationIndentWidth: 4 +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 8 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +QualifierAlignment: Left +PointerAlignment: Right +ReflowComments: false +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 0 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 8 +UseTab: ForContinuationAndIndentation diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..183b1d8 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,34 @@ +Checks: >- + bugprone-*, + cppcoreguidelines-*, + google-*, + misc-*, + modernize-*, + performance-*, + readability-*, + -bugprone-lambda-function-name, + -bugprone-reserved-identifier, + -cppcoreguidelines-avoid-goto, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-avoid-non-const-global-variables, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-type-vararg, + -google-readability-braces-around-statements, + -google-readability-function-size, + -misc-no-recursion, + -modernize-return-braced-init-list, + -modernize-use-nodiscard, + -modernize-use-trailing-return-type, + -performance-unnecessary-value-param, + -readability-identifier-length, + -readability-magic-numbers + +CheckOptions: + - key: readability-function-cognitive-complexity.Threshold + value: 100 + - key: readability-function-cognitive-complexity.IgnoreMacros + value: true + # Set naming conventions for your style below (there are dozens of naming settings possible): + # See https://clang.llvm.org/extra/clang-tidy/checks/readability/identifier-naming.html + - key: readability-identifier-naming.ClassCase + value: CamelCase diff --git a/.gitignore b/.gitignore index 42334a5..979d0c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,59 +1,7 @@ -*.o -*.lo -*.a -*.la -*.dirstamp -*.pc -*.log -*.trs +build +cmake-build-* + TAGS tags core* -# autoconf output -autom4te.cache -*.in -!/src/libemsha-1.pc.in -config.* -compile -*.m4 -configure -depcomp -*.info -mdate-sh -stamp-* -texinfo.tex -version.texi -install-sh -missing -Makefile -.deps -.libs -libtool -ltmain.sh - -RELEASE_NOTES -debian/files -debian/libemsha-1.postinst.debhelper -debian/libemsha-1.postrm.debhelper -debian/libemsha-1.substvars -debian/libemsha-1/ -debian/libemsha-dev.substvars -debian/libemsha-dev/ -debian/shlibs.local -debian/source/ -debian/tmp/ -doc/source/header.dated.rst -doc/source/header.rst -src/cov-int/ -src/emsha_core_test -src/emsha_hmac_test -src/emsha_mem_test -src/emsha_sha256_test -src/emsha_static_hmac_test -src/emsha_static_mem_test -src/emsha_static_sha_test -src/libemsha.tgz -doc/source/conf.py -/test-driver -do-release diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..5ff5750 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..41aee02 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/emsha.iml b/.idea/emsha.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/emsha.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..536a3da --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..799808a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/scopes/ProjectSources.xml b/.idea/scopes/ProjectSources.xml new file mode 100644 index 0000000..15fa1f8 --- /dev/null +++ b/.idea/scopes/ProjectSources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.trunk/.gitignore b/.trunk/.gitignore new file mode 100644 index 0000000..1e24652 --- /dev/null +++ b/.trunk/.gitignore @@ -0,0 +1,8 @@ +*out +*logs +*actions +*notifications +*tools +plugins +user_trunk.yaml +user.yaml diff --git a/.trunk/configs/.clang-tidy b/.trunk/configs/.clang-tidy new file mode 100644 index 0000000..e4bd819 --- /dev/null +++ b/.trunk/configs/.clang-tidy @@ -0,0 +1,39 @@ +Checks: >- + bugprone-*, + cppcoreguidelines-*, + google-*, + misc-*, + modernize-*, + performance-*, + readability-*, + -bugprone-lambda-function-name, + -bugprone-reserved-identifier, + -cppcoreguidelines-avoid-goto, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-avoid-non-const-global-variables, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-type-vararg, + -google-readability-braces-around-statements, + -google-readability-function-size, + -misc-no-recursion, + -modernize-return-braced-init-list, + -modernize-use-nodiscard, + -modernize-use-trailing-return-type, + -performance-unnecessary-value-param, + -readability-magic-numbers, + +CheckOptions: + - key: readability-function-cognitive-complexity.Threshold + value: 100 + - key: readability-function-cognitive-complexity.IgnoreMacros + value: true + # Set naming conventions for your style below (there are dozens of naming settings possible): + # See https://clang.llvm.org/extra/clang-tidy/checks/readability/identifier-naming.html + # - key: readability-identifier-naming.ClassCase + # value: CamelCase + # - key: readability-identifier-naming.NamespaceCase + # value: lower_case + # - key: readability-identifier-naming.PrivateMemberSuffix + # value: _ + # - key: readability-identifier-naming.StructCase + # value: CamelCase diff --git a/.trunk/configs/.isort.cfg b/.trunk/configs/.isort.cfg new file mode 100644 index 0000000..b9fb3f3 --- /dev/null +++ b/.trunk/configs/.isort.cfg @@ -0,0 +1,2 @@ +[settings] +profile=black diff --git a/.trunk/configs/.markdownlint.yaml b/.trunk/configs/.markdownlint.yaml new file mode 100644 index 0000000..fb94039 --- /dev/null +++ b/.trunk/configs/.markdownlint.yaml @@ -0,0 +1,10 @@ +# Autoformatter friendly markdownlint config (all formatting rules disabled) +default: true +blank_lines: false +bullet: false +html: false +indentation: false +line_length: false +spaces: false +url: false +whitespace: false diff --git a/.trunk/configs/.shellcheckrc b/.trunk/configs/.shellcheckrc new file mode 100644 index 0000000..8c7b1ad --- /dev/null +++ b/.trunk/configs/.shellcheckrc @@ -0,0 +1,7 @@ +enable=all +source-path=SCRIPTDIR +disable=SC2154 + +# If you're having issues with shellcheck following source, disable the errors via: +# disable=SC1090 +# disable=SC1091 diff --git a/.trunk/configs/.yamllint.yaml b/.trunk/configs/.yamllint.yaml new file mode 100644 index 0000000..4d44466 --- /dev/null +++ b/.trunk/configs/.yamllint.yaml @@ -0,0 +1,10 @@ +rules: + quoted-strings: + required: only-when-needed + extra-allowed: ["{|}"] + empty-values: + forbid-in-block-mappings: true + forbid-in-flow-mappings: true + key-duplicates: {} + octal-values: + forbid-implicit-octal: true diff --git a/.trunk/configs/ruff.toml b/.trunk/configs/ruff.toml new file mode 100644 index 0000000..f5a235c --- /dev/null +++ b/.trunk/configs/ruff.toml @@ -0,0 +1,5 @@ +# Generic, formatter-friendly config. +select = ["B", "D3", "E", "F"] + +# Never enforce `E501` (line length violations). This should be handled by formatters. +ignore = ["E501"] diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml new file mode 100644 index 0000000..0881aa2 --- /dev/null +++ b/.trunk/trunk.yaml @@ -0,0 +1,39 @@ +# This file controls the behavior of Trunk: https://docs.trunk.io/cli +# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml +version: 0.1 +cli: + version: 1.17.0 +plugins: + sources: + - id: trunk + ref: v1.2.6 + uri: https://github.com/trunk-io/plugins +runtimes: + enabled: + - go@1.21.0 + - node@18.12.1 + - python@3.10.8 +lint: + enabled: + - clang-tidy@16.0.3 + - bandit@1.7.5 + - black@23.9.1 + - checkov@2.5.9 + - git-diff-check + - isort@5.12.0 + - markdownlint@0.37.0 + - osv-scanner@1.4.1 + - prettier@3.0.3 + - ruff@0.0.292 + - shellcheck@0.9.0 + - shfmt@3.6.0 + - trivy@0.46.0 + - trufflehog@3.60.0 + - yamllint@1.32.0 +actions: + disabled: + - trunk-announce + - trunk-check-pre-push + - trunk-fmt-pre-commit + enabled: + - trunk-upgrade-available diff --git a/CHANGELOG b/CHANGELOG index 4572473..c2d342e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,11 @@ LIBEMSHA CHANGELOG ================== +1.0.3 (2023-10-17): + +Changed: + + Switched from autotools to cmake. + 1.0.2 (2015-01-28): Added: diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..90f2778 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 3.22) +project(emsha + VERSION 1.0.3 + LANGUAGES CXX + DESCRIPTION "A compact HMAC-SHA-256 C++11 library.") +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_VERBOSE_MAKEFILES ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +set(EMSHA_NO_HEXSTRING OFF CACHE BOOL + "Don't include support for hex strings.") +set(EMSHA_NO_HEXLUT OFF CACHE BOOL + "Don't use a LUT for hex strings (saves ~256B of memory).") + +include(CTest) +enable_testing() + +# compile options: +# -Wall Default to all errors. +# -Wextra And a few extra. +# -Werror And require them to be fixed to build. +# -Wno-unused-function This is a library. Not every function is used here. +# -Wno-unused-parameter Some functions have parameters defined for compatibility, +# and aren't used in the implementation. +add_compile_options( + "-static" + "-Wall" + "-Wextra" + "-Werror" + "-Wno-unused-function" + "-Wno-unused-parameter" + "-g" + "$<$:-O2>" +) +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + add_compile_options("-stdlib=libc++") +else () + # nothing special for gcc at the moment +endif () + +### Set up the build ### +set(HEADERS + emsha/emsha.h + emsha/sha256.h + emsha/hmac.h + emsha/internal.h) +set(SOURCES emsha.cc sha256.cc hmac.cc) + +include_directories(SYSTEM .) + +### Build products ### + +add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) + +### TESTS ### + +set(TEST_SOURCES test_utils.cc) +macro(generate_test name) + add_executable(${name} ${name}.cc ${TEST_SOURCES} ${ARGN}) + target_link_libraries(${name} ${PROJECT_NAME}) + add_test(${name} ${name}) +endmacro() + +generate_test(test_${PROJECT_NAME} test_${PROJECT_NAME}.cc) +generate_test(test_hmac) +generate_test(test_mem) +generate_test(test_sha256) + +include(cmake/docs.cmake) +include(cmake/install.cmake) +include(cmake/packaging.cmake) diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 92642e1..0000000 --- a/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = src - -TESTS = src/emsha_core_test \ - src/emsha_sha256_test \ - src/emsha_hmac_test - -dist_data_DATA = LICENSE \ - README.rst \ - doc/libemsha.rst -dist_noinst_DATA = autobuild \ - doc/source \ - doc/Makefile - -.PHONY: valgrind-check -valgrind-check: - cd src && make $@ - -.PHONY: cloc-report -cloc-report: - cd src && make $@ - -.PHONY: coverity-scan -coverity-scan: - cd src && make $@ - -epub: - cd doc && make $@ diff --git a/autobuild b/autobuild deleted file mode 100755 index cc7467b..0000000 --- a/autobuild +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -CXX=g++ -command -v clang 2>&1 > /dev/null && CXX=clang++ -[ -d m4 ] || mkdir m4 -autoreconf -i && ./configure --enable-silent-rules CXX=$CXX \ - && make && make check diff --git a/cleanroom b/cleanroom deleted file mode 100755 index 8d9e5db..0000000 --- a/cleanroom +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -echo ' ____ _ _ _ ____ _____ ____ ' -echo ' | _ \ / \ | \ | |/ ___| ____| _ \ ' -echo ' | | | |/ _ \ | \| | | _| _| | |_) |' -echo ' | |_| / ___ \| |\ | |_| | |___| _ < ' -echo ' |____/_/ \_\_| \_|\____|_____|_| \_\' -echo '' - -echo "[!] This script will destroy anything not tracked by git." -echo "[!] Waiting 5 seconds before running. Press ^C to abort." - -echo -n "5" -sleep 1 -echo -n " 4" -sleep 1 -echo -n " 3" -sleep 1 -echo -n " 2" -sleep 1 -echo -n " 1" -sleep 1 -echo " nuking from orbit!" -sleep 1 - -echo "" -git clean -fxd - -echo "" -echo "-------------------------------------------------------------" -echo "If you wish to make an apple pie from scratch, you must first" -echo "create the universe." -echo " -- Carl Fucking Sagan" -echo "-------------------------------------------------------------" -echo "" -./autobuild - diff --git a/cmake/docs.cmake b/cmake/docs.cmake new file mode 100644 index 0000000..af153ff --- /dev/null +++ b/cmake/docs.cmake @@ -0,0 +1,41 @@ +# Doxygen support for scsl. + +add_custom_target(manpages) + +macro(md2man source) + block() + set(SOURCE_MANPAGE) + set(SOURCE_SECTION) + string(REGEX REPLACE "^.+/([^/]+)\.md$" "\\1" SOURCE_MANPAGE ${source}) + string(REGEX REPLACE "^.+/[^/]+\.([0-9])\.md$" "\\1" SOURCE_SECTION ${source}) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/man/man${SOURCE_SECTION}) + configure_file(${source} ${SOURCE_MANPAGE}.scdoc) + add_custom_command(TARGET manpages + COMMAND scdoc < ${SOURCE_MANPAGE}.scdoc > man/man${SOURCE_SECTION}/${SOURCE_MANPAGE}) + endblock() +endmacro() + +md2man(docs/emsha.3.md) + +find_package(Doxygen) +if (${DOXYGEN_FOUND}) + # prefer scdocs for manpages. + set(DOXYGEN_GENERATE_MAN NO) + set(DOXYGEN_GENERATE_LATEX YES) + set(DOXYGEN_EXTRACT_ALL YES) + set(DOXYGEN_USE_MDFILE_AS_MAINPAGE "${CMAKE_CURRENT_SOURCE_DIR}/docs/mainpage.md") + message(STATUS "Doxygen found, building docs.") + + doxygen_add_docs(${PROJECT_NAME}_docs + ${HEADER_FILES} + ${SOURCE_FILES} + USE_STAMP_FILE) + add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_docs) + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html + ${CMAKE_CURRENT_BINARY_DIR}/latex + DESTINATION share/doc/${PROJECT_NAME}/doxygen) + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/man + DESTINATION share) + add_dependencies(${PROJECT_NAME}_docs manpages) +endif () + diff --git a/cmake/emshaConfig.cmake b/cmake/emshaConfig.cmake new file mode 100644 index 0000000..bef07a5 --- /dev/null +++ b/cmake/emshaConfig.cmake @@ -0,0 +1,3 @@ +set(EMSHA_INCLUDE_DIRS include/@PROJECT_NAME@) +set(EMSHA_LIBRARIES libemsha-@PROJECT_VERSION_MAJOR@.a) + diff --git a/cmake/install.cmake b/cmake/install.cmake new file mode 100644 index 0000000..c6e7bc4 --- /dev/null +++ b/cmake/install.cmake @@ -0,0 +1,27 @@ +### Install ### + +include(CMakePackageConfigHelpers) + +### library packaging for CMake and pkgconfig to find built targets. +write_basic_package_version_file( + ${PROJECT_NAME}Config.cmake + VERSION ${PACKAGE_VERSION} + COMPATIBILITY SameMajorVersion +) +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) +configure_file(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY) + +### set up installation targets. + +install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION lib) +install(FILES ${HEADERS} DESTINATION include/${PROJECT_NAME}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc + DESTINATION lib/pkgconfig) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + DESTINATION share/${PROJECT_CMAKE_CONFIG_NAME}/cmake) + + diff --git a/cmake/packaging.cmake b/cmake/packaging.cmake new file mode 100644 index 0000000..ae2d21f --- /dev/null +++ b/cmake/packaging.cmake @@ -0,0 +1,41 @@ +### Packaging ### + +include(InstallRequiredSystemLibraries) + +set(CPACK_PACKAGE_VENDOR "K. Isom") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_DESCRIPTION}) +set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) +set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) +set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) + +set(CPACK_PACKAGE_FILE_NAME + ${PROJECT_NAME}-${PROJECT_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_ARCH}${CMAKE_HOST_SYSTEM_PROCESSOR}) + +# Debian settings +set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${CPACK_PACKAGE_VENDOR}) +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${CPACK_PACKAGE_DESCRIPTION}) +set(CPACK_PACKAGE_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION}) +set(CPACK_PACKAGE_DEPENDS) +set(CPACK_DEBIAN_PACKAGE_SECTION devel) +set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON) +set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT) + +if(LINUX) +set(CPACK_GENERATOR "DEB;STGZ;TGZ") +elseif(APPLE) +set(CPACK_GENERATOR "productbuild") +elseif(MSVC OR MSYS OR MINGW) +set(CPACK_GENERATOR "NSIS;ZIP") +else() +set(CPACK_GENERATOR "ZIP") +endif() + +set(CPACK_SOURCE_GENERATOR "TGZ;ZIP") + +set(CPACK_SOURCE_IGNORE_FILES + /.git + /dist + /.*build.*) + +include (CPack) +add_custom_target(package_docs DEPENDS emsha_docs package package_source) diff --git a/configure.ac b/configure.ac deleted file mode 100644 index c637299..0000000 --- a/configure.ac +++ /dev/null @@ -1,62 +0,0 @@ -# autoconf version 2.68 and automake version 1.11 seem to be the latest -# versions that can be used with Travis right now. -AC_PREREQ([2.68]) -AC_INIT([libemsha], - [1.0.2], - [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/source/conf.py doc/source/header.rst src/libemsha-1.pc]) -AC_CONFIG_FILES([do-release], [chmod +x do-release]) -AC_CONFIG_MACRO_DIR([m4]) - -PKG_PROG_PKG_CONFIG -AC_CHECK_HEADERS - -LT_INIT -AC_PROG_CXX -AC_PROG_INSTALL -AC_PROG_CC_C_O - -AC_CHECK_PROGS([SPHINX], [sphinx-build]) -if test -z "$SPHINX"; -then - AC_MSG_WARN([Sphinx not found - continuing without Sphinx support]) -fi - -AC_ARG_ENABLE([hexstring], - AS_HELP_STRING([--disable-hexstring], [Don't build with support for hex string output (default enabled)]), - [:], [enable_hexstring=check]) - -AC_ARG_ENABLE([hexlut], - AS_HELP_STRING([--disable-hexlut], [Don't build with the larger LUT for building hex strings (saves ~1KB of memory). This has no effect if hex strings are disabled.]), - [:], [enable_hexlut=check]) - -AC_ARG_ENABLE([selftest], - AS_HELP_STRING([--disable-selftest], [Don't build with support for internal self-tests (saves some memory that is used by the test vectors.)]), - [:], [enable_selftest=check]) - -# The default for the ARG_ENABLE options is to have them enabled. -AS_IF([test "x$enable_hexstring" == "xno"], [ - AC_MSG_NOTICE([disabling hexstrings.]) - AC_DEFINE(EMSHA_NO_HEXSTRING) -]) - -AS_IF([test "x$enable_hexlut" == "xno"], [ - AC_MSG_NOTICE([disabling the large hexstring LUT.]) - AC_DEFINE(EMSHA_NO_HEXLUT) -]) - -AS_IF([test "x$enable_selftest" == "xno"], [ - AC_MSG_NOTICE([disabling the internal self tests.]) - AC_DEFINE(EMSHA_NO_SELFTEST) -]) - - -AM_CONDITIONAL([HAVE_SPHINX], - [test -n "$SPHINX"]) - -AC_OUTPUT diff --git a/do-release.in b/do-release.in deleted file mode 100755 index 96a83ea..0000000 --- a/do-release.in +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh - -set -e - -VERSION="@PACKAGE_VERSION@" -TARBALL="@PACKAGE_NAME@-$VERSION" - -make clean -echo "[+] rebuilding single ReST doc" -cd doc && make clean singlerst clean && cd .. -echo "[+] building release tarballs" -make dist-gzip -if [ ! -e "$TARBALL.tar.gz" ] -then - >&2 echo "[!] Expected to find ${TARBALL}.tar.gz, but it wasn't found." - >&2 echo " Cannot proceed, aborting." - exit 1 -fi - -make dist-zip -if [ ! -e "$TARBALL.zip" ] -then - >&2 echo "[!] Expected to find ${TARBALL}.zip, but it wasn't found." - >&2 echo " Cannot proceed, aborting." - exit 1 -fi - -mv "${TARBALL}.tar.gz" "@PACKAGE_NAME@-release.tar.gz" -mv "${TARBALL}.zip" "@PACKAGE_NAME@-release.zip" - -echo "[+] building release notes" -RELEASE_NOTES_AWK="/^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)? \([0-9]{4}-[0-9]{2}-[0-9]{2}\):/{ - nmatch++; - if (nmatch>1) exit -} - -{ - if (nmatch>0) - print \$0; -}" - -awk "$RELEASE_NOTES_AWK" CHANGELOG > RELEASE_NOTES -echo "[+] release is ready" diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index a6f9e61..0000000 --- a/doc/Makefile +++ /dev/null @@ -1,204 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -# 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 check - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -# The autotools Makefiles don't seem to do anything for docs in all or check. -all: -check: - -distclean: clean - rm -f source/header*.rst - rm -f source/conf.py - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PACKAGE_NAME.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PACKAGE_NAME.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/PACKAGE_NAME" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PACKAGE_NAME" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/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..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -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/build/.gitkeep b/doc/build/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/doc/libemsha.rst b/doc/libemsha.rst deleted file mode 100644 index 7134fad..0000000 --- a/doc/libemsha.rst +++ /dev/null @@ -1,601 +0,0 @@ -======== -libemsha -======== - -Version: 1.0.2 - -Date: 2016-01-28 - - ------------------ -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/_static/.gitkeep b/doc/source/_static/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/doc/source/_templates/.gitkeep b/doc/source/_templates/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/doc/source/building.rst b/doc/source/building.rst deleted file mode 100644 index 41d538c..0000000 --- a/doc/source/building.rst +++ /dev/null @@ -1,37 +0,0 @@ -------------------------------- -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. - diff --git a/doc/source/conf.py.in b/doc/source/conf.py.in deleted file mode 100644 index 581a6eb..0000000 --- a/doc/source/conf.py.in +++ /dev/null @@ -1,335 +0,0 @@ -# -*- coding: utf-8 -*- -# -# @PACKAGE_NAME@ documentation build configuration file, created by -# sphinx-quickstart on Tue Dec 15 23:35:10 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os - -import sphinx_rtd_theme - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.todo', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'@PACKAGE_NAME@' -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 -# built documents. -# -# The short X.Y version. -version = '@PACKAGE_VERSION@' -# The full version, including alpha/beta/rc tags. -release = '@PACKAGE_VERSION@' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - -highlight_language = 'c++' - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'sphinx_rtd_theme' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = '@PACKAGE_NAME@doc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('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 -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -latex_show_pagerefs = True - -# If true, show URL addresses after external links. -# latex_show_urls = True - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'package_name', u'@PACKAGE_NAME@ Documentation', - [u'K. Isom '], 1) -] - -# If true, show URL addresses after external links. -man_show_urls = True - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('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. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False - - -# -- Options for Epub output ---------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = u'@PACKAGE_NAME@' -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@' - -# The HTML theme for the epub output. Since the default themes are not optimized -# for small screen space, using the same theme for HTML and epub output is -# usually not wise. This defaults to 'epub', a theme designed to save visual -# space. -#epub_theme = 'epub' - -# The language of the text. It defaults to the language option -# or en if the language is not set. -#epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -#epub_identifier = '' - -# A unique identification for the text. -#epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -#epub_cover = () - -# A sequence of (type, uri, title) tuples for the guide element of content.opf. -#epub_guide = () - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_post_files = [] - -# A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] - -# The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 - -# Allow duplicate toc entries. -#epub_tocdup = True - -# Choose between 'default' and 'includehidden'. -#epub_tocscope = 'default' - -# Fix unsupported image types using the PIL. -#epub_fix_images = False - -# Scale large images. -#epub_max_image_width = 0 - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#epub_show_urls = 'inline' - -# If false, no index is generated. -#epub_use_index = True diff --git a/doc/source/hash.rst b/doc/source/hash.rst deleted file mode 100644 index 0c77c72..0000000 --- a/doc/source/hash.rst +++ /dev/null @@ -1,74 +0,0 @@ ------------------- -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. - diff --git a/doc/source/header.rst.in b/doc/source/header.rst.in deleted file mode 100644 index a3704ed..0000000 --- a/doc/source/header.rst.in +++ /dev/null @@ -1,24 +0,0 @@ -======== -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 - - diff --git a/doc/source/hmac.rst b/doc/source/hmac.rst deleted file mode 100644 index 615a2df..0000000 --- a/doc/source/hmac.rst +++ /dev/null @@ -1,113 +0,0 @@ --------------- -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/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 3408366..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. libemsha documentation master file, created by - sphinx-quickstart on Tue Dec 15 23:35:10 2015. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -libemsha -======== - -.. toctree:: - :maxdepth: 2 - - intro - building - overview - hash - sha256 - hmac - misc - tests - refs - - -Indices and tables -================== - -* :ref:`genindex` - diff --git a/doc/source/intro.rst b/doc/source/intro.rst deleted file mode 100644 index d269820..0000000 --- a/doc/source/intro.rst +++ /dev/null @@ -1,21 +0,0 @@ -------------- -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 deleted file mode 100644 index b526385..0000000 --- a/doc/source/misc.rst +++ /dev/null @@ -1,107 +0,0 @@ ------------------------ -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/source/overview.rst b/doc/source/overview.rst deleted file mode 100644 index 35e17f0..0000000 --- a/doc/source/overview.rst +++ /dev/null @@ -1,46 +0,0 @@ ----------------- -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` - - diff --git a/doc/source/refs.rst b/doc/source/refs.rst deleted file mode 100644 index a696dde..0000000 --- a/doc/source/refs.rst +++ /dev/null @@ -1,17 +0,0 @@ ----------- -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/sha256.rst b/doc/source/sha256.rst deleted file mode 100644 index 5d65b4f..0000000 --- a/doc/source/sha256.rst +++ /dev/null @@ -1,112 +0,0 @@ ------------------ -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``. - - diff --git a/doc/source/tests.rst b/doc/source/tests.rst deleted file mode 100644 index 9a152a1..0000000 --- a/doc/source/tests.rst +++ /dev/null @@ -1,50 +0,0 @@ -------------- -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/docs/emsha.3.md b/docs/emsha.3.md new file mode 100644 index 0000000..200bbd8 --- /dev/null +++ b/docs/emsha.3.md @@ -0,0 +1,25 @@ +libemsha(3) "@PROJECT_VERSION@" + +# 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. + +# References + +- FIPS 180-4, the Secure Hash Standard: (http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf) +- FIPS 198-1, The Keyed-Hash Message Authentication Code (HMAC): (http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf) +- RFC 2014, HMAC: Keyed-Hashing for Message Authentication: (https://tools.ietf.org/html/rfc2104) +- RFC 6234, US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF): (https://tools.ietf.org/html/rfc6234) +- The Power of Ten – Rules for Developing Safety Critical Code: (http://spinroot.com/gerard/pdf/P10.pdf) + +# Validation + +- The behaviour of this package was cross-checked using the Go 1.5.1 linux/amd64 standard library\'s + crypto/sha256 package. diff --git a/docs/libemsha.7.md b/docs/libemsha.7.md new file mode 100644 index 0000000..31a11bd --- /dev/null +++ b/docs/libemsha.7.md @@ -0,0 +1,13 @@ +@PROJECT_NAME@(7) "@PROJECT_VERSION@" + +# NAME + +# DESCRIPTION + +# DATA STRUCTURES + +# HEADER FILES + +# NOTES + +# SEE ALSO diff --git a/docs/mainpage.md b/docs/mainpage.md new file mode 100644 index 0000000..12194cd --- /dev/null +++ b/docs/mainpage.md @@ -0,0 +1,198 @@ +# libemsha + +Version: 1.0.2 + +Date: 2016-01-28 + +## 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](http://spinroot.com/gerard/pdf/P10.pdf) 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](https://tools.ietf.org/html/rfc6234); instead a standalone +implementation was decided on. + +Additional resources: + +- [Github page](https://github.com/kisom/libemsha) +- [Travis CI status](https://travis-ci.org/kisom/libemsha/) +- [Coverity Scan page](https://scan.coverity.com/projects/libemsha-52f2a5fd-e759-43c2-9073-cf6c2ed9abdb) + +## Getting and Building the Source + +The source code is available via +[Github](https://github.com/kisom/libemsha/); 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](https://github.com/kisom/libemsha/archive/1.0.0.zip). + +The project is built using Autotools and `make`. + +When building from a git checkout, the [autobuild]{.title-ref} 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 + +The package provides a pair of classes, :cpp`SHA256`{.interpreted-text +role="class"} and :cpp`HMAC`{.interpreted-text role="class"}, that both +satisfy a common interface :cpp`Hash`{.interpreted-text role="class"}. +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: + + // 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`EMSHA_RESULT`{.interpreted-text +> role="type"} + +## The Hash interface + +In general, a [Hash]{.title-ref} 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 + +## The SHA256 class + +## The HMAC class + +## Miscellaneous functions + +## 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](http://valgrind.org/) 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](http://tools.ietf.org/html/rfc4231) +test vectors to the HMAC code. + +## References + +- [FIPS 180-4, the Secure Hash + Standard](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf) +- [FIPS 198-1, The Keyed-Hash Message Authentication Code + (HMAC)](http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf) +- [RFC 2014, HMAC: Keyed-Hashing for Message + Authentication](https://tools.ietf.org/html/rfc2104) +- [RFC 6234, US Secure Hash Algorithms (SHA and SHA-based HMAC and + HKDF)](https://tools.ietf.org/html/rfc6234)[^1] +- The behaviour of this package was cross-checked using the Go 1.5.1 + linux/amd64 standard library\'s + [crypto/sha256](https://golang.org/src/crypto/sha256/) package. + +**Footnotes** + +[^1]: + 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/src/emsha.cc b/emsha.cc similarity index 89% rename from src/emsha.cc rename to emsha.cc index dfccdcf..b590b07 100644 --- a/src/emsha.cc +++ b/emsha.cc @@ -28,31 +28,23 @@ #include #include -#include +#include using std::uint8_t; using std::uint32_t; -using std::cout; -using std::endl; namespace emsha { -Hash::~Hash() -{ - // Nothing to see here. -} - - bool -hash_equal(const uint8_t *a, const uint8_t *b) +HashEqual(const uint8_t *a, const uint8_t *b) { uint8_t res = 0; - EMSHA_CHECK(a != NULL, false); - EMSHA_CHECK(b != NULL, false); + EMSHA_CHECK(a != nullptr, false); + EMSHA_CHECK(b != nullptr, false); for (uint32_t i = 0; i < SHA256_HASH_SIZE; i++) { res += a[i] ^ b[i]; @@ -67,7 +59,7 @@ hash_equal(const uint8_t *a, const uint8_t *b) // If using a lookup table is permitted, then the faster way to do this // is to use one. static void -write_hex_char(uint8_t *dest, uint8_t src) +writeHexChar(uint8_t *dest, uint8_t src) { static constexpr uint8_t lut[256][3] = { "00", "01", "02", "03", "04", "05", "06", "07", @@ -108,13 +100,14 @@ write_hex_char(uint8_t *dest, uint8_t src) *(dest + 1) = lut[src][1]; } + #else // #ifndef EMSHA_NO_HEXLUT // If the full lookup table can't be used, e.g. because MSP430-level // memory constraints, we'll work around this using a small (16-byte) // lookup table and some bit shifting. On platforms where even this is -// too much, the hexstring functionality will just be disabled. +// too much, the HexString functionality will just be disabled. static void -write_hex_char(uint8_t *dest, uint8_t src) +writeHexChar(uint8_t *dest, uint8_t src) { static constexpr uint8_t lut[] = { '0', '1', '2', '3', '4', '5', '6', '7', @@ -124,23 +117,21 @@ write_hex_char(uint8_t *dest, uint8_t src) *dest = lut[((src & 0xF0) >> 4)]; *(dest + 1) = lut[(src & 0xF)]; } - #endif // #ifndef EMSHA_NO_HEXLUT void -hexstring(uint8_t *dest, uint8_t *src, uint32_t srclen) +HexString(uint8_t *dest, uint8_t *src, uint32_t srclen) { - uint8_t *dp = dest; + size_t dp = 0; for (uint32_t i = 0; i < srclen; i++) { - write_hex_char(dp, src[i]); + writeHexChar(&dest[dp], src[i]); dp += 2; } } - - #endif // #ifndef EMSHA_NO_HEXSTRING } // end of namespace emsha + diff --git a/emsha.pc.in b/emsha.pc.in new file mode 100644 index 0000000..a231a47 --- /dev/null +++ b/emsha.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: @PROJECT_NAME@ +Description: C++11 HMAC-SHA256 library +URL: https://git.wntrmute.dev/kyle/emsha +Version: @PROJECT_VERSION@ +Libs: -L${libdir} -lemsha diff --git a/emsha/emsha.h b/emsha/emsha.h new file mode 100644 index 0000000..5587ebb --- /dev/null +++ b/emsha/emsha.h @@ -0,0 +1,170 @@ +/// +/// \file emsha/emsha.h +/// \author K. Isom +/// \date 2015-12-17 +/// \brief Declares an interface for an EMbedded Secure HAshing interface. +/// +/// The MIT License (MIT) +/// +/// Copyright (c) 2015 K. Isom +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +/// IN THE SOFTWARE. +/// + + +#ifndef EMSHA_EMSHA_H +#define EMSHA_EMSHA_H + + +#include + + +// Emsha is an EMbedded Secure HAshing interface. +namespace emsha { + + +/// EMSHA_CHECK is used for sanity checks in certain parts of the code. +#ifdef NDEBUG +/// EMSHA_CHECK is used for sanity checks in certain parts of +/// the code. If asserts are turned off, expand the check to an +/// if statement that will return with retval if the condition +/// isn't met. +#define EMSHA_CHECK(condition, retval) if (!(condition)) { return (retval); } +#else +/// EMSHA_CHECK is used for sanity checks in certain parts of +/// the code. If asserts are turned on, the check is expanded to +/// an assertion that the condition holds. In this case, retval +/// is not used. +#define EMSHA_CHECK(condition, retval) (assert((condition))) +#endif + +/// SHA256_HASH_SIZE is the output length of SHA-256 in bytes. +const std::uint32_t SHA256_HASH_SIZE = 32; + + +/// The EMSHA_RESULT type is used to indicate whether an +/// operation succeeded, and if not, what the general fault type +/// was. +typedef enum _EMSHA_RESULT_ : std::uint8_t { + /// All operations have completed successfully so far. + EMSHA_ROK = 0, + + /// 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 +} EMSHA_RESULT; + + +// A Hash is generalised superclass supporting concrete classes +// that produce digests of data. +class Hash { +public: + virtual ~Hash() = default; + + /// Reset should bring the Hash back into its + /// initial state. That is, the idea is that + /// + /// hash->reset(); hash->update(...)... ; + /// hash->result(...) ; + /// + /// 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. + virtual EMSHA_RESULT Reset() = 0; + + // Update is writes message data into the Hash. + virtual EMSHA_RESULT Update(const std::uint8_t *m, + std::uint32_t ml) = 0; + + /// Finalise carries out any final operations + /// on the Hash; after a call to finalize, no + /// more data can be written. Additionally, it + /// transfers out the resulting hash into its + /// argument. + virtual EMSHA_RESULT Finalise(std::uint8_t *d) = 0; + + /// Result transfers out the hash to the + /// argument. The Hash must keep enough state + /// for repeated calls to result to work. + virtual EMSHA_RESULT Result(std::uint8_t *d) = 0; + + /// Size should return the output size of the + /// Hash; this is, how large the buffers written + /// to by result should be. + virtual std::uint32_t Size() = 0; +}; + +/// HashEqual provides a constant time function for comparing +/// two hashes. The caller *must* ensure that both a and b are +/// the same size. The recommended approach is to use fixed-size +/// buffers of emsha::SHA256_HASH_SIZE length: +/// +/// ```c++ +/// uint8_t expected[emsha::SHA256_HASH_SIZE]; +/// uint8_t actual[emsha::SHA256_HASH_SIZE]; +/// +/// // Fill in expected and actual using the Hash operations. +/// +/// if (hash_equal(expected, actual)) { +/// proceed(); +/// } +/// ``` +/// +/// \param a A byte buffer of size Hash::Size(). +/// \param b A byte buffer of size Hash::Size(). +/// \return True if both byte arrays match. +bool +HashEqual(const std::uint8_t *a, const std::uint8_t *b); + +#ifndef EMSHA_NO_HEXSTRING +/// HexString writes a hex-encoded version of the src byte +/// array into dest. The caller *must* ensure that dest is +/// srclen * 2 bytes or longer. +/// +/// +/// \param dest The destination byte array at least (2*srclen) +/// bytes in length. +/// \param src A byte array containing the data to hexify.. +/// \param srclen The size in bytes of src. +void +HexString(std::uint8_t *dest, std::uint8_t *src, std::uint32_t srclen); +#endif // EMSHA_NO_HEXSTRING + + +} // end of namespace emsha + + +#endif // EMSHA_EMSHA_H diff --git a/emsha/hmac.h b/emsha/hmac.h new file mode 100644 index 0000000..b8d540b --- /dev/null +++ b/emsha/hmac.h @@ -0,0 +1,194 @@ +/// +/// \file emsha/hmac.h +/// \author K. Isom +/// \date 2015-12-17 +/// \brief Declares an interface for HMAC tagging. +/// +/// The MIT License (MIT) +/// +/// Copyright (c) 2015 K. Isom +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +/// IN THE SOFTWARE. +/// + +#ifndef EMSHA_HMAC_H +#define EMSHA_HMAC_H + + +#include + +#include "emsha.h" +#include "sha256.h" + + +namespace emsha { + +const uint32_t HMAC_KEY_LENGTH = SHA256_MB_SIZE; + +/// HMAC is a keyed hash that can be used to produce an +/// authenticated hash of some data. The HMAC is built on +/// (and uses internally) the SHA-256 class; it's helpful to +/// note that faults that occur in the SHA-256 code will be +/// propagated up as the return value from many of the HMAC +/// functions. +class HMAC : Hash { +public: + /// An HMAC is constructed with a key and the + /// length of the key. This key is stored in + /// the HMAC context, and is wiped by the HMAC + /// destructor. + /// + /// \param k The HMAC key. + /// \param kl THe length of the HMAC key. + HMAC(const uint8_t *k, uint32_t kl); + + /// Reset clears any data written to the HMAC; + /// this is equivalent to constructing a new HMAC, + /// but it preserves the keys. + /// + /// \return EMSHA_ROK is returned if the reset + /// occurred without (detected) fault. + /// If a fault occurs with the under- + /// lying SHA-256 context, the error + /// code is returned. + EMSHA_RESULT Reset() override; + + /// Update writes data into the context. While + /// there is an upper limit on the size of data + /// that the underlying hash can operate on, + /// this package is designed for small systems + /// that will not approach that level of data + /// (which is on the order of 2 exabytes), so it + /// is not thought to be a concern. + /// + /// \param m A byte array containing the message + /// to be written. + /// \param ml The message length, in bytes. + /// \return + /// - EMSHA_NULLPTR is returned if m is NULL and ml is + /// nonzero. + /// - EMSHA_INVALID_STATE is returned if the update + /// is called after a call to finalize. + /// - SHA256_INPUT_TOO_LONG is returned if too much + /// data has been written to the context. + /// - EMSHA_ROK is returned if the data was + /// successfully written into the HMAC context. + /// + EMSHA_RESULT Update(const uint8_t *, uint32_t) override; + + // Finalise completes the HMAC computation. Once this + // method is called, the context cannot be updated + // unless the context is reset. + // + // Inputs: + // d: a byte buffer that must be at least + // HMAC.size() in length. + // + // Outputs: + // EMSHA_NULLPTR is returned if d is the null + // pointer. + // + // EMSHA_INVALID_STATE is returned if the HMAC + // context is in an invalid state, such as if there + // were errors in previous updates. + // + // EMSHA_ROK is returned if the context was + // successfully finalised and the digest copied to + // d. + // + EMSHA_RESULT Finalise(uint8_t *) override; + + // Result copies the result from the HMAC context into + // the buffer pointed to by d, running finalize if + // needed. Once called, the context cannot be updated + // until the context is reset. + // + // Inputs: + // d: a byte buffer that must be at least + // HMAC.size() in length. + // + // Outputs: + // EMSHA_NULLPTR is returned if d is the null + // pointer. + // + // EMSHA_INVALID_STATE is returned if the HMAC + // context is in an invalid state, such as if there + // were errors in previous updates. + // + // EMSHA_ROK is returned if the context was + // successfully finalised and the digest copied to + // d. + // + EMSHA_RESULT Result(uint8_t *) override; + + + // size returns the output size of HMAC-SHA-256, e.g. + // the size that the buffers passed to finalize and + // result should be. + // + // Outputs: + // A uint32_t representing the expected size + // of buffers passed to result and finalize. + std::uint32_t Size() override; + + // When an HMAC context is destroyed, it is reset and + // the key material is zeroised using the STL fill + // function. + ~HMAC(void); +private: + uint8_t hstate; + SHA256 ctx; + uint8_t k[HMAC_KEY_LENGTH]; + uint8_t buf[SHA256_HASH_SIZE]; + + EMSHA_RESULT reset(); + inline EMSHA_RESULT + finalResult(uint8_t *d); +}; + +// compute_hmac performs a single-pass HMAC computation over +// a message. +// +// Inputs: +// k: a byte buffer containing the HMAC key. +// +// kl: the length of the HMAC key. +// +// m: the message data over which the HMAC is to be computed. +// +// ml: the length of the message. +// +// d: a byte buffer that will be used to store the resulting +// HMAC. It should be SHA256_HASH_SIZE bytes in size. +// +// Outputs: +// This function handles setting up the HMAC context with +// the given key, calling update with the message data, and +// then calling finalize to place the result in the output +// buffer. Any of the faults that can occur in these functions +// can be returned here, or EMSHA_ROK if the HMAC was +// successfully computed. +EMSHA_RESULT +ComputeHMAC(const uint8_t *k, uint32_t kl, + const uint8_t *m, uint32_t ml, + uint8_t *d); +} // end of namespace emsha + + +#endif // EMSHA_HMAC_H diff --git a/emsha/internal.h b/emsha/internal.h new file mode 100644 index 0000000..5fd5bb3 --- /dev/null +++ b/emsha/internal.h @@ -0,0 +1,96 @@ +/// +/// \file emsha/internal.h +/// \author K. Isom +/// \date 2015-12-17 +/// \brief Declares internal interfaces for the emsha library. +/// +/// The MIT License (MIT) +/// +/// Copyright (c) 2015 K. Isom +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +/// IN THE SOFTWARE. +/// + +#ifndef EMSHA_INTERNAL_H +#define EMSHA_INTERNAL_H + + +#include + +using std::uint8_t; +using std::uint32_t; + + +namespace emsha { + + +static inline uint32_t +rotr32(uint32_t x, uint8_t n) +{ + return ((x >> n) | (x << (32 - n))); +} + + +static inline uint32_t +sha_ch(uint32_t x, uint32_t y, uint32_t z) +{ + return ((x & y) ^ ((~x) & z)); +} + + +static inline uint32_t +sha_maj(uint32_t x, uint32_t y, uint32_t z) +{ + return (x & y) ^ (x & z) ^ (y & z); +} + + +static inline uint32_t +sha_Sigma0(uint32_t x) +{ + return rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22); +} + + +static inline uint32_t +sha_Sigma1(uint32_t x) +{ + return rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25); +} + + +static inline uint32_t +sha_sigma0(uint32_t x) +{ + return rotr32(x, 7) ^ rotr32(x, 18) ^ (x >> 3); +} + + +static inline uint32_t +sha_sigma1(uint32_t x) +{ + return rotr32(x, 17) ^ rotr32(x, 19) ^ (x >> 10); +} + + + +} // end of namespace emsha + + +#endif // EMSHA_INTERNAL_H diff --git a/emsha/sha256.h b/emsha/sha256.h new file mode 100644 index 0000000..e9e796d --- /dev/null +++ b/emsha/sha256.h @@ -0,0 +1,218 @@ +/// +/// \file emsha/sha256.h +/// \author K. Isom +/// \date 2015-12-17 +/// \brief Declares an interface for producing SHA-256 hashes. +/// +/// The MIT License (MIT) +/// +/// Copyright (c) 2015 K. Isom +/// +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// copy of this software and associated documentation files (the "Software"), +/// to deal in the Software without restriction, including without limitation +/// the rights to use, copy, modify, merge, publish, distribute, sublicense, +/// and/or sell copies of the Software, and to permit persons to whom the +/// Software is furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +/// IN THE SOFTWARE. +/// + +#ifndef EMSHA_SHA256_H +#define EMSHA_SHA256_H + + +#include + +#include + + +namespace emsha { + + +// SHA256_MB_SIZE is the size of a message block. +const uint32_t SHA256_MB_SIZE = 64; + +class SHA256 : Hash { +public: + // A SHA256 context does not need any special + // construction. It can be declared and + // immediately start being used. + SHA256(); + + // The SHA256 destructor will clear out its internal + // message buffer; all the members are local and + // not resource handles, so cleanup is minimal. + ~SHA256(); + + // reset clears the internal state of the SHA256 + // context and returns it to its initial state. + // It should always return EMSHA_ROK. + EMSHA_RESULT Reset() override; + + // update writes data into the context. While + // there is an upper limit on the size of data + // that SHA-256 can operate on, this package is + // designed for small systems that will not + // approach that level of data (which is on the + // order of 2 exabytes), so it is not thought + // to be a concern. + // + // Inputs: + // m: a byte array containing the message to + // be written. It must not be NULL (unless + // the message length is zero). + // + // ml: the message length, in bytes. + // + // Outputs: + // EMSHA_NULLPTR is returned if m is NULL + // and ml is nonzero. + // + // EMSHA_INVALID_STATE is returned if the + // update is called after a call to + // finalize. + // + // SHA256_INPUT_TOO_LONG is returned if too + // much data has been written to the + // context. + // + // EMSHA_ROK is returned if the data was + // successfully added to the SHA-256 + // context. + // + EMSHA_RESULT Update(const uint8_t *m, uint32_t ml) override; + + // Finalise completes the digest. Once this + // method is called, the context cannot be + // updated unless the context is reset. + // + // Inputs: + // d: a byte buffer that must be at least + // SHA256.size() in length. + // + // Outputs: + // EMSHA_NULLPTR is returned if d is the + // null pointer. + // + // EMSHA_INVALID_STATE is returned if the + // SHA-256 context is in an invalid state, + // such as if there were errors in previous + // updates. + // + // EMSHA_ROK is returned if the context was + // successfully finalised and the digest + // copied to d. + // + EMSHA_RESULT Finalise(uint8_t *d) override; + + // result copies the result from the SHA-256 + // context into the buffer pointed to by d, + // running Finalise if needed. Once called, + // the context cannot be updated until the + // context is reset. + // + // Inputs: + // d: a byte buffer that must be at least + // SHA256.size() in length. + // + // Outputs: + // EMSHA_NULLPTR is returned if d is the + // null pointer. + // + // EMSHA_INVALID_STATE is returned if the + // SHA-256 context is in an invalid state, + // such as if there were errors in previous + // updates. + // + // EMSHA_ROK is returned if the context was + // successfully finalised and the digest + // copied to d. + // + EMSHA_RESULT Result(uint8_t *d) override; + + // 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. + std::uint32_t Size() override; + +private: + // mlen stores the current message length. + uint64_t mlen; + + // The intermediate hash is 8x 32-bit blocks. + uint32_t i_hash[8]; + + // hStatus is the hash status, and hComplete indicates + // whether the hash has been finalised. + EMSHA_RESULT hStatus; + uint8_t hComplete; + + // mb is the message block, and mbi is the message + // block index. + uint8_t mbi; + uint8_t mb[SHA256_MB_SIZE]; + + inline EMSHA_RESULT addLength(const uint32_t); + inline void updateMessageBlock(void); + inline void padMessage(uint8_t pc); + EMSHA_RESULT reset(); +}; // end class SHA256 + +// sha256Digest performs a single pass hashing of the message +// passed in. +// +// Inputs: +// m: byte buffer containing the message to hash. +// +// ml: the length of m. +// +// d: byte buffer that will be used to store the resulting +// hash; it should have at least emsha::SHA256_HASH_SIZE +// bytes available. +// +// Outputs: +// This function handles setting up a SHA256 context, calling +// update using the message data, and then calling finalize. Any +// of the errors that can occur in those functions can be +// returned here, or EMSHA_ROK if the digest was computed +// successfully. +// +EMSHA_RESULT +sha256Digest(const uint8_t *m, uint32_t ml, uint8_t *d); + +// sha256SelfTest runs through two test cases to ensure that the +// SHA-256 functions are working correctly. +// +// Outputs: +// EMSHA_ROK is returned if the self tests pass. +// +// EMSHA_SELFTEST_DISABLED is returned if the self tests +// have been disabled (e.g., libemsha was compiled with the +// EMSHA_NO_SELFTEST #define). +// +// If a fault occurred inside the SHA-256 code, the error +// code from one of the update, finalize, result, or reset +// methods is returned. +// +// If the fault is that the output does not match the test +// vector, EMSHA_TEST_FAILURE is returned. +EMSHA_RESULT +sha256SelfTest(void); +} // end of namespace emsha + + +#endif // EMSHA_SHA256_H diff --git a/src/hmac.cc b/hmac.cc similarity index 77% rename from src/hmac.cc rename to hmac.cc index 96d9477..7e8b347 100644 --- a/src/hmac.cc +++ b/hmac.cc @@ -28,31 +28,32 @@ #include -#include -#include -#include +#include +#include +#include namespace emsha { + // These constants are used to keep track of the state of the HMAC. -// HMAC is in a clean-slate state following a call to reset(). -constexpr uint8_t HMAC_INIT = 0; +// HMAC is in a clean-slate state following a call to Reset(). +constexpr uint8_t HMAC_INIT = 0; // The ipad constants have been XOR'd into the key and written to the // SHA-256 context. -constexpr uint8_t HMAC_IPAD = 1; +constexpr uint8_t HMAC_IPAD = 1; // The opad constants have been XOR'd into the key and written to the // SHA-256 context. -constexpr uint8_t HMAC_OPAD = 2; +constexpr uint8_t HMAC_OPAD = 2; // HMAC has been finalised -constexpr uint8_t HMAC_FIN = 3; +constexpr uint8_t HMAC_FIN = 3; // HMAC is in an invalid state. -constexpr uint8_t HMAC_INVALID = 4; +constexpr uint8_t HMAC_INVALID = 4; static constexpr uint8_t ipad = 0x36; @@ -60,9 +61,9 @@ static constexpr uint8_t opad = 0x5c; HMAC::HMAC(const uint8_t *ik, uint32_t ikl) - :hstate(), ctx() + : hstate(HMAC_INIT), k{0}, buf{0} { - this->hstate = HMAC_INIT; + std::fill(this->k, this->k + emsha::HMAC_KEY_LENGTH, 0); if (ikl < HMAC_KEY_LENGTH) { @@ -71,9 +72,9 @@ HMAC::HMAC(const uint8_t *ik, uint32_t ikl) this->k[ikl++] = 0; } } else if (ikl > HMAC_KEY_LENGTH) { - this->ctx.update(ik, ikl); - this->ctx.result(this->k); - this->ctx.reset(); + this->ctx.Update(ik, ikl); + this->ctx.Result(this->k); + this->ctx.Reset(); } else { std::copy(ik, ik + ikl, this->k); } @@ -92,25 +93,32 @@ HMAC::~HMAC() } +EMSHA_RESULT +HMAC::Reset() +{ + return this->reset(); +} + + EMSHA_RESULT HMAC::reset() { - EMSHA_RESULT res; + EMSHA_RESULT res; // Following a reset, both SHA-256 contexts and result buffer should be // zero'd out for a clean slate. The HMAC state should be reset // accordingly. - this->ctx.reset(); + this->ctx.Reset(); std::fill(this->buf, this->buf + SHA256_HASH_SIZE, 0); // Set up the k0 ⊕ ipad construction, and write it into the // SHA-256 context. - uint8_t key[HMAC_KEY_LENGTH]; + uint8_t key[HMAC_KEY_LENGTH]; for (uint32_t i = 0; i < HMAC_KEY_LENGTH; i++) { key[i] = this->k[i] ^ ipad; } - res = this->ctx.update(key, HMAC_KEY_LENGTH); + res = this->ctx.Update(key, HMAC_KEY_LENGTH); if (EMSHA_ROK != res) { this->hstate = HMAC_INVALID; return res; @@ -125,15 +133,16 @@ HMAC::reset() EMSHA_RESULT -HMAC::update(const uint8_t *m, uint32_t ml) +HMAC::Update(const uint8_t *m, uint32_t ml) { - EMSHA_RESULT res; - SHA256& hctx = this->ctx; + EMSHA_RESULT res; + SHA256 &hctx = this->ctx; + EMSHA_CHECK(m != nullptr, EMSHA_NULLPTR); EMSHA_CHECK(HMAC_IPAD == this->hstate, EMSHA_INVALID_STATE); // Write the message to the SHA-256 context. - res = hctx.update(m, ml); + res = hctx.Update(m, ml); if (EMSHA_ROK != res) { this->hstate = HMAC_INVALID; return res; @@ -145,7 +154,7 @@ HMAC::update(const uint8_t *m, uint32_t ml) inline EMSHA_RESULT -HMAC::final_result(uint8_t *d) +HMAC::finalResult(uint8_t *d) { if (nullptr == d) { return EMSHA_NULLPTR; @@ -160,11 +169,11 @@ HMAC::final_result(uint8_t *d) EMSHA_CHECK(HMAC_IPAD == this->hstate, EMSHA_INVALID_STATE); - EMSHA_RESULT res; + EMSHA_RESULT res; // Use the result buffer as an intermediate buffer to store the result // of the inner hash. - res = this->ctx.result(this->buf); + res = this->ctx.Result(this->buf); if (EMSHA_ROK != res) { this->hstate = HMAC_INVALID; return EMSHA_INVALID_STATE; @@ -173,16 +182,16 @@ HMAC::final_result(uint8_t *d) // The SHA-256 context needs to be reset so that it may be // re-used for the outer digest. - this->ctx.reset(); + this->ctx.Reset(); // Set up the k0 ⊕ opad construction, and write it into the // SHA-256 context. - uint8_t key[HMAC_KEY_LENGTH]; + uint8_t key[HMAC_KEY_LENGTH]; for (uint32_t i = 0; i < HMAC_KEY_LENGTH; i++) { key[i] = this->k[i] ^ opad; } - res = this->ctx.update(key, HMAC_KEY_LENGTH); + res = this->ctx.Update(key, HMAC_KEY_LENGTH); if (EMSHA_ROK != res) { this->hstate = HMAC_INVALID; return res; @@ -193,14 +202,14 @@ HMAC::final_result(uint8_t *d) std::fill(key, key + HMAC_KEY_LENGTH, 0); // 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) { this->hstate = HMAC_INVALID; return res; } // Write the outer hash result into the working buffer. - res = this->ctx.finalize(this->buf); + res = this->ctx.Finalise(this->buf); if (EMSHA_ROK != res) { this->hstate = HMAC_INVALID; return res; @@ -214,32 +223,39 @@ HMAC::final_result(uint8_t *d) EMSHA_RESULT -HMAC::finalize(uint8_t *d) +HMAC::Finalise(uint8_t *d) { - return this->final_result(d); + return this->finalResult(d); } EMSHA_RESULT -HMAC::result(uint8_t *d) +HMAC::Result(uint8_t *d) { - return this->final_result(d); + return this->finalResult(d); +} + + +std::uint32_t +HMAC::Size() +{ + return SHA256_HASH_SIZE; } EMSHA_RESULT -compute_hmac(const uint8_t *k, uint32_t kl, const uint8_t *m, uint32_t ml, - uint8_t *d) +ComputeHMAC(const uint8_t *k, uint32_t kl, const uint8_t *m, uint32_t ml, + uint8_t *d) { - EMSHA_RESULT res; - HMAC h(k, kl); + EMSHA_RESULT res; + HMAC h(k, kl); - res = h.update(m, ml); + res = h.Update(m, ml); if (EMSHA_ROK != res) { return res; } - res = h.result(d); + res = h.Result(d); if (EMSHA_ROK != res) { return res; } @@ -249,3 +265,4 @@ compute_hmac(const uint8_t *k, uint32_t kl, const uint8_t *m, uint32_t ml, } // end of namespace emsha + diff --git a/scripts/check-code.sh b/scripts/check-code.sh new file mode 100755 index 0000000..c0359d8 --- /dev/null +++ b/scripts/check-code.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env sh + +###################################################################### +# @author : kyle (kyle@midgard) +# @file : check-code +# @created : Tuesday Oct 17, 2023 22:39:39 PDT +# +# @description : +###################################################################### + + +run_clang_tidy () { + sources="${1:-*.cc}" + echo "[+] clang-tidy ${sources}" + + if [ ! -e compile_commands.json ] + then + echo "[!] compile_commands.json not found" > /dev/stderr + candidate=$(find -name compile_commands.json | head) + + if [ -z "${candidates}" ] + then + echo "[!] no suitable candidates found; can't proceed" > /dev/stderr + exit 1 + fi + + echo "[+] compile_commands.json candidate: $candidate" + ln -s ${candidate} . + echo "[+] if this isn't correct, you will need to manually link it" + fi + + clang-tidy ${sources} +} + + +run_cppcheck () { + sources="${1:-*.cc}" + echo "[+] cppcheck ${sources}" + + cppcheck --enable=all --suppress=unusedFunction --suppress=missingIncludeSystem -I. ${sources} +} + + +run_trunk () { + sources="${1:-}" + echo "[+] trunk check ${sources}" + + trunk check --filter clang-tidy ${sources} +} + + +main () { + command="${1:-usage}" + shift + + case ${command} in + clang-tidy) run_clang_tidy $@ ;; + cppcheck) run_cppcheck $@ ;; + trunk) run_trunk $@ ;; + *) + echo "[!] scanner ${command} isn't supported" > /dev/stderr + exit 1 + ;; + esac +} + +main $@ + diff --git a/scripts/install-cmake-debian.sh b/scripts/install-cmake-debian.sh new file mode 100755 index 0000000..1b4bd5c --- /dev/null +++ b/scripts/install-cmake-debian.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +set -eu + + +source /etc/lsb-release + +preinstall () { + echo "[+] preparing to install" + sudo apt-get update + sudo apt-get install ca-certificates gpg wget +} + +do_install () { + if [ ! -f /etc/apt/sources.list.d/kitware.list ] + then + echo "[+] fetching initial keyring" + wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null + + echo "[+] adding repo to sources.list.d" + echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ ${DISTRIB_CODENAME} main" | \ + sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null + sudo apt-get update + + echo "[+] installing kitware keyring" + if [ -f "/usr/share/keyrings/kitware-archive-keyring.gpg" ] + then + sudo rm /usr/share/keyrings/kitware-archive-keyring.gpg + fi + sudo apt-get install kitware-archive-keyring + fi + + if [ "${USE_CMAKE_RC}" = "YES" ] + then + echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ ${DISTRIB_RELEASE}-rc main' | \ + sudo tee -a /etc/apt/sources.list.d/kitware.list >/dev/null + sudo apt-get update + fi +} + +do_install +sudo apt-get install cmake diff --git a/scripts/install-depdendencies.sh b/scripts/install-depdendencies.sh new file mode 100755 index 0000000..3aa7684 --- /dev/null +++ b/scripts/install-depdendencies.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash + +##################################################################### +# This script attempts to install the appopriate build dependencies # +# for the host system. # +# # +# This is primarily developed on the latest Ubuntu LTS release and # +# MacOS; other platforms are not supported. # +##################################################################### + +set -eu + +AUTOMATED_MODE=${AUTOMATED_MODE:-} + +install_debianesque () { + APTARGS="" + + if [ ! -z "${AUTOMATED_MODE}" ] + then + APTARGS="-y" + fi + + echo "[+] distribution is ${DISTRIB_ID}, choosing Debianesque install." + + if [ -z "$(command -v cmake)" ] + then + ./scripts/install-cmake-debian.sh + + echo "[+] installing tools" + sudo apt-get $APTARGS install git cmake clang scdoc python3-pip + + ( cd docs/ && python3 -m pip install -r requirements.txt ) +} + +install_unsupported () { + echo "[+] distribution is ${DISTRIB_ID}, choosing Redhat install." + echo "[!] This distribution is unsupported." > /dev/stderr + exit 1; +} + +install_macos () { + # TODO: consider supporting macports? + echo "[+] host system is MacOS" + + echo "[+] installing tools" + brew install git cmake scdoc + + echo "[+] installing libraries and development headers" + # TODO: look up proper package names in homebrew +} + + +install_linux () { + echo "[+] host system is Linux" + [[ -f "/etc/lsb-release" ]] && source /etc/lsb-release + if [ -z "${DISTRIB_ID}" ] + then + if [ -d /etc/apt ] + then + DISTRIB_ID="apt-based" + else + DISTRIB_ID="unsupported/unknown" + fi + fi + + case ${DISTRIB_ID} in + Ubuntu) install_debianesque ;; + Debian) install_debianesque ;; + apt-based) install_debianesque ;; + *) + echo "[!] distribution ${DISTRIB_ID} isn't supported in this script." > /dev/null + ;; + esac +} + + +case "$(uname -s)" in + Linux) install_linux ;; + Darwin) install_macos ;; + *) + echo "[!] platform $(uname -s) isn't supported in this script." > /dev/null + ;; +esac + + diff --git a/sha256.cc b/sha256.cc new file mode 100644 index 0000000..5612dab --- /dev/null +++ b/sha256.cc @@ -0,0 +1,493 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 K. Isom + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#include +#include +#include + +#include +#include +#include +#include +#include + + +namespace emsha { + + +/* + * SHA-256 constants, from FIPS 180-4 page 11. + */ +static constexpr uint32_t sha256K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + + +/* + * SHA-256 initialisation vector, from FIPS 180-4 page 15. + */ +static constexpr uint32_t emsha256H0[] = { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 +}; + + +EMSHA_RESULT +sha256Digest(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.Finalise(d); +} + + +SHA256::SHA256() + : mlen(), hStatus(), hComplete(), mbi() +{ + this->reset(); +} + + +SHA256::~SHA256() +{ + memset(this->mb, 0, SHA256_MB_SIZE); +} + + +EMSHA_RESULT +SHA256::addLength(const uint32_t l) +{ + uint32_t tmp = this->mlen + l; + + if (tmp < this->mlen) { + return SHA256_INPUT_TOO_LONG; + } + + this->mlen = tmp; + assert(this->mlen > 0); + + return EMSHA_ROK; +} + + +EMSHA_RESULT +SHA256::Reset() +{ + return this->reset(); +} + +EMSHA_RESULT +SHA256::reset() +{ + // The message block is set to the initial hash vector. + this->i_hash[0] = emsha256H0[0]; + this->i_hash[1] = emsha256H0[1]; + this->i_hash[2] = emsha256H0[2]; + this->i_hash[3] = emsha256H0[3]; + this->i_hash[4] = emsha256H0[4]; + this->i_hash[5] = emsha256H0[5]; + this->i_hash[6] = emsha256H0[6]; + this->i_hash[7] = emsha256H0[7]; + + this->mbi = 0; + this->hStatus = EMSHA_ROK; + this->hComplete = 0; + this->mlen = 0; + memset(this->mb, 0, SHA256_MB_SIZE); + + return this->hStatus; +} + + +// Read 32 bits from the byte buffer chunk as an unsigned 32-bit integer. +static uint32_t +chunkToUint32(const uint8_t *chunk) +{ + return ((*chunk) << 24) | + ((*(chunk + 1)) << 16) | + ((*(chunk + 2)) << 8) | + (*(chunk + 3)); +} + + +// Copy an unsigned 32-bit integer into the start of the byte buffer chunk. +static void +uint32ToChunk(uint32_t x, uint8_t *chunk) +{ + chunk[0] = (x & 0xff000000) >> 24; + chunk[1] = (x & 0x00ff0000) >> 16; + chunk[2] = (x & 0x0000ff00) >> 8; + chunk[3] = (x & 0x000000ff); +} + + +// FIPS 180-4, page 22. +void +SHA256::updateMessageBlock() +{ + uint32_t w[64]; + uint32_t i = 0; + uint32_t chunk = 0; + uint32_t a = 0; + uint32_t b = 0; + uint32_t c = 0; + uint32_t d = 0; + uint32_t e = 0; + uint32_t f = 0; + uint32_t g = 0; + uint32_t h = 0; + + while (i < 16) { + w[i++] = chunkToUint32(this->mb + chunk); + chunk += 4; + } + this->mbi = 0; + + for (i = 16; i < 64; i++) { + w[i] = sha_sigma1(w[i - 2]) + w[i - 7] + + sha_sigma0(w[i - 15]) + w[i - 16]; + } + + a = this->i_hash[0]; + b = this->i_hash[1]; + c = this->i_hash[2]; + d = this->i_hash[3]; + e = this->i_hash[4]; + f = this->i_hash[5]; + g = this->i_hash[6]; + h = this->i_hash[7]; + + for (i = 0; i < 64; i++) { + uint32_t t1 = 0; + uint32_t t2 = 0; + t1 = h + sha_Sigma1(e) + sha_ch(e, f, g) + sha256K[i] + w[i]; + t2 = sha_Sigma0(a) + sha_maj(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + this->i_hash[0] += a; + this->i_hash[1] += b; + this->i_hash[2] += c; + this->i_hash[3] += d; + this->i_hash[4] += e; + this->i_hash[5] += f; + this->i_hash[6] += g; + this->i_hash[7] += h; +} + + +EMSHA_RESULT +SHA256::Update(const uint8_t *m, uint32_t ml) +{ + // Checking invariants: + // If the message length is zero, there's nothing to be done. + if (0 == ml) { return EMSHA_ROK; } + + // The message passed in cannot be the null pointer if the + // message length is greater than 0. + if (nullptr == m) { return EMSHA_NULLPTR; } + + // If the SHA256 object is in a bad state, don't proceed. + if (EMSHA_ROK != this->hStatus) { return this->hStatus; } + + // If the hash has been finalised, don't proceed. + if (0 != this->hComplete) { return EMSHA_INVALID_STATE; } + // Invariants satisfied by here. + + for (uint32_t i = 0; i < ml; i++) { + this->mb[this->mbi] = *(m + i); + mbi++; + + if (EMSHA_ROK == this->addLength(8)) { + if (SHA256_MB_SIZE == this->mbi) { + this->updateMessageBlock(); + + // Assumption: following the message block + // write, the context should still be in a good + // state. + assert(EMSHA_ROK == this->hStatus); + } + } + } + + return this->hStatus; +} + + +inline void +SHA256::padMessage(uint8_t pc) +{ + // Assumption: the context is not in a corrupted state. + assert(EMSHA_ROK == this->hStatus); + + if (this->mbi < (SHA256_MB_SIZE - 8)) { + this->mb[this->mbi++] = pc; + } else { + bool pc_add = false; + + if (this->mbi < SHA256_MB_SIZE - 1) { + this->mb[this->mbi++] = pc; + pc_add = true; + } + + while (this->mbi < SHA256_MB_SIZE) { + this->mb[this->mbi++] = 0; + } + + this->updateMessageBlock(); + if (!pc_add) { + this->mb[this->mbi++] = pc; + } + + // Assumption: updating the message block has not left the + // context in a corrupted state. + assert(EMSHA_ROK == this->hStatus); + } + + while (this->mbi < (SHA256_MB_SIZE - 8)) { + this->mb[this->mbi++] = 0; + } + + // lstart marks the starting point for the length packing. + uint32_t const lstart = SHA256_MB_SIZE - 8; + + this->mb[lstart] = static_cast(this->mlen >> 56); + this->mb[lstart + 1] = + static_cast((this->mlen & 0x00ff000000000000L) >> 48); + this->mb[lstart + 2] = + static_cast((this->mlen & 0x0000ff0000000000L) >> 40); + this->mb[lstart + 3] = + static_cast((this->mlen & 0x000000ff00000000L) >> 32); + this->mb[lstart + 4] = + static_cast((this->mlen & 0x00000000ff000000L) >> 24); + this->mb[lstart + 5] = + static_cast((this->mlen & 0x0000000000ff0000L) >> 16); + this->mb[lstart + 6] = + static_cast((this->mlen & 0x000000000000ff00L) >> 8); + this->mb[lstart + 7] = + static_cast(this->mlen & 0x00000000000000ffL); + + this->updateMessageBlock(); + + // Assumption: updating the message block has not left the context in a + // corrupted state. + assert(EMSHA_ROK == this->hStatus); +} + + +EMSHA_RESULT +SHA256::Finalise(uint8_t *d) +{ + // Check invariants. + // The digest cannot be a null pointer; this library allocates + // no memory of its own. + if (nullptr == d) { return EMSHA_NULLPTR; } + + // If the SHA256 object is in a bad state, don't proceed. + if (EMSHA_ROK != this->hStatus) { return this->hStatus; } + + // If the hash has been finalised, don't proceed. + if (0 != this->hComplete) { return EMSHA_INVALID_STATE; } + // Invariants satisfied by here. + + this->padMessage(0x80); + + // Assumption: padding the message block has not left the context in a + // corrupted state. + assert(EMSHA_ROK == this->hStatus); + std::fill(this->mb, this->mb + SHA256_MB_SIZE, 0); + + this->hComplete = 1; + this->mlen = 0; + + uint32ToChunk(this->i_hash[0], d); + uint32ToChunk(this->i_hash[1], d + 4); + uint32ToChunk(this->i_hash[2], d + 8); + uint32ToChunk(this->i_hash[3], d + 12); + uint32ToChunk(this->i_hash[4], d + 16); + uint32ToChunk(this->i_hash[5], d + 20); + uint32ToChunk(this->i_hash[6], d + 24); + uint32ToChunk(this->i_hash[7], d + 28); + + return EMSHA_ROK; +} + + +EMSHA_RESULT +SHA256::Result(uint8_t *d) +{ + // Check invariants. + + // The digest cannot be a null pointer; this library allocates + // no memory of its own. + if (nullptr == d) { return EMSHA_NULLPTR; } + + // If the SHA256 object is in a bad state, don't proceed. + if (EMSHA_ROK != this->hStatus) { return this->hStatus; } + + // Invariants satisfied by here. + + if (this->hComplete == 0U) { + return this->Finalise(d); + } + + uint32ToChunk(this->i_hash[0], d); + uint32ToChunk(this->i_hash[1], d + 4); + uint32ToChunk(this->i_hash[2], d + 8); + uint32ToChunk(this->i_hash[3], d + 12); + uint32ToChunk(this->i_hash[4], d + 16); + uint32ToChunk(this->i_hash[5], d + 20); + uint32ToChunk(this->i_hash[6], d + 24); + uint32ToChunk(this->i_hash[7], d + 28); + + return EMSHA_ROK; +} + + +std::uint32_t +SHA256::Size() +{ + return SHA256_HASH_SIZE; +} + + +#ifndef EMSHA_NO_SELFTEST +static const uint8_t emptyVector[] = { + 0xe3, 0xb0, 0xc4, 0x42, + 0x98, 0xfc, 0x1c, 0x14, + 0x9a, 0xfb, 0xf4, 0xc8, + 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, + 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, + 0x78, 0x52, 0xb8, 0x55 +}; + + +static const uint8_t helloWorld[] = { + 0x09, 0xca, 0x7e, 0x4e, + 0xaa, 0x6e, 0x8a, 0xe9, + 0xc7, 0xd2, 0x61, 0x16, + 0x71, 0x29, 0x18, 0x48, + 0x83, 0x64, 0x4d, 0x07, + 0xdf, 0xba, 0x7c, 0xbf, + 0xbc, 0x4c, 0x8a, 0x2e, + 0x08, 0x36, 0x0d, 0x5b, +}; + +constexpr uint32_t EMSHA_SELF_TEST_ITERS = 4; + +static EMSHA_RESULT +runTest(const uint8_t *input, uint32_t input_len, const uint8_t *expected) +{ + uint8_t hexString[65]{0}; + uint8_t d[SHA256_HASH_SIZE]{0}; + emsha::SHA256 ctx; + emsha::EMSHA_RESULT res; + + res = ctx.Update(input, input_len); + if (EMSHA_ROK != res) { + return res; + } + + for (uint32_t n = 0; n < EMSHA_SELF_TEST_ITERS; n++) { + res = ctx.Result(d); + if (EMSHA_ROK != res) { + return res; + } + + for (uint32_t i = 0; i < SHA256_HASH_SIZE; i++) { + if (expected[i] != d[i]) { + HexString(hexString, const_cast(d), 32); + std::cerr << "[!] have: " << hexString << "\n"; + HexString(hexString, const_cast(helloWorld), 32); + std::cerr << "[!] want: " << hexString << "\n"; + return EMSHA_TEST_FAILURE; + } + } + } + + return EMSHA_ROK; +} + + +EMSHA_RESULT +sha256SelfTest() +{ + EMSHA_RESULT res; + + res = runTest(reinterpret_cast(""), 0, emptyVector); + if (EMSHA_ROK == res) { + res = runTest(reinterpret_cast("hello, world"), 12, helloWorld); + if (res != EMSHA_ROK) { + std::cerr << "[!] failed on hello, world.\n"; + } + } else { + std::cerr << "[!] failed on empty vector\n"; + } + + return res; +} + + +#else // #ifdef EMSHA_NO_SELFTEST +EMSHA_RESULT +sha256_self_test() +{ + return EMSHA_SELFTEST_DISABLED; +} + + +#endif // EMSHA_NO_SELFTEST + + +} // end namespace emsha diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 0e87322..0000000 --- a/src/Makefile.am +++ /dev/null @@ -1,85 +0,0 @@ -AM_CPPFLAGS = -Wall -Wextra -pedantic -Wshadow -Wpointer-arith -Wcast-align -AM_CPPFLAGS += -Wwrite-strings -Wmissing-declarations -Wno-long-long -Werror -AM_CPPFLAGS += -Wunused-variable -std=c++11 -D_XOPEN_SOURCE -Os -I. -AM_CPPFLAGS += -fno-elide-constructors -Weffc++ -TEST_UTILS = test_utils.hh test_utils.cc -CLOC_PSOURCES = emsha.cc sha256.cc hmac.cc internal.hh \ - emsha/emsha.hh emsha/hmac.hh emsha/sha256.hh -CLOC_TSOURCES = test_emsha.cc test_hmac.cc test_mem.cc test_sha256.cc \ - test_utils.cc test_utils.hh -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libemsha-1.pc - -lib_LTLIBRARIES = libemsha.la -nobase_include_HEADERS = emsha/sha256.hh emsha/hmac.hh emsha/emsha.hh -libemsha_la_SOURCES = emsha.cc sha256.cc hmac.cc internal.hh -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_hmac_test -check_CPPFLAGS = $(AM_CPPFLAGS) -Wnoinline - -# emsha_sha256_test runs through some SHA-256 test vectors, ensuring -# that the library's behaviour is correct. -emsha_sha256_test_SOURCES = test_sha256.cc $(TEST_UTILS) -emsha_sha256_test_LDADD = libemsha.la - -# emsha_hmac_test runs through a set of HMAC-SHA-256 test vectors, -# ensuring that the library's behaviour is correct. -emsha_hmac_test_SOURCES = test_hmac.cc $(TEST_UTILS) -emsha_hmac_test_LDADD = libemsha.la - -# emsha_core_test validates some of the additional functions provided -# by the emsha library. -emsha_core_test_SOURCES = test_emsha.cc $(TEST_UTILS) -emsha_core_test_LDADD = libemsha.la - -# emsha_mem_test is used for testing with valgrind; it aims to introduce -# no heap allocations via the test harness so that memory usage inside -# the library may be more accurately checked. -emsha_mem_test_SOURCES = test_mem.cc $(TEST_UTILS) -emsha_mem_test_LDADD = libemsha.la - -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_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_static_mem_test ms_print - -.PHONY: cloc-report -cloc-report: - @echo "=== Library Sources ===" - @cloc $(CLOC_PSOURCES) - @echo - @echo "=== Test Sources ===" - @cloc $(CLOC_TSOURCES) - -.PHONY: coverity-scan -coverity-scan: clean - cov-build --dir cov-int make all check - tar czf $(PACKAGE_NAME)-$(PACKAGE_VERSION)_coverity.tar.gz cov-int - rm -rf cov-int - -.PHONY: scanners clang-scanner cppcheck-scanner -scanners: clang-scanner cppcheck-scanner -clang-scanner: - clang++ $(AM_CPPFLAGS) --analyze $(CLOC_PSOURCES) - -cppcheck-scanner: - cppcheck --quiet --enable=all -I ./ $(CLOC_PSOURCES) - - diff --git a/src/emsha/emsha.hh b/src/emsha/emsha.hh deleted file mode 100644 index aaa57c3..0000000 --- a/src/emsha/emsha.hh +++ /dev/null @@ -1,169 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 K. Isom - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - - -#ifndef __EMSHA_EMSHA_HH -#define __EMSHA_EMSHA_HH - - -#include - - -namespace emsha { - - -// EMSHA_CHECK is used for sanity checks in certain parts of the code. -#ifdef NDEBUG - // If asserts are turned off, expand the check to an if - // statement that will return with retval if the condition - // isn't met. - #define EMSHA_CHECK(condition, retval) if (!(condition)) { return (retval); } -#else - // If asserts are turned on, the check is expanded to an - // assertion that the condition holds. In this case, retval is - // not used. - #define EMSHA_CHECK(condition, retval) (assert((condition))) -#endif - - - // SHA256_HASH_SIZE is the output length of SHA-256 in bytes. - const std::uint32_t SHA256_HASH_SIZE = 32; - - - // The EMSHA_RESULT type is used to indicate whether an - // operation succeeded, and if not, what the general fault type - // was. - typedef enum _EMSHA_RESULT_: std::uint8_t { - // All operations have completed successfully so far. - EMSHA_ROK = 0, - - // 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 - } EMSHA_RESULT; - - - // A Hash is generalised superclass supporting concrete classes - // that produce digests of data. - class Hash { - public: - virtual ~Hash() =0; - - // reset should bring the Hash back into its initial - // state. That is, the idea is that - // - // hash->reset(); hash->update(...)...; - // hash->result(...); - // - // is idempotent, assuming the inputs to update and - // result are constant. The implications of 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. - virtual EMSHA_RESULT reset(void) =0; - - // update is used to write message data into the Hash. - virtual EMSHA_RESULT update(const std::uint8_t *m, - std::uint32_t ml) =0; - - // 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. - virtual EMSHA_RESULT finalize(std::uint8_t *d) =0; - - // 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. - virtual EMSHA_RESULT result(std::uint8_t *d) =0; - - // size should return the output size of the Hash; this - // is, how large the buffers written to by result should - // be. - virtual std::uint32_t size(void) =0; - }; - - // hash_equal provides a constant time function for comparing two - // hashes. The caller *must* ensure that both a and b are the same - // size. The recommended approach is to use fixed-size buffers of - // emsha::SHA256_HASH_SIZE length: - // - // uint8_t expected[emsha::SHA256_HASH_SIZE]; - // uint8_t actual[emsha::SHA256_HASH_SIZE]; - // - // // Fill in expected and actual using the Hash operations. - // - // if (hash_equal(expected, actual)) { - // proceed(); - // } - // - // Inputs: - // a, b: byte arrays that MUST contain at least - // emsha::SHA256_HASH_SIZE bytes. Only the first - // emsha::SHA256_HASH_SIZE bytes will be compared. - // - // Outputs: - // true iff both byte arrays match - // - // false if the arrays do not match - // - bool hash_equal(const std::uint8_t *a, const std::uint8_t *b); - -#ifndef EMSHA_NO_HEXSTRING - // hexstring writes a hex-encoded version of the src byte - // array into dest. The caller *must* ensure that dest is - // srclen * 2 bytes or longer. - // - // 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 - - -#endif // __EMSHA_EMSHA_HH diff --git a/src/emsha/hmac.hh b/src/emsha/hmac.hh deleted file mode 100644 index 9e68236..0000000 --- a/src/emsha/hmac.hh +++ /dev/null @@ -1,197 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 K. Isom - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - - -#ifndef __EMSHA_HMAC_HH -#define __EMSHA_HMAC_HH - - -#include - -#include -#include - - -namespace emsha { - - const uint32_t HMAC_KEY_LENGTH = SHA256_MB_SIZE; - - // HMAC is a keyed hash that can be used to produce an - // authenticated hash of some data. The HMAC is built on (and - // uses internally) the SHA-256 class; it's helpful to note that - // faults that occur in the SHA-256 code will be propagated up - // as the return value from many of the HMAC functions. - class HMAC : Hash { - public: - // An HMAC is constructed with a key and the - // length of the key. This key is stored in - // the HMAC context, and is wiped by the HMAC - // destructor. - // - // Inputs: - // k: the HMAC key. - // kl: the length of the HMAC key. - // - HMAC(const uint8_t *k, uint32_t kl); - - // reset clears any data written to the HMAC; - // this is equivalent to constructing a new HMAC, - // but it preserves the keys. - // - // Outputs: - // EMSHA_ROK is returned if the reset occurred - // without (detected) fault. - // - // If a fault occurs with the underlying SHA-256 - // context, the error code is returned. - // - EMSHA_RESULT reset(void); - - // update writes data into the context. While there is - // an upper limit on the size of data that the - // underlying hash can operate on, this package is - // designed for small systems that will not approach - // that level of data (which is on the order of 2 - // exabytes), so it is not thought to be a concern. - // - // Inputs: - // m: a byte array containing the message to be - // written. It must not be NULL (unless the message - // length is zero). - // - // ml: the message length, in bytes. - // - // Outputs: - // EMSHA_NULLPTR is returned if m is NULL and ml is - // nonzero. - // - // EMSHA_INVALID_STATE is returned if the update - // is called after a call to finalize. - // - // SHA256_INPUT_TOO_LONG is returned if too much - // data has been written to the context. - // - // EMSHA_ROK is returned if the data was - // successfully written into the HMAC context. - // - EMSHA_RESULT update(const uint8_t *, uint32_t); - - // finalize completes the HMAC computation. Once this - // method is called, the context cannot be updated - // unless the context is reset. - // - // Inputs: - // d: a byte buffer that must be at least - // HMAC.size() in length. - // - // Outputs: - // EMSHA_NULLPTR is returned if d is the null - // pointer. - // - // EMSHA_INVALID_STATE is returned if the HMAC - // context is in an invalid state, such as if there - // were errors in previous updates. - // - // EMSHA_ROK is returned if the context was - // successfully finalised and the digest copied to - // d. - // - EMSHA_RESULT finalize(uint8_t *); - - // result copies the result from the HMAC context into - // the buffer pointed to by d, running finalize if - // needed. Once called, the context cannot be updated - // until the context is reset. - // - // Inputs: - // d: a byte buffer that must be at least - // HMAC.size() in length. - // - // Outputs: - // EMSHA_NULLPTR is returned if d is the null - // pointer. - // - // EMSHA_INVALID_STATE is returned if the HMAC - // context is in an invalid state, such as if there - // were errors in previous updates. - // - // EMSHA_ROK is returned if the context was - // successfully finalised and the digest copied to - // d. - // - EMSHA_RESULT result(uint8_t *); - - - // size returns the output size of HMAC-SHA-256, e.g. - // the size that the buffers passed to finalize and - // result should be. - // - // Outputs: - // A uint32_t representing the expected size - // of buffers passed to result and finalize. - uint32_t size(void) { return SHA256_HASH_SIZE; } - - // When an HMAC context is destroyed, it is reset and - // the key material is zeroised using the STL fill - // function. - ~HMAC(void); - private: - uint8_t hstate; - SHA256 ctx; - uint8_t k[HMAC_KEY_LENGTH]; - uint8_t buf[SHA256_HASH_SIZE]; - - inline EMSHA_RESULT - final_result(uint8_t *); - }; - - // compute_hmac performs a single-pass HMAC computation over - // a message. - // - // Inputs: - // k: a byte buffer containing the HMAC key. - // - // kl: the length of the HMAC key. - // - // m: the message data over which the HMAC is to be computed. - // - // ml: the length of the message. - // - // d: a byte buffer that will be used to store the resulting - // HMAC. It should be SHA256_HASH_SIZE bytes in size. - // - // Outputs: - // This function handles setting up the HMAC context with - // the given key, calling update with the message data, and - // then calling finalize to place the result in the output - // buffer. Any of the faults that can occur in these functions - // can be returned here, or EMSHA_ROK if the HMAC was - // successfully computed. - EMSHA_RESULT compute_hmac(const uint8_t *k, uint32_t kl, - const uint8_t *m, uint32_t ml, - uint8_t *d); -} // end of namespace emsha - - -#endif // __EMSHA_HMAC_HH diff --git a/src/emsha/sha256.hh b/src/emsha/sha256.hh deleted file mode 100644 index e5b668e..0000000 --- a/src/emsha/sha256.hh +++ /dev/null @@ -1,211 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 K. Isom - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - - -#ifndef __EMSHA_SHA256_HH -#define __EMSHA_SHA256_HH - - -#include - -#include - - -namespace emsha { - - - // SHA256_MB_SIZE is the size of a message block. - const uint32_t SHA256_MB_SIZE = 64; - - class SHA256 : Hash { - public: - // A SHA256 context does not need any special - // construction. It can be declared and - // immediately start being used. - 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. - ~SHA256(); - - // reset clears the internal state of the SHA256 - // context and returns it to its initial state. - // It should always return EMSHA_ROK. - EMSHA_RESULT reset(void); - - // update writes data into the context. While - // there is an upper limit on the size of data - // that SHA-256 can operate on, this package is - // designed for small systems that will not - // approach that level of data (which is on the - // order of 2 exabytes), so it is not thought - // to be a concern. - // - // Inputs: - // m: a byte array containing the message to - // be written. It must not be NULL (unless - // the message length is zero). - // - // ml: the message length, in bytes. - // - // Outputs: - // EMSHA_NULLPTR is returned if m is NULL - // and ml is nonzero. - // - // EMSHA_INVALID_STATE is returned if the - // update is called after a call to - // finalize. - // - // SHA256_INPUT_TOO_LONG is returned if too - // much data has been written to the - // context. - // - // EMSHA_ROK is returned if the data was - // successfully added to the SHA-256 - // context. - // - EMSHA_RESULT update(const uint8_t *m, uint32_t ml); - - // 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. - // - EMSHA_RESULT finalize(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. - // - EMSHA_RESULT result(uint8_t *d); - - // 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. - uint32_t size(void) { return SHA256_HASH_SIZE; } - private: - // mlen stores the current message length. - uint64_t mlen; - - // The intermediate hash is 8x 32-bit blocks. - uint32_t i_hash[8]; - - // hstatus is the hash status, and hcomplete indicates - // whether the hash has been finalised. - EMSHA_RESULT hstatus; - uint8_t hcomplete; - - // mb is the message block, and mbi is the message - // block index. - uint8_t mbi; - uint8_t mb[SHA256_MB_SIZE]; - - inline EMSHA_RESULT add_length(uint32_t); - inline void update_message_block(void); - inline void pad_message(uint8_t); - }; // end class SHA256 - - // sha256_digest 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 sha256_digest(const uint8_t *m, uint32_t ml, uint8_t *d); - - // sha256_self_test runs through two test cases to ensure that the - // SHA-256 functions are working correctly. - // - // Outputs: - // EMSHA_ROK is returned if the self tests pass. - // - // EMSHA_SELFTEST_DISABLED is returned if the self tests - // have been disabled (e.g., libemsha was compiled with the - // EMSHA_NO_SELFTEST #define). - // - // If a fault occurred inside the SHA-256 code, the error - // code from one of the update, finalize, result, or reset - // methods is returned. - // - // If the fault is that the output does not match the test - // vector, EMSHA_TEST_FAILURE is returned. - // - EMSHA_RESULT sha256_self_test(void); -} // end of namespace emsha - - -#endif // __EMSHA_SHA256_HH diff --git a/src/internal.hh b/src/internal.hh deleted file mode 100644 index 9709695..0000000 --- a/src/internal.hh +++ /dev/null @@ -1,92 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 K. Isom - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - - -#ifndef __EMSHA_INTERNAL_HH -#define __EMSHA_INTERNAL_HH - - -#include - -using std::uint8_t; -using std::uint32_t; - - -namespace emsha { - - -static inline uint32_t -rotr32(uint32_t x, uint8_t n) -{ - return ((x >> n) | (x << (32 - n))); -} - - -static inline uint32_t -sha_ch(uint32_t x, uint32_t y, uint32_t z) -{ - return ((x & y) ^ ((~x) & z)); -} - - -static inline uint32_t -sha_maj(uint32_t x, uint32_t y, uint32_t z) -{ - return (x & y) ^ (x & z) ^ (y & z); -} - - -static inline uint32_t -sha_Sigma0(uint32_t x) -{ - return rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22); -} - - -static inline uint32_t -sha_Sigma1(uint32_t x) -{ - return rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25); -} - - -static inline uint32_t -sha_sigma0(uint32_t x) -{ - return rotr32(x, 7) ^ rotr32(x, 18) ^ (x >> 3); -} - - -static inline uint32_t -sha_sigma1(uint32_t x) -{ - return rotr32(x, 17) ^ rotr32(x, 19) ^ (x >> 10); -} - - - -} // end of namespace emsha - - -#endif // __EMSHA_INTERNAL_HH diff --git a/src/libemsha-1.pc.in b/src/libemsha-1.pc.in deleted file mode 100644 index a713c3e..0000000 --- a/src/libemsha-1.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: @PACKAGE_NAME@ -Description: C++11 HMAC-SHA256 library -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -Wl,-rpath,${libdir} -lemsha diff --git a/src/sha256.cc b/src/sha256.cc deleted file mode 100644 index 8674dc7..0000000 --- a/src/sha256.cc +++ /dev/null @@ -1,459 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 K. Isom - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - - -#include -#include -#include - -#include -#include -#include "internal.hh" - - -namespace emsha { - - -/* - * SHA-256 constants, from FIPS 180-4 page 11. - */ -static constexpr uint32_t SHA256_K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - - -/* - * SHA-256 initialisation vector, from FIPS 180-4 page 15. - */ -static constexpr uint32_t EMSHA_256_H0[] = { - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, - 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 -}; - - -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); -} - - -SHA256::SHA256() - :mlen(), hstatus(), hcomplete(), mbi() -{ - this->reset(); -} - - -SHA256::~SHA256() -{ - memset(this->mb, 0, SHA256_MB_SIZE); -} - - -inline EMSHA_RESULT -SHA256::add_length(uint32_t l) -{ - uint32_t tmp = this->mlen + l; - - if (tmp < this->mlen) { - return SHA256_INPUT_TOO_LONG; - } - this->mlen = tmp; - assert(this->mlen > 0); - - return EMSHA_ROK; -} - - -EMSHA_RESULT -SHA256::reset() -{ - // The message block is set to the initial hash vector. - this->i_hash[0] = EMSHA_256_H0[0]; - this->i_hash[1] = EMSHA_256_H0[1]; - this->i_hash[2] = EMSHA_256_H0[2]; - this->i_hash[3] = EMSHA_256_H0[3]; - this->i_hash[4] = EMSHA_256_H0[4]; - this->i_hash[5] = EMSHA_256_H0[5]; - this->i_hash[6] = EMSHA_256_H0[6]; - this->i_hash[7] = EMSHA_256_H0[7]; - - this->mbi = 0; - this->hstatus = EMSHA_ROK; - this->hcomplete = 0; - this->mlen = 0; - memset(this->mb, 0, SHA256_MB_SIZE); - - return this->hstatus; -} - - -// Read 32 bits from the byte buffer chunk as an unsigned 32-bit integer. -static inline uint32_t -chunk_to_uint32(uint8_t *chunk) -{ - return ((*chunk) << 24) | - ((*(chunk + 1)) << 16) | - ((*(chunk + 2)) << 8) | - (*(chunk + 3)); -} - - -// Copy an unsigned 32-bit integer into the start of the byte buffer chunk. -static inline void -uint32_to_chunk(uint32_t x, uint8_t *chunk) -{ - chunk[0] = (x & 0xff000000) >> 24; - chunk[1] = (x & 0x00ff0000) >> 16; - chunk[2] = (x & 0x0000ff00) >> 8; - chunk[3] = (x & 0x000000ff); -} - - -// FIPS 180-4, page 22. -void -SHA256::update_message_block() -{ - uint32_t w[64]; - uint32_t i = 0; - uint32_t chunk = 0; - uint32_t a, b, c, d, e, f, g, h; - - while (i < 16) { - w[i++] = chunk_to_uint32(this->mb + chunk); - chunk += 4; - } - this->mbi = 0; - - for (i = 16; i < 64; i++) { - w[i] = sha_sigma1(w[i - 2]) + w[i - 7] + - sha_sigma0(w[i - 15]) + w[i - 16]; - } - - a = this->i_hash[0]; - b = this->i_hash[1]; - c = this->i_hash[2]; - d = this->i_hash[3]; - e = this->i_hash[4]; - f = this->i_hash[5]; - g = this->i_hash[6]; - h = this->i_hash[7]; - - for (i = 0; i < 64; i++) { - uint32_t t1, t2; - t1 = h + sha_Sigma1(e) + sha_ch(e, f, g) + SHA256_K[i] + w[i]; - t2 = sha_Sigma0(a) + sha_maj(a, b, c); - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - - this->i_hash[0] += a; - this->i_hash[1] += b; - this->i_hash[2] += c; - this->i_hash[3] += d; - this->i_hash[4] += e; - this->i_hash[5] += f; - this->i_hash[6] += g; - this->i_hash[7] += h; -} - - -EMSHA_RESULT -SHA256::update(const uint8_t *m, uint32_t ml) -{ - // Checking invariants: - // If the message length is zero, there's nothing to be done. - if (0 == ml) return EMSHA_ROK; - - // The message passed in cannot be the null pointer if the - // message length is greater than 0. - if (nullptr == m) return EMSHA_NULLPTR; - - // If the SHA256 object is in a bad state, don't proceed. - if (EMSHA_ROK != this->hstatus) return this->hstatus; - - // If the hash has been finalised, don't proceed. - if (0 != this->hcomplete) return EMSHA_INVALID_STATE; - // Invariants satisfied by here. - - for (uint32_t i = 0; i < ml; i++) { - this->mb[this->mbi] = *(m + i); - mbi++; - - if (EMSHA_ROK == this->add_length(8)) { - if (SHA256_MB_SIZE == this->mbi) { - this->update_message_block(); - - // Assumption: following the message block - // write, the context should still be in a good - // state. - assert(EMSHA_ROK == this->hstatus); - } - } - } - - return this->hstatus; -} - - -inline void -SHA256::pad_message(uint8_t pc) -{ - // Assumption: the context is not in a corrupted state. - assert(EMSHA_ROK == this->hstatus); - - if (this->mbi < (SHA256_MB_SIZE - 8)) { - this->mb[this->mbi++] = pc; - } else { - bool pc_add = false; - - if (this->mbi < SHA256_MB_SIZE - 1) { - this->mb[this->mbi++] = pc; - pc_add = true; - } - - while (this->mbi < SHA256_MB_SIZE) { - this->mb[this->mbi++] = 0; - } - - this->update_message_block(); - if (!pc_add) { - this->mb[this->mbi++] = pc; - } - - // Assumption: updating the message block has not left the - // context in a corrupted state. - assert(EMSHA_ROK == this->hstatus); - } - - while (this->mbi < (SHA256_MB_SIZE - 8)) { - this->mb[this->mbi++] = 0; - } - - // lstart marks the starting point for the length packing. - uint32_t lstart = SHA256_MB_SIZE - 8; - - this->mb[lstart] = (uint8_t)(this->mlen >> 56); - this->mb[lstart+1] = - (uint8_t)((this->mlen & 0x00ff000000000000L) >> 48); - this->mb[lstart+2] = - (uint8_t)((this->mlen & 0x0000ff0000000000L) >> 40); - this->mb[lstart+3] = - (uint8_t)((this->mlen & 0x000000ff00000000L) >> 32); - this->mb[lstart+4] = - (uint8_t)((this->mlen & 0x00000000ff000000L) >> 24); - this->mb[lstart+5] = - (uint8_t)((this->mlen & 0x0000000000ff0000L) >> 16); - this->mb[lstart+6] = - (uint8_t)((this->mlen & 0x000000000000ff00L) >> 8); - this->mb[lstart+7] = - (uint8_t)(this->mlen & 0x00000000000000ffL); - - this->update_message_block(); - - // Assumption: updating the message block has not left the context in a - // corrupted state. - assert(EMSHA_ROK == this->hstatus); -} - - -EMSHA_RESULT -SHA256::finalize(uint8_t *d) -{ - // Check invariants. - // The digest cannot be a null pointer; this library allocates - // no memory of its own. - if (nullptr == d) return EMSHA_NULLPTR; - - // If the SHA256 object is in a bad state, don't proceed. - if (EMSHA_ROK != this->hstatus) return this->hstatus; - - // If the hash has been finalised, don't proceed. - if (0 != this->hcomplete) return EMSHA_INVALID_STATE; - // Invariants satisfied by here. - - this->pad_message(0x80); - - // Assumption: padding the message block has not left the context in a - // corrupted state. - assert(EMSHA_ROK == this->hstatus); - for (uint8_t i = 0; i < SHA256_MB_SIZE; i++) { - this->mb[i] = 0; - } - - this->hcomplete = 1; - this->mlen = 0; - - uint32_to_chunk(this->i_hash[0], d); - uint32_to_chunk(this->i_hash[1], d+4); - uint32_to_chunk(this->i_hash[2], d+8); - uint32_to_chunk(this->i_hash[3], d+12); - uint32_to_chunk(this->i_hash[4], d+16); - uint32_to_chunk(this->i_hash[5], d+20); - uint32_to_chunk(this->i_hash[6], d+24); - uint32_to_chunk(this->i_hash[7], d+28); - - return EMSHA_ROK; -} - - -EMSHA_RESULT -SHA256::result(uint8_t *d) -{ - // Check invariants. - // The digest cannot be a null pointer; this library allocates - // no memory of its own. - if (nullptr == d) return EMSHA_NULLPTR; - - // If the SHA256 object is in a bad state, don't proceed. - if (EMSHA_ROK != this->hstatus) return this->hstatus; - // Invariants satisfied by here. - - if (!this->hcomplete) { - return this->finalize(d); - } - - uint32_to_chunk(this->i_hash[0], d); - uint32_to_chunk(this->i_hash[1], d+4); - uint32_to_chunk(this->i_hash[2], d+8); - uint32_to_chunk(this->i_hash[3], d+12); - uint32_to_chunk(this->i_hash[4], d+16); - uint32_to_chunk(this->i_hash[5], d+20); - uint32_to_chunk(this->i_hash[6], d+24); - uint32_to_chunk(this->i_hash[7], d+28); - - return EMSHA_ROK; -} - - -#ifndef EMSHA_NO_SELFTEST -static const uint8_t empty_vector[] = { - 0xe3, 0xb0, 0xc4, 0x42, - 0x98, 0xfc, 0x1c, 0x14, - 0x9a, 0xfb, 0xf4, 0xc8, - 0x99, 0x6f, 0xb9, 0x24, - 0x27, 0xae, 0x41, 0xe4, - 0x64, 0x9b, 0x93, 0x4c, - 0xa4, 0x95, 0x99, 0x1b, - 0x78, 0x52, 0xb8, 0x55 -}; - - -static const uint8_t hello_world[] = { - 0x09, 0xca, 0x7e, 0x4e, - 0xaa, 0x6e, 0x8a, 0xe9, - 0xc7, 0xd2, 0x61, 0x16, - 0x71, 0x29, 0x18, 0x48, - 0x83, 0x64, 0x4d, 0x07, - 0xdf, 0xba, 0x7c, 0xbf, - 0xbc, 0x4c, 0x8a, 0x2e, - 0x08, 0x36, 0x0d, 0x5b, -}; - -constexpr uint32_t EMSHA_SELF_TEST_ITERS = 4; - -static EMSHA_RESULT -run_test(const uint8_t *input, uint32_t input_len, const uint8_t *expected) -{ - uint8_t d[SHA256_HASH_SIZE]; - emsha::SHA256 ctx; - emsha::EMSHA_RESULT res; - - res = ctx.update(input, input_len); - if (EMSHA_ROK != res) { - return res; - } - - for (uint32_t n = 0; n < EMSHA_SELF_TEST_ITERS; n++) { - res = ctx.result(d); - if (EMSHA_ROK != res) { - return res; - } - - for (uint32_t i = 0; i < SHA256_HASH_SIZE; i++) { - if (expected[i] != d[i]) { - return EMSHA_TEST_FAILURE; - } - } - } - - return EMSHA_ROK; -} - - -EMSHA_RESULT -sha256_self_test() -{ - EMSHA_RESULT res; - - res = run_test((const uint8_t *)"", 0, empty_vector); - if (EMSHA_ROK == res) { - res = run_test((const uint8_t *)"hello, world", 12, hello_world); - } - - return res; -} - - -#else // #ifdef EMSHA_NO_SELFTEST -EMSHA_RESULT -sha256_self_test() -{ - return EMSHA_SELFTEST_DISABLED; -} - - -#endif // EMSHA_NO_SELFTEST - - -} // end namespace emsha diff --git a/src/test_mem.cc b/src/test_mem.cc deleted file mode 100644 index c9de9e4..0000000 --- a/src/test_mem.cc +++ /dev/null @@ -1,214 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 K. Isom - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - - -#ifdef NDEBUG -#undef NDEBUG -#endif -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -// Number of test iterations. -static constexpr std::uint32_t ITERS = 3000000; - -// The key used for HMAC. -static constexpr std::uint8_t k[] = { - 0xc5, 0xb6, 0x80, 0xac, 0xdc, 0xf4, 0xff, 0xa1, - 0x37, 0x05, 0xc0, 0x71, 0x11, 0x24, 0x31, 0x7c, - 0xa5, 0xa2, 0xcf, 0x4d, 0x33, 0x00, 0x56, 0x4f, - 0x69, 0x0f, 0x76, 0x70, 0x87, 0xd9, 0x35, 0xce, - 0xa3, 0xad, 0xa3, 0x4f, 0x30, 0xe2, 0x7c, 0x58, - 0x88, 0xd4, 0x89, 0x6a, 0xb5, 0xe0, 0x97, 0x1c, - 0x7a, 0x69, 0x65, 0xc7, 0x61, 0x0d, 0x6d, 0xb6, - 0x9b, 0x0e, 0x56, 0xd7, 0x0f, 0x5a, 0x01, 0x50, -}; -static constexpr std::uint32_t kl = sizeof(k) / sizeof(k[0]); - -// The message provided to both SHA-256 and HMAC-SHA-256; it is -// "The fugacity of a constituent in a mixture of gases at a given -// temperature is proportional to its mole fraction. Lewis-Randall Rule", -// chosen as one of the longer test vectors. -static const std::uint8_t m[] = { - 0x54, 0x68, 0x65, 0x20, 0x66, 0x75, 0x67, 0x61, - 0x63, 0x69, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x20, - 0x61, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x69, - 0x74, 0x75, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, - 0x20, 0x61, 0x20, 0x6d, 0x69, 0x78, 0x74, 0x75, - 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x67, 0x61, - 0x73, 0x65, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61, - 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x74, - 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 0x72, - 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, - 0x61, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x74, - 0x73, 0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x20, 0x66, - 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x20, 0x20, 0x4c, 0x65, 0x77, 0x69, 0x73, 0x2d, - 0x52, 0x61, 0x6e, 0x64, 0x61, 0x6c, 0x6c, 0x20, - 0x52, 0x75, 0x6c, 0x65 -}; - -// d is the expected result of SHA256(m). -static constexpr std::uint8_t d[emsha::SHA256_HASH_SIZE] = { - 0x39, 0x55, 0x85, 0xce, 0x30, 0x61, 0x7b, 0x62, - 0xc8, 0x0b, 0x93, 0xe8, 0x20, 0x8c, 0xe8, 0x66, - 0xd4, 0xed, 0xc8, 0x11, 0xa1, 0x77, 0xfd, 0xb4, - 0xb8, 0x2d, 0x39, 0x11, 0xd8, 0x69, 0x64, 0x23 -}; - -// t is the expected result of HMAC-SHA-256(k, m). -static constexpr std::uint8_t t[emsha::SHA256_HASH_SIZE] = { - 0xbb, 0xc4, 0x7c, 0x35, 0x33, 0x4b, 0x9d, 0x90, - 0xee, 0x20, 0x88, 0x30, 0xe1, 0x1a, 0x0f, 0xf3, - 0xf4, 0x7d, 0xcc, 0xb0, 0xc5, 0xfb, 0x83, 0xe5, - 0xc2, 0xf5, 0xa7, 0x94, 0x50, 0xb6, 0xe0, 0xe0, -}; - -// dig is used to store the output of SHA-256 and HMAC-SHA-256. -static std::uint8_t dig[emsha::SHA256_HASH_SIZE]; - - -static void -init(void) -{ - std::fill(dig, dig+emsha::SHA256_HASH_SIZE, 0); -} - - -static void -iterate_sha(void) -{ - emsha::SHA256 ctx; - int cmp; - emsha::EMSHA_RESULT res; - - res = ctx.update(m, sizeof(m)); - assert(emsha::EMSHA_ROK == res); - res = ctx.result(dig); - assert(emsha::EMSHA_ROK == res); - - cmp = std::memcmp(dig, d, emsha::SHA256_HASH_SIZE); - assert(0 == cmp); -} - - -static void -iterate_hmac(void) -{ - emsha::HMAC ctx(k, kl); - int cmp; - emsha::EMSHA_RESULT res; - - res = ctx.update(m, sizeof(m)); - assert(emsha::EMSHA_ROK == res); - res = ctx.result(dig); - assert(emsha::EMSHA_ROK == res); - - cmp = std::memcmp(dig, t, emsha::SHA256_HASH_SIZE); - assert(0 == cmp); -} - - -static void -iterate_sha_sp(void) -{ - int cmp; - - assert(emsha::EMSHA_ROK == emsha::sha256_digest(m, sizeof(m), dig)); - cmp = std::memcmp(dig, d, emsha::SHA256_HASH_SIZE); - assert(0 == cmp); -} - - -static void -iterate_hmac_sp(void) -{ - int cmp; - emsha::EMSHA_RESULT res; - - res = emsha::compute_hmac(k, kl, m, sizeof(m), dig); - assert(emsha::EMSHA_ROK == res); - - cmp = std::memcmp(dig, t, emsha::SHA256_HASH_SIZE); - assert(0 == cmp); -} - - -static void -iterate(std::string label, void(iteration)(void)) -{ - std::cout << "=== " << label << " ===" << std::endl; - auto start = std::chrono::steady_clock::now(); - - for (std::uint32_t i = 0; i < ITERS; i++) - iteration(); - - auto end = std::chrono::steady_clock::now(); - auto delta = (end - start ); - - std::cout << "Total time: " - << std::chrono::duration (delta).count() - << " ms" << std::endl; - std::cout << "Average over " << ITERS << " tests: " - << std::chrono::duration (delta).count() / ITERS - << " ns" << std::endl; -} - - -static void -cold_start(void) -{ - std::cout << "=== SHA-256 cold start ===\n"; - auto start = std::chrono::steady_clock::now(); - - iterate_sha(); - - auto end = std::chrono::steady_clock::now(); - auto delta = (end - start ); - - std::cout << "Total time: " - << std::chrono::duration (delta).count() - << " ns" << std::endl; -} - -int -main(void) -{ - init(); - - cold_start(); - iterate("SHA-256", iterate_sha); - iterate("SHA-256 single-pass", iterate_sha_sp); - iterate("HMAC-SHA-256", iterate_hmac); - iterate("HMAC-SHA-256 single-pass", iterate_hmac_sp); -} diff --git a/src/test_emsha.cc b/test_emsha.cc similarity index 65% rename from src/test_emsha.cc rename to test_emsha.cc index d46a5e1..34b09eb 100644 --- a/src/test_emsha.cc +++ b/test_emsha.cc @@ -25,9 +25,9 @@ #include -#include +#include -#include "test_utils.hh" +#include "test_utils.h" using namespace std; @@ -35,27 +35,27 @@ using namespace std; #ifndef EMSHA_NO_HEXSTRING static void -hexstring_test(void) +hexStringTest() { - uint8_t buf[32]; - uint8_t out[65]; - string expected = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; + uint8_t buf[32]; + uint8_t out[65]; + string const expected = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; out[64] = 0; for (uint32_t i = 0; i < 32; i++) { - buf[i] = (uint8_t)i; + buf[i] = static_cast(i); } - emsha::hexstring(out, buf, emsha::SHA256_HASH_SIZE); - string outs(reinterpret_cast(out)); + emsha::HexString(out, buf, emsha::SHA256_HASH_SIZE); + string const outs(reinterpret_cast(out)); if (outs != expected) { - cerr << "FAILED: hexstring" << endl; + cerr << "FAILED: HexString" << endl; cerr << "\twanted: " << expected << endl; cerr << "\thave: " << out << endl; exit(1); } - cout << "PASSED: hexstring "; + cout << "PASSED: HexString "; #ifdef EMSHA_NO_HEXLUT cout << "(small LUT)"; #else // #ifdef EMSHA_NO_HEXLUT @@ -69,23 +69,23 @@ hexstring_test(void) // TODO(kyle): build a test harness around this to verify times between // runs. static void -hash_equal_test(void) +hashEqualTest() { - uint8_t a[emsha::SHA256_HASH_SIZE]; - uint8_t b[emsha::SHA256_HASH_SIZE]; + uint8_t a[emsha::SHA256_HASH_SIZE]; + uint8_t b[emsha::SHA256_HASH_SIZE]; for (uint32_t i = 0; i < emsha::SHA256_HASH_SIZE; i++) { a[i] = static_cast(i); b[i] = static_cast(i); } - if (!(emsha::hash_equal(a, b))) { - string s; - cerr << "FAILED: hash_equal\n"; - cerr << "\thash_equal should have succeeded comparing a and b.\n"; - dump_hexstring(s, a, emsha::SHA256_HASH_SIZE); + if (!(emsha::HashEqual(a, b))) { + string s; + cerr << "FAILED: HashEqual\n"; + cerr << "\tHashEqual should have succeeded comparing a and b.\n"; + DumpHexString(s, a, emsha::SHA256_HASH_SIZE); cerr << "\ta <- " << s << std::endl; - dump_hexstring(s, b, emsha::SHA256_HASH_SIZE); + DumpHexString(s, b, emsha::SHA256_HASH_SIZE); cerr << "\tb <- " << s << std::endl; exit(1); } @@ -95,13 +95,13 @@ hash_equal_test(void) b[i] = static_cast(emsha::SHA256_HASH_SIZE - i); } - if (emsha::hash_equal(a, b)) { - string s; - cerr << "FAILED: hash_equal\n"; - cerr << "\thash_equal should not have succeeded comparing a and b.\n"; - dump_hexstring(s, a, emsha::SHA256_HASH_SIZE); + if (emsha::HashEqual(a, b)) { + string s; + cerr << "FAILED: HashEqual\n"; + cerr << "\tHashEqual should not have succeeded comparing a and b.\n"; + DumpHexString(s, a, emsha::SHA256_HASH_SIZE); cerr << "\ta <- " << s << std::endl; - dump_hexstring(s, b, emsha::SHA256_HASH_SIZE); + DumpHexString(s, b, emsha::SHA256_HASH_SIZE); cerr << "\tb <- " << s << std::endl; exit(1); } @@ -112,32 +112,31 @@ hash_equal_test(void) // res += a[i] ^ b[i]; for (uint32_t i = 0; i < emsha::SHA256_HASH_SIZE; i++) { a[i] = static_cast(i); - b[i] = static_cast(i+1); + b[i] = static_cast(i + 1); } b[emsha::SHA256_HASH_SIZE - 1]--; - if (emsha::hash_equal(a, b)) { - string s; - cerr << "FAILED: hash_equal\n"; - cerr << "\tREGRESSION: hash_equal should not have succeeded comparing a and b.\n"; - dump_hexstring(s, a, emsha::SHA256_HASH_SIZE); + if (emsha::HashEqual(a, b)) { + string s; + cerr << "FAILED: HashEqual\n"; + cerr << "\tREGRESSION: HashEqual should not have succeeded comparing a and b.\n"; + DumpHexString(s, a, emsha::SHA256_HASH_SIZE); cerr << "\ta <- " << s << std::endl; - dump_hexstring(s, b, emsha::SHA256_HASH_SIZE); + DumpHexString(s, b, emsha::SHA256_HASH_SIZE); cerr << "\tb <- " << s << std::endl; exit(1); } - - cout << "PASSED: hash_equal\n"; + cout << "PASSED: HashEqual\n"; } int -main(void) +main() { #ifndef EMSHA_NO_HEXSTRING - hexstring_test(); + hexStringTest(); #endif - hash_equal_test(); + hashEqualTest(); } diff --git a/src/test_hmac.cc b/test_hmac.cc similarity index 94% rename from src/test_hmac.cc rename to test_hmac.cc index 77df8c3..a14500f 100644 --- a/src/test_hmac.cc +++ b/test_hmac.cc @@ -25,15 +25,15 @@ #include -#include -#include +#include +#include -#include "test_utils.hh" +#include "test_utils.h" using namespace std; -const struct hmac_test rfc4231[] = { +const struct hmacTest rfc4231[] = { { {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, @@ -122,13 +122,13 @@ const struct hmac_test rfc4231[] = { int -main(void) +main() { - int res; + int res = 0; - res = run_hmac_tests((struct hmac_test *)rfc4231, - sizeof rfc4231 / sizeof rfc4231[0], - "RFC 4231"); + res = runHMACTests((struct hmacTest *) rfc4231, + sizeof rfc4231 / sizeof rfc4231[0], + "RFC 4231"); if (-1 == res) { exit(1); } diff --git a/test_mem.cc b/test_mem.cc new file mode 100644 index 0000000..70edd39 --- /dev/null +++ b/test_mem.cc @@ -0,0 +1,217 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 K. Isom + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#ifdef NDEBUG +#undef NDEBUG +#endif + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +// Number of test iterations. +static constexpr std::uint32_t ITERS = 8192; + +// The key used for HMAC. +static constexpr std::uint8_t k[] = { + 0xc5, 0xb6, 0x80, 0xac, 0xdc, 0xf4, 0xff, 0xa1, + 0x37, 0x05, 0xc0, 0x71, 0x11, 0x24, 0x31, 0x7c, + 0xa5, 0xa2, 0xcf, 0x4d, 0x33, 0x00, 0x56, 0x4f, + 0x69, 0x0f, 0x76, 0x70, 0x87, 0xd9, 0x35, 0xce, + 0xa3, 0xad, 0xa3, 0x4f, 0x30, 0xe2, 0x7c, 0x58, + 0x88, 0xd4, 0x89, 0x6a, 0xb5, 0xe0, 0x97, 0x1c, + 0x7a, 0x69, 0x65, 0xc7, 0x61, 0x0d, 0x6d, 0xb6, + 0x9b, 0x0e, 0x56, 0xd7, 0x0f, 0x5a, 0x01, 0x50, +}; +static constexpr std::uint32_t kl = sizeof(k) / sizeof(k[0]); + +// The message provided to both SHA-256 and HMAC-SHA-256; it is +// "The fugacity of a constituent in a mixture of gases at a given +// temperature is proportional to its mole fraction. Lewis-Randall Rule", +// chosen as one of the longer test vectors. +static const std::uint8_t m[] = { + 0x54, 0x68, 0x65, 0x20, 0x66, 0x75, 0x67, 0x61, + 0x63, 0x69, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x20, + 0x61, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x69, + 0x74, 0x75, 0x65, 0x6e, 0x74, 0x20, 0x69, 0x6e, + 0x20, 0x61, 0x20, 0x6d, 0x69, 0x78, 0x74, 0x75, + 0x72, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x67, 0x61, + 0x73, 0x65, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61, + 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x20, 0x74, + 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 0x72, + 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x74, + 0x73, 0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x20, 0x66, + 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x20, 0x20, 0x4c, 0x65, 0x77, 0x69, 0x73, 0x2d, + 0x52, 0x61, 0x6e, 0x64, 0x61, 0x6c, 0x6c, 0x20, + 0x52, 0x75, 0x6c, 0x65 +}; + +// d is the expected result of SHA256(m). +static constexpr std::uint8_t d[emsha::SHA256_HASH_SIZE] = { + 0x39, 0x55, 0x85, 0xce, 0x30, 0x61, 0x7b, 0x62, + 0xc8, 0x0b, 0x93, 0xe8, 0x20, 0x8c, 0xe8, 0x66, + 0xd4, 0xed, 0xc8, 0x11, 0xa1, 0x77, 0xfd, 0xb4, + 0xb8, 0x2d, 0x39, 0x11, 0xd8, 0x69, 0x64, 0x23 +}; + +// t is the expected result of HMAC-SHA-256(k, m). +static constexpr std::uint8_t t[emsha::SHA256_HASH_SIZE] = { + 0xbb, 0xc4, 0x7c, 0x35, 0x33, 0x4b, 0x9d, 0x90, + 0xee, 0x20, 0x88, 0x30, 0xe1, 0x1a, 0x0f, 0xf3, + 0xf4, 0x7d, 0xcc, 0xb0, 0xc5, 0xfb, 0x83, 0xe5, + 0xc2, 0xf5, 0xa7, 0x94, 0x50, 0xb6, 0xe0, 0xe0, +}; + +// dig is used to store the output of SHA-256 and HMAC-SHA-256. +static std::uint8_t dig[emsha::SHA256_HASH_SIZE]; + + +static void +init() +{ + std::fill(dig, dig + emsha::SHA256_HASH_SIZE, 0); +} + + +static void +iterateSHA() +{ + emsha::SHA256 ctx; + int cmp = 0; + emsha::EMSHA_RESULT res; + + res = ctx.Update(m, sizeof(m)); + assert(emsha::EMSHA_ROK == res); + res = ctx.Result(dig); + assert(emsha::EMSHA_ROK == res); + + cmp = std::memcmp(dig, d, emsha::SHA256_HASH_SIZE); + assert(0 == cmp); +} + + +static void +iterateHMAC() +{ + emsha::HMAC ctx(k, kl); + int cmp = 0; + emsha::EMSHA_RESULT res; + + res = ctx.Update(m, sizeof(m)); + assert(emsha::EMSHA_ROK == res); + res = ctx.Result(dig); + assert(emsha::EMSHA_ROK == res); + + cmp = std::memcmp(dig, t, emsha::SHA256_HASH_SIZE); + assert(0 == cmp); +} + + +static void +iterateSHASP() +{ + int cmp = 0; + + assert(emsha::EMSHA_ROK == emsha::sha256Digest(m, sizeof(m), dig)); + cmp = std::memcmp(dig, d, emsha::SHA256_HASH_SIZE); + assert(0 == cmp); +} + + +static void +iterateHMACSP() +{ + int cmp = 0; + emsha::EMSHA_RESULT res; + + res = emsha::ComputeHMAC(k, kl, m, sizeof(m), dig); + assert(emsha::EMSHA_ROK == res); + + cmp = std::memcmp(dig, t, emsha::SHA256_HASH_SIZE); + assert(0 == cmp); +} + + +static void +iterate(const std::string &label, void(iteration)(void)) +{ + std::cout << "=== " << label << " ===" << std::endl; + auto start = std::chrono::steady_clock::now(); + + for (std::uint32_t i = 0; i < ITERS; i++) { + iteration(); + } + + auto end = std::chrono::steady_clock::now(); + auto delta = (end - start); + + std::cout << "Total time: " + << std::chrono::duration(delta).count() + << " ms" << std::endl; + std::cout << "Average over " << ITERS << " tests: " + << std::chrono::duration(delta).count() / ITERS + << " ns" << std::endl; +} + + +static void +coldStart() +{ + std::cout << "=== SHA-256 cold start ===\n"; + auto start = std::chrono::steady_clock::now(); + + iterateSHA(); + + auto end = std::chrono::steady_clock::now(); + auto delta = (end - start); + + std::cout << "Total time: " + << std::chrono::duration(delta).count() + << " ns" << std::endl; +} + +int +main() +{ + init(); + + coldStart(); + iterate("SHA-256", iterateSHA); + iterate("SHA-256 single-pass", iterateSHASP); + iterate("HMAC-SHA-256", iterateHMAC); + iterate("HMAC-SHA-256 single-pass", iterateHMACSP); +} diff --git a/src/test_sha256.cc b/test_sha256.cc similarity index 88% rename from src/test_sha256.cc rename to test_sha256.cc index 68fb0df..5436248 100644 --- a/src/test_sha256.cc +++ b/test_sha256.cc @@ -23,19 +23,17 @@ */ -#include -#include #include +#include +#include -#include - -#include "test_utils.hh" +#include "test_utils.h" using namespace std; // Tests taken from the Go SHA-256 package. -const struct hash_test golden_tests[] = { +const struct hashTest goldenTests[] = { {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""}, {"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a"}, {"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab"}, @@ -69,32 +67,33 @@ const struct hash_test golden_tests[] = { {"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++? -Paul Glick"}, }; +static constexpr auto numGoldenTests = sizeof goldenTests / sizeof goldenTests[0]; +static const std::string labelGoldenTests = "golden tests"; int -main(void) +main() { - int res; - #ifdef EMSHA_NO_SELFTEST cout << "[NOTICE] internal self-tests have been disabled.\n"; #else - res = emsha::sha256_self_test(); - switch (res) { + auto selfTestStatus = emsha::sha256SelfTest(); + switch (selfTestStatus) { case emsha::EMSHA_ROK: - cout << "PASSED: SHA-256 self test" << endl; + cout << "PASSED: SHA-256 self test\n"; break; case emsha::EMSHA_TEST_FAILURE: - cout << "FAILED: SHA-256 self test (test failure)" << endl; + cout << "FAILED: SHA-256 self test (test failure)\n"; break; default: - cout << "FAILED: SHA-256 self test (fault " << res << ")" - << endl; + cout << "FAILED: SHA-256 self test (fault " << selfTestStatus << ")\n"; } + assert(selfTestStatus == emsha::EMSHA_ROK); #endif - res = run_hash_tests(const_cast(golden_tests), - sizeof golden_tests / sizeof golden_tests[0], - "golden tests"); - if (-1 == res) { + + + auto res = runHashTests(static_cast(goldenTests), + numGoldenTests, labelGoldenTests); + if (res == -1) { exit(1); } diff --git a/src/test_utils.cc b/test_utils.cc similarity index 80% rename from src/test_utils.cc rename to test_utils.cc index 8c2b55b..39dd2e6 100644 --- a/src/test_utils.cc +++ b/test_utils.cc @@ -28,7 +28,7 @@ #include #include -#include "test_utils.hh" +#include "test_utils.h" using std::uint8_t; using std::uint32_t; @@ -39,14 +39,14 @@ using std::endl; void -dump_hexstring(string& hs, uint8_t *s, uint32_t sl) +DumpHexString(std::string& hs, uint8_t *s, uint32_t sl) { - uint32_t bl = (2 * sl) + 1; + uint32_t const bl = (2 * sl) + 1; char *buf = new char[bl]; string tmp; memset(buf, 0, bl); - emsha::hexstring((uint8_t *)buf, s, sl); + emsha::HexString(reinterpret_cast(buf), s, sl); tmp = string(buf); hs.swap(tmp); delete[] buf; @@ -54,25 +54,25 @@ dump_hexstring(string& hs, uint8_t *s, uint32_t sl) emsha::EMSHA_RESULT -run_hmac_test(struct hmac_test test, string label) +runHMACTest(const struct hmacTest test, const string& label) { emsha::HMAC h(test.key, test.keylen); emsha::EMSHA_RESULT res; uint8_t dig[emsha::SHA256_HASH_SIZE]; - 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) { goto exit; } for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) { - res = h.result(dig); + res = h.Result(dig); if (emsha::EMSHA_ROK != res) { goto exit; } - dump_hexstring(hs, dig, emsha::SHA256_HASH_SIZE); + DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); if (hs != test.output) { res = emsha::EMSHA_TEST_FAILURE; goto exit; @@ -81,20 +81,20 @@ run_hmac_test(struct hmac_test test, string label) } // Ensure that a reset and update gives the same results. - 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) { goto exit; } for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) { - res = h.result(dig); + res = h.Result(dig); if (emsha::EMSHA_ROK != res) { goto exit; } - dump_hexstring(hs, dig, emsha::SHA256_HASH_SIZE); + DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); if (hs != test.output) { res = emsha::EMSHA_TEST_FAILURE; goto exit; @@ -103,7 +103,7 @@ run_hmac_test(struct hmac_test test, string label) } // Test that the single-pass function works. - res = emsha::compute_hmac(test.key, test.keylen, + res = emsha::ComputeHMAC(test.key, test.keylen, (uint8_t *)test.input.c_str(), test.input.size(), dig); if (emsha::EMSHA_ROK != res) { @@ -111,7 +111,7 @@ run_hmac_test(struct hmac_test test, string label) goto exit; } - dump_hexstring(hs, dig, emsha::SHA256_HASH_SIZE); + DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); if (hs != test.output) { cerr << "(comparing single pass function output)\n"; res = emsha::EMSHA_TEST_FAILURE; @@ -134,38 +134,38 @@ exit: int -run_hmac_tests(struct hmac_test *tests, uint32_t ntests, string label) +runHMACTests(const struct hmacTest *tests, size_t nTests, const string& label) { - for (uint32_t i = 0; i < ntests; i++) { - if (emsha::EMSHA_ROK != run_hmac_test(*(tests + i), label)) { + for (uint32_t i = 0; i < nTests; i++) { + if (emsha::EMSHA_ROK != runHMACTest(*(tests + i), label)) { return -1; } } - cout << "PASSED: " << label << " (" << ntests << ")" << endl; + cout << "PASSED: " << label << " (" << nTests << ")" << endl; return 0; } emsha::EMSHA_RESULT -run_hash_test(struct hash_test test, string label) +runHashTest(const struct hashTest& test, const string& label) { emsha::SHA256 ctx; emsha::EMSHA_RESULT res; uint8_t dig[emsha::SHA256_HASH_SIZE]; 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) { goto exit; } for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) { - res = ctx.result(dig); + res = ctx.Result(dig); if (emsha::EMSHA_ROK != res) { goto exit; } - dump_hexstring(hs, dig, emsha::SHA256_HASH_SIZE); + DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); if (hs != test.output) { res = emsha::EMSHA_TEST_FAILURE; goto exit; @@ -174,20 +174,20 @@ run_hash_test(struct hash_test test, string label) } // Ensure that a reset and update gives the same results. - 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) { goto exit; } for (uint32_t n = 0; n < RESULT_ITERATIONS; n++) { - res = ctx.result(dig); + res = ctx.Result(dig); if (emsha::EMSHA_ROK != res) { goto exit; } - dump_hexstring(hs, dig, emsha::SHA256_HASH_SIZE); + DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); if (hs != test.output) { res = emsha::EMSHA_TEST_FAILURE; goto exit; @@ -196,14 +196,14 @@ run_hash_test(struct hash_test test, string label) } // Test that the single-pass function works. - res = emsha::sha256_digest((uint8_t *)test.input.c_str(), - test.input.size(), dig); + res = emsha::sha256Digest((uint8_t *) test.input.c_str(), + test.input.size(), dig); if (emsha::EMSHA_ROK != res) { cerr << "(running single pass function test)\n"; goto exit; } - dump_hexstring(hs, dig, emsha::SHA256_HASH_SIZE); + DumpHexString(hs, dig, emsha::SHA256_HASH_SIZE); if (hs != test.output) { cerr << "(comparing single pass function output)\n"; res = emsha::EMSHA_TEST_FAILURE; @@ -224,10 +224,10 @@ exit: int -run_hash_tests(struct hash_test *tests, uint32_t ntests, string label) +runHashTests(const struct hashTest *tests, const size_t ntests, const string& label) { for (uint32_t i = 0; i < ntests; i++) { - if (emsha::EMSHA_ROK != run_hash_test(*(tests + i), label)) { + if (emsha::EMSHA_ROK != runHashTest(*(tests + i), label)) { return -1; } } @@ -284,7 +284,7 @@ write_hex_char(uint8_t *dest, uint8_t src) void -hexstring(uint8_t *dest, uint8_t *src, uint32_t srclen) +HexString(uint8_t *dest, uint8_t *src, uint32_t srclen) { uint8_t *dp = dest; diff --git a/src/test_utils.hh b/test_utils.h similarity index 78% rename from src/test_utils.hh rename to test_utils.h index 5719ea6..52a40dc 100644 --- a/src/test_utils.hh +++ b/test_utils.h @@ -30,9 +30,9 @@ #include #include -#include -#include -#include +#include +#include +#include // How many times should a test result be checked? The goal is to @@ -44,13 +44,13 @@ constexpr uint32_t RESULT_ITERATIONS = 5; // Test data structures. -struct hash_test { +struct hashTest { std::string output; std::string input; }; -struct hmac_test { +struct hmacTest { std::uint8_t key[256]; std::uint32_t keylen; std::string input; @@ -59,20 +59,20 @@ struct hmac_test { // General-purpose debuggery. -void dump_hexstring(std::string&, std::uint8_t *, std::uint32_t); +void DumpHexString(std::string&, std::uint8_t *, std::uint32_t); void dump_pair(std::uint8_t *, std::uint8_t *); // SHA-256 testing functions. -emsha::EMSHA_RESULT run_hash_test(struct hash_test, std::string); -int run_hash_tests(struct hash_test *, std::uint32_t, - std::string); +emsha::EMSHA_RESULT runHashTest(const struct hashTest& test, const std::string& label); +int runHashTests(const struct hashTest *tests, const std::size_t nTests, + const std::string& label); // HMAC-SHA-256 testery. -emsha::EMSHA_RESULT run_hmac_test(struct hmac_test, std::string); -int run_hmac_tests(struct hmac_test *, std::uint32_t, - std::string); +emsha::EMSHA_RESULT runHMACTest(struct hmacTest test, const std::string& label); +int runHMACTests(const struct hmacTest *tests, std::size_t nTests, + const std::string& label); #ifdef EMSHA_NO_HEXSTRING