lean cryptography in every aspect

leancrypto Cryptographic Library

leancrypto offers a lean and versatile cryptographic library building on Post Quantum Cryptography.

Study and Analysis of Cryptography

Papers study and analyze various aspects of cryptographic algorithms and use cases.

XDRBG Specification and Reference Implementation

XDRBG provides the documentation of the XDRBG random number generator algorithm along with a reference implementation.

Subsections of lean cryptography in every aspect

Leancrypto

Properties of leancrypto

The leancrypto library is a cryptographic library that exclusively contains only PQC-resistant cryptographic algorithms. The algorithm implementations have the following properties:

  • minimal dependencies: only minimal POSIX environment needed - function calls are abstracted into helper code that may need to be replaced for other environments:

  • extractable: the algorithms can be extracted and compiled as part of a separate project,

  • flexible: you can disable algorithms on an as-needed basis using meson configure,

  • fully thread-safe when using different cipher contexts for an invocation: there is no global state maintained for the algorithms,

  • stack-only support: all algorithms can be allocated on stack if needed. In addition, allocation functions for a usage on heap is also supported,

  • size: minimizing footprint when statically linking by supporting dead-code stripping,

  • performance: provide optimized code invoked with minimal overhead, thus significantly faster compared to other libraries like OpenSSL,

  • testable: all algorithm implementations are directly accessible via their data structures at runtime - regularly executed tests:

    • All algorithms testable with NIST’s ACVP are tested and official CAVP certificates are received

    • Automated test system using the meson build system covering all algorithms

    • Automated testing of various scenarios using Github Testing

    • Automated testing of various CPU architectures using OpenSUSE Build Service

    • Continuous testing for Memory Leaks

    • Continuous Security Scans

  • versatile: The following execution environments are supported with all accelerated implementations:

    • Linux user space

    • Linux kernel space

    • BSD user space

    • Apple OSes user space

    • Windows user space

    • EFI environment

  • accelerated: Accelerated implementations are provided for the following algorithms which also benefit aggregated algorithms building on those primitives:

    • Ascon permutation: x86_64, ARMv7 (Neon)

    • SHA2: x64_64 (AVX2, SHA-NI, SHA-NI-512), ARMv8 (Neon, CE), RISCV64 (assembler, Zbb)

    • SHA-3 and derivatives: x86_64 (AVX2, AVX2 4x parallel, AVX512), ARMv8 (Neon, Neon 2x parallel, CE), ARMv7 (Neon), RISCV64 (assembler, Zbb)

    • Curve 25519: x86_64

    • ML-DSA / Dilithium: x86_64, ARMv8, ARMv7, RISCV64 (assembler, RVV)

    • ML-KEM / Kyber: x86_64, ARMv8, ARMv8, RISCV64 (assembler, RVV)

    • SLH-DSA / Sphincs+: AVX2, ARMv8

    • AES: x86_64 (AES-NI), ARMv8 (CE, assembler), ARMv7, RISCV64 (assembler)

    • BIKE: x86_64 (AVX2, AVX512)

  • side-channel-resistant: A valgrind-based dynamic side channel analysis is applied to find time-variant code paths based on secret data.

  • X.509 and PKCS#7 generator and parser support

Subsections of Leancrypto

Subsections of Build Instructions

POSIX User Space

If you want to build the leancrypto shared library, use the provided Meson build system:

  1. Setup: meson setup build

  2. Compile: meson compile -C build

  3. Test: meson test -C build --suite regression

  4. Install: meson install -C build

Testing

The leancrypto build system contains the following types of testing. To execute all tests in unison, invoke meson test -C build:

  • Regression testing: invoked with meson test -C build --suite regression

  • Performance testing: invoked with meson test -C build --suite performance

Limiting the Size of leancrypto

Using Meson, the leancrypto library can be limited in size by deselecting the different algorithms not required. With the following command, all options can be listed:

meson configure build

Each option can be deselected by using the meson command meson configure build -D<option>=disabled.

However, some dependencies exist which are reported by Meson. For example, SHA-3 support is needed for all post-quantum algorithms.

NOTE: All offered options are considered to be selectable independent of each other, except when Meson complains. However, unfortunately it is not feasible to test all permutations. Thus, it is possible that some permutations of options may cause compilation errors. If you spot such, please report them at the Github Issue Tracker to have them resolved.

Example: Compiling Post-Quantum-Algorithms Only

The following command disables all algorithms except the post-quantum asymmetric algorithms approved by NIST without their hybrid algorithms, but including all relevant accelerations:

meson setup build \
 -Dascon=disabled \
 -Dascon_keccak=disabled \
 -Dbike_5=disabled \
 -Dbike_3=disabled \
 -Dbike_1=disabled \
 -Dkyber_x25519=disabled \
 -Ddilithium_ed25519=disabled \
 -Dx509_parser=disabled \
 -Dx509_generator=disabled \
 -Dpkcs7_parser=disabled \
 -Dpkcs7_generator=disabled \
 -Dsha2-256=disabled \
 -Dsha2-512=disabled \
 -Dchacha20=disabled \
 -Dchacha20_drng=disabled \
 -Ddrbg_hash=disabled \
 -Ddrbg_hmac=disabled \
 -Dhash_crypt=disabled \
 -Dhmac=disabled \
 -Dhkdf=disabled \
 -Dkdf_ctr=disabled \
 -Dkdf_fb=disabled \
 -Dkdf_dpi=disabled \
 -Dpbkdf2=disabled \
 -Dkmac_drng=disabled \
 -Dcshake_drng=disabled \
 -Dhotp=disabled \
 -Dtotp=disabled \
 -Daes_block=disabled \
 -Daes_cbc=disabled \
 -Daes_ctr=disabled \
 -Daes_kw=disabled \
 -Dapps=disabled

Example: Compiling ML-KEM Support Only

The following command disables all algorithms except ML-KEM without the hybrid algorithms, but including all relevant accelerations:

meson setup build \
 -Dascon=disabled \
 -Dascon_keccak=disabled \
 -Dbike_5=disabled \
 -Dbike_3=disabled \
 -Dbike_1=disabled \
 -Dkyber_x25519=disabled \
 -Ddilithium_ed25519=disabled \
 -Dx509_parser=disabled \
 -Dx509_generator=disabled \
 -Dpkcs7_parser=disabled \
 -Dpkcs7_generator=disabled \
 -Dsha2-256=disabled \
 -Dsha2-512=disabled \
 -Dchacha20=disabled \
 -Dchacha20_drng=disabled \
 -Ddrbg_hash=disabled \
 -Ddrbg_hmac=disabled \
 -Dhash_crypt=disabled \
 -Dhmac=disabled \
 -Dhkdf=disabled \
 -Dkdf_ctr=disabled \
 -Dkdf_fb=disabled \
 -Dkdf_dpi=disabled \
 -Dpbkdf2=disabled \
 -Dkmac_drng=disabled \
 -Dcshake_drng=disabled \
 -Dhotp=disabled \
 -Dtotp=disabled \
 -Daes_block=disabled \
 -Daes_cbc=disabled \
 -Daes_ctr=disabled \
 -Daes_kw=disabled \
 -Dapps=disabled \
 -Ddilithium_87=disabled \
 -Ddilithium_65=disabled \
 -Ddilithium_44=disabled \
 -Dsphincs_shake_256s=disabled \
 -Dsphincs_shake_256f=disabled \
 -Dsphincs_shake_192s=disabled \
 -Dsphincs_shake_192f=disabled \
 -Dsphincs_shake_128s=disabled \
 -Dsphincs_shake_128f=disabled

Example: Compiling SHA2-256 Support Only

The following command disables all algorithms except SHA2-256 including all relevant accelerations which yields a shared library of 43kBytes on Intel 64-bit systems:

meson setup build \
 -Dascon=disabled \
 -Dascon_keccak=disabled \
 -Dbike_5=disabled \
 -Dbike_3=disabled \
 -Dbike_1=disabled \
 -Dkyber_x25519=disabled \
 -Ddilithium_ed25519=disabled \
 -Dx509_parser=disabled \
 -Dx509_generator=disabled \
 -Dpkcs7_parser=disabled \
 -Dpkcs7_generator=disabled \
 -Dsha2-512=disabled \
 -Dchacha20=disabled \
 -Dchacha20_drng=disabled \
 -Ddrbg_hash=disabled \
 -Ddrbg_hmac=disabled \
 -Dhash_crypt=disabled \
 -Dhmac=disabled \
 -Dhkdf=disabled \
 -Dkdf_ctr=disabled \
 -Dkdf_fb=disabled \
 -Dkdf_dpi=disabled \
 -Dpbkdf2=disabled \
 -Dkmac_drng=disabled \
 -Dcshake_drng=disabled \
 -Dhotp=disabled \
 -Dtotp=disabled \
 -Daes_block=disabled \
 -Daes_cbc=disabled \
 -Daes_ctr=disabled \
 -Daes_kw=disabled \
 -Dapps=disabled \
 -Ddilithium_87=disabled \
 -Ddilithium_65=disabled \
 -Ddilithium_44=disabled \
 -Dsphincs_shake_256s=disabled \
 -Dsphincs_shake_256f=disabled \
 -Dsphincs_shake_192s=disabled \
 -Dsphincs_shake_192f=disabled \
 -Dsphincs_shake_128s=disabled \
 -Dsphincs_shake_128f=disabled \
 -Dkmac=disabled \
 -Dkyber_1024=disabled \
 -Dkyber_768=disabled \
 -Dkyber_512=disabled \
 -Dsha3=disabled \
 -Dxdrbg=disabled

Linux Kernel

