From 538859949e0c6276eb444e610b89ae54e0ba5676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Gu=C5=A1tin?= Date: Sat, 30 Apr 2022 13:25:51 +0200 Subject: [PATCH 01/11] Slight simplification of permutation code The temporary sponge is written into with struct initialisation syntax and is set to const rather than declaring it and then initialising it. No effects seen in terms of performance, but it seems easier to read and understand. --- src/ascon_permutations.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/ascon_permutations.c b/src/ascon_permutations.c index d22c335..d922555 100644 --- a/src/ascon_permutations.c +++ b/src/ascon_permutations.c @@ -49,7 +49,6 @@ ASCON_INLINE void ascon_round(ascon_sponge_t* sponge, const uint_fast8_t round_const) { - ascon_sponge_t temp; // addition of round constant sponge->x2 ^= round_const; // substitution layer @@ -57,16 +56,13 @@ ascon_round(ascon_sponge_t* sponge, sponge->x4 ^= sponge->x3; sponge->x2 ^= sponge->x1; // start of keccak s-box - temp.x0 = ~sponge->x0; - temp.x1 = ~sponge->x1; - temp.x2 = ~sponge->x2; - temp.x3 = ~sponge->x3; - temp.x4 = ~sponge->x4; - temp.x0 &= sponge->x1; - temp.x1 &= sponge->x2; - temp.x2 &= sponge->x3; - temp.x3 &= sponge->x4; - temp.x4 &= sponge->x0; + const ascon_sponge_t temp = { + .x0 = (~sponge->x0) & sponge->x1, + .x1 = (~sponge->x1) & sponge->x2, + .x2 = (~sponge->x2) & sponge->x3, + .x3 = (~sponge->x3) & sponge->x4, + .x4 = (~sponge->x4) & sponge->x0, + }; sponge->x0 ^= temp.x1; sponge->x1 ^= temp.x2; sponge->x2 ^= temp.x3; From 3e0bb9ed89f2a978026c7a0873b624497a0227eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Gu=C5=A1tin?= Date: Sat, 30 Apr 2022 14:36:22 +0200 Subject: [PATCH 02/11] Constant-time hash-digest comparison - Constant time evaluations help against timing attacks. Comparisons are done using uint64_t values, with the expected digest uint8_t[] being converted into uint64_t. It's probably slightly more efficient than byte-wise memcmp, but hard to guess compared to what the optimised does behind the scenes. --- src/ascon_hash.c | 51 ++++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/src/ascon_hash.c b/src/ascon_hash.c index a439c2c..b847764 100644 --- a/src/ascon_hash.c +++ b/src/ascon_hash.c @@ -304,17 +304,6 @@ ascon_hash_cleanup(ascon_hash_ctx_t* const ctx) } } -/** @internal Simplistic clone of `memcmp() != 0`, true when NOT equal. */ -inline static bool -small_neq(const uint8_t* restrict a, const uint8_t* restrict b, size_t amount) -{ - while (amount--) - { - if (*(a++) != *(b++)) { return true; } - } - return false; -} - /** * @internal * Final step of the hashing flow with tag equality checks, same for Hash, XOF, @@ -334,33 +323,31 @@ hash_final_matches(permutation_fptr permutation, ascon_permutation_12(&ctx->sponge); // Squeeze the digest from the inner state 8 bytes at the time to compare // it chunk by chunk with the expected digest - uint8_t computed_digest_chunk[ASCON_RATE]; + bool digests_differ = false; + uint64_t expected_digest_chunk; while (expected_digest_len > ASCON_RATE) { - // Note: converting the sponge uint64_t to bytes to then check them as - // is required, as the conversion to bytes ensures the - // proper tag's byte order regardless of the platform's endianness. - bigendian_encode_u64(computed_digest_chunk, ctx->sponge.x0); + // Note: converting the expected digest from uint8_t[] to uint64_t + // for a faster comparison. It has to be decoded explicitly to ensure + // it works the same on all platforms, regardless of endianness. + // Type-punning like `*(uint64_t*) expected_digest` is NOT portable. + expected_digest_chunk = bigendian_decode_u64(expected_digest); + // Constant time comparison expected vs computed digest chunk + digests_differ |= (expected_digest_chunk ^ ctx->sponge.x0); + // Permute and shift to next chunk permutation(&ctx->sponge); - if (small_neq(computed_digest_chunk, expected_digest, sizeof(computed_digest_chunk))) - { - ascon_hash_cleanup(ctx); - return ASCON_TAG_INVALID; - } - expected_digest_len -= sizeof(computed_digest_chunk); - expected_digest += sizeof(computed_digest_chunk); - } - bigendian_encode_varlen(computed_digest_chunk, ctx->sponge.x0, - (uint_fast8_t) expected_digest_len); - // Check the remaining bytes in the chunk, potentially less than ASCON_RATE - if (small_neq(computed_digest_chunk, expected_digest, expected_digest_len)) - { - ascon_hash_cleanup(ctx); - return ASCON_TAG_INVALID; + expected_digest_len -= sizeof(expected_digest_chunk); + expected_digest += sizeof(expected_digest_chunk); } + // Extract the remaining n most significant bytes of the two digest chunks + ctx->sponge.x0 &= byte_mask((uint_fast8_t) expected_digest_len); + expected_digest_chunk = bigendian_decode_varlen( + expected_digest, (uint_fast8_t) expected_digest_len); + // Constant time comparison expected vs computed chunk + digests_differ |= (expected_digest_chunk ^ ctx->sponge.x0); // Final security cleanup of the internal state and buffer. ascon_hash_cleanup(ctx); - return ASCON_TAG_OK; + return !digests_differ; // True if they are equal } ASCON_API bool From d88d6653eec5f90e1468d3488d7954c9b93d4d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Gu=C5=A1tin?= Date: Sat, 30 Apr 2022 14:38:50 +0200 Subject: [PATCH 03/11] Rename byte_mask() -> mask_most_signif_bytes() for clarity --- src/ascon_aead128.c | 2 +- src/ascon_aead128a.c | 4 ++-- src/ascon_aead80pq.c | 2 +- src/ascon_buffering.c | 2 +- src/ascon_hash.c | 2 +- src/ascon_internal.h | 7 ++++++- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/ascon_aead128.c b/src/ascon_aead128.c index 242cf9f..08e82d3 100644 --- a/src/ascon_aead128.c +++ b/src/ascon_aead128.c @@ -259,7 +259,7 @@ ascon_aead128_decrypt_final(ascon_aead_ctx_t* const ctx, ctx->bufstate.buffer_len); freshly_generated_plaintext_len += ctx->bufstate.buffer_len; // Final state changes at decryption's end - ctx->bufstate.sponge.x0 &= ~byte_mask(ctx->bufstate.buffer_len); + ctx->bufstate.sponge.x0 &= ~mask_most_signif_bytes(ctx->bufstate.buffer_len); ctx->bufstate.sponge.x0 |= c_0; ctx->bufstate.sponge.x0 ^= PADDING(ctx->bufstate.buffer_len); // End of decryption, start of tag validation. diff --git a/src/ascon_aead128a.c b/src/ascon_aead128a.c index 5ef4a60..7416ccf 100644 --- a/src/ascon_aead128a.c +++ b/src/ascon_aead128a.c @@ -344,7 +344,7 @@ ascon_aead128a_decrypt_final(ascon_aead_ctx_t* const ctx, second_half); // Final state changes at decryption's end ctx->bufstate.sponge.x0 = c_0; - ctx->bufstate.sponge.x1 &= ~byte_mask(second_half); + ctx->bufstate.sponge.x1 &= ~mask_most_signif_bytes(second_half); ctx->bufstate.sponge.x1 |= c_1; ctx->bufstate.sponge.x1 ^= PADDING(second_half); } @@ -357,7 +357,7 @@ ascon_aead128a_decrypt_final(ascon_aead_ctx_t* const ctx, bigendian_encode_varlen(plaintext, ctx->bufstate.sponge.x0 ^ c_0, ctx->bufstate.buffer_len); // Final state changes at decryption's end - ctx->bufstate.sponge.x0 &= ~byte_mask(ctx->bufstate.buffer_len); + ctx->bufstate.sponge.x0 &= ~mask_most_signif_bytes(ctx->bufstate.buffer_len); ctx->bufstate.sponge.x0 |= c_0; ctx->bufstate.sponge.x0 ^= PADDING(ctx->bufstate.buffer_len); } diff --git a/src/ascon_aead80pq.c b/src/ascon_aead80pq.c index c0d35ae..8cd2004 100644 --- a/src/ascon_aead80pq.c +++ b/src/ascon_aead80pq.c @@ -187,7 +187,7 @@ ascon_aead80pq_decrypt_final(ascon_aead_ctx_t* const ctx, bigendian_encode_varlen(plaintext, ctx->bufstate.sponge.x0 ^ c_0, ctx->bufstate.buffer_len); // Final state changes at decryption's end - ctx->bufstate.sponge.x0 &= ~byte_mask(ctx->bufstate.buffer_len); + ctx->bufstate.sponge.x0 &= ~mask_most_signif_bytes(ctx->bufstate.buffer_len); ctx->bufstate.sponge.x0 |= c_0; ctx->bufstate.sponge.x0 ^= PADDING(ctx->bufstate.buffer_len); freshly_generated_plaintext_len += ctx->bufstate.buffer_len; diff --git a/src/ascon_buffering.c b/src/ascon_buffering.c index 129ec85..1cd30a6 100644 --- a/src/ascon_buffering.c +++ b/src/ascon_buffering.c @@ -87,7 +87,7 @@ bigendian_encode_varlen(uint8_t* const bytes, const uint64_t x, const uint_fast8 } uint64_t -byte_mask(const uint_fast8_t n) +mask_most_signif_bytes(uint_fast8_t n) { uint64_t x = 0; // Unsigned int should be the fastest unsigned on the machine. diff --git a/src/ascon_hash.c b/src/ascon_hash.c index b847764..878b922 100644 --- a/src/ascon_hash.c +++ b/src/ascon_hash.c @@ -340,7 +340,7 @@ hash_final_matches(permutation_fptr permutation, expected_digest += sizeof(expected_digest_chunk); } // Extract the remaining n most significant bytes of the two digest chunks - ctx->sponge.x0 &= byte_mask((uint_fast8_t) expected_digest_len); + ctx->sponge.x0 &= mask_most_signif_bytes((uint_fast8_t) expected_digest_len); expected_digest_chunk = bigendian_decode_varlen( expected_digest, (uint_fast8_t) expected_digest_len); // Constant time comparison expected vs computed chunk diff --git a/src/ascon_internal.h b/src/ascon_internal.h index 6eb4f25..950dc79 100644 --- a/src/ascon_internal.h +++ b/src/ascon_internal.h @@ -204,9 +204,14 @@ bigendian_encode_varlen(uint8_t* bytes, uint64_t x, uint_fast8_t n); /** * @internal * Creates a mask to extract the n most significant bytes of a uint64_t. + * + * Examples: + * + * - `n == 1` returns `FF00 0000 0000 0000` (spaces are just for readability) + * - `n == 5` returns `FFFF FFFF FF00 0000` */ uint64_t -byte_mask(uint_fast8_t n); +mask_most_signif_bytes(uint_fast8_t n); /** * @internal From ab69a7e5a2824911f7bacf245154b5a170adca03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Gu=C5=A1tin?= Date: Sat, 30 Apr 2022 14:53:08 +0200 Subject: [PATCH 04/11] Constant-time AEAD-tag comparison - Constant time evaluations help against timing attacks. Comparisons are done using uint64_t values, with the expected digest uint8_t[] being converted into uint64_t. It's probably slightly more efficient than byte-wise memcmp, but hard to guess compared to what the optimised does behind the scenes. - Minor changes in code style in hash-digest comparison to make the two tag/digest comparison functions look similar. --- src/ascon_aead_common.c | 67 +++++++++++++++++------------------------ src/ascon_hash.c | 15 ++++----- 2 files changed, 36 insertions(+), 46 deletions(-) diff --git a/src/ascon_aead_common.c b/src/ascon_aead_common.c index 1ff102e..e79d75e 100644 --- a/src/ascon_aead_common.c +++ b/src/ascon_aead_common.c @@ -77,56 +77,45 @@ ascon_aead_generate_tag(ascon_aead_ctx_t* const ctx, bigendian_encode_varlen(tag, ctx->bufstate.sponge.x4, (uint_fast8_t) tag_len); } -/** @internal Simplistic clone of `memcmp() != 0`, true when NOT equal. */ -inline static bool -small_neq(const uint8_t* restrict a, const uint8_t* restrict b, size_t amount) -{ - while (amount--) - { - if (*(a++) != *(b++)) { return true; } - } - return false; -} - bool ascon_aead_is_tag_valid(ascon_aead_ctx_t* const ctx, const uint8_t* expected_tag, size_t expected_tag_len) { - uint8_t computed_tag_chunk[ASCON_RATE]; + uint64_t expected_tag_chunk; + bool tags_differ = false; while (expected_tag_len > ASCON_AEAD_TAG_MIN_SECURE_LEN) { - // All bytes before the last 16 - // Note: converting the sponge uint64_t to bytes to then check them as - // is required, as the conversion to bytes ensures the - // proper tag's byte order regardless of the platform's endianness. - bigendian_encode_u64(computed_tag_chunk, ctx->bufstate.sponge.x3); - if (small_neq(computed_tag_chunk, expected_tag, sizeof(computed_tag_chunk))) - { - return ASCON_TAG_INVALID; - } - expected_tag += sizeof(computed_tag_chunk); - expected_tag_len -= sizeof(computed_tag_chunk); - bigendian_encode_u64(computed_tag_chunk, ctx->bufstate.sponge.x4); - if (small_neq(computed_tag_chunk, expected_tag, sizeof(computed_tag_chunk))) - { - return ASCON_TAG_INVALID; - } - expected_tag += sizeof(computed_tag_chunk); - expected_tag_len -= sizeof(computed_tag_chunk); + // Note: converting the expected tag from uint8_t[] to uint64_t + // for a faster comparison. It has to be decoded explicitly to ensure + // it works the same on all platforms, regardless of endianness. + // Type-punning like `*(uint64_t*) expected_tag` is NOT portable. + // + // Constant time comparison expected vs computed digest chunk, part 1 + expected_tag_chunk = bigendian_decode_u64(expected_tag); + tags_differ |= (expected_tag_chunk ^ ctx->bufstate.sponge.x3); + expected_tag += sizeof(expected_tag_chunk); + expected_tag_len -= sizeof(expected_tag_chunk); + // Constant time comparison expected vs computed digest chunk, part 2 + expected_tag_chunk = bigendian_decode_u64(expected_tag); + tags_differ |= (expected_tag_chunk ^ ctx->bufstate.sponge.x4); + expected_tag += sizeof(expected_tag_chunk); + expected_tag_len -= sizeof(expected_tag_chunk); + // Permute and go to next chunk ascon_permutation_12(&ctx->bufstate.sponge); } - // The last 16 or fewer bytes (also 0) - size_t remaining = MIN(sizeof(computed_tag_chunk), expected_tag_len); - bigendian_encode_varlen(computed_tag_chunk, ctx->bufstate.sponge.x3, (uint_fast8_t) remaining); - if (small_neq(computed_tag_chunk, expected_tag, remaining)) { return ASCON_TAG_INVALID; } + // Extract the remaining n most significant bytes of expected/computed tags + size_t remaining = MIN(sizeof(expected_tag_chunk), expected_tag_len); + uint64_t ms_mask = mask_most_signif_bytes((uint_fast8_t) remaining); + expected_tag_chunk = bigendian_decode_varlen(expected_tag, (uint_fast8_t) remaining); + tags_differ |= (expected_tag_chunk ^ (ctx->bufstate.sponge.x3 & ms_mask)); expected_tag += remaining; - // The last 8 or fewer bytes (also 0) expected_tag_len -= remaining; - remaining = MIN(sizeof(computed_tag_chunk), expected_tag_len); - bigendian_encode_varlen(computed_tag_chunk, ctx->bufstate.sponge.x4, (uint_fast8_t) remaining); - if (small_neq(computed_tag_chunk, expected_tag, remaining)) { return ASCON_TAG_INVALID; } - return ASCON_TAG_OK; + remaining = MIN(sizeof(expected_tag_chunk), expected_tag_len); + ms_mask = mask_most_signif_bytes((uint_fast8_t) remaining); + expected_tag_chunk = bigendian_decode_varlen(expected_tag, (uint_fast8_t) remaining); + tags_differ |= (expected_tag_chunk ^ (ctx->bufstate.sponge.x4 & ms_mask)); + return !tags_differ; // True if they are equal } ASCON_API void diff --git a/src/ascon_hash.c b/src/ascon_hash.c index 878b922..5b495e1 100644 --- a/src/ascon_hash.c +++ b/src/ascon_hash.c @@ -323,28 +323,29 @@ hash_final_matches(permutation_fptr permutation, ascon_permutation_12(&ctx->sponge); // Squeeze the digest from the inner state 8 bytes at the time to compare // it chunk by chunk with the expected digest - bool digests_differ = false; uint64_t expected_digest_chunk; + bool digests_differ = false; while (expected_digest_len > ASCON_RATE) { // Note: converting the expected digest from uint8_t[] to uint64_t // for a faster comparison. It has to be decoded explicitly to ensure // it works the same on all platforms, regardless of endianness. // Type-punning like `*(uint64_t*) expected_digest` is NOT portable. - expected_digest_chunk = bigendian_decode_u64(expected_digest); + // // Constant time comparison expected vs computed digest chunk + expected_digest_chunk = bigendian_decode_u64(expected_digest); digests_differ |= (expected_digest_chunk ^ ctx->sponge.x0); - // Permute and shift to next chunk - permutation(&ctx->sponge); expected_digest_len -= sizeof(expected_digest_chunk); expected_digest += sizeof(expected_digest_chunk); + // Permute and go to next chunk + permutation(&ctx->sponge); } - // Extract the remaining n most significant bytes of the two digest chunks - ctx->sponge.x0 &= mask_most_signif_bytes((uint_fast8_t) expected_digest_len); + // Extract the remaining n most significant bytes of expected/computed digests + const uint64_t ms_mask = mask_most_signif_bytes((uint_fast8_t) expected_digest_len); expected_digest_chunk = bigendian_decode_varlen( expected_digest, (uint_fast8_t) expected_digest_len); // Constant time comparison expected vs computed chunk - digests_differ |= (expected_digest_chunk ^ ctx->sponge.x0); + digests_differ |= (expected_digest_chunk ^ (ctx->sponge.x0 & ms_mask)); // Final security cleanup of the internal state and buffer. ascon_hash_cleanup(ctx); return !digests_differ; // True if they are equal From cb44577a8a125298ca2546d5327bfc3216d99b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Gu=C5=A1tin?= Date: Sat, 30 Apr 2022 14:59:38 +0200 Subject: [PATCH 05/11] Default to MinSizeRel build as it's faster than Release No reason known for this fenomenon. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8cfa31..0394c66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,9 +11,9 @@ project(LibAscon "Lightweight Authenticated Encryption & Hashing, \ also with Init-Update-Final paradigm.") -# Unless specified, by default create Release builds +# Default build type, if not specified explicitly with `-DCMAKE_BUILD_TYPE` if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) + set(CMAKE_BUILD_TYPE MinSizeRel) endif () set(CMAKE_EXPORT_COMPILE_COMMANDS ON) From ffa4461508a815825ea35ec7b4c40ca09b941634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Gu=C5=A1tin?= Date: Sat, 30 Apr 2022 15:02:21 +0200 Subject: [PATCH 06/11] Strip symbols of Release and MinSizeRel binaries As an example, the shared library (DLL) size dropped as follows - MinSizeRel: 106 kB (100%) --> 24 kB (22.6%) - Release: 114 kB (100%) --> 31 kB (27.2%) --- compiler_flags.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler_flags.cmake b/compiler_flags.cmake index defbd1c..bc0af4b 100644 --- a/compiler_flags.cmake +++ b/compiler_flags.cmake @@ -79,6 +79,7 @@ else () # Release mode optimised for speed string(APPEND CMAKE_C_FLAGS_RELEASE " -O3") # Max optimisation for speed + string(APPEND CMAKE_C_FLAGS_RELEASE " -s") # Strip symbols string(APPEND CMAKE_C_FLAGS_RELEASE " -Werror") # Warnings as errors string(APPEND CMAKE_C_FLAGS_RELEASE " -fomit-frame-pointer") string(APPEND CMAKE_C_FLAGS_RELEASE " -march=native") @@ -86,6 +87,7 @@ else () # Release mode optimised for size string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -Os") # Optimise for size + string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -s") # Strip symbols string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -fomit-frame-pointer") string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -march=native") string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -mtune=native") From 383b9b0ff14f37f5d0a014df454a6367383c5b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Gu=C5=A1tin?= Date: Sat, 30 Apr 2022 15:36:47 +0200 Subject: [PATCH 07/11] Enforce libascon.* as shared library file name on all toolchains --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0394c66..8650cb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ project(LibAscon # Default build type, if not specified explicitly with `-DCMAKE_BUILD_TYPE` if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE MinSizeRel) + message("CMAKE_BUILD_TYPE unspecified, defaulting to ${CMAKE_BUILD_TYPE}") endif () set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -122,14 +123,17 @@ target_include_directories(ascon128ahash PUBLIC inc/ PRIVATE src/) add_library(ascon80pqhash STATIC ${LIB_SRC_FILES_80pq} ${LIB_SRC_FILES_HASH}) target_include_directories(ascon80pqhash PUBLIC inc/ PRIVATE src/) -# Shared library (.dylib / .dll) +# Shared library (.so / .dylib / .dll) # Does not reuse the static library object files, as they are # recompiled in order to have position-independent code add_library(ascon SHARED ${LIB_SRC_FILES_FULL}) target_include_directories(ascon PUBLIC inc/ PRIVATE src/) set_target_properties(ascon PROPERTIES POSITION_INDEPENDENT_CODE ON - INTERPROCEDURAL_OPTIMISATION TRUE) + INTERPROCEDURAL_OPTIMISATION TRUE + # Remove any "msys-" and enforce the same lib name with all toolchains + PREFIX lib + OUTPUT_NAME ascon) # Copy test vectors files to build directory. # They are used by the test runner From c22fc9b41c223f59691139d70793b2476afa15e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Gu=C5=A1tin?= Date: Sat, 30 Apr 2022 15:38:55 +0200 Subject: [PATCH 08/11] Add more Doxygen options to produce a consistent result --- CMakeLists.txt | 64 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8650cb0..ee048e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,20 +190,69 @@ set_target_properties(ascon_benchmark PROPERTIES INTERPROCEDURAL_OPTIMISATION TRUE) # Doxygen documentation builder -find_package(Doxygen) +find_package(Doxygen OPTIONAL_COMPONENTS dot) if (DOXYGEN_FOUND) # Cmake's wrapper of Doxygen, constructing a doxyfile from the # DOXYGEN_* variables, which are mapped to the Doxygen variables. - set(DOXYGEN_GENERATE_HTML YES) - set(DOXYGEN_GENERATE_MAN YES) + + # Parts of the source documentation to work on + set(DOXYGEN_EXTRACT_ALL YES) + set(DOXYGEN_EXTRACT_PRIVATE NO) + set(DOXYGEN_EXTRACT_PRIV_VIRTUAL NO) + set(DOXYGEN_EXTRACT_PACKAGE NO) + set(DOXYGEN_EXTRACT_STATIC NO) + set(DOXYGEN_EXTRACT_LOCAL_CLASSES NO) + set(DOXYGEN_EXTRACT_LOCAL_METHODS NO) + set(DOXYGEN_EXTRACT_ANON_NSPACES NO) + set(DOXYGEN_INTERNAL_DOCS NO) + set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md) + set(DOXYGEN_IMAGE_PATH ${PROJECT_SOURCE_DIR}/images) + + # How to process the source code + set(DOXYGEN_INPUT_ENCODING UTF-8) + set(DOXYGEN_BRIEF_MEMBER_DESC YES) + set(DOXYGEN_REPEAT_BRIEF YES) set(DOXYGEN_JAVADOC_AUTOBRIEF YES) set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES) + set(DOXYGEN_MARKDOWN_SUPPORT YES) + set(DOXYGEN_TAB_SIZE 4) + + # Components and look of the output + set(DOXYGEN_OUTPUT_LANGUAGE English) + set(DOXYGEN_TOC_INCLUDE_HEADINGS 5) + set(DOXYGEN_AUTOLINK_SUPPORT YES) + set(DOXYGEN_HIDE_UNDOC_MEMBERS NO) + set(DOXYGEN_HIDE_UNDOC_CLASSES NO) + set(DOXYGEN_HIDE_IN_BODY_DOCS NO) set(DOXYGEN_SORT_MEMBER_DOCS NO) - set(DOXYGEN_IMAGE_PATH ${PROJECT_SOURCE_DIR}/images) + set(DOXYGEN_SORT_BRIEF_DOCS NO) + set(DOXYGEN_MAX_INITIALIZER_LINES 30) + #set(DOXYGEN_PROJECT_LOGO ) + + # Format of the output + set(DOXYGEN_GENERATE_HTML YES) + set(DOXYGEN_GENERATE_MAN YES) + + # Processing + set(DOXYGEN_NUM_PROC_THREADS 0) # As many as CPU cores + set(DOXYGEN_QUIET YES) + set(DOXYGEN_WARNINGS YES) + set(DOXYGEN_WARN_IF_UNDOCUMENTED YES) + set(DOXYGEN_WARN_IF_DOC_ERROR YES) + set(DOXYGEN_WARN_NO_PARAMDOC YES) + set(DOXYGEN_WARN_AS_ERROR YES) + if (DOT_FOUND) + set(DOXYGEN_DOT_PATH ) # Empty = find it in PATH + set(DOXYGEN_DOT_NUM_THREADS 0) # As many as CPU cores + set(DOXYGEN_CALL_GRAPH YES) + set(DOXYGEN_CALLER_GRAPH YES) + set(DOXYGEN_DIRECTORY_GRAPH YES) + endif() + + # Customisations set(DOXYGEN_ALIASES license="**License:**") - set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md) set(DOXYGEN_PREDEFINED WIN32 ASCON_INPUT_ASSERTS) - set(DOXYGEN_DOT_PATH ) # Empty = find it in PATH + doxygen_add_docs(ascon_doxygen # Do NOT build doxygen on make-all, to avoid polluting the stdout # List of input files for Doxygen @@ -211,7 +260,8 @@ if (DOXYGEN_FOUND) ${PROJECT_SOURCE_DIR}/LICENSE.md ${PROJECT_SOURCE_DIR}/AUTHORS.md ${PROJECT_SOURCE_DIR}/README.md - ${PROJECT_SOURCE_DIR}/CHANGELOG.md) + ${PROJECT_SOURCE_DIR}/CHANGELOG.md + COMMENT "Generating Doxygen documentation...") else (DOXYGEN_FOUND) message(WARNING "Doxygen not found. Cannot generate documentation.") endif (DOXYGEN_FOUND) From ed73b4416418c4b89abebc26385efb29864980a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Gu=C5=A1tin?= Date: Sat, 30 Apr 2022 16:34:57 +0200 Subject: [PATCH 09/11] Verify whether compiler flags are supported before using them This happens at cmake-configuration time and the results are cached. --- compiler_flags.cmake | 177 ++++++++++++++++++++++++++----------------- 1 file changed, 106 insertions(+), 71 deletions(-) diff --git a/compiler_flags.cmake b/compiler_flags.cmake index bc0af4b..44dc94e 100644 --- a/compiler_flags.cmake +++ b/compiler_flags.cmake @@ -3,113 +3,148 @@ set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) - message(STATUS "C compiler ID: ${CMAKE_C_COMPILER_ID}") +# https://cmake.org/cmake/help/latest/module/CheckCCompilerFlag.html +include(CheckCCompilerFlag) + +# Check if a compiler supports a flag, appending it to the proper flags +# variable. Cache the result so it's faster on the next config. +# Ispired by https://gist.github.com/jibsen/74c64ac50d7a37a3f5f329ccfc749970 +function(compflag COMPILER_FLAGS) + foreach(FLAG ${ARGN}) + # Create a string representing the compiler flag with only alphanumeric + # characters, so it's easy to cache + string(REGEX REPLACE "[^0-9A-Za-z]+" "_" + ACCEPTED "COMPILER_FLAG_ACCEPTED_${FLAG}") + # Verify whether the FLAG is accepted by the compiler. The result is + # cached into the ACCEPTED variable so the next configuration is fast. + check_c_compiler_flag("${FLAG}" ${ACCEPTED}) + if(${ACCEPTED}) + set(${COMPILER_FLAGS} "${${COMPILER_FLAGS}} ${FLAG}") + else() + set(COMPILER_FLAGS_REJECTED "${COMPILER_FLAGS_REJECTED} ${FLAG}") + endif() + endforeach() + # Copy local variables to outer scope + set(${COMPILER_FLAGS} "${${COMPILER_FLAGS}}" PARENT_SCOPE) + set(COMPILER_FLAGS_REJECTED "${COMPILER_FLAGS_REJECTED}" PARENT_SCOPE) +endfunction() + + if (MSVC) - message(STATUS "Using compiler flags for MSVC") - # Options specific for the Microsoft Visual C++ compiler CL + message(STATUS "Using compiler flags for Microsoft Visual C++ compiler CL (MSVC)") + # Activate a million warnings to have the cleanest possible code - string(APPEND CMAKE_C_FLAGS " -Wall") # Activate all warnings + compflag(CMAKE_C_FLAGS "-Wall") # Activate all warnings # (compared to GCC, this actually turns on ALL of the warnings, not just most) - string(APPEND CMAKE_C_FLAGS " -Qspectre") # Let the compiler inject Spectre mitigation code - string(APPEND CMAKE_C_FLAGS " -wd5045") # Suppress the warning about Spectre mitigation + compflag(CMAKE_C_FLAGS "-Qspectre") # Let the compiler inject Spectre mitigation code + + # Suppress the warning about Spectre mitigation. # The problem is that even when the Spectre mitigation flag is enabled, the warning about # the mitigation being required still appears, so we have to forcibly disable it. - string(APPEND CMAKE_C_FLAGS " -wd4996") # Suppress warning about deprecated stdio functions + compflag(CMAKE_C_FLAGS "-wd5045") + + # Suppress warning about deprecated stdio functions. # The warning notifies that the functions should be replaced with the safer C11 alternatives # fopen -> fopen_s, fscanf -> fscanf_s etc. Here they are only used in the test framework, # not in the Ascon implementation, so they are not critical. They are also used in a safe # manner to start with, given that the parsed data is fixed (the test vectors). # Finally, not every clib implements them, so we cannot assume the compilation succeeds # if we use them. Thus, better deactivated. - string(APPEND CMAKE_C_FLAGS " -wd4127") # Suppress warning about constant conditional expr. + compflag(CMAKE_C_FLAGS "-wd4996") + + # Suppress warning about constant conditional expr. # This warning only pops up in the test suite's checks of the Ascon context and state struct # sizes, which ARE constant. The tests are there just as a double-check, an assertion, # and must stay, so the warning is disabled. - string(APPEND CMAKE_C_FLAGS " -wd4710 -wd4711") # Suppress informational warning about inlining + compflag(CMAKE_C_FLAGS "-wd4127") + + # Suppress informational warning about inlining. # MSVC notifies with a warning when the optimised inlines/does not inline a function that # is not/is marked for inlining. The warning is informational, thus disabled. + compflag(CMAKE_C_FLAGS "-wd4710 -wd4711") # Debug mode - string(APPEND CMAKE_C_FLAGS_DEBUG " -Od") # Do not optimise + compflag(CMAKE_C_FLAGS_DEBUG "-Od") # Do not optimise # Release mode optimised for speed - string(APPEND CMAKE_C_FLAGS_RELEASE " -O2") # Optimise for speed - string(APPEND CMAKE_C_FLAGS_RELEASE " -WX") # Warnings as errors + compflag(CMAKE_C_FLAGS_RELEASE "-O2") # Optimise for speed + compflag(CMAKE_C_FLAGS_RELEASE "-WX") # Warnings as errors # Release mode optimised for size - string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -O1") # Optimise for size - string(APPEND CMAKE_C_FLAGS_RELEASE " -WX") # Warnings as errors + compflag(CMAKE_C_FLAGS_MINSIZEREL "-O1") # Optimise for size + compflag(CMAKE_C_FLAGS_RELEASE "-WX") # Warnings as errors else () message(STATUS "Using compiler flags for GCC and Clang") - # Options for other compilers (generally GCC and Clang) + # Activate a million warnings to have the cleanest possible code - string(APPEND CMAKE_C_FLAGS " -Wall -Wextra -pedantic") # Activate most warnings - string(APPEND CMAKE_C_FLAGS " -Wconversion") # Values are implicitly converted - string(APPEND CMAKE_C_FLAGS " -Wsign-conversion") # Signed to/from unsigned implicit conversion - string(APPEND CMAKE_C_FLAGS " -Wdouble-promotion") # Floats implicitly promoted to doubles - string(APPEND CMAKE_C_FLAGS " -Wfloat-equal") # Floats compared exactly instead of approx. - string(APPEND CMAKE_C_FLAGS " -Wswitch-default") # Switch-case missing default - string(APPEND CMAKE_C_FLAGS " -Wswitch-enum") # Switch-case of an enum not covering all values - string(APPEND CMAKE_C_FLAGS " -Wuninitialized") # Usage of uninitialised variable - string(APPEND CMAKE_C_FLAGS " -Wno-unused-variable") # Variable never used - string(APPEND CMAKE_C_FLAGS " -Wpacked") # Packing of struct not needed + compflag(CMAKE_C_FLAGS "-Wall -Wextra -pedantic") # Activate most warnings + compflag(CMAKE_C_FLAGS "-Wconversion") # Values are implicitly converted + compflag(CMAKE_C_FLAGS "-Wsign-conversion") # Signed to/from unsigned implicit conversion + compflag(CMAKE_C_FLAGS "-Wdouble-promotion") # Floats implicitly promoted to doubles + compflag(CMAKE_C_FLAGS "-Wfloat-equal") # Floats compared exactly instead of approx. + compflag(CMAKE_C_FLAGS "-Wswitch-default") # Switch-case missing default + compflag(CMAKE_C_FLAGS "-Wswitch-enum") # Switch-case of an enum not covering all values + compflag(CMAKE_C_FLAGS "-Wuninitialized") # Usage of uninitialised variable + compflag(CMAKE_C_FLAGS "-Wno-unused-variable") # Variable never used + compflag(CMAKE_C_FLAGS "-Wpacked") # Packing of struct not needed + # NOTE: deactivating padded struct warning: all structs in LibAscon have been inspected and # optimised. Some will still inevitably have trailing padding (to reach the aligned address # where the next struct in an array of structs would start) and this padding varies on each # platform. There is not much to be done anymore. - #string(APPEND CMAKE_C_FLAGS " -Wpadded") # Struct contains paddings - string(APPEND CMAKE_C_FLAGS " -Wshadow") # Shadowing variable name - string(APPEND CMAKE_C_FLAGS " -Waggregate-return") # Returning a struct from a function - string(APPEND CMAKE_C_FLAGS " -Wformat-security") # (s/f)printf format string vulnerability - string(APPEND CMAKE_C_FLAGS " -Wlogical-not-parentheses") # Unclear boolean expression - string(APPEND CMAKE_C_FLAGS " -Wmissing-declarations") # - string(APPEND CMAKE_C_FLAGS " -Wnull-dereference") # Potential NULL pointer dereference - - if ("${CMAKE_C_COMPILER_ID}" STREQUAL "gcc") - string(APPEND CMAKE_C_FLAGS " -Wduplicate-cond") # Checking same thing twice - string(APPEND CMAKE_C_FLAGS " -Wjump-misses-init") # Switch/goto jump skips variable init - endif () + #compflag(CMAKE_C_FLAGS "-Wpadded") # Struct contains paddings + + compflag(CMAKE_C_FLAGS "-Wshadow") # Shadowing variable name + compflag(CMAKE_C_FLAGS "-Waggregate-return") # Returning a struct from a function + compflag(CMAKE_C_FLAGS "-Wformat-security") # (s/f)printf format string vulnerability + compflag(CMAKE_C_FLAGS "-Wlogical-not-parentheses") # Unclear boolean expression + compflag(CMAKE_C_FLAGS "-Wmissing-declarations") # + compflag(CMAKE_C_FLAGS "-Wnull-dereference") # Potential NULL pointer dereference + compflag(CMAKE_C_FLAGS "-Wduplicate-cond") # Checking same thing twice + + # NOTE: deactivating goto warnings: they are used only within the test suite, not the library + #compflag(CMAKE_C_FLAGS "-Wjump-misses-init") # Switch/goto jump skips variable init # Debug mode - string(APPEND CMAKE_C_FLAGS_DEBUG " -g3") # Max debug info - string(APPEND CMAKE_C_FLAGS_DEBUG " -O0") # Do not optimise - string(APPEND CMAKE_C_FLAGS_DEBUG " -coverage") # Gather code coverage info + compflag(CMAKE_C_FLAGS_DEBUG "-g3") # Max debug info + compflag(CMAKE_C_FLAGS_DEBUG "-O0") # Do not optimise + compflag(CMAKE_C_FLAGS_DEBUG "-coverage") # Gather code coverage info # Release mode optimised for speed - string(APPEND CMAKE_C_FLAGS_RELEASE " -O3") # Max optimisation for speed - string(APPEND CMAKE_C_FLAGS_RELEASE " -s") # Strip symbols - string(APPEND CMAKE_C_FLAGS_RELEASE " -Werror") # Warnings as errors - string(APPEND CMAKE_C_FLAGS_RELEASE " -fomit-frame-pointer") - string(APPEND CMAKE_C_FLAGS_RELEASE " -march=native") - string(APPEND CMAKE_C_FLAGS_RELEASE " -mtune=native") + compflag(CMAKE_C_FLAGS_RELEASE "-O3") # Max optimisation for speed + compflag(CMAKE_C_FLAGS_RELEASE "-s") # Strip binary + compflag(CMAKE_C_FLAGS_RELEASE "-Werror") # Warnings as errors + compflag(CMAKE_C_FLAGS_RELEASE "-fomit-frame-pointer") + compflag(CMAKE_C_FLAGS_RELEASE "-march=native") + compflag(CMAKE_C_FLAGS_RELEASE "-mtune=native") # Release mode optimised for size - string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -Os") # Optimise for size - string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -s") # Strip symbols - string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -fomit-frame-pointer") - string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -march=native") - string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -mtune=native") - string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -funroll-loops") + compflag(CMAKE_C_FLAGS_MINSIZEREL "-Os") # Optimise for size + compflag(CMAKE_C_FLAGS_MINSIZEREL "-s") # Strip binary + compflag(CMAKE_C_FLAGS_MINSIZEREL "-fomit-frame-pointer") + compflag(CMAKE_C_FLAGS_MINSIZEREL "-march=native") + compflag(CMAKE_C_FLAGS_MINSIZEREL "-mtune=native") + compflag(CMAKE_C_FLAGS_MINSIZEREL "-funroll-loops") endif () # Options for all compilers -string(APPEND CMAKE_C_FLAGS " ") -string(APPEND CMAKE_C_FLAGS_DEBUG " -DDEBUG") -string(APPEND CMAKE_C_FLAGS_RELEASE " -DRELEASE") -string(APPEND CMAKE_C_FLAGS_MINSIZEREL " -DMINSIZEREL") - -# Append sanitiser flags on non-Windows systems -if (NOT WIN32 AND NOT CYGWIN AND NOT MSYS) - if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" - OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") - string(APPEND CMAKE_C_FLAGS_DEBUG " -static-libsan") # Note: san, not Asan - - else () # GCC - string(APPEND CMAKE_C_FLAGS_DEBUG " -static-libasan") # Note: Asan, not san - - endif () - string(APPEND CMAKE_C_FLAGS_DEBUG " -fsanitize=address,undefined") - string(APPEND CMAKE_C_FLAGS_DEBUG " -fno-omit-frame-pointer") - string(APPEND CMAKE_C_FLAGS_DEBUG " -mno-omit-leaf-frame-pointer") -endif () +compflag(CMAKE_C_FLAGS "") +compflag(CMAKE_C_FLAGS_DEBUG "-DDEBUG") +compflag(CMAKE_C_FLAGS_RELEASE "-DRELEASE") +compflag(CMAKE_C_FLAGS_MINSIZEREL "-DMINSIZEREL") +# Sanitiser flags +compflag(CMAKE_C_FLAGS_DEBUG "-static-libsan") # Note: san, not Asan, for GCC +compflag(CMAKE_C_FLAGS_DEBUG "-static-libasan") # Note: Asan, not san, for Clang +compflag(CMAKE_C_FLAGS_DEBUG "-fsanitize=address,undefined") +compflag(CMAKE_C_FLAGS_DEBUG "-fno-omit-frame-pointer") +compflag(CMAKE_C_FLAGS_DEBUG "-mno-omit-leaf-frame-pointer") + +# Some information for the user +message(STATUS "Accepted compiler flags: CMAKE_C_FLAGS = ${CMAKE_C_FLAGS}") +message(STATUS "Accepted compiler flags: CMAKE_C_FLAGS_DEBUG = ${CMAKE_C_FLAGS_DEBUG}") +message(STATUS "Accepted compiler flags: CMAKE_C_FLAGS_RELEASE = ${CMAKE_C_FLAGS_RELEASE}") +message(STATUS "Accepted compiler flags: CMAKE_C_FLAGS_MINSIZEREL = ${CMAKE_C_FLAGS_MINSIZEREL}") +if (COMPILER_FLAGS_REJECTED) + message(STATUS "Rejected compiler flags: COMPILER_FLAGS_REJECTED = ${COMPILER_FLAGS_REJECTED}") +endif() From 8e158e06040f3cb9b51779a7313fc7cdba803389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Gu=C5=A1tin?= Date: Sat, 30 Apr 2022 17:02:44 +0200 Subject: [PATCH 10/11] Revert binary stripping: problematic with Clang Should use the `strip` executable instead, where possible. --- compiler_flags.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler_flags.cmake b/compiler_flags.cmake index 44dc94e..bc2bc0d 100644 --- a/compiler_flags.cmake +++ b/compiler_flags.cmake @@ -114,7 +114,6 @@ else () # Release mode optimised for speed compflag(CMAKE_C_FLAGS_RELEASE "-O3") # Max optimisation for speed - compflag(CMAKE_C_FLAGS_RELEASE "-s") # Strip binary compflag(CMAKE_C_FLAGS_RELEASE "-Werror") # Warnings as errors compflag(CMAKE_C_FLAGS_RELEASE "-fomit-frame-pointer") compflag(CMAKE_C_FLAGS_RELEASE "-march=native") @@ -122,7 +121,6 @@ else () # Release mode optimised for size compflag(CMAKE_C_FLAGS_MINSIZEREL "-Os") # Optimise for size - compflag(CMAKE_C_FLAGS_MINSIZEREL "-s") # Strip binary compflag(CMAKE_C_FLAGS_MINSIZEREL "-fomit-frame-pointer") compflag(CMAKE_C_FLAGS_MINSIZEREL "-march=native") compflag(CMAKE_C_FLAGS_MINSIZEREL "-mtune=native") From 9f2b36d0debc308f1b45303ed96aee973532b0e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Gu=C5=A1tin?= Date: Sat, 30 Apr 2022 17:18:30 +0200 Subject: [PATCH 11/11] Bump version to v1.2.1, add changelog for it --- CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- README.md | 16 +++++++++++----- inc/ascon.h | 4 ++-- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d10ca5..1a55a73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,39 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ******************************************************************************* +[1.2.1] - 2022-04-30 +---------------------------------------- + +Constant-time tag/digest validation against timing attacks, improved CMake +portability. + +### Fixed + +#### Security + +- Use constant-time tag/digest validation to offer some resistance against + timing attacks. Applies to all decryption functions + (`ascon_aead*_decrypt*()`) and all hashing functions which compare + the generated digest to the expected (`ascon_hash_*_matches()`). + +#### Cross-platform portability + +- Enforced name `libascon.{dll|so|dylib}` for the shared library, so it's the + same when built with any toolchain. +- CMake will not verify whether a compiler supports a flag before using it. + This makes the CMake configuration phase slightly longer, but the result + is cached, so it happens only the first time. +- CMake now defaults to `MinSizeRel` build type if `CMAKE_BUILD_TYPE` is not + specified, because binary size matters more than speed for a cross-platform + implementation. Additionaly, on some platforms it overperforms the + `Release` build. +- Explicitly setting many Doxygen settings. + +#### Internal changes + +- Simplified Ascon permutation code, to increase its readability. +- Internal function `byte_mask()` renamed to `mask_most_signif_bytes()`. + [1.2.0] - 2022-02-05 ---------------------------------------- diff --git a/CMakeLists.txt b/CMakeLists.txt index ee048e6..1b2a223 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.9) project(LibAscon - VERSION 1.2.0 + VERSION 1.2.1 LANGUAGES C DESCRIPTION "Lightweight Authenticated Encryption & Hashing, \ diff --git a/README.md b/README.md index 57e7492..9538823 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,19 @@ associated data (AEAD) and hashing functions, but it also includes Init-Update-Final processing and variable tag length. Heavily tested and ready for embedded systems! -### Disclaimer +### Security disclaimer -This is not a security-hardened implementation, just a simple one focused -mostly on usability, portability and high(er) set of features There is no added -protection against side-channel attacks other than what the Ascon algorithm -itself provides by design. +This is **not a security-hardened implementation**, just a simple one, focused +mostly on usability, portability, and high(er) set of features compared to the +reference implementation. There is no explicit protection against side-channel +attacks other than what the Ascon algorithm itself provides by design. +Nevertheless, this implementation: + +- uses constant-time operations (should help against timing attacks), +- **tries** to force the compiler to actually clear sensitive data instead of + optimising the operations away (this is hard to achieve properly), +- has 100% line and 100% branch test coverage. Features ---------------------------------------- diff --git a/inc/ascon.h b/inc/ascon.h index d3e8219..8261ebe 100644 --- a/inc/ascon.h +++ b/inc/ascon.h @@ -99,9 +99,9 @@ extern "C" /** Minor version of this API conforming to semantic versioning. */ #define ASCON_API_VERSION_MINOR 2 /** Bugfix/patch version of this API conforming to semantic versioning. */ -#define ASCON_API_VERSION_BUGFIX 0 +#define ASCON_API_VERSION_BUGFIX 1 /** Version of this API conforming to semantic versioning as a string. */ -#define ASCON_API_VERSION "1.2.0" +#define ASCON_API_VERSION "1.2.1" /** * Length in bytes of the secret symmetric key used for the Ascon128 cipher.