diff --git a/.editorconfig b/.editorconfig index 3db26ea..656931f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,6 +17,11 @@ tab_width = 4 max_line_length = 100 trim_trailing_whitespace = true +[{*.md, *.markdown}] +max_line_length = 79 +trim_trailing_whitespace = false +indent_size = 3 +tab_width = 3 [{*.yml, *.yaml, *.json, *.md}] indent_size = 2 diff --git a/.gitignore b/.gitignore index feaa84a..dd4a4bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea cmake-build-* -build +build* original +ideas.md diff --git a/AUTHORS.md b/AUTHORS.md index acf10b0..48436f1 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -8,14 +8,12 @@ The [Ascon cipher](https://ascon.iaik.tugraz.at/) is designed by: - Florian Mendel - Martin Schläffer - The [reference C implementation](https://github.com/ascon/ascon-c), on which this reimplementation is based upon, is made by: - Christoph Dobraunig - Martin Schläffer - [This reimplementation](https://github.com/TheMatjaz/LibAscon) is made by: - Matjaž Guštin diff --git a/CHANGELOG.md b/CHANGELOG.md index db813c5..9fbefc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,50 +4,69 @@ Changelog All notable changes to this project will be documented in this file. The format is based on -[Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to -[Semantic Versioning](https://semver.org/spec/v2.0.0.html). +[Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project +adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ******************************************************************************* +[1.1.2] - 2022-02-04 +---------------------------------------- + +Fix new compiler warnings appearing in GCC v11. + +### Fixed + +- Fix GCC v11 warnings about `uint8*` vs `uint8[]` data types differing in + signature of function declaration and definition. It was working fine so far, + apparently now the compiler wants them to be consistent, so they now are. + Arrays were chosen as data type (although they are just pointers behind the + scenes), so the known, constant length of the binary key/nonce can be + explicitly indicated for code clarity, following the recommended practice + from the MISRA-C standard. +- Fixed GCC v11 warning appearing only in Release mode about the internal + `small_cpy()` function "writing 1 byte into a region of size 0" + `[-Werror=stringop-overflow=]` +- Fixed `ascon_aead_common.c` file mentioning BSD license and full copyright + statement, when the project is CC0 (new-file-template error). +- Auto-formatting `benchmark.c` and some markdown files, including this + changelog. +- Simplify assert macro usage in the codebase: make it do nothing when off, + thus the `#ifdef ASCON_INPUT_ASSERTS ... #endif` condition can be removed. + [1.1.1] - 2021-05-17 ---------------------------------------- Compilation fixes for some GCC versions, added `ascon_` to some internal target names to avoid name clashing. - ### Fixed -- Avoid type-punning when clearing the context and when comparing the - expected and computed tag/digest, which may cause compilation errors +- Avoid type-punning when clearing the context and when comparing the expected + and computed tag/digest, which may cause compilation errors with `-Werror=strict-aliasing` in some GCC versions. - Renamed some build targets to avoid name collisions when including the whole LibAscon project into another CMake project with `add_subdirectory()` - `doxygen` -> `ascon_doxygen` - `benchmark` -> `ascon_benchmark` - `copytestvectors` -> `ascon_copytestvectors` - As these are all internal targets, it should hopefully not affect the - library user. - - + As these are all internal targets, it should hopefully not affect the + library user. [1.1.0] - 2021-05-11 ---------------------------------------- -New hashing functions comparing the expected and computed digest, -support for virtually any tag and digest size, removed dependencies `malloc.h` -and `string.h`, better context cleanup, optional asserts validating the -library input. - +New hashing functions comparing the expected and computed digest, support for +virtually any tag and digest size, removed dependencies `malloc.h` +and `string.h`, better context cleanup, optional asserts validating the library +input. ### Added - 4 new hash functions that compute the digest of a message and compare it with the expected one, informing the user if they match. This is done with constant stack memory usage, like the AEAD functions now validate the tags - too. The functions need the data and the expected digest as input, - providing a boolean as output, indicating whether the digest matches or not. + too. The functions need the data and the expected digest as input, providing + a boolean as output, indicating whether the digest matches or not. - `ascon_hash_matches()` and `ascon_hash_xof_matches()` to validate the digest of a contiguous message. - `ascon_hash_final_matches()` and `ascon_hash_xof_final_matches()` to @@ -55,9 +74,9 @@ library input. removing the need from the user to call `ascon_hash_final()` or `ascon_hash_xof_final()` and run `memcmp()` on the just calculated digest. -- **Optional** runtime asserts to validate the argument of the - library API functions, mostly checking for NULL pointers and correct - order of calling of the Init-Update-Final functions. +- **Optional** runtime asserts to validate the argument of the library API + functions, mostly checking for NULL pointers and correct order of calling of + the Init-Update-Final functions. - Suggested use only in Debug mode. - Uses `assert.h` by default, but can be overridden by defining `ASCON_ASSERT` at compile time too. @@ -70,22 +89,20 @@ library input. - Offline encryption/decryption of contiguous data. - Hashing functions, including new digest-comparison functions. - ### Changed - Library internals (not impacting API): - The AEAD tag validation is not performed one chunk of 8 bytes at the time - rather than generating the whole contiguous tag from the user-given data and - comparing it in its entirety (`memcmp()`) with the user-given tag. - This implies that tag lengths don't have a physical limitation anymore + rather than generating the whole contiguous tag from the user-given data + and comparing it in its entirety (`memcmp()`) with the user-given tag. This + implies that tag lengths don't have a physical limitation anymore (previously tag lengths > 64 bytes were discouraged). - Renamed state variable `ascon_bufstate_t.assoc_data_state` to `ascon_bufstate_t.flow_state`. - Enlarged state enum `ascon_flow_t`. - Renamed `const uint8_t* tag` parameter in AEAD function to `expected_tag` - to emphasise that is the one that comes next to the ciphertext. - It's length is now similarly `expected_tag_len`. - + to emphasise that is the one that comes next to the ciphertext. It's length + is now similarly `expected_tag_len`. ### Removed @@ -97,7 +114,6 @@ library input. `memset()`/`memset_s()` (see Fixed section) not being used anymore, the library is not used. - ### Fixed - The clearing of the context, both for AEAD and hash functions is performed @@ -110,46 +126,42 @@ library input. - Better copying of the test vectors to the build directory: use a custom target, set it as a dependency to `testascon` and `testasconshared` to avoid issues on some systems. - - Building with CMake should now work properly when using LibAscon in a - Git Submodule. + - Building with CMake should now work properly when using LibAscon in a Git + Submodule. - Small fixes in the hash/XOF function tests. - - [1.0.3] - 2021-05-08 ---------------------------------------- Support for compilation on Windows with MSVC, other CMake improvements. -Thanks to [mataron](https://github.com/mataron) for providing the initial -fixes for MSVC! - +Thanks to [mataron](https://github.com/mataron) for providing the initial fixes +for MSVC! ### Added - Enable `ctest` command to run the test executables. - Added `.editorconfig` for a portable text editing configuration. - ### Fixed - All `tag_len` parameters in the library API now are of type `size_t` - instead of `uint8_t` so that `sizeof()` can be used on the tag buffers. - As the tags are internally allocated on the stack, the lengths should not - be excessive (e.g. anything above 64 B = 512 bit is already a lot for - security purposes). + instead of `uint8_t` so that `sizeof()` can be used on the tag buffers. As + the tags are internally allocated on the stack, the lengths should not be + excessive (e.g. anything above 64 B = 512 bit is already a lot for security + purposes). - LibAscon now successfully compiles with CL (MSVC) on Windows: - Fixed errors due to inlining of static function into exposed functions. - Fixed errors at link time as the linker did not find the library's public API functions: now a `ASCON_API` macro is set to export their symbols properly (does nothing on any other OS) with `__declspec(dllexport)`. - - Use `_malloca()` and `_freea()` to declare arrays on the stack without - a constant length at compile-time. - - Fixed a variety of compiler warnings and errors for the test suite code - and benchmark executable, including paddings, Spectre mitigations, - inlining notifications, incorrect macro checking. + - Use `_malloca()` and `_freea()` to declare arrays on the stack without a + constant length at compile-time. + - Fixed a variety of compiler warnings and errors for the test suite code and + benchmark executable, including paddings, Spectre mitigations, inlining + notifications, incorrect macro checking. - Moved compiler flag settings to a separate CMake file: `compiler_flags.cmake` - Improved support for GCC vs. Clang differences in the compiler flags @@ -157,25 +169,21 @@ fixes for MSVC! - Replaced Travis CI with GitHub Actions CI: - Support for MSVC compilation using CL on Windows - - [1.0.2] - 2021-04-30 ---------------------------------------- -CMake and build process improvements, 4 new targets, minor fix to avoid unwanted -compiler optimisations. - +CMake and build process improvements, 4 new targets, minor fix to avoid +unwanted compiler optimisations. ### Added - Add static build targets `ascon128hash`, `ascon128ahash`, `ascon80pqhash` - which compile to static libraries with the indicated AEAD cipher and - the Ascon-Hash/Xof functions. Useful to avoid setting manual compile targets - when only one cipher and the hash functions are needed. + which compile to static libraries with the indicated AEAD cipher and the + Ascon-Hash/Xof functions. Useful to avoid setting manual compile targets when + only one cipher and the hash functions are needed. - Add test runner which tests the shared library build target `testasconshared` to check that everything works also with dynamic linking. - ### Fixed - Prefer `memset_s` when available to clear the context, as `memset` may be @@ -194,31 +202,27 @@ compiler optimisations. - Enable parallel make-all. - Install MSYS2 and use GCC on Windows to compile properly. - - [1.0.1] - 2020-05-30 ---------------------------------------- Fixed slowdowns - now as fast as reference implementation, 100% test coverage. - ### Fixed -- Fixed 2x slowdown compared to original reference implementation by - unrolling loops in `ascon_permutation_[a12|b8|b6]`. Apparently the - compiler does not do that automatically, even when requested with - `-funroll-loops`. - This brings LibAscon to the same performance as the reference implementation, - when compiled in _Release_ mode. +- Fixed 2x slowdown compared to original reference implementation by unrolling + loops in `ascon_permutation_[a12|b8|b6]`. Apparently the compiler does not do + that automatically, even when requested with + `-funroll-loops`. This brings LibAscon to the same performance as the + reference implementation, when compiled in _Release_ mode. -- When building in _MinSizeRel_ mode (`-DCMAKE_BUILD_TYPE=MinSizeRel`), the core - round and permutation functions are not hinted to be inlined by the compiled, - thus the library takes slightly less space. +- When building in _MinSizeRel_ mode (`-DCMAKE_BUILD_TYPE=MinSizeRel`), the + core round and permutation functions are not hinted to be inlined by the + compiled, thus the library takes slightly less space. - Replaced rewritten benchmark runner with original one (copy-pasted and slightly changed). Apparently the rewritten benchmark was about 2x slower. - Now the benchmark results are comparable between original implementation - and LibAscon. + Now the benchmark results are comparable between original implementation and + LibAscon. - Test coverage reached 100%: removed a dead branch in `ascon_aead80pq_decrypt_final()`, which was a copy-paste error. @@ -228,18 +232,15 @@ Fixed slowdowns - now as fast as reference implementation, 100% test coverage. - Removed unused internal `log_sponge()` function, making the library slightly smaller. -- Add initial Travis-CI script for a few builds. Some are still failing, but the - reasons seems to be in the system configuration or old compiler versions +- Add initial Travis-CI script for a few builds. Some are still failing, but + the reasons seems to be in the system configuration or old compiler versions or "linker not found", not in the LibAscon source code. - - [1.0.0] - 2020-05-21 ---------------------------------------- First stable version with all ciphers. - ### Modified - **Breaking** change from previous versions: removed `total_output_len` @@ -248,19 +249,18 @@ First stable version with all ciphers. - `ascon_aead*_decrypt()` - `ascon_aead*_encrypt_final()` - `ascon_aead*_decrypt_final()` - and from the `ascon_bufstate_t` struct, making it 8 B smaller. - Why? TL;DR it's redundant. + and from the `ascon_bufstate_t` struct, making it 8 B smaller. Why? TL;DR + it's redundant. The reasoning is that the user of the first two (offline processing) already knows the length of the plaintext/ciphertext; the user of the second - two obtains the length of the processed chunks as return values so they - can simply sum the up - and anyhow the user known the length of all the - chunks provided to the cipher; those could be summed up to. In most of the - cases the argument was `NULL` in the function usage. For details on how to - obtain the total length, the example in the Readme should suffice. + two obtains the length of the processed chunks as return values so they can + simply sum the up - and anyhow the user known the length of all the chunks + provided to the cipher; those could be summed up to. In most of the cases the + argument was `NULL` in the function usage. For details on how to obtain the + total length, the example in the Readme should suffice. - Renamed all files in `src` so they start with `ascon_`. - ### Fixed - Added more tests to cover more branching cases of the online-buffering @@ -268,99 +268,85 @@ First stable version with all ciphers. - Removal of some minor warnings after inspection with static analyser (`scan-build`) and CLion code inspection tool. - Typos -- Added missing _Known limitations_ paragraphs to the previous releases - in this Changelog. - +- Added missing _Known limitations_ paragraphs to the previous releases in this + Changelog. ### Known limitations -- Because LibAscon is implemented with reuse of existing functions in mind, - in order to spare on code size and with the Init-Update-Digest paradigm, - which has some internal buffering, the cipher is about **4x slower** than the +- Because LibAscon is implemented with reuse of existing functions in mind, in + order to spare on code size and with the Init-Update-Digest paradigm, which + has some internal buffering, the cipher is about **4x slower** than the [reference implementation (`ref`)](https://github.com/ascon/ascon-c). - There is no architecture-specific optimisation, only a generic portable implementation using mostly `uint64_t` data types. - - [0.4.0] - 2020-05-20 ---------------------------------------- Added Ascon80pq cipher, example in Readme. - ### Added - `ascon_aead128a_*` functions, working exactly as the `aead128` versions. Internally they absorb the data with a double rate. - Example encryption and decrpytion code into Readme. - ### Removed -- Macros to exclude some parts of the library from the previous version, - as they only complicate the building process. It's easier to exclude some - source files from the build, now that they are better organised. +- Macros to exclude some parts of the library from the previous version, as + they only complicate the building process. It's easier to exclude some source + files from the build, now that they are better organised. - `ASCON_COMPILE_AEAD128` - `ASCON_COMPILE_AEAD128a` - `ASCON_COMPILE_AEAD80pq` - -` ASCON_COMPILE_HASH` - + -` ASCON_COMPILE_HASH` ### Known limitations -- Because LibAscon is implemented with reuse of existing functions in mind, - in order to spare on code size and with the Init-Update-Digest paradigm, - which has some internal buffering, the cipher is about **4x slower** than the +- Because LibAscon is implemented with reuse of existing functions in mind, in + order to spare on code size and with the Init-Update-Digest paradigm, which + has some internal buffering, the cipher is about **4x slower** than the [reference implementation (`ref`)](https://github.com/ascon/ascon-c). - There is no architecture-specific optimisation, only a generic portable implementation using mostly `uint64_t` data types. - - [0.3.0] - 2020-05-20 ---------------------------------------- Added Ascon128a cipher and macros to exclude some parts of the library. - ### Added - `ascon_aead128a_*` functions, working exactly as the `aead128` versions. Internally they absorb the data with a double rate. -- Added macros to exclude some parts of the library if they are not needed - for a smaller build +- Added macros to exclude some parts of the library if they are not needed for + a smaller build - `ASCON_COMPILE_AEAD128` - `ASCON_COMPILE_AEAD128a` - `ASCON_COMPILE_AEAD80pq` (which is not included in the lib yet) - -` ASCON_COMPILE_HASH` - + -` ASCON_COMPILE_HASH` ### Known limitations -- Because LibAscon is implemented with reuse of existing functions in mind, - in order to spare on code size and with the Init-Update-Digest paradigm, - which has some internal buffering, the cipher is about **4x slower** than the +- Because LibAscon is implemented with reuse of existing functions in mind, in + order to spare on code size and with the Init-Update-Digest paradigm, which + has some internal buffering, the cipher is about **4x slower** than the [reference implementation (`ref`)](https://github.com/ascon/ascon-c). - There is no architecture-specific optimisation, only a generic portable implementation using mostly `uint64_t` data types. - The only AEAD algorithms implemented are Ascon128 and Ascon128a. Ascon80pq is still to be done. - - [0.2.0] - 2020-05-17 ---------------------------------------- Variable tags length, secure context cleanup, minor QOL improvements. - ### Added -- `ascon_aead128_cleanup()` and `ascon_hash_cleanup()` to securely cleanup - the context in case the online processing is not terminated with the - final function. - +- `ascon_aead128_cleanup()` and `ascon_hash_cleanup()` to securely cleanup the + context in case the online processing is not terminated with the final + function. ### Changed @@ -380,31 +366,26 @@ Variable tags length, secure context cleanup, minor QOL improvements. - Because of the previous point: `srtbool.h` as now a dependency. -- Changed ISO C standard for compilation from C99 to C11, as there are - no noticeable differences for this codebase. - +- Changed ISO C standard for compilation from C99 to C11, as there are no + noticeable differences for this codebase. ### Fixed - Improvements in the Doxygen documentation, especially the security warnings. -- Some warnings about type casting when compiling on GCC for Windows or - ARM microcontrollers with strict warning settings (`-Wall`, `-Wextra` etc.). +- Some warnings about type casting when compiling on GCC for Windows or ARM + microcontrollers with strict warning settings (`-Wall`, `-Wextra` etc.). - Variety of typos and linter warnings. - Minor readme improvements. - ### Known limitations - Same as in v0.1.0 - - [0.1.0] - 2020-02-11 ---------------------------------------- Initial version. - ### Added - AEAD encryption and decryption with Ascon128, both offline and online @@ -412,16 +393,15 @@ Initial version. - Test suite checking against test vectors - Wrapping everything with single extensively documented header file - ### Known limitations -- At the moment the library is **optimised for size**, making the cipher - about 4x slower than the - [reference implementation](https://github.com/ascon/ascon-c). - On the other hand the size of the whole library is about 2x smaller than the - AEAD-Ascon128 implementation alone, while the library includes online - processing, Ascon-Hash and Ascon-XOF. -- There is no architecture-specific optimisation yet, only a generic portable - C implementation using mostly `uint64_t` data types. +- At the moment the library is **optimised for size**, making the cipher about + 4x slower than the + [reference implementation](https://github.com/ascon/ascon-c). On the other + hand the size of the whole library is about 2x smaller than the AEAD-Ascon128 + implementation alone, while the library includes online processing, + Ascon-Hash and Ascon-XOF. +- There is no architecture-specific optimisation yet, only a generic portable C + implementation using mostly `uint64_t` data types. - The only AEAD algorithm implemented is the Ascon128 AEAD. The Ascon128a and Ascon80pq are still to be done. diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d2f8ab..c94ed1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.9) project(LibAscon - VERSION 1.1.1 + VERSION 1.1.2 LANGUAGES C DESCRIPTION "Lightweight Authenticated Encryption & Hashing, \ @@ -197,6 +197,7 @@ if (DOXYGEN_FOUND) 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 diff --git a/README.md b/README.md index 06c668d..bd1fbe2 100644 --- a/README.md +++ b/README.md @@ -10,16 +10,15 @@ LibAscon is an ISO C99/C11 cryptographic library wrapping the [reference C implementation](https://github.com/ascon/ascon-c) of the Ascon family of lightweight authenticated encryption schemes with 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! - +Init-Update-Final processing and variable tag length. Heavily tested and ready +for embedded systems! ### 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. +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. Features @@ -37,13 +36,13 @@ LibAscon provides: - Ascon-XOF v1.2 (variable-length output) - **Online processing** (**Init-Update-Final** paradigm) for hashing and - encryption/decryption. This means that the data can be processed one - chunk at the time. Useful when operating on large amounts of data that are - not available contiguously in memory, e.g. a too-large file or data in + encryption/decryption. This means that the data can be processed one chunk at + the time. Useful when operating on large amounts of data that are not + available contiguously in memory, e.g. a too-large file or data in transmission. -- **Offline processing** (whole data contiguous in memory) is also - available with a simple wrapper. +- **Offline processing** (whole data contiguous in memory) is also available + with a simple wrapper. - **Variable tag length** for authenticated encryption: can generate any tag length. Of course at least 16 bytes (128 bits) is recommended. @@ -57,17 +56,16 @@ LibAscon provides: - AEAD tag may be provided to a **separate location**, i.e. not concatenated to the ciphertext. -- Same performance as the original C implementation in _Release_ mode, - about 2x slower in _MinSizeRel_ mode. +- Same performance as the original C implementation in _Release_ mode, about 2x + slower in _MinSizeRel_ mode. - A **[heavily documented](https://thematjaz.github.io/LibAscon/) - developer-friendly API**, making it easier to compile and add to your project, - both through static and dynamic inclusion. + developer-friendly API**, making it easier to compile and add to your + project, both through static and dynamic inclusion. - Tested with **100% line coverage**, with CI running on Linux, macOS and Windows with GCC, Clang and CL (MSVC). - Usage example ---------------------------------------- @@ -266,9 +264,9 @@ Only the C standard library, mostly C99 features: Optional dependency: `assert.h`, for `assert()`. Used to add runtime checks of the Ascon API input for debugging (NULL pointers and incorrect order of -function calling). The CMake script uses it only if `assert.h` is found -and only in the debug build type (`CMAKE_BUILD_TYPE=Debug`). -If compiled without the included `CMakeLists.txt`, it's not used unless +function calling). The CMake script uses it only if `assert.h` is found and +only in the debug build type (`CMAKE_BUILD_TYPE=Debug`). If compiled without +the included `CMakeLists.txt`, it's not used unless `ASCON_INPUT_ASSERTS` is defined at compile time. The assertion function `ASCON_ASSERT` can also be changed, if `assert()` is not available. @@ -288,23 +286,23 @@ FAQ - **Q**: Where is the documentation? - **A**: The [library header file `inc/ascon.h`](inc/ascon.h) is documented with - Doxygen and you can find it + **A**: The [library header file `inc/ascon.h`](inc/ascon.h) is documented + with Doxygen and you can find it [compiled here](https://thematjaz.github.io/LibAscon/). - **Q**: Why should I use Ascon-AEAD instead of, say, AES? **A**: Ascon is designed to be lightweight (great for embedded systems) and - natively supports authenticated encryption of data of any length, while - AES must be wrapped in an AEAD mode such as AES-GCM, which is well-proven - but heavier. + natively supports authenticated encryption of data of any length, while AES + must be wrapped in an AEAD mode such as AES-GCM, which is well-proven but + heavier. - **Q**: Why should I use Ascon-Hash instead of, say, SHA-256? **A**: Ascon is designed to be lightweight (great for embedded systems) and does not suffer from length-extension attacks as SHA-256, given its - sponge construction (similarly to what SHA-3 does). Additionally Ascon - offers also the XOF hashing producing digests of variable length. + sponge construction (similarly to what SHA-3 does). Additionally Ascon offers + also the XOF hashing producing digests of variable length. - **Q**: Who designed Ascon? Who wrote this library? @@ -312,21 +310,19 @@ FAQ - **Q**: I don't trust Ascon. - **A**: Good. You should not keep your guard up for everything, but Ascon - has been selected as the primary choice for lightweight authenticated - encryption in the final portfolio of the + **A**: Good. You should not keep your guard up for everything, but Ascon has + been selected as the primary choice for lightweight authenticated encryption + in the final portfolio of the [CAESAR competition (2014–2019)](https://competitions.cr.yp.to/caesar-submissions.html) and is currently competing in the - [NIST Lightweight Cryptography competition (2019–)](https://csrc.nist.gov/projects/lightweight-cryptography). - Cryptographers like it and that's a good sign, right? + [NIST Lightweight Cryptography competition (2019–)](https://csrc.nist.gov/projects/lightweight-cryptography) + . Cryptographers like it and that's a good sign, right? - **Q**: I don't trust this implementation. - **A**: Good, again. You can read the source code to see what it - does to be sure ;) If you find any bugs or possible improvements, - open a pull request or an issue. I would like to make as clear and as good - as possible. - + **A**: Good, again. You can read the source code to see what it does to be + sure ;) If you find any bugs or possible improvements, open a pull request or + an issue. I would like to make as clear and as good as possible. Known limitations ---------------------------------------- @@ -334,19 +330,17 @@ Known limitations - There is no architecture-specific optimisation, only a generic portable implementation using mostly `uint64_t` data types. - Compiling ---------------------------------------- -The project's compilation has been tested with GCC, Clang and CL (MSVC). -Most compiler warnings have already been mitigated, so they hopefully don't -occur on your platform. - +The project's compilation has been tested with GCC, Clang and CL (MSVC). Most +compiler warnings have already been mitigated, so they hopefully don't occur on +your platform. ### Static source inclusion -The project is relatively small, so you can simply include it into yours -as a Git Subtree, Git Submodule or by simply copy-pasting the `inc` and `src` +The project is relatively small, so you can simply include it into yours as a +Git Subtree, Git Submodule or by simply copy-pasting the `inc` and `src` folders. Be sure to: - Add `inc` and `src` to the include folders list @@ -354,7 +348,6 @@ folders. Be sure to: - Add `src` to the sources folders list. - Compile. - ### Compiling Ascon into all possible targets with CMake A note if you are compiling on Windows from the command line: @@ -382,22 +375,24 @@ This will build all useful targets: - `asconhash` with only Ascon-hash and Ascon-XOF - `ascon128hash` with only Ascon128, Ascon-hash and Ascon-XOF - `ascon128ahash` with only Ascon128a, Ascon-hash and Ascon-XOF - - `ascon80pqhash` with only Ascon80pq, Ascon-hash and Ascon-XOF - for a smaller build result when not all features are needed + - `ascon80pqhash` with only Ascon80pq, Ascon-hash and Ascon-XOF for a smaller + build result when not all features are needed - `ascon` a shared library (`.dll` or `.dylib` or `.so`) with full feature set (like `asconfull`, but shared) -- `testascon` a test runner executable , which test all features of the - static library -- `testasconshared` a test runner executable , which test all features - of the shared library +- `testascon` a test runner executable , which test all features of the static + library +- `testasconshared` a test runner executable , which test all features of the + shared library Doxygen (if installed) is built separately to avoid recompiling it for any library change: + ``` cmake --build . --target ascon_doxygen ``` To compile only a single target, for example `ascon80pq`, run + ``` mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release diff --git a/compiler_flags.cmake b/compiler_flags.cmake index b72287c..defbd1c 100644 --- a/compiler_flags.cmake +++ b/compiler_flags.cmake @@ -70,7 +70,7 @@ else () 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() + endif () # Debug mode string(APPEND CMAKE_C_FLAGS_DEBUG " -g3") # Max debug info @@ -102,9 +102,11 @@ 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 + + else () # GCC string(APPEND CMAKE_C_FLAGS_DEBUG " -static-libasan") # Note: Asan, not san - endif() + + 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") diff --git a/inc/ascon.h b/inc/ascon.h index cf9ba08..6f1d21d 100644 --- a/inc/ascon.h +++ b/inc/ascon.h @@ -45,25 +45,36 @@ extern "C" /** * @def ASCON_INPUT_ASSERTS * When defined, enables the runtime assertions on the parameters of all - * functions of the library API using #ASCON_ASSERT - undefined (disabled) - * by default. + * functions of the library API using #ASCON_ASSERT. + * * The check is mostly against NULL pointers, for the correct order of calling * of the many Init-Update-Final functions and against mixing functions from - * different AEAD algorithms (128 vs 128a vs 80pq). It's generally useful - * for debugging only. - * @see ASCON_ASSERT + * different AEAD algorithms (128 vs 128a vs 80pq). It's recommended to + * use it in debug mode, optionally also in release mode. + * + * If #ASCON_INPUT_ASSERTS is defined, the user can also pre-define + * #ASCON_ASSERT to any custom assertion macro or function. + * + * @see #ASCON_ASSERT */ // Redefining ASCON_INPUT_ASSERTS otherwise Doxygen does not find it #undef ASCON_INPUT_ASSERTS #define ASCON_INPUT_ASSERTS 1 /** * @def ASCON_ASSERT - * Assertion macro, defaulting to `assert` from `assert.h`, when - * #ASCON_INPUT_ASSERTS is defined, but #ASCON_ASSERT is not. - * Redefine it to something else if required. + * Assertion macro, used to stop execution when a critical error is + * encountered. + * + * - Equal to `assert` from `assert.h` if #ASCON_INPUT_ASSERTS is defined. + * - Can also be pre-defined by the user to any custom assertion. + * - Otherwise does nothing. */ #include /* For assert() */ #define ASCON_ASSERT(expr) assert(expr) +#elif !defined(ASCON_ASSERT) +// Neither ASCON_INPUT_ASSERTS nor ASCON_ASSERT are defined, +// so make the assert macro do nothing. +#define ASCON_ASSERT(expr) #endif /** @@ -88,9 +99,9 @@ extern "C" /** Minor version of this API conforming to semantic versioning. */ #define ASCON_API_VERSION_MINOR 1 /** Bugfix/patch version of this API conforming to semantic versioning. */ -#define ASCON_API_VERSION_BUGFIX 1 +#define ASCON_API_VERSION_BUGFIX 2 /** Version of this API conforming to semantic versioning as a string. */ -#define ASCON_API_VERSION "1.1.1" +#define ASCON_API_VERSION "1.1.2" /** * Length in bytes of the secret symmetric key used for the Ascon128 cipher. diff --git a/src/ascon_aead128.c b/src/ascon_aead128.c index cf223af..9e3fa37 100644 --- a/src/ascon_aead128.c +++ b/src/ascon_aead128.c @@ -12,22 +12,20 @@ ASCON_API void ascon_aead128_encrypt(uint8_t* ciphertext, uint8_t* tag, - const uint8_t* key, - const uint8_t* nonce, + const uint8_t key[ASCON_AEAD128_KEY_LEN], + const uint8_t nonce[ASCON_AEAD_NONCE_LEN], const uint8_t* assoc_data, const uint8_t* plaintext, size_t assoc_data_len, size_t plaintext_len, size_t tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(plaintext_len == 0 || ciphertext != NULL); ASCON_ASSERT(tag_len != 0 || tag != NULL); ASCON_ASSERT(key != NULL); ASCON_ASSERT(nonce != NULL); ASCON_ASSERT(assoc_data_len == 0 || assoc_data != NULL); ASCON_ASSERT(plaintext_len == 0 || plaintext != NULL); -#endif ascon_aead_ctx_t ctx; ascon_aead128_init(&ctx, key, nonce); ascon_aead128_assoc_data_update(&ctx, assoc_data, assoc_data_len); @@ -40,8 +38,8 @@ ascon_aead128_encrypt(uint8_t* ciphertext, ASCON_API bool ascon_aead128_decrypt(uint8_t* plaintext, - const uint8_t* key, - const uint8_t* nonce, + const uint8_t key[ASCON_AEAD128_KEY_LEN], + const uint8_t nonce[ASCON_AEAD_NONCE_LEN], const uint8_t* assoc_data, const uint8_t* ciphertext, const uint8_t* expected_tag, @@ -49,14 +47,12 @@ ascon_aead128_decrypt(uint8_t* plaintext, size_t ciphertext_len, size_t expected_tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ciphertext_len == 0 || plaintext != NULL); ASCON_ASSERT(key != NULL); ASCON_ASSERT(nonce != NULL); ASCON_ASSERT(assoc_data_len == 0 || assoc_data != NULL); ASCON_ASSERT(ciphertext_len == 0 || ciphertext != NULL); ASCON_ASSERT(expected_tag_len != 0 || expected_tag != NULL); -#endif ascon_aead_ctx_t ctx; bool is_tag_valid; ascon_aead128_init(&ctx, key, nonce); @@ -72,14 +68,12 @@ ascon_aead128_decrypt(uint8_t* plaintext, ASCON_API void ascon_aead128_init(ascon_aead_ctx_t* const ctx, - const uint8_t* const key, - const uint8_t* const nonce) + const uint8_t key[ASCON_AEAD128_KEY_LEN], + const uint8_t nonce[ASCON_AEAD_NONCE_LEN]) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(key != NULL); ASCON_ASSERT(nonce != NULL); -#endif ascon_aead_init(ctx, key, nonce, AEAD128_IV); ctx->bufstate.flow_state = ASCON_FLOW_AEAD128_80pq_INITIALISED; } @@ -141,12 +135,10 @@ ascon_aead128_assoc_data_update(ascon_aead_ctx_t* const ctx, const uint8_t* assoc_data, size_t assoc_data_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(assoc_data_len == 0 || assoc_data != NULL); ASCON_ASSERT(ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_INITIALISED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_ASSOC_DATA_UPDATED); -#endif if (assoc_data_len > 0) { ctx->bufstate.flow_state = ASCON_FLOW_AEAD128_80pq_ASSOC_DATA_UPDATED; @@ -161,14 +153,12 @@ ascon_aead128_encrypt_update(ascon_aead_ctx_t* const ctx, const uint8_t* plaintext, size_t plaintext_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(plaintext_len == 0 || plaintext != NULL); ASCON_ASSERT(plaintext_len == 0 || ciphertext != NULL); ASCON_ASSERT(ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_INITIALISED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_ASSOC_DATA_UPDATED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_ENCRYPT_UPDATED); -#endif if (ctx->bufstate.flow_state != ASCON_FLOW_AEAD128_80pq_ENCRYPT_UPDATED) { // Finalise the associated data if not already done sos. @@ -186,14 +176,12 @@ ascon_aead128_encrypt_final(ascon_aead_ctx_t* const ctx, uint8_t* tag, size_t tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(ciphertext != NULL); ASCON_ASSERT(tag_len == 0 || tag != NULL); ASCON_ASSERT(ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_INITIALISED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_ASSOC_DATA_UPDATED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_ENCRYPT_UPDATED); -#endif if (ctx->bufstate.flow_state != ASCON_FLOW_AEAD128_80pq_ENCRYPT_UPDATED) { // Finalise the associated data if not already done sos. @@ -228,14 +216,12 @@ ascon_aead128_decrypt_update(ascon_aead_ctx_t* const ctx, const uint8_t* ciphertext, size_t ciphertext_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(ciphertext_len == 0 || ciphertext != NULL); ASCON_ASSERT(ciphertext_len == 0 || plaintext != NULL); ASCON_ASSERT(ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_INITIALISED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_ASSOC_DATA_UPDATED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_DECRYPT_UPDATED); -#endif if (ctx->bufstate.flow_state != ASCON_FLOW_AEAD128_80pq_DECRYPT_UPDATED) { // Finalise the associated data if not already done sos. @@ -254,12 +240,10 @@ ascon_aead128_decrypt_final(ascon_aead_ctx_t* const ctx, const uint8_t* const expected_tag, size_t expected_tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(plaintext != NULL); ASCON_ASSERT(expected_tag_len == 0 || expected_tag != NULL); ASCON_ASSERT(is_tag_valid != NULL); -#endif if (ctx->bufstate.flow_state != ASCON_FLOW_AEAD128_80pq_DECRYPT_UPDATED) { // Finalise the associated data if not already done sos. diff --git a/src/ascon_aead128a.c b/src/ascon_aead128a.c index 8fded67..f921e21 100644 --- a/src/ascon_aead128a.c +++ b/src/ascon_aead128a.c @@ -12,22 +12,20 @@ ASCON_API void ascon_aead128a_encrypt(uint8_t* ciphertext, uint8_t* tag, - const uint8_t* key, - const uint8_t* nonce, + const uint8_t key[ASCON_AEAD128a_KEY_LEN], + const uint8_t nonce[ASCON_AEAD_NONCE_LEN], const uint8_t* assoc_data, const uint8_t* plaintext, size_t assoc_data_len, size_t plaintext_len, size_t tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(plaintext_len == 0 || ciphertext != NULL); ASCON_ASSERT(tag_len != 0 || tag != NULL); ASCON_ASSERT(key != NULL); ASCON_ASSERT(nonce != NULL); ASCON_ASSERT(assoc_data_len == 0 || assoc_data != NULL); ASCON_ASSERT(plaintext_len == 0 || plaintext != NULL); -#endif ascon_aead_ctx_t ctx; ascon_aead128a_init(&ctx, key, nonce); ascon_aead128a_assoc_data_update(&ctx, assoc_data, assoc_data_len); @@ -40,8 +38,8 @@ ascon_aead128a_encrypt(uint8_t* ciphertext, ASCON_API bool ascon_aead128a_decrypt(uint8_t* plaintext, - const uint8_t* key, - const uint8_t* nonce, + const uint8_t key[ASCON_AEAD128a_KEY_LEN], + const uint8_t nonce[ASCON_AEAD_NONCE_LEN], const uint8_t* assoc_data, const uint8_t* ciphertext, const uint8_t* expected_tag, @@ -49,14 +47,12 @@ ascon_aead128a_decrypt(uint8_t* plaintext, size_t ciphertext_len, size_t expected_tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ciphertext_len == 0 || plaintext != NULL); ASCON_ASSERT(key != NULL); ASCON_ASSERT(nonce != NULL); ASCON_ASSERT(assoc_data_len == 0 || assoc_data != NULL); ASCON_ASSERT(ciphertext_len == 0 || ciphertext != NULL); ASCON_ASSERT(expected_tag_len != 0 || expected_tag != NULL); -#endif ascon_aead_ctx_t ctx; bool is_tag_valid; ascon_aead128a_init(&ctx, key, nonce); @@ -72,14 +68,12 @@ ascon_aead128a_decrypt(uint8_t* plaintext, ASCON_API void ascon_aead128a_init(ascon_aead_ctx_t* const ctx, - const uint8_t* const key, - const uint8_t* const nonce) + const uint8_t key[ASCON_AEAD128a_KEY_LEN], + const uint8_t nonce[ASCON_AEAD_NONCE_LEN]) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(key != NULL); ASCON_ASSERT(nonce != NULL); -#endif ascon_aead_init(ctx, key, nonce, AEAD128a_IV); ctx->bufstate.flow_state = ASCON_FLOW_AEAD128a_INITIALISED; } @@ -148,12 +142,10 @@ ascon_aead128a_assoc_data_update(ascon_aead_ctx_t* const ctx, const uint8_t* assoc_data, size_t assoc_data_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(assoc_data_len == 0 || assoc_data != NULL); ASCON_ASSERT(ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_INITIALISED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_ASSOC_DATA_UPDATED); -#endif if (assoc_data_len > 0) { ctx->bufstate.flow_state = ASCON_FLOW_AEAD128a_ASSOC_DATA_UPDATED; @@ -214,14 +206,12 @@ ascon_aead128a_encrypt_update(ascon_aead_ctx_t* const ctx, const uint8_t* plaintext, size_t plaintext_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(plaintext_len == 0 || plaintext != NULL); ASCON_ASSERT(plaintext_len == 0 || ciphertext != NULL); ASCON_ASSERT(ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_INITIALISED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_ASSOC_DATA_UPDATED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_ENCRYPT_UPDATED); -#endif if (ctx->bufstate.flow_state != ASCON_FLOW_AEAD128a_ENCRYPT_UPDATED) { // Finalise the associated data if not already done sos. @@ -240,14 +230,12 @@ ascon_aead128a_encrypt_final(ascon_aead_ctx_t* const ctx, uint8_t* tag, size_t tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(ciphertext != NULL); ASCON_ASSERT(tag_len == 0 || tag != NULL); ASCON_ASSERT(ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_INITIALISED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_ASSOC_DATA_UPDATED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_ENCRYPT_UPDATED); -#endif if (ctx->bufstate.flow_state != ASCON_FLOW_AEAD128a_ENCRYPT_UPDATED) { // Finalise the associated data if not already done so. @@ -301,14 +289,12 @@ ascon_aead128a_decrypt_update(ascon_aead_ctx_t* const ctx, const uint8_t* ciphertext, size_t ciphertext_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(ciphertext_len == 0 || ciphertext != NULL); ASCON_ASSERT(ciphertext_len == 0 || plaintext != NULL); ASCON_ASSERT(ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_INITIALISED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_ASSOC_DATA_UPDATED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_DECRYPT_UPDATED); -#endif if (ctx->bufstate.flow_state != ASCON_FLOW_AEAD128a_DECRYPT_UPDATED) { // Finalise the associated data if not already done sos. @@ -328,7 +314,6 @@ ascon_aead128a_decrypt_final(ascon_aead_ctx_t* const ctx, const uint8_t* const expected_tag, const size_t expected_tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(plaintext != NULL); ASCON_ASSERT(expected_tag_len == 0 || expected_tag != NULL); @@ -336,7 +321,6 @@ ascon_aead128a_decrypt_final(ascon_aead_ctx_t* const ctx, ASCON_ASSERT(ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_INITIALISED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_ASSOC_DATA_UPDATED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128a_DECRYPT_UPDATED); -#endif if (ctx->bufstate.flow_state != ASCON_FLOW_AEAD128a_DECRYPT_UPDATED) { // Finalise the associated data if not already done sos. diff --git a/src/ascon_aead80pq.c b/src/ascon_aead80pq.c index 7a209fa..1aab5ab 100644 --- a/src/ascon_aead80pq.c +++ b/src/ascon_aead80pq.c @@ -12,22 +12,20 @@ ASCON_API void ascon_aead80pq_encrypt(uint8_t* ciphertext, uint8_t* tag, - const uint8_t* key, - const uint8_t* nonce, + const uint8_t key[ASCON_AEAD80pq_KEY_LEN], + const uint8_t nonce[ASCON_AEAD_NONCE_LEN], const uint8_t* assoc_data, const uint8_t* plaintext, size_t assoc_data_len, size_t plaintext_len, size_t tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(plaintext_len == 0 || ciphertext != NULL); ASCON_ASSERT(tag_len != 0 || tag != NULL); ASCON_ASSERT(key != NULL); ASCON_ASSERT(nonce != NULL); ASCON_ASSERT(assoc_data_len == 0 || assoc_data != NULL); ASCON_ASSERT(plaintext_len == 0 || plaintext != NULL); -#endif ascon_aead_ctx_t ctx; ascon_aead80pq_init(&ctx, key, nonce); ascon_aead80pq_assoc_data_update(&ctx, assoc_data, assoc_data_len); @@ -40,8 +38,8 @@ ascon_aead80pq_encrypt(uint8_t* ciphertext, ASCON_API bool ascon_aead80pq_decrypt(uint8_t* plaintext, - const uint8_t* key, - const uint8_t* nonce, + const uint8_t key[ASCON_AEAD80pq_KEY_LEN], + const uint8_t nonce[ASCON_AEAD_NONCE_LEN], const uint8_t* assoc_data, const uint8_t* ciphertext, const uint8_t* expected_tag, @@ -49,14 +47,12 @@ ascon_aead80pq_decrypt(uint8_t* plaintext, size_t ciphertext_len, size_t expected_tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ciphertext_len == 0 || plaintext != NULL); ASCON_ASSERT(key != NULL); ASCON_ASSERT(nonce != NULL); ASCON_ASSERT(assoc_data_len == 0 || assoc_data != NULL); ASCON_ASSERT(ciphertext_len == 0 || ciphertext != NULL); ASCON_ASSERT(expected_tag_len != 0 || expected_tag != NULL); -#endif ascon_aead_ctx_t ctx; bool is_tag_valid; ascon_aead80pq_init(&ctx, key, nonce); @@ -72,14 +68,12 @@ ascon_aead80pq_decrypt(uint8_t* plaintext, ASCON_API void ascon_aead80pq_init(ascon_aead_ctx_t* const ctx, - const uint8_t* const key, - const uint8_t* const nonce) + const uint8_t key[ASCON_AEAD80pq_KEY_LEN], + const uint8_t nonce[ASCON_AEAD_NONCE_LEN]) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(key != NULL); ASCON_ASSERT(nonce != NULL); -#endif // Store the key in the context as it's required in the final step. ctx->k0 = bigendian_decode_u64(key) >> 32U; ctx->k1 = bigendian_decode_u64(key + 4U); @@ -120,14 +114,12 @@ ascon_aead80pq_encrypt_final(ascon_aead_ctx_t* const ctx, uint8_t* tag, size_t tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(ciphertext != NULL); ASCON_ASSERT(tag_len == 0 || tag != NULL); ASCON_ASSERT(ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_INITIALISED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_ASSOC_DATA_UPDATED || ctx->bufstate.flow_state == ASCON_FLOW_AEAD128_80pq_ENCRYPT_UPDATED); -#endif if (ctx->bufstate.flow_state != ASCON_FLOW_AEAD128_80pq_ENCRYPT_UPDATED) { // Finalise the associated data if not already done sos. @@ -163,11 +155,9 @@ ascon_aead80pq_decrypt_update(ascon_aead_ctx_t* ctx, const uint8_t* ciphertext, size_t ciphertext_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(ciphertext_len == 0 || ciphertext != NULL); ASCON_ASSERT(ciphertext_len == 0 || plaintext != NULL); -#endif return ascon_aead128_decrypt_update(ctx, plaintext, ciphertext, ciphertext_len); } @@ -178,12 +168,10 @@ ascon_aead80pq_decrypt_final(ascon_aead_ctx_t* const ctx, const uint8_t* const expected_tag, const size_t expected_tag_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(plaintext != NULL); ASCON_ASSERT(expected_tag_len == 0 || expected_tag != NULL); ASCON_ASSERT(is_tag_valid != NULL); -#endif if (ctx->bufstate.flow_state != ASCON_FLOW_AEAD128_80pq_DECRYPT_UPDATED) { // Finalise the associated data if not already done sos. diff --git a/src/ascon_aead_common.c b/src/ascon_aead_common.c index 930999c..9fbfe6c 100644 --- a/src/ascon_aead_common.c +++ b/src/ascon_aead_common.c @@ -1,9 +1,9 @@ /** * @file + * Code used in multiple AEAD versions of Ascon. * - * @copyright Copyright © 2020, Matjaž Guštin - * . All rights reserved. - * @license BSD 3-clause license. + * @license Creative Commons Zero (CC0) 1.0 + * @authors see AUTHORS.md file */ #include "ascon.h" @@ -133,9 +133,7 @@ ascon_aead_is_tag_valid(ascon_aead_ctx_t* const ctx, ASCON_API void ascon_aead_cleanup(ascon_aead_ctx_t* const ctx) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); -#endif // Manual cleanup using volatile pointers to have more assurance the // cleanup will not be removed by the optimiser. ((volatile ascon_aead_ctx_t*) ctx)->bufstate.sponge.x0 = 0U; diff --git a/src/ascon_buffering.c b/src/ascon_buffering.c index 1340146..ce42757 100644 --- a/src/ascon_buffering.c +++ b/src/ascon_buffering.c @@ -18,13 +18,19 @@ * * It should work faster than memcpy for very small amounts of bytes given * the reduced overhead. + * + * Initially implemented with a while-loop, but it triggers a + * `-Werror=stringop-overflow=` warning in GCC v11. Replaced it with a for-loop + * that does the exact same thing instead to make it work without deactivating + * the warning. We instead let the optimiser figure out the best way to make it + * as fast as possible. */ inline static void -small_cpy(uint8_t* dst, const uint8_t* src, uint_fast8_t amount) +small_cpy(uint8_t* const dst, const uint8_t* const src, const size_t amount) { - while (amount--) + for (uint_fast8_t i = 0U; i < amount; i++) { - *(dst++) = *(src++); + dst[i] = src[i]; } } @@ -147,7 +153,7 @@ buffered_accumulation(ascon_bufstate_t* const ctx, // cache it into the buffer for the next update call or digest call. if (data_in_len > 0) { - small_cpy(ctx->buffer, data_in, (uint_fast8_t) data_in_len); + small_cpy(ctx->buffer, data_in, data_in_len); ctx->buffer_len = (uint8_t) data_in_len; } return fresh_out_bytes; diff --git a/src/ascon_hash.c b/src/ascon_hash.c index 79c8de2..9d06edb 100644 --- a/src/ascon_hash.c +++ b/src/ascon_hash.c @@ -14,10 +14,8 @@ ascon_hash(uint8_t digest[ASCON_HASH_DIGEST_LEN], const uint8_t* const data, const size_t data_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(digest != NULL); ASCON_ASSERT(data_len == 0 || data != NULL); -#endif ascon_hash_ctx_t ctx; ascon_hash_init(&ctx); ascon_hash_update(&ctx, data, data_len); @@ -29,10 +27,8 @@ ascon_hash_matches(const uint8_t expected_digest[ASCON_HASH_DIGEST_LEN], const uint8_t* const data, const size_t data_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(expected_digest != NULL); ASCON_ASSERT(data_len == 0 || data != NULL); -#endif ascon_hash_ctx_t ctx; ascon_hash_init(&ctx); ascon_hash_update(&ctx, data, data_len); @@ -45,10 +41,8 @@ ascon_hash_xof(uint8_t* const digest, const size_t digest_len, const size_t data_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(digest_len == 0 || digest != NULL); ASCON_ASSERT(data_len == 0 || data != NULL); -#endif ascon_hash_ctx_t ctx; ascon_hash_xof_init(&ctx); ascon_hash_xof_update(&ctx, data, data_len); @@ -61,10 +55,8 @@ ascon_hash_xof_matches(const uint8_t* const expected_digest, const size_t expected_digest_len, const size_t data_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(expected_digest_len == 0 || expected_digest != NULL); ASCON_ASSERT(data_len == 0 || data != NULL); -#endif ascon_hash_ctx_t ctx; ascon_hash_xof_init(&ctx); ascon_hash_xof_update(&ctx, data, data_len); @@ -74,9 +66,7 @@ ascon_hash_xof_matches(const uint8_t* const expected_digest, ASCON_API void ascon_hash_cleanup(ascon_hash_ctx_t* const ctx) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); -#endif // Manual cleanup using volatile pointers to have more assurance the // cleanup will not be removed by the optimiser. ((volatile ascon_hash_ctx_t*) ctx)->sponge.x0 = 0U; @@ -109,26 +99,20 @@ init(ascon_hash_ctx_t* const ctx, const uint64_t iv) ctx->sponge.x4 = 0; ctx->buffer_len = 0; ascon_permutation_a12(&ctx->sponge); -#ifdef ASCON_INPUT_ASSERTS ctx->flow_state = ASCON_FLOW_HASH_INITIALISED; -#endif } ASCON_API void ascon_hash_init(ascon_hash_ctx_t* const ctx) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); -#endif init(ctx, HASH_IV); } ASCON_API void ascon_hash_xof_init(ascon_hash_ctx_t* const ctx) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); -#endif init(ctx, XOF_IV); } @@ -151,16 +135,12 @@ ascon_hash_xof_update(ascon_hash_ctx_t* const ctx, const uint8_t* data, size_t data_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(data_len == 0 || data != NULL); ASCON_ASSERT(ctx->flow_state == ASCON_FLOW_HASH_INITIALISED || ctx->flow_state == ASCON_FLOW_HASH_UPDATED); -#endif buffered_accumulation(ctx, NULL, data, absorb_hash_data, data_len, ASCON_RATE); -#ifdef ASCON_INPUT_ASSERTS ctx->flow_state = ASCON_FLOW_HASH_UPDATED; -#endif } ASCON_API void @@ -176,12 +156,10 @@ ascon_hash_xof_final(ascon_hash_ctx_t* const ctx, uint8_t* digest, size_t digest_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(digest_len == 0 || digest != NULL); ASCON_ASSERT(ctx->flow_state == ASCON_FLOW_HASH_INITIALISED || ctx->flow_state == ASCON_FLOW_HASH_UPDATED); -#endif // If there is any remaining less-than-a-block data to be absorbed // cached in the buffer, pad it and absorb it. ctx->sponge.x0 ^= bigendian_decode_varlen(ctx->buffer, ctx->buffer_len); @@ -223,12 +201,10 @@ ascon_hash_xof_final_matches(ascon_hash_ctx_t* const ctx, const uint8_t* expected_digest, size_t expected_digest_len) { -#ifdef ASCON_INPUT_ASSERTS ASCON_ASSERT(ctx != NULL); ASCON_ASSERT(expected_digest_len == 0 || expected_digest != NULL); ASCON_ASSERT(ctx->flow_state == ASCON_FLOW_HASH_INITIALISED || ctx->flow_state == ASCON_FLOW_HASH_UPDATED); -#endif // If there is any remaining less-than-a-block data to be absorbed // cached in the buffer, pad it and absorb it. ctx->sponge.x0 ^= bigendian_decode_varlen(ctx->buffer, ctx->buffer_len); diff --git a/tst/atto/atto.h b/tst/atto/atto.h index 2fee85e..bed85a0 100644 --- a/tst/atto/atto.h +++ b/tst/atto/atto.h @@ -101,7 +101,7 @@ extern unsigned long long atto_counter; */ #define atto_assert(expression) do { \ if (!(expression)) { \ - printf("FAIL | File: %s | Line: %4d | Test case: %s | Ctr: %llu\n", \ + printf("FAIL | File: %s:%d | Test case: %s | Ctr: %llu\n", \ __FILE__, __LINE__, __func__, atto_counter); \ atto_at_least_one_fail = 1U; \ return; \ diff --git a/tst/benchmark.c b/tst/benchmark.c index ccaa9de..59f85e5 100644 --- a/tst/benchmark.c +++ b/tst/benchmark.c @@ -36,8 +36,8 @@ #endif #if defined(__ARM_ARCH_6__) \ - || (defined(__ARM_ARCH_6__) && __ARM_ARCH == 6) \ - || (defined(_M_ARM) && _M_ARM == 6) + || (defined(__ARM_ARCH_6__) && __ARM_ARCH == 6) \ + || (defined(_M_ARM) && _M_ARM == 6) #define ALIGN(x) __attribute__((aligned(x))) #pragma message("Using ARMv6 PMU to count cycles") #define init_cpucycles() \ @@ -77,95 +77,109 @@ unsigned char ALIGN(16) h[CRYPTO_BYTES]; unsigned long long cycles[NUM_MLENS][NUM_RUNS * 2]; unsigned int tmp; -static void init_input(void) { - int i; - for (i = 0; i < MAX_LEN; ++i) m[i] = (uint8_t) rand(); +static void init_input(void) +{ + int i; + for (i = 0; i < MAX_LEN; ++i) { m[i] = (uint8_t) rand(); } #if defined(CRYPTO_AEAD) - for (i = 0; i < MAX_LEN; ++i) a[i] = (uint8_t) rand(); - for (i = 0; i < CRYPTO_KEYBYTES; ++i) k[i] = (uint8_t) rand(); - for (i = 0; i < CRYPTO_NPUBBYTES; ++i) npub[i] = (uint8_t) rand(); + for (i = 0; i < MAX_LEN; ++i) { a[i] = (uint8_t) rand(); } + for (i = 0; i < CRYPTO_KEYBYTES; ++i) { k[i] = (uint8_t) rand(); } + for (i = 0; i < CRYPTO_NPUBBYTES; ++i) { npub[i] = (uint8_t) rand(); } #endif } -static unsigned long long measure(unsigned long long mlen) { - unsigned long long NREPS = NUM_BYTES / mlen; - unsigned long long i; +static unsigned long long measure(unsigned long long mlen) +{ + unsigned long long NREPS = NUM_BYTES / mlen; + unsigned long long i; #if defined(__arm__) || defined(_M_ARM) - unsigned int before, after; + unsigned int before, after; #else - unsigned long long before, after; + unsigned long long before, after; #endif - init_input(); - cpucycles(before); - for (i = 0; i < NREPS; ++i) + init_input(); + cpucycles(before); + for (i = 0; i < NREPS; ++i) #if defined(CRYPTO_AEAD) - ascon_aead128_encrypt(c, - c + mlen, - k, - npub, - NULL, - m, - 0, - mlen, - 16); + { + ascon_aead128_encrypt(c, + c + mlen, + k, + npub, + NULL, + m, + 0, + mlen, + 16); + } #elif defined(CRYPTO_HASH) crypto_hash(h, m, mlen); #endif - cpucycles(after); - return after - before; + cpucycles(after); + return after - before; } -static int compare_uint64(const void* first, const void* second) { - const unsigned long long* ia = (const unsigned long long*)first; - const unsigned long long* ib = (const unsigned long long*)second; - if (*ia > *ib) return 1; - if (*ia < *ib) return -1; - return 0; +static int compare_uint64(const void* first, const void* second) +{ + const unsigned long long* ia = (const unsigned long long*) first; + const unsigned long long* ib = (const unsigned long long*) second; + if (*ia > *ib) { return 1; } + if (*ia < *ib) { return -1; } + return 0; } -int main(int argc, char* argv[]) { - unsigned long long i, j; - double factor = 1.0; - if (argc == 2) factor = atof(argv[1]); - - init_cpucycles(); - - for (i = 0; i < NUM_MLENS; ++i) { - for (j = 0; j < NUM_RUNS; ++j) cycles[i][j] = measure(mlens[i]); - qsort(cycles[i], NUM_RUNS, sizeof(unsigned long long), &compare_uint64); - } - - printf("\nsorted cycles:\n"); - for (i = 0; i < NUM_MLENS; ++i) { - unsigned long long NREPS = NUM_BYTES / mlens[i]; - printf("%5d: ", (int)mlens[i]); - for (j = 0; j < NUM_RUNS; ++j) printf("%d ", (int)(cycles[i][j] / NREPS)); +int main(int argc, char* argv[]) +{ + unsigned long long i, j; + double factor = 1.0; + if (argc == 2) { factor = atof(argv[1]); } + + init_cpucycles(); + + for (i = 0; i < NUM_MLENS; ++i) + { + for (j = 0; j < NUM_RUNS; ++j) { cycles[i][j] = measure(mlens[i]); } + qsort(cycles[i], NUM_RUNS, sizeof(unsigned long long), &compare_uint64); + } + + printf("\nsorted cycles:\n"); + for (i = 0; i < NUM_MLENS; ++i) + { + unsigned long long NREPS = NUM_BYTES / mlens[i]; + printf("%5d: ", (int) mlens[i]); + for (j = 0; j < NUM_RUNS; ++j) { printf("%d ", (int) (cycles[i][j] / NREPS)); } + printf("\n"); + } + + printf("\ncycles per byte (min,median):\n"); + for (i = 0; i < NUM_MLENS; ++i) + { + unsigned long long NREPS = NUM_BYTES / mlens[i]; + unsigned long long bytes = mlens[i] * NREPS; + printf("%5d: %6.1f %6.1f\n", (int) mlens[i], + factor * (double) cycles[i][0] / (double) bytes + 0.05, + factor * (double) cycles[i][NUM_RUNS / 2] / (double) bytes + 0.05); + } printf("\n"); - } - - printf("\ncycles per byte (min,median):\n"); - for (i = 0; i < NUM_MLENS; ++i) { - unsigned long long NREPS = NUM_BYTES / mlens[i]; - unsigned long long bytes = mlens[i] * NREPS; - printf("%5d: %6.1f %6.1f\n", (int)mlens[i], - factor * (double) cycles[i][0] / (double) bytes + 0.05, - factor * (double) cycles[i][NUM_RUNS / 2] / (double) bytes + 0.05); - } - printf("\n"); - - for (i = 0; i < NUM_MLENS; ++i) printf("| %5d ", (int)mlens[i]); - printf("|\n"); - for (i = 0; i < NUM_MLENS; ++i) printf("|------:"); - printf("|\n"); - for (i = 0; i < NUM_MLENS; ++i) { - unsigned long long NREPS = NUM_BYTES / mlens[i]; - unsigned long long bytes = mlens[i] * NREPS; - if (mlens[i] <= 32) - printf("| %5.0f ", factor * (double) cycles[i][0] / (double) bytes + 0.5); - else - printf("| %5.1f ", factor * (double) cycles[i][0] / (double) bytes + 0.05); - } - printf("|\n"); - - return 0; + + for (i = 0; i < NUM_MLENS; ++i) { printf("| %5d ", (int) mlens[i]); } + printf("|\n"); + for (i = 0; i < NUM_MLENS; ++i) { printf("|------:"); } + printf("|\n"); + for (i = 0; i < NUM_MLENS; ++i) + { + unsigned long long NREPS = NUM_BYTES / mlens[i]; + unsigned long long bytes = mlens[i] * NREPS; + if (mlens[i] <= 32) + { + printf("| %5.0f ", factor * (double) cycles[i][0] / (double) bytes + 0.5); + } + else + { + printf("| %5.1f ", factor * (double) cycles[i][0] / (double) bytes + 0.05); + } + } + printf("|\n"); + + return 0; } diff --git a/tst/vectors.c b/tst/vectors.c index e31c361..334d2ed 100644 --- a/tst/vectors.c +++ b/tst/vectors.c @@ -241,6 +241,14 @@ static vecs_err_t fscan_plaintext(vecs_ctx_t* const ctx, static vecs_err_t fscan_assoc_data(vecs_ctx_t* const ctx, vecs_aead_t* const testcase) { + // IMPORTANT!!! + // This function may crash if the underscores are removed from the test + // vector files, because "AD" is a valid hexadecimal string (value 173) + // and without the underscore in "_AD", the previous function would end + // up scanning the Plaintext (PT) until the "=" character of the "AD = " + // line. The underscores are basically field separators. This is required + // because fscanf skips EVERY type of whitespace when reading a regular + // whitespace in its format string, including newline characters. char string[10]; const int obtained_len = fscanf(ctx->handle, " _%s = ", string); if (obtained_len != 1)