The leancrypto library is intended to provide the identical services for user space as well as Linux kernel space. This shall allow developers to only have one crypto provider which they need to maintain and learn to develop with.

The user space and kernel space versions of leancrypto are fully independent of each other. Neither requires the presence of the other for full operation.

Leancrypto therefore can be compiled into a separate Linux kernel module called leancrypto.ko.

Building

The leancrypto library can also be built as an independent Linux kernel module. This kernel module offers the same APIs and functions as the user space version of the library. This implies that a developer wanting to develop kernel and user space users of cryptographic mechanisms do not need to adjust to a new API.

Note: The user space and kernel space versions of leancrypto are fully independent of each other. Neither requires the presence of the other for full operation.

To build the leancrypto Linux kernel module, use the Makefile in the directory linux_kernel:

  1. cd linux_kernel

  2. make

  3. the leancrypto library is provided with leancrypto.ko

The API specified by the header files installed as part of the meson install -C build command for the user space library is applicable to the kernel module as well. When compiling kernel code, the flag -DLINUX_KERNEL needs to be set.

Test Modules

In addition to the leancrypto.ko kernel module, a large number of additional kernel modules are compiled. They are all test modules for regression testing and are not required and even not intended for production use. Insert the kernel modules and check dmesg for the results. Unload the kernel modules afterwards.

The test modules almost all are the user space test application the meson test framework uses too, but compiled into kernel modules. They invoke the leancrypto API to demonstrate that the identical code is supported in user as well as user space.

In addition to the standard leancrypto test code, the following test modules are provided to validate the leancrypto integration into the kernel crypto API:

  • leancrypto_kernel_aead_ascon_tester.ko invokes the Linux kernel crypto API of type skcipher to perform a Ascon and Ascon-Keccak encryption / decryption operation.

  • leancrypto_kernel_ascon_tester.ko invokes the Linux kernel crypto API of type shash to perform a Ascon 128 and Ascon 128a message digest calculation.

  • leancrypto_kernel_dilithium*_tester.ko invokes the Linux kernel crypto API of type akcipher to perform a FIPS 204 (CRYSTALS Dilithium) signature generation and verification.

  • leancrypto_kernel_sphincs_shake_*_tester.ko invokes the Linux kernel crypto API of type akcipher to perform a FIPS 205 (Sphincs Plus) signature generation and verification.

  • leancrypto_kernel_kmac_tester.ko invokes the Linux kernel crypto API type shash to invoke KMAC256 XOF, a keyed message digest using FIPS 202 defined in SP800-185.

  • leancrypto_kernel_kyber*_tester.ko tests the Linux kernel crypto API type kpp to invoke FIPS 203 (CRYSTALS Kyber) key generation, encapsulation and decapsulation.

  • leancrypto_kernel_rng_tester.ko invokes the Linux kernel crypto API type rng to utilize the XDRBG256 deterministic random number generator.

  • leancrypto_kernel_sha3_tester.ko performs the testing of leancrypto’s SHA-3 implementation which is registered as a shash.

  • leancrypto_kernel_sha256_tester.ko performs the testing of leancrypto’s SHA2-256 implementation which is registered as a shash.

  • leancrypto_kernel_sha3_tester.ko performs the testing of leancrypto’s SHA2-512 implementation which is registered as a shash.

Leancrypto Registered with the Linux Kernel Crypto API

The leancrypto.ko offers its own API interface as discussed above. In addition, it registers a subset of algorithms with the kernel crypto API to allow other kernel users, that already use the kernel crypto API for its purposes, to use the algorithms of the leancrypto library without further changes. All algorithms adhere to the kernel crypto API standards and should be usable out of the box.

For the ML-KEM (CRYSTALS Kyber) support, some special precautions need to be applied considering that there are two modes of operation a user must be aware of: acting as an Initiator or a Responder of a Kyber key agreement. This consideration is identical to the one that needs to be applied for (EC)Diffie-Hellman. The following listing enumerates the call sequence the user must apply for the given mode. The following sequences for both, the initiator and the responder is implemented in leancrypto_kernel_kyber_tester.c as a reference.

  • Acting as Initiator of a ML-KEM operation:

    1. Generate new keypair: crypto_kpp_set_secret(tfm, NULL, 0); Note, it is permissible to also set an externally-provided key here.

    2. Get public key: crypto_kpp_generate_public_key(req->src = NULL, req->dst = PK)

    3. Send the ML-KEM PK to the responder and retrieve the ML-KEM CT from the responder.

    4. Calculate shared secret: crypto_kpp_compute_shared_secret(req->src = CT, req->dst = SS)

  • Acting as Responder of a ML-KEM operation:

    1. Generate new keypair: crypto_kpp_set_secret(tfm, NULL, 0); Note, it is permissible to also set an externally-provided key here.

    2. Get the initiator PK to generate the CT and shared secret: crypto_kpp_generate_public_key(req->src = PK, req->dst = CT)

    3. Send CT to the initiator

    4. Get the shared secret that was already calculated in step 2: crypto_kpp_compute_shared_secret(req->src = NULL, req->dst = SS)

Please note that the leancrypto ML-KEM support allows specifying arbitrary sizes of the shared secret (referenced as SS above). When the caller specifies a length that is not equal to 32 bytes, the leancrypto built-in KDF is applied to generate the shared secret of appropriate size.

Leancrypto Kernel Support Configuration

The kernel-compilation of leancrypto is equally flexible as the user space part and thus can still be called “lean”. It allows at compile time to enable or disable algorithms as needed.

Unfortunately, the Linux kernel build system’s graphical configuration tools cannot be used for out-of-tree modules. Thus, if changes to the set of algorithms is intended, the file Kbuild.config must be modified as follows:

The file Kbuild.config contains a configuration of the services. Simply comment out the respective symbols that are not desired to be present. The Kbuild.config file contains a description of each option including its dependencies, if any. You MUST adhere to the specified dependencies as otherwise the compilation will fail due to missing symbols.

EFI Environment

The leancrypto library is designed to run without any dependencies and thus can be used in environments like (U)EFI. To compile it for the EFI environment, configure the compilation with the following command:

meson setup build -Defi=enabled -Dpkcs7_generator=disabled -Dx509_generator=disabled
meson compile -C build
meson compile -C build pkcs7_trust_tester.efi

The PKCS#7 message generator and X.509 certificate generator are assumed to be not required and thus use POSIX service functions that are not available in EFI.

The compilation uses the GNU-EFI environment and generates:

  1. The static library leancrypto.a that could be bound into an EFI application compiled externally to the build environment.

  2. A test application in build/efi/tests/pkcs7_trust_tester.efi which is statically linked with leancrypto.a and implements the test “PKCS7 Trust Validation - PKCS#7 with trust chain” from asn1/tests/meson.build. This application is a UEFI application:

    $ file ./build/efi/tests/pkcs7_trust_tester.efi
    ./build/efi/tests/pkcs7_trust_tester.efi: PE32+ executable for EFI (application), x86-64 (stripped to external PDB), 7 sections

Naturally, all other options offered by the meson build enviornment can be toggled for EFI support as well allowing leancrypto to be configured to implement the exact algorithms required. See POSIX user space for details about the use of options.

When programming with leancrypto in the EFI environment, the following considerations must be applied:

  • The API specified by the header files installed as part of the meson install -C build command for the user space library is applicable to the EFI environment as well.

  • As the EFI environment does not offer an automatic constructor functionality the leancrypto initalization function of lc_init must be called as the very first API call before calling any other leancrypto service function.

Windows User Space

The leancrypto library can be built on Windows using MSYS2. Once MSYS2 is installed along with meson and the mingw compiler, the standard compilation procedure outlined for the POSIX user space can be used.

The support for full assembler acceleration is enabled.

Building for Other Environments

If you need leancrypto to work in other environments like small embedded systems, you need:

  1. Adjust the build system as needed to compile and link it

  2. Adjust the file ext_headers.h to point to the right header files and locations.

  3. set the flag LC_MEM_ON_HEAP if your environment only has a limited stack size. When set, functions with large memory requirements use the heap instead of the stack for this memory. The maximum stack size used by a function is 2048 bytes and is verified by a compiler check.

  4. If your environment does not offer an automated constructor logic that is invoked by the compiler attribute __attribute__((constructor)) you must add the appropriate handling to visibility.h by adding an appropriate LC_CONSTRUCTOR macro. It could be as easy as making LC_CONSTRUCTOR just defining the symbol (see how this macro is defined for LC_EFI) and require that leancrypto is initialized with lc_init.

An example on the approach is given with the Linux kernel support found in the directory linux_kernel.

Subsections of Releases

Leancrypto Version 1.2.0

Code

Changes 1.2.0

  • Locking für seeded_rng added to avoid requiring the caller providing a lock

  • Addition of ASN.1 decoder, X.509 parser, PKCS#7 / CMS parser

  • Addition of ASN.1 encoder, X.509 generator, PKCS#7 / CMS generator for ML-DSA, SLH-DSA, ML-DSA-ED25519

  • ML-DSA-ED25519: Hybrid implementation changed to match definition https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html

  • RISCV64: Keccak - add assembler and ZBB implementation

  • RISCV64: ML-KEM - add assembler implementation

  • RISCV64: ML-DSA - add assembler implementation

  • Add FIPS 140 mode (as of now, it does not yet implement full FIPS 140 compliance)

  • Ascon AEAD, Hash, XOF, Ascon-Keccak: Update to comply with SP800-232

  • Dilithium AVX2: Add side channel analysis

  • leancrypto passes X.509 IETF-Hackathon tests: https://ietf-hackathon.github.io/pqc-certificates/pqc_hackathon_results_certs_r4_automated_tests.html

  • Add compilation support for (U)EFI environment

  • RISCV64 RVV: ML-KEM, ML-DSA - add assembler implementation using RVV support

  • Seeded DRNG: Require a reseed after 2**14 bytes to comply with AIS20/31 3.0 DRG.4 and the discussed upcoming changes to SP800-90A.

  • SHA-512 / 384 / 256: Addition of AVX2, SHA_NI, SHA_NI-512, ARMv8 Neon, ARMv8 CE, RISCV ASM, RISCV ZBB acceleration

  • Add lc_init API

  • Intel non-AVX2 systems: remove all SIGILL causes by ensuring no AVX2 code is executed

  • Linux kernel: support version 6.13 kernel crypto signature API

  • Allow switching the central leancrypto seeded RNG instance with a caller-provided RNG

Leancrypto Version 1.1.0

Code

Changes 1.1.0

  • ML-KEM remove modulus check of decapsulation key (not required by FIPS 203)

  • ML-KEM: add key pair PCT API - leancrypto cannot invoke it itself as it does not know when both keys are provided from outside

  • ML-DSA: add consistency with FIPS 204 - the signature changes as the input data handling is added (if you want to apply the old signature, use the new lc_dilithium_[sign|verify]_ctx API with ctx->ml_dsa_internal = 1)

  • ML-DSA: add API to allow caller to provide a user context as allowed by FIPS 204, to invoke ML-DSA.Sign_internal, ML-DSA.Verify_internal and HashML-DSA

  • ML-KEM: rename source code directory to ml-kem

  • ML-DSA: rename source code directory to ml-dsa

  • BIKE: Add NIST round 4 KEM candiate

  • ML-DSA: Add support to retain the expanded key to increase the performance of signature operations by 15 to 20%

  • ML-DSA: add key pair PCT API - leancrypto will not invoke it, but provides it for FIPS 140 support

  • SLH-DSA: Add SLH-DSA-SHAKE-256s, SLH-DSA-SHAKE-256f, SLH-DSA-SHAKE-192s, SLH-DSA-SHAKE-192f, SLH-DSA-SHAKE-128s, SLH-DSA-SHAKE-128f

  • ML-DSA, ML-KEM, SLH-DSA, BIKE, Hash, AEAD, RNG, HMAC, HKDF, symmetric: move API implementation from H to C file - this implies that no RUST wrappers are needed

  • Linux kernel: ML-DSA / SLH-DSA sigver input changed to be compliant to existing kernel structures: req->src SGL contains signature || msg, req->dst SGL is not processed

Leancrypto Version 1.0.1

Code

Changes 1.0.1

  • fix: Kyber keygen - add LC_KYBER_K to initial hash (change is only relevant when storing keys as seed and for interoperability)

  • fix: Dilithium keygen - add dimensions K and L (change is only relevant when storing keys as seed and for interoperability)

  • small performance improvements for hasher apps

Leancrypto Version 1.0.0

Code

Changes 1.0.0

  • enhancement: add Doxygen support - it is automatically compiled if Doxygen is present

  • enhancement: add Dilithium-ED25519 stream mode operation (i.e. init/update/final)

  • due to the Dilithium-ED25519 stream mode support, the Dilithium-ED25519 now used ED25519ph signature algorithm mode

  • Dilithium API change: the stream mode uses struct lc_dilithium_ctx instead of lc_hash_ctx to reflect the newly added Dilithium-ED25519 API - the lc_dilithium_ctx can be allocated on the stack or heap using LC_DILITHIUM_CTX_ON_STACK or lc_dilithium_ctx_alloc

  • enhancement: add Dilithium-ED25519 as Linux kernel akcipher algorithm

  • enhancement: make Kyber-X25519 as Linux kernel kpp algorithm consistent with the standalone Kyber kpp implementation and add a tester

  • seeded_rng: when using the ESDM as entropy source, use DRBG without prediction resistance. When having heavy respawning of applications, using the PR DRBG will strain the entropy source significantly.

  • Dilithium: add edge case tests as referenced by https://github.com/usnistgov/ACVP/pull/1525.patch and https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/G8Zf0hC-uu0/m/Kb3qNJb0AwAJ

Leancrypto Version 0.11.0

Code

Changes 0.11.0

  • security fix: fix possible leak of message in Kyber

  • Kyber: reduce memory footprint, use common lc_memcmp_secure API

  • Ascon-Keccak: include the tag length into the IV and thus implicitly authenticate the tag length (thanks to Markku-Juhani Saarinen to suggest this)

  • Kyber: change standard API such that caller can select Kyber type

  • Dilithium: change standard API such that caller can select Dilithium type

  • security: addition of Timecop and instrumentation of tests to find side-channels

  • enhancement: add Linux kernel crypto API support for Ascon / Ascon-Keccak

  • fix: performance of seeded RNG by setting reseed threshold to 1MB

  • fix: Linux kernel warning on return thunk

  • enhancement: add ASM ARMv7 and ARMv8 implementation for X25519

  • enhancement: add Ascon support for XDRBG

  • enhancement: performance increase for XDRBG256

  • enhancement: add ED25519ph to support Dilithium hybrid init/update/final handling

Leancrypto Version 0.10.1

Code

Changes 0.10.1

  • enhancement: Linux kernel - Kyber: allow parallel compilation of all Kyber types including all optimizations

  • enhancement: Linux kernel - Dilithium: allow parallel compilation of all Dilithium types including all optimizations

  • add additional hardening compiler flags stipulated by openssf.org

Changes 0.10.0

  • enhancement: add Sponge APIs

  • enhancement: add Ascon Keccak 512 and 256

Leancrypto Version 0.10.0

Code

Changes 0.10.0

  • enhancement: add Sponge APIs

  • enhancement: add Ascon Keccak 512 and 256

  • update AEAD: add lc_aead_enc|dec_init and change all AEAD algo’s tag calculation to now perform MAC(AAD || ciphertext) instead of MAC(ciphertext || AAD) - this brings it in line with all AEAD algorithms

  • enhancement: add Ascon AEAD 128 and 128b

  • rename API lc_shake to lc_xof

  • enhancement: add Ascon Hash 128 and 128a

  • enhancement: add Ascon XOF and XOFa

  • enhancement: add Ascon 128/128a hasher apps

  • large data tests can now execute on small systems by using smaller memory sizes

  • remove riscv64 hash assembler directory: it is a duplicate of the riscv32 assembler code

  • Kyber 768: Add AVX2, ARMv8, ARMv7 support

  • Dilithium 65: Add AVX2, ARMv8, ARMv7 support

  • Enable compilation of Kyber 1024, Kyber-768 and Kyber-512 at the same time (APIs starting with lc_kyber_768/lc_kex_768 refer to Kyber-768, APIs starting with lc_kyber_512/lc_kex_512 refer to Kyber-512, all others refer to Kyber-1024)

  • Enable compilation of Dilithium 87, Dilithium-65 and Dilithium-44 at the same time (APIs starting with lc_dilithium_65 refer to Dilithium-768, APIs starting with lc_dilithium_44 refer to Dilithium-44, all others refer to Dilithium-87)

  • enhancement: Windows is now supported as target platform using the MINGW compiler with full acceleration support

  • Dilithium: update SampleInBall implementation following https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/y8ul-ZcVWI4 - implementation is fully checked against NIST ACVP Demo server

Leancrypto Version 0.9.2

Code

Changes 0.9.2

  • fix: update “reduce memory footprint of Keccak state” to handle big-endian systems

  • enhancement: Seed the lc_seeded_rng with (random.c || Jitter RNG)

Leancrypto Version 0.9.1

Code

Changes 0.9.1

  • fix: move XOR-256 memory definitions to lc_memory_support.h as otherwise compilation of external applications and libraries fail due to missing xor256.h

Leancrypto Version 0.9.0

Code

Changes 0.9.0

  • enhancement: X/ED25519: enable 128 bit mode on Intel for both, kernel and user space

  • add Rust binding support

  • enhancement: reduce memory footprint of Keccak state

  • enhancement: add cSHAKE re-init support

  • fix: KMAC-AEAD / cSHAKE-AEAD - ensure proper re-initialization

  • enhancement: add RISC-V 64 bit Keccak - currently disabled due to a bug

  • enhancement: compile Dilithium ARMv8 support in Linux kernel (excluding the SIMD Keccak operation)

  • fix: fix ARM-CE detection logic

  • fix: potential Kyber side channel

  • fix: KMAC min MAC size is 32 bits

  • enhancement: use accelerated XOR for KMAC/cSHAKE AEAD

  • fix: enable poly_compress_avx for Linux kernel compilation when GCC >= 13 is present

  • enhancement: add interface code to register leancrypto with Linux kernel crypto API

Leancrypto Version 0.8.0

Code

Changes 0.8.0

  • enhancement: add applications

  • enhancement: add Dilithium ARMv8 support (including SHAKE 2x ARMv8 support)

  • enhancement: add Dilithium ARMv7 support

  • enhancement: add Kyber ARMv7 support

  • reduce memory footprint of Dilithium and Kyber

  • enhancement: Add Kyber-X25519 KEM, KEX, and IES

  • enhancement: Add Dilithium-ED25519

  • hardening: use -fzero-call-used-regs=used-gpr if available to counter ROP attacks

  • fix: Add fork-detection for seeded_rng

  • update XDRBG256 implementation based on latest draft

Leancrypto Version 0.7.0

Code

Changes 0.7.0

  • enhancement: add XDRBG256 - the SHAKE256-based DRNG discussed for SP800-90A inclusion (almost idential to cSHAKE/KMAC DRNG specified with leancrypto)

  • enhancement: add SymKMAC AEAD algorithm - it uses 100 bytes less context than SymHMAC (it is less than 1024 bytes now), uses accelerated Keccak for KDF and authentication but is otherwise identical to SymHMAC

  • Kyber: switch responder and initiator definitions

  • enhancement: add ESDM seed source to seed lc_seeded_rng

  • editorial: reformat code using clang-format and provided configuration file

  • Dilithium: Update implementation to match FIPS 204 (draft from Aug 24, 2023)

  • Kyber: Update implementation to match FIPS 203 (draft from Aug 24, 2023)

  • enhancement: Dilithium and Kyber security strengths are selectable via Meson options

  • Kyber KEM: Update shared secret KDF (as the KDF is now removed from FIPS 203, it can be adjusted to be more performant and consistent with SP800-108)

  • Kyber KEX: Updated shared secret KDF to use SP800-108 compliant KMAC KDF

  • enhancement: Add input parameter validatino to Kyber as specified in FIPS 203

  • enhancement: consolidate all testing requiring an RNG to use selftest_rng

Leancrypto Version 0.6.0

Code

Changes 0.6.0

  • enhancement: Linux - add memfd_secret(2) support for secure memory allocation

  • fix: documentation of lc_kyber_keypair

  • enhancement: remove the rng_ctx parameter in all Kyber APIs except the key generation - internally lc_seeded_rng is used instead

  • enhancement: use -Wmissing-prototypes and fix reported issues

  • enhancement: provide standalone CBC, CTR, KW implementation

  • enhancement: provide AESNI implementation

  • enhancement: provide AES ARM CE implementation

  • enhancement: provide AES RISC-V 64 assembler implementation

  • enhancement: provide Linux kernel configuration option to enable startup health tests

  • fix: apply fixes such that all self tests and regression tests pass when compiled for Linux kernel

  • fix: properly zeroize memory when using the workspace memory

Leancrypto Version 0.5.3

Code

Changes 0.5.3

  • convert to safe min/max implementations

  • enhancement: allow kernel modules to be compiled directly from installed user space headers

  • enhancement: make ARMv8 code compile on macOS

  • use O3 compiler optimization instead of Os - O3 is significantly faster especially for Kyber C implementation, yet both options work fine

Leancrypto Version 0.5.2

Code

Changes 0.5.2

  • enhancement: add ARMv7 Neon assembler support for Keccak

  • enhancement: add but disable ARMv8 Neon assembler support for Keccak (it is slower than optimized C)

  • enhancement: add sign/update/final Dilithium APIs

  • enhancement: add RISC-V assembler support for Keccak (yet disabled)

  • enhancement: add ARMv8 assembler implementation of Kyber

  • enhancement: add counter KDF RNG interface

  • enhancement: add ARMv8 assembler and ARMv8 CE Keccak support

Leancrypto Version 0.5.1

Code

Changes 0.5.1

  • enhancement: add Linux kernel configuration options

  • enhancement: add lc_rerun_selftests API

  • enhancement: add AVX2 support for memcmp_secure

  • fix: some comments

Leancrypto Version 0.5.0

Code

Changes 0.5.0

  • enhancement: add ability to compile leancrypto for the Linux kernel including all tests

  • enhancement: make leancrypto generic such that it can be used in environments other than user space

  • enhancement: add compile time option small_stack which ensures that leancrypto’s stack usage is always less than 2048 (also verified by the compiler warning if it is bigger)

  • enhancement: Add assembler accelerations for SHA3 (AVX2 and AVX512 are verified with NIST’s ACVP service)

  • bug fix: Fix the SHA-3 C implementation on big-endian system (one byte-swap missing)

  • bug fix: SHAKE128 state had wrong size causing an overflow with the memset_secure in lc_hash_zero

  • fix: remove compile-time warnings on 32 bit systems

  • enhancement: SHAKE AVX2 4x implementation used by Kyber AVX2 implementation

  • enhancement: Kyber AVX2 support

  • enhancement: Dilithium AVX2 support

  • leancrypto tested on macOS with an M2 system

  • bug fix: Dilithium C on Big Endian had implicit type casts leading to endianess issues

  • enhancement: add RPM SPEC file - successful build on OpenSUSE build service on x86_64, i586, aarch64, armv7l, armv6l, ppc64, ppc64le, riscv64

  • rename memset_secure to lc_memset_secure preventing any possible name space clash

  • enhancement: add self tests to all algorithms

  • bug fix: ChaCha20 on BigEndian systems

Leancrypto Version 0.4.0

Code

Changes 0.4.0

  • simplify Kyber code

  • add RNG context to HKDF

  • add RNG context to KMAC

  • add AES 128/192/256, ECB, CBC, CTR, KW

  • add lc_seeded_rng

  • add lc_aead API to provide common interface to AEAD algorithms

  • add KyberIES

  • change API to Kyber KEM: allow caller to specify size of generated key

  • add leancrypto.h for ease of use

  • add SymHMAC AEAD algorithm

  • add cSHAKE 128

  • add KMAC 128

Leancrypto Version 0.3.0

Code

Changes 0.3.0

  • Introduce lc_rng.h as a common interface to the random number generators

  • add KMAC DRNG

  • add cSHAKE DRNG

  • add SHAKE-128

  • add dilithium signature PQC schema - test vectors were generated by leancrypto, but compared with the reference implementation which calculate the same results

  • add kyber KEM PQC schema - test vectors were generated by leancrypto, but compared with the reference implementation which calculate the same results

  • add cSHAKE AEAD cipher

  • KMAC-AEAD cipher: auth key is now set to 256 bits

Cryptographic Algorithms

Leancrypto offers various cryptographic algorithms:

  • Authenticated Encryption with Associated Data

    • Ascon-AEAD128 (SP800-232)

    • Ascon Keccak 256 and 512 AEAD, see Ascon-Keccak for full specification

    • cSHAKE-based AEAD algorithm - algorithm devised with leancrypto, see cSHAKE-AEAD for full specification

    • hash-based AEAD algorithm - algorithm devised with leancrypto, see hash_crypt.c for full specification

    • KMAC-based AEAD algorithm - algorithm devised with leancrypto, see KMAC-AEAD for full specification

    • AES-based AEAD algorithm using SHA2 - see symhmac_crypt.c for full specification

    • AES-based AEAD algorithm using Keccak-based KMAC - see symkmac_crypt.c for full specification

  • Pseudo Random Number Generators

  • Message Digest algorithms

    • SHA2-256, SHA2-512

    • SHA3-224, SHA3-256, SHA3-384, SHA3-512

    • SHAKE-128, SHAKE-256

    • cSHAKE-128, cSHAKE-256

    • Ascon-Hash256 (SP800-232)

    • Ascon-XOF128 (SP800-232)

  • Keyed Message Digest algorithms

    • HMAC

    • KMAC

  • Key Derivation Functions

    • HKDF

    • SP800-108 KDF (counter, feedback, double pipelining mode)

    • PBKDF2

  • Key Encapsulation Mechanism

  • One Time Pad algorithms

    • HOTP

    • TOTP

  • Signature algorithm

    • ML-DSA (Dilithium) including HashML-DSA

    • ML-DSA (Dilithium) hybrid signature operation with Curve25519

    • SLH-DSA (Sphincs+) including HashSLH-DSA

  • Symmetric algorithms

    • AES: ECB, CBC, CTR, KW

    • ChaCha20

Leancrypto API Documentation

Doxygen Documentation

The Doxygen Documentation is automatically generated during the compilation of the source code if the doxygen binary is found on the host system.

API Documentation in Header Files

The leancrypto API is documented in the exported header files. The only header file that needs to be included in the target code is #include <leancrypto.h>. This header file includes all algorithm-specific header files for the compiled and supported algorithms.

To fully understand the API, please consider the following base concept of leancrypto: Different algorithm implementations are accessible via common APIs. For example, different random number generator algorithms are accessible via the RNG API. To ensure the common APIs act on the proper algorithm, the caller must use algorithm-specific initialization functions. The initialization logic returns a “cipher handle” that can be used with the common API for all subequent operations.

The various header files contain data structures which are provided solely for the purpose that appropriate memory on stack can be allocated. These data structures do not consititute an API in the sense that calling applications should access member variables directly. If access to member variables is desired, proper accessor functions are available. This implies that changes to the data structures in newer versions of the library are not considered as API changes!

The following list enumerates all algorithm-specific header files which contains the respective API documentation:

Example Code

Almost all test cases found in the various tests directories use the aforementioned public APIs and thus serve as example code for the given algorithms.

Debugging Support

The leancrypto library offers various types of debugging support outlined in the following sections.

Kyber / Dilithium: Print Results of Intermediate Calculation Steps

An implementation that is compliant with the NIST implementation that complies with FIPS 203 draft as well as additional changes expressed by NIST at the PQC-Forum is provided with leancrypto. It allows developers to compile both Kyber and Dilithium in a debug mode where the calculation results of each step of the key generation, Kyber encapsulation and decapsulation, as well as the Dilithium signature generation and verification can be displayed. This allows other developers to compare their implementation to match with leancrypto. The following steps have to be taken to obtain the debug output after fetching the library from the provided link and making sure the meson build system is available:

Kyber:

  1. Setup of the build directory: meson setup build

  2. Configure Kyber debug mode: meson configure build -Dkyber_debug=enabled

  3. Compile the code: meson compile -C build

  4. Execute the test tool providing the output of Kyber, ML-KEM-1024: build/kem/tests/kyber_kem_tester_c

  5. Execute the test tool providing the output of Kyber, ML-KEM-768: build/kem/tests/kyber_768_kem_tester_c

  6. Execute the test tool providing the output of Kyber, ML-KEM-512: build/kem/tests/kyber_512_kem_tester_c

Dilithium:

  1. Setup of the build directory (if it was not already set up for the Kyber tests): meson setup build

  2. Configure Dilithium debug mode: meson configure build -Ddilithium_debug=enabled`

  3. Compile the code: meson compile -C build

  4. Execute the test tool providing the output of Dilithium, ML-DSA-87: build/signature/tests/dilithium_tester_c

  5. Execute the test tool providing the output of Dilithium, ML-DSA-65: build/signature/tests/dilithium_65_tester_c

  6. Execute the test tool providing the output of Dilithium, ML-DSA-44: build/signature/tests/dilithium_44_tester_c

The test tool outputs is segmented into the key generation steps, Dilithium signature generation and verification steps, as well as Kyber encapsulation and decapsulation steps. The output specifies the mathematical operation whose result is shown. When displaying the output of a vector, one line is used. When displaying a matrix, the output of one row of the matrix is displayed per line. This implies that as many lines are printed as rows are present in the matrix.

During the course of the development of both Kyber and Dilithium reference implementations, NIST developers reached out to compare intermediate results of both algorithms with the ones produced by leancrypto. The debug logging information was used as a basis for the discussion with the NIST development team to verify that both implementations i.e. the NIST reference implementation as well as leancrypto, correspond.

Side-Channel Analysis

Side channels is a recurring problem which can inadvertently leak sensitive data where the leak may be visible not just locally, but possibly also remotely. Thus, finding side channels based on sensitive data is important.

The leancrypto library has built-in support for finding side-channels (or the lack thereof) by marking memory holding sensitive data and using Valgrind to identify any possible side channels. The concept is summarized on the Timecop web page as follows:

Even though modern CPUs and operating systems have various methods to separate processes from one another, some side-channels can remain that allow attackers to extract information across process, CPU, or even network boundaries.

One such side-channel can open up when the execution time of a piece of code depends on secret data. This class of vulnerabilities has been used succesfully in the past to extract encryption keys from AES, private keys from RSA, and other kinds of attacks.

Timing side-channels can be hard to spot in the wild, but they can be detected automatically to some degree with dynamic analysis.

How it works

Most timing side-channels are rooted in one of the following three causes:

  • Conditional jumps based on secret data [1] e.g. if (key[i] == 0)

  • Table lookups at secret indices [2], [3], [4], [5] e.g. s[i] = substitution_table[key[i]]

  • Variable-time CPU instructions operating on secret data [6], e.g. key[i] / c On Intel Pentium 4, the number of cycles for a division instruction depends on the arguments.

Adam Langley described in 2010 how the first two types can be detected automatically using Valgrind.

Valgrind is a framework for dynamic code analysis that comes with a large range of tools for specific analysis tasks. One of those tools checks memory usage to identify memory leaks, use of uninitialized memory, read after free, and other common problems related to memory management.

When Valgrind checks for the use of uninitialized memory, it performs exactly the checks necessary to spot timing side-channels. By flagging secret data as uninitialized for Valgrind, it will report any cases where conditional jumps or table lookups are based on secret data.

Limitations

Valgrind cannot spot cases where variable-time code is caused by variable-time CPU instructions.

Testing Instructions

To perform such a side channel analysis, apply the following steps:

  1. Configure leancrypto with the following option: meson configure build -Dtimecop=enabled

  2. Compile the code

  3. Execute different test cases with Valgrind as follows: valgrind --track-origins=yes build/kem/tests/kyber_kem_tester_common

  4. A side channel is present if Valgrind reports an issue like the following where it reports a “Conditional jump or move depends on uninitialised value(s)” based on “Uninitialised value was created by a client request”:

==13317== Conditional jump or move depends on uninitialised value(s)
==13317==    at 0x4851A2E: bcmp (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==13317==    by 0x10A86F: lc_compare (../internal/src/compare.c:52)
==13317==    by 0x10A6A8: _kmac_256_tester (../kmac/tests/kmac_256_tester.c:912)
==13317==    by 0x10A410: kmac_tester (../kmac/tests/kmac_256_tester.c:942)
==13317==    by 0x10A410: main (???:956)
==13317==  Uninitialised value was created by a client request
==13317==    at 0x48A0E7A: lc_kmac_init (../kmac/src/kmac.c:119)
==13317==    by 0x10A665: _kmac_256_tester (../kmac/tests/kmac_256_tester.c:909)
==13317==    by 0x10A410: kmac_tester (../kmac/tests/kmac_256_tester.c:942)
==13317==    by 0x10A410: main (???:956)

References

[1] Onur Acıiçmez, Çetin Kaya Koç, Jean-Pierre Seifert, Predicting secret keys via branch prediction. In Proceedings of the 7th Cryptographers’ Track at the RSA Conference on Topics in Cryptology

[2] Yuval Yarom, Katrina Falkner, FLUSH+RELOAD: a High Resolution, Low Noise, L3 Cache Side-Channel Attack.

[3] Daniel J. Bernstein, Cache-timing attacks on AES.

[4] Paul C. Kocher, Timing Attacks in Implementations of Diffie-Hellman, RSA, DSS, and Other Systems.

[5] Mehmet Sinan İnci, Berk Gülmezoğlu, Gorka Irazoqui, Thomas Eisenbarth, Berk Sunar, Seriously, get off my cloud! Cross-VM RSA Key Recovery in a Public Cloud.

[6] Thierry Kaufmann, Hervé Pelletier, Serge Vaudenay, and Karine Villegas When Constant-time Source Yields Variable-time Binary: Exploiting Curve25519-donna Built with MSVC 2015.

CAVP Certificates

The leancrypto library is tested with the NIST ACVP framework and received the following certificates.

The testing was conducted using the ACVP Parser.

Version 1.2.0

leancrypto CAVP Certificates

Version 1.1.0

leancrypto CAVP Certificates

Version 1.0.1

leancrypto CAVP certificates

Version 1.0.0

This version obtained the first ever ML-DSA and ML-KEM CAVP certificates!

leancrypto CAVP certificates

Version 0.8.0

Version 0.7.0

Version 0.6.0

FIPS 140 Support

Leancrypto intends to implement all FIPS 140 requirements, albeit sometimes in its own ways. This document gives an overview of the FIPS 140 compliance.

Status

The following status regarding FIPS 140 compliance is achieved:

  • leancrypto compiled as ELF binary (e.g. Linux): fully FIPS 140 compliant

  • other binary types (e.g. Apple, Windows, EFI): FIPS 140 compliance achieved for all aspects except the integrity test. See section Integrity Test for details.

General Approach

The leancrypto library always is compiled as a FIPS 140 module. To achieve that, it is compiled into two binaries:

  1. leancrypto-fips.[so|a] contains the FIPS 140 compliant code, all FIPS-approved algorithms and defines the FIPS 140 physical / logical boundary. This means that this library forms the “FIPS module”.

  2. leancrypto.[so|a] contains the full leancrypto code base including the FIPS 140 code and FIPS-non-approved algorithms.

When a caller wants to request services from the FIPS module, the caller MUST link to leancrypto-fips.

The compilation provides both libraries to allow developers to choose even at startup time of the consuming application whether the FIPS module version of leancrypto is used. Both are API-identical with the exception that the leancrypto-fips only contains FIPS-approved algorithms and activates FIPS-approved functionality.

NOTE: Due to time constraints, the Linux kernel variant is not split up into FIPS-approved and -non-approved code. Albeit technically it is simple to ensure the Linux kernel variant of leancrypto compiles the FIPS module, this is not yet offered.

Available Services

Leancrypto allows the de-selection of algorithms at compile time with the various meson options. This is also allowed for the FIPS-approved version of leancrypto.

When de-selecting algorithms at compile time, the respective services are reduced by this set of services.

List of Cryptographic Algorithms

Leancrypto offers approved cryptographic algorithms as defined by the ACVP-Proxy definition. This definition also covers all implementations of the cryptographic algorithm.

NOTE: The reference of “C” implementations in the ACVP Proxy may be a bit deceiving for ML-KEM and ML-DSA as for some platforms, assembler accelerations are natively used by the C code (ARMv7 and RISCV). Yet, the reference is correct as the caller interacts with the implementation that does not require specific CPU instructions.

NOTE2: The referenced ACVP proxy definitions explicitly exclude SHA LDT tests. This is only due to the fact that for the release testing of leancrypto, some test systems do not have more than 1GB of RAM which means that a linear buffer of 1GB or more cannot be allocated. There is no cryptographic limitation in leancrypto preventing the testing of LDT test vectors. Thus, if your platform has more RAM, you SHOULD enable the LDT testing.

Service Indicator

The leancrypto-fips FIPS module implements a global service indicator. This implies that all algorithms are FIPS-approved and the fact that the FIPS module is active is the indicator that FIPS-approved services are available.

The API of lc_status provides the version information along with the status whether the FIPS mode is active.

Cryptographic Algorithm Self Test

Each cryptographic algorithm has its own power-up self test which is executed before this algorithm is used for the first time.

The caller may trigger a complete new round of self tests, i.e. all algorithms will perform a new self test before the next use, when using the API of lc_rerun_selftests. To reperform the integrity test, the API lc_fips_integrity_checker is provided.

When a self-test fails, leancrypto-fips aborts and terminates itself as well as the calling application.

Leancrypto provides multiple implementations of one algorithm. Furthermore, it contains a “selector” heuristic which selects the fastest implementation at the time when using the algorithm at runtime. This heuristic depends on the detection of CPU mechanisms required by the accelerated algorithm implementations. Considering that on one given CPU (i.e. execution environment) the heuristic will always select the same algorithm, the self test is executed only once for the selected implementation.

Integrity Test

NOTE: The integrity test is only supported for ELF binaries only so far. To change that, perform the following steps:

  • Create a suitable replacement for fips_integrity_checker.c and compile it (search for “FIPS 140 Integrity check” in the internal/src/meson.build).

  • If applicable, add the required compilation options for libleancrypto-fips in the main meson.build (search for “FIPS 140 Integrity check”).

The integrity test uses SHA3-256. Due to the architecture of leancrypto, the selected message digest is executed after its self test is performed.

ELF Binary Integrity Test

The FIPS 140 integrity test on the leancrypto-fips library instance is implemented as follows but only for the libleancrypto-fips.[so|a] variants.

First, a libleancrypto-real.a is compiled which contains all FIPS approved algorithm code, the self tests and auxiliary code required to comply with all FIPS requirements. The only exception is the file fips_integrity_checker.c which contains the constructor starting up the integrity test and the integrity check control values.

The libleancrypto-real.a is linked together with fips_integrity_checker_elf.c into libleancrypto-fips.[so|a] using the linker script fips_integrity_check.ld. This linker script adds a start and end pointers for the text and rodata ELF segments. Both segments contains all code and readonly data (e.g. self test data) from libleancrypto-real.a and the fips_integrity_checker_elf.c, i.e. all FIPS module code / data. The only exception is the integrity check control value which are placed into a different section. This approach now allows to calculate the integrity of the text and rodata segments by the start/end pointers added by the linker script and adjust the integrity control values after compilation.

The following ELF sections are covered by the integrity check in their entirety:

  • .init section (covering the initialization steps)

  • .ctors section (covering constructors)

  • .text section (covering the entire code - note, some static data provided with assembler files is also placed into the text section)

  • fips_rodata section: This section is specifically introduced to cover all static data required by algorithm implementations (e.g. ML-KEM / ML-DSA constants, SHA2 constants, AES S-Boxes)

  • .rodata section (covering the constant data) is not covered due to technical limitations - it is not required to be covered as this section contains the self-test values. Considering that the self-test data is verified before the first use of an algorithm and all parts of an algorithm are self tested, the self-test vectors do not need to be covered by integrity verification.

The sizes of the sections covered by the integrity check can be shown by invoking the command leancrypto-fips-raw-generator that is created during compile time. When invoking it, it reports that the used integrity check values are wrong followed by the used start/end pointers of the sections and their length. The lengths can be compared to the sizes reported by readelf -WS libleancrypto-fips.so. The sizes reported by the leancrypto-fips-raw-generator tool may be a bit larger than the real segment sizes because the start/end markers of the sections encapsulate the section meta data.

Pairwise Consistency Test

The PCT is automatically enabled for the following algorithms:

  • ML-KEM

  • hybrid ML-KEM - only the ML-KEM key pair generation

  • ML-DSA

  • hybrid ML-DSA - only the ML-DSA key pair generation

  • SLH-DSA

  • ED25519

Initialization

Leancrypto utilizes the “constructor” functionality from the underlying platform to automatically perform initialization operations at startup time before the consuming application can interact with leancrypto. This constructor usage is defined with the macro LC_CONSTRUCTOR.

For environments where no constructor is offered, such as the EFI environment or the Linux kernel, the function lc_init is provided. This function must be registered such that it is triggered during load time of the library before a consumer can use the services offered by leancrypto. For example, the Linux kernel code linux_kernel/leancrypto_kernel.c which would be part of a FIPS module invokes lc_init automatically during loading of the leancrypto.ko kernel module.

Random Number Generator and Entropy Source

Leancrypto offers a fully seeded RNG instance that can readily be used everywhere where a FIPS-approved random number generator is required by using lc_seeded_rng.

Leancrypto does not implement any entropy source. Yet, it implements support for several entropy sources that can be selected at compile time:

  • builtin: This option uses the underlying operating system’s default entropy sources as implemented in drng/src/seeded_rng_*.c such as the getrandom system call on Linux or getentropy system call on BSD / macOS.

  • cpu: This option uses the CPU entropy sources as implemented in drng/src/es_cpu, such as RDSEED on Intel x86 systems. This option is the default when compiling leancrypto for the EFI environment.

  • esdm: This option uses the ESDM as entropy source.

  • jent: This option uses the Jitter RNG as entropy source.

NOTE: The default RNG used by leancrypto is the XDRBG. At the time of writing (beginning 2025), it is not yet FIPS-approved. However, SP800-90A is subject to revision at the time of writing and it is planned to add the XDRBG as an approved algorithm. Therefore, leancrypto selects XDRBG as default. If that shall be changed, the macros LC_SEEDED_RNG_CTX_SIZE and LC_SEEDED_RNG_CTX found in drng/src/seeded_rng.c must be set to either the Hash DRBG or HMAC DRBG at compile time.

API and Usage Documentation

The documentation of the API as well as the usage of leancrypto, including the FIPS module variant, is provided with Doxygen. Either the online version is used or Doxygen is present during compile time to automatically generate the guidance out of the source code. The resulting documentation is found in <meson-build-directory>/doc.

ACVP Testing

ACVP-Testing is provided with the ACVP-Parser. This parser offers the testing of the user space as well as the kernel space variant of leancrypto.

The mentioned ACVP-Parser was used to obtain all certificates listed on the leancrypto CAVP website.

Random Notes

ECDH 25519 is compiled as part of the FIPS module, but is non-approved. This is considered acceptable because the algorithm is not available via an API. Instead, the algorithm is used as part of the hybrid ML-KEM which use it as follows: Hybrid ML-KEM performs an SP800-108 KDF (KMAC256) using the concatenated output of ML-KEM and ECDH 25519 to generate the final shared secret. This is approved as per SP800-56C rev 2 chapter 2.

X.509 and PKCS#7 Support

X.509 Certificate Generator

The leancrypto library offers a X.509 certificate generator along with the X.509 parser. This generator allows to generate PQC certificates using all PQC algorithms offered by the library.

The generator is accessed by one of the following means:

  • Use of the X.509 API offered with lc_x509_generator.h.

  • Use of the X.509 generator application lc_x509_generator implemented in the apps/src directory.

The lc_509_generator application is to be considered a frontend to the API which implies that the API implements all important operations with respect to the generation.

The following sections outline lc_509_generator commands to obtain certificates.

The X.509 generator and parser for PQC certificates are tested with the artifacts from all other cryptographic providers collected at the IETF-Hackathon. In particular, the following algorithms were tested with the other implementations:

  • ML-DSA 44, ML-DSA 65, ML-DSA 87

  • SLH-DSA SHAKE256: 128s, 128f, 192s, 192f, 256s, 256f

  • Composite ML-DSA: ML-DSA44-ED25519, ML-DSA65-ED25519

Leancrypto passes the interoperability tests of the mentioned cipher algorithms.

Generate CA Certificate

The following command generates a new ML-DSA 87 key pair, generates a self-signed CA certificate with all proper key usage flags, and stores the following files:

  • ml-dsa87_cacert.der: X.509 Root-CA certificate

  • ml-dsa87_cacert.privkey: Raw ML-DSA 87 secret key

lc_x509_generator
  --keyusage digitalSignature
  --keyusage keyEncipherment
  --keyusage keyCertSign
  --keyusage critical
  --ca 
  --valid-from 1729527728
  --valid-to 2044210606
  --subject-cn "leancrypto test CA"
  --subject-ou "leancrypto test OU"
  --subject-o leancrypto
  --subject-st Saxony
  --subject-c DE
  --issuer-cn "leancrypto test CA"
  --issuer-ou "leancrypto test OU"
  --issuer-o leancrypto
  --issuer-st Saxony
  --issuer-c DE
  --serial 0102030405060708
  -o ml-dsa87_cacert.der
  --sk-file ml-dsa87_cacert.privkey
  --create-keypair ML-DSA87

The generated result looks like:

Serial Number: 01:02:03:04:05:06:07:08
Signature Algorithm: ML-DSA 87 <builtin>
Issuer: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test CA
Subject: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test CA
Valid From: 2024-10-21 18:22:08
Valid To: 2034-10-11 22:16:46
Public Key Algorithm: ML-DSA87
X509v3 Subject Key Identifier: 15:37:53:0b:15:c8:1c:27:31:f0:62:98:9f:c5:f7:d7:a9:bb:dc:36:14:78:38:fd:cb:30:80:01:43:2b:04:26
X509v3 Authority Key Identifier: 15:37:53:0b:15:c8:1c:27:31:f0:62:98:9f:c5:f7:d7:a9:bb:dc:36:14:78:38:fd:cb:30:80:01:43:2b:04:26
X509v3 Basic Constraints: CA (critical)
X509v3 Key Usage: (critical) digitalSignature keyEncipherment keyCertSign 
AuthID[0] = 
AuthID[1] = 1537530b15c81c2731f062989fc5f7d7a9bbdc36147838fdcb308001432b0426
AuthID[2] = 31633019060355040304126c65616e63727970746f20746573742043413011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
X.509 ID = 010203040506070831633019060355040304126c65616e63727970746f20746573742043413011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
Public key size 2592
Self-signed: yes

Note: If no --skid or no --akid are used, then they are generated by hasing the public key using the default message digest algorithm of SHA3-256.

Generate Intermediate 1 Certificate

The following command generates a new ML-DSA 65 key pair, generates an intermediate certificate signed by the root certificate generated in section [Generate CA Certificate], and stores the following files:

  • ml-dsa65_int1.der: X.509 intermediate CA certificate

  • ml-dsa65_int1.privkey: Raw ML-DSA 65 secret key

lc_x509_generator
  --keyusage digitalSignature
  --keyusage keyEncipherment
  --keyusage keyCertSign
  --keyusage critical
  --ca
  --valid-from 1729527728
  --valid-to 2044210606
  --subject-cn "leancrypto test int1"
  --subject-ou "leancrypto test OU"
  --subject-o leancrypto
  --subject-st Saxony
  --subject-c DE
  --serial 0203030405060708
  -o ml-dsa65_int1.der
  --sk-file ml-dsa65_int1.privkey
  --create-keypair ML-DSA65
  --x509-signer ml-dsa87_cacert.der
  --signer-sk-file ml-dsa87_cacert.privkey

The generated result looks like:

Serial Number: 02:03:03:04:05:06:07:08
Signature Algorithm: ML-DSA 87 <builtin>
Issuer: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test CA
Subject: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test int1
Valid From: 2024-10-21 18:22:08
Valid To: 2034-10-11 22:16:46
Public Key Algorithm: ML-DSA65
X509v3 Subject Key Identifier: eb:0f:c7:e1:2c:61:d5:96:04:c8:3a:46:c0:16:a1:18:5b:24:9b:6a:ff:87:0e:ce:4b:a8:a4:96:53:7c:62:f3
X509v3 Authority Key Identifier: 15:37:53:0b:15:c8:1c:27:31:f0:62:98:9f:c5:f7:d7:a9:bb:dc:36:14:78:38:fd:cb:30:80:01:43:2b:04:26
X509v3 Basic Constraints: CA (critical)
X509v3 Key Usage: (critical) digitalSignature keyEncipherment keyCertSign 
AuthID[0] = 
AuthID[1] = 1537530b15c81c2731f062989fc5f7d7a9bbdc36147838fdcb308001432b0426
AuthID[2] = 31633019060355040304126c65616e63727970746f20746573742043413011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
X.509 ID = 020303040506070831633019060355040304126c65616e63727970746f20746573742043413011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
Public key size 1952
Self-signed: no

Generate Intermediate 2 Certificate

The following command generates a new ML-DSA 44 key pair, generates an intermediate certificate signed by the intermediate 1 certificate generated in section [Generate Intermediate 1 Certificate], and stores the following files:

  • ml-dsa44_int2.der: X.509 intermediate CA certificate

  • ml-dsa44_int2.privkey: Raw ML-DSA 44 secret key

lc_x509_generator 
  --keyusage digitalSignature
  --keyusage keyEncipherment
  --keyusage keyCertSign
  --keyusage critical
  --ca
  --valid-from 1729527728
  --valid-to 2044210606
  --subject-cn "leancrypto test int2"
  --subject-ou "leancrypto test OU"
  --subject-o leancrypto
  --subject-st Saxony
  --subject-c DE
  --serial 0303040506070809
  -o ml-dsa44_int2.der
  --sk-file ml-dsa44_int2.privkey
  --create-keypair ML-DSA44
  --x509-signer ml-dsa65_int1.der
  --signer-sk-file ml-dsa65_int1.privkey

The generated result looks like:

Serial Number: 03:03:04:05:06:07:08:09
Signature Algorithm: ML-DSA 65 <builtin>
Issuer: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test int1
Subject: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test int2
Valid From: 2024-10-21 18:22:08
Valid To: 2034-10-11 22:16:46
Public Key Algorithm: ML-DSA44
X509v3 Subject Key Identifier: 3d:f5:05:f8:c2:fe:1a:95:e4:96:d5:40:3c:39:82:ff:4b:c7:41:ce:30:78:74:f8:22:8f:34:32:5c:17:3e:1d
X509v3 Authority Key Identifier: eb:0f:c7:e1:2c:61:d5:96:04:c8:3a:46:c0:16:a1:18:5b:24:9b:6a:ff:87:0e:ce:4b:a8:a4:96:53:7c:62:f3
X509v3 Basic Constraints: CA (critical)
X509v3 Key Usage: (critical) digitalSignature keyEncipherment keyCertSign 
AuthID[0] = 
AuthID[1] = eb0fc7e12c61d59604c83a46c016a1185b249b6aff870ece4ba8a496537c62f3
AuthID[2] = 3165301b060355040304146c65616e63727970746f207465737420696e74313011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
X.509 ID = 03030405060708093165301b060355040304146c65616e63727970746f207465737420696e74313011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
Public key size 1312
Self-signed: no

Generate Leaf Certificate

The following command generates a new ML-DSA 87 key pair, generates a leaf signed by the intermediate 2 certificate generated in section [Generate Intermediate 2 Certificate], and stores the following files:

  • ml-dsa87_leaf.der: X.509 leaf certificate with usual key usage and EKU flags

  • ml-dsa87_leaf.privkey: Raw ML-DSA 87 secret key

lc_x509_generator
  --keyusage dataEncipherment
  --keyusage critical
  --eku critical
  --eku serverAuth
  --eku codeSigning
  --valid-from 1729527728
  --valid-to 2044210606
  --subject-cn "leancrypto test leaf"
  --subject-ou "leancrypto test OU"
  --subject-o leancrypto
  --subject-st Saxony
  --subject-c DE
  --serial 0405060708090001
  -o ml-dsa87_leaf.der
  --sk-file ml-dsa87_leaf.privkey
  --create-keypair ML-DSA87
  --x509-signer ml-dsa44_int2.der
  --signer-sk-file ml-dsa44_int2.privkey

The generated result looks like:

Serial Number: 04:05:06:07:08:09:00:01
Signature Algorithm: ML-DSA 44 <builtin>
Issuer: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test int2
Subject: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test leaf
Valid From: 2024-10-21 18:22:08
Valid To: 2034-10-11 22:16:46
Public Key Algorithm: ML-DSA87
X509v3 Subject Key Identifier: c7:e3:6f:df:03:93:c2:25:06:2b:ee:85:02:73:c5:31:1f:6f:86:c8:31:05:93:f3:c2:44:bf:92:56:73:34:54
X509v3 Authority Key Identifier: 3d:f5:05:f8:c2:fe:1a:95:e4:96:d5:40:3c:39:82:ff:4b:c7:41:ce:30:78:74:f8:22:8f:34:32:5c:17:3e:1d
X509v3 Key Usage: (critical) dataEncipherment 
X509v3 Extended Key Usage: (critical) ServerAuthentication CodeSigning 
AuthID[0] = 
AuthID[1] = 3df505f8c2fe1a95e496d5403c3982ff4bc741ce307874f8228f34325c173e1d
AuthID[2] = 3165301b060355040304146c65616e63727970746f207465737420696e74323011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
X.509 ID = 04050607080900013165301b060355040304146c65616e63727970746f207465737420696e74323011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
Public key size 2592
Self-signed: no

PKCS#7 Message Generator

The leancrypto library offers a PKCS#7 message generator along with the PKCS#7 parser. This generator allows to generate PQC certificates using all PQC algorithms offered by the library.

The generator is accessed by one of the following means:

  • Use of the PKCS#7 API offered with lc_pkcs7_generator.h.

  • Use of the PKCS#7 generator application lc_pkcs7_generator implemented in the apps/src directory.

The lc_pkcs7_generator application is to be considered a frontend to the API which implies that the API implements all important operations with respect to the generation.

The following sections outline lc_pkcs7_generator commands to obtain such messages.

Generate PKCS#7 Message with 4-way Certificate Chain

The following command uses X.509 certificates and keys generated in the preceding sections:

  1. generates a PKCS#7 message ml-dsa.p7b

  2. signs the data found in the file ml-dsa87_cacert.der

  3. signs with the signer X.509 certificate ml-dsa87_leaf.der and its associated private key ml-dsa87_leaf.privkey

  4. adds the signer certificate, and the 3 CA certificates of ml-dsa44_int2.der, ml-dsa65_int1.der, and the root CA certificate ml-dsa87_cacert.der (the root or the intermediate certificates are not needed, provided they are present in the trust store during later verification)

  5. verifies the PKCS#7 message against a trust store holding the root CA certificate ml-dsa87_cacert.der

The command generates:

  • ml-dsa.p7b: PKCS#7 message
lc_pkcs7_generator
  -o ml-dsa.p7b 
  -i ml-dsa87_cacert.der
  --x509-signer ml-dsa87_leaf.der
  --signer-sk-file ml-dsa87_leaf.privkey
  --x509-cert ml-dsa44_int2.der
  --x509-cert ml-dsa65_int1.der
  --x509-cert ml-dsa87_cacert.der
  --trust-anchor ml-dsa87_cacert.der

Verify PKCS#7 Message with 4-way Certificate Chain

The following command verifies the PKCS#7 message generated in the preceding sections. It uses

  • the data in the file in the file ml-dsa87_cacert.der that was signed

  • the PKCS#7 message in ml-dsa.p7b

  • using the trust anchor ml-dsa87_cacert.der

lc_pkcs7_geerator
  --print-pkcs7 ml-dsa.p7b
  -i ml-dsa87_cacert.der
  --trust-anchor ml-dsa87_cacert.der

The command should return without an error. The command also prints out the PKCS#7 message with its 4-way certificate chain:

======= X.509 certificate listing ==========
Serial Number: 04:05:06:07:08:09:00:01
Signature Algorithm: ML-DSA44 <builtin hash>
Issuer: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test int2
Subject: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test leaf
Valid From: 2024-10-21 18:22:08
Valid To: 2034-10-11 22:16:46
Public Key Algorithm: ML-DSA87
X509v3 Subject Key Identifier: 0d:0e:0f:00:01:02:03
X509v3 Authority Key Identifier: 0c:0d:0e:0f:00:01:02
X509v3 Key Usage: (critical) dataEncipherment 
X509v3 Extended Key Usage: (critical) ServerAuthentication CodeSigning 
AuthID[0] = 
AuthID[1] = 0c0d0e0f000102
AuthID[2] = 3165301b060355040304146c65616e63727970746f207465737420696e74323011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
X.509 ID = 04050607080900013165301b060355040304146c65616e63727970746f207465737420696e74323011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
Public key size 2592
Self-signed: no
====== End one certificate ==========
Serial Number: 03:03:04:05:06:07:08:09
Signature Algorithm: ML-DSA65 <builtin hash>
Issuer: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test int1
Subject: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test int2
Valid From: 2024-10-21 18:22:08
Valid To: 2034-10-11 22:16:46
Public Key Algorithm: ML-DSA44
X509v3 Subject Key Identifier: 0c:0d:0e:0f:00:01:02
X509v3 Authority Key Identifier: 0b:0c:0d:0e:0f:00:01
X509v3 Basic Constraints: CA (critical)
X509v3 Key Usage: (critical) digitalSignature keyEncipherment keyCertSign 
AuthID[0] = 
AuthID[1] = 0b0c0d0e0f0001
AuthID[2] = 3165301b060355040304146c65616e63727970746f207465737420696e74313011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
X.509 ID = 03030405060708093165301b060355040304146c65616e63727970746f207465737420696e74313011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
Public key size 1312
Self-signed: no
====== End one certificate ==========
Serial Number: 02:03:03:04:05:06:07:08
Signature Algorithm: ML-DSA87 <builtin hash>
Issuer: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test CA
Subject: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test int1
Valid From: 2024-10-21 18:22:08
Valid To: 2034-10-11 22:16:46
Public Key Algorithm: ML-DSA65
X509v3 Subject Key Identifier: 0b:0c:0d:0e:0f:00:01
X509v3 Authority Key Identifier: 0a:0b:0c:0d:0e:0f
X509v3 Basic Constraints: CA (critical)
X509v3 Key Usage: (critical) digitalSignature keyEncipherment keyCertSign 
AuthID[0] = 
AuthID[1] = 0a0b0c0d0e0f
AuthID[2] = 31633019060355040304126c65616e63727970746f20746573742043413011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
X.509 ID = 020303040506070831633019060355040304126c65616e63727970746f20746573742043413011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
Public key size 1952
Self-signed: no
====== End one certificate ==========
Serial Number: 01:02:03:04:05:06:07:08
Signature Algorithm: ML-DSA87 <builtin hash>
Issuer: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test CA
Subject: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test CA
Valid From: 2024-10-21 18:22:08
Valid To: 2034-10-11 22:16:46
Public Key Algorithm: ML-DSA87
X509v3 Subject Key Identifier: 0a:0b:0c:0d:0e:0f
X509v3 Authority Key Identifier: 0a:0b:0c:0d:0e:0f
X509v3 Basic Constraints: CA (critical)
X509v3 Key Usage: (critical) digitalSignature keyEncipherment keyCertSign 
AuthID[0] = 
AuthID[1] = 0a0b0c0d0e0f
AuthID[2] = 31633019060355040304126c65616e63727970746f20746573742043413011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
X.509 ID = 010203040506070831633019060355040304126c65616e63727970746f20746573742043413011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
Public key size 2592
Self-signed: yes
====== End one certificate ==========
======= PKCS7 signed info listing ==========
Serial Number: 04:05:06:07:08:09:00:01
Signature Algorithm: ML-DSA44 <builtin hash>
Issuer: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test int2
Subject: C = DE, ST = Saxony, O = leancrypto, OU = leancrypto test OU, CN = leancrypto test leaf
Valid From: 2024-10-21 18:22:08
Valid To: 2034-10-11 22:16:46
Public Key Algorithm: ML-DSA87
X509v3 Subject Key Identifier: 0d:0e:0f:00:01:02:03
X509v3 Authority Key Identifier: 0c:0d:0e:0f:00:01:02
X509v3 Key Usage: (critical) dataEncipherment 
X509v3 Extended Key Usage: (critical) ServerAuthentication CodeSigning 
AuthID[0] = 
AuthID[1] = 0c0d0e0f000102
AuthID[2] = 3165301b060355040304146c65616e63727970746f207465737420696e74323011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
X.509 ID = 04050607080900013165301b060355040304146c65616e63727970746f207465737420696e74323011060355040a040a6c65616e63727970746f3009060355040604024445300d060355040804065361786f6e793019060355040b04126c65616e63727970746f2074657374204f55
Public key size 2592
Self-signed: no
Signed Authinfo = 8189304f06092a864886f70d0109043142044016cc53131266f12f8dbb5b10de31c1868a44c1b1a4eadb0d1ea43e36802cf5fe7aa2c22659be36ea3f8d4462a66eb2500533b1ac8378f8f96ae6e91031779878301806092a864886f70d010903310b00092a864886f70d010701301c06092a864886f70d010905310f170d3234313132313038313833385a
Signature Algorithm: ML-DSA87 <builtin hash>
AuthID[0] = 0d0e0f00010203
AuthID[1] = 
AuthID[2] = 
signerInfos messageDigest = 7f155a4b8be3f85994060b90c3ec0e6a2e4dc5dac44d904940289bf3006b421b8b7613825368d6c451676acd5b03df307f8921171fff4261fd0584ac0653160a
Message digest algorithm: SHA3-512
Size of protected data: 7606
====== End one PKCS7 signed info listing ==========

PKCS#7 Trust Verification

The trust verification is implemented with the API call of lc_pkcs7_verify. It applies the following approach:

  • The signer of the message must be present in the PKCS#7 message and its signature of the message is verified along with the signer certificate validity.

  • If no trust store is used, ensure that the certificate chain contains a root CA and that there is a certificate chain starting with the message signer to the CA. If such certificate chain validation was successful, the PKCS#7 message verification succeeds.

  • When generating a trust store, all added certificates are validated to lead to a root CA found in the trust store.

  • If a trust store is used, ensure that the certificate chain starts with the signer of the message and leads to a certificate found in the trust store. As any certificate in the trust store is guaranteed to have a valid chain to a root CA (see preceding bullet), no further certificate chain validation is applied. If such certificate chain validation is successful, the PKCS#7 message verification succeeds.

  • A root CA or intermediate CA certificate are required to possess the key usage flag of keyCertSign for successful validation.

  • A caller can provide the required key usage or EKU flags that a signer must bear for successful validation to lc_pkcs7_verify or via lc_pkcs7_generator.

Papers

The following table present papers written for various topics.

Link Abstract
Kyber and TLS This document outlines the shortcomings of a current proposal to add CRYSTALS Kyber into TLS and proposes an alternative solution.
KyberIES Specification This document provides the specification of Kyber Integrated Encryption Schema (IES) conceptually similar to ECIES.
Kyber KEX 2-way Approach This document provides the specification of Kyber Key Exchange (KEX) with integrated authentication that can serve as a Diffie-Hellman drop-in replacement.
AEAD algorithm based on KMAC or cSHAKE This document provides the specification of the cryptographic algorithm following the Authenticated Encryption with Additional Data (AEAD) approach using KMAC and cSHAKE.
Hybrid KEM Specification This document specifies the Hybrid KEM cryptographic algorithm combining Kyber and X25519.
Deterministic RNG Based on cSHAKE and KMAC This specification defines a simple deterministic random number generator (DRNG) which can be used to generate cryptographically secure random bit strings for various use cases including symmetric and asymmetric key generation services. The DRNG is based on either cSHAKE or KECCAK Message Authentication Code (KMAC) and is intended to support a wide range of applications and requirements, and is conservative in its resource consumption.
XDRBG Specification The document provides a specification of a deterministic random bit generator (DRBG) based on extensible output functions (XOF). It includes a security proof.
Ascon-Keccak Specification The document provides a specification of Ascon using the Keccak sponge to provide an AEAD algorithm with 256 and 512 bit classic security strength or 128 and 256 bit quantum security strength. The specification is also published at IACR.

XDRBG

The XDRBG is a random number generator using the SHAKE cryptographic primitive.

Algorithm Specification

The algorithm specification as publised at the ToSC 2024 conference.

The XDRBG specification provides the algorithm definition of the XDRBG along with the security proof. An updated version of the paper with the AIS 20/31 definition will be released soon. In addition, the XDRBG presentation provides a brief overview.

Source Code

The source code is available at the Github repository. The source code shows that XDRBG is lean compared to other deterministic random number generators. In addition, the code contains various tests to demonstrate the correctness of the implementation.

The XDRBG is also the default deterministic random number generator in leancrypto. The implementation of XDRBG in leancrypto uses accelerated Keccak primitives. The test harness executed with meson test also provides performance data for generating 1GBytes of data which can be compared to other deterministic random number generators offered by leancrypto.

About This Site

Code Signing Certificate

All source code distributed on this web site is signed. In order to verify the signature and thus the integrity and authenticity of the obtained code, use the following command:

1
gpg --verify leancrypto-*.tar.xz.asc leancrypto-*.tar.xz

This command only performs the verification if the associated public key was previously imported into the key ring. In case the public key needs to be imported, use the following command which imports the key from 2024:

1
curl https://leancrypto.org/about/smuellerDD-2024.asc | gpg --import

The following public keys are available: