diff options
Diffstat (limited to 'Documentation/crypto')
| -rw-r--r-- | Documentation/crypto/api-samples.rst | 2 | ||||
| -rw-r--r-- | Documentation/crypto/architecture.rst | 2 | ||||
| -rw-r--r-- | Documentation/crypto/async-tx-api.rst | 4 | ||||
| -rw-r--r-- | Documentation/crypto/index.rst | 2 | ||||
| -rw-r--r-- | Documentation/crypto/krb5.rst | 17 | ||||
| -rw-r--r-- | Documentation/crypto/libcrypto-auth-encryption.rst | 20 | ||||
| -rw-r--r-- | Documentation/crypto/libcrypto-blockcipher.rst | 19 | ||||
| -rw-r--r-- | Documentation/crypto/libcrypto-hash.rst | 88 | ||||
| -rw-r--r-- | Documentation/crypto/libcrypto-signature.rst | 11 | ||||
| -rw-r--r-- | Documentation/crypto/libcrypto-unauth-encryption.rst | 49 | ||||
| -rw-r--r-- | Documentation/crypto/libcrypto-utils.rst | 6 | ||||
| -rw-r--r-- | Documentation/crypto/libcrypto.rst | 168 | ||||
| -rw-r--r-- | Documentation/crypto/sha3.rst | 2 | ||||
| -rw-r--r-- | Documentation/crypto/userspace-if.rst | 144 |
14 files changed, 476 insertions, 58 deletions
diff --git a/Documentation/crypto/api-samples.rst b/Documentation/crypto/api-samples.rst index e923f17bc2bd..388bb7d7a460 100644 --- a/Documentation/crypto/api-samples.rst +++ b/Documentation/crypto/api-samples.rst @@ -159,7 +159,7 @@ Code Example For Random Number Generator Usage static int get_random_numbers(u8 *buf, unsigned int len) { struct crypto_rng *rng = NULL; - char *drbg = "drbg_nopr_sha256"; /* Hash DRBG with SHA-256, no PR */ + char *drbg = "stdrng"; int ret; if (!buf || !len) { diff --git a/Documentation/crypto/architecture.rst b/Documentation/crypto/architecture.rst index 249b54d0849f..ec2e99d99aff 100644 --- a/Documentation/crypto/architecture.rst +++ b/Documentation/crypto/architecture.rst @@ -95,7 +95,7 @@ additional templates may enclose other templates, such as :: - template1(template2(single block cipher))) + template1(template2(single block cipher)) The kernel crypto API may provide multiple implementations of a template diff --git a/Documentation/crypto/async-tx-api.rst b/Documentation/crypto/async-tx-api.rst index f88a7809385e..49fcfc66314a 100644 --- a/Documentation/crypto/async-tx-api.rst +++ b/Documentation/crypto/async-tx-api.rst @@ -82,9 +82,9 @@ xor_val xor a series of source buffers and set a flag if the pq generate the p+q (raid6 syndrome) from a series of source buffers pq_val validate that a p and or q buffer are in sync with a given series of sources -datap (raid6_datap_recov) recover a raid6 data block and the p block +datap (raid6_recov_datap) recover a raid6 data block and the p block from the given sources -2data (raid6_2data_recov) recover 2 raid6 data blocks from the given +2data (raid6_recov_2data) recover 2 raid6 data blocks from the given sources ======== ==================================================================== diff --git a/Documentation/crypto/index.rst b/Documentation/crypto/index.rst index 4ee667c446f9..705f186d662b 100644 --- a/Documentation/crypto/index.rst +++ b/Documentation/crypto/index.rst @@ -13,6 +13,7 @@ for cryptographic use cases, as well as programming examples. :caption: Table of contents :maxdepth: 2 + libcrypto intro api-intro architecture @@ -27,4 +28,3 @@ for cryptographic use cases, as well as programming examples. descore-readme device_drivers/index krb5 - sha3 diff --git a/Documentation/crypto/krb5.rst b/Documentation/crypto/krb5.rst index beffa0133446..f62e07ac6811 100644 --- a/Documentation/crypto/krb5.rst +++ b/Documentation/crypto/krb5.rst @@ -158,13 +158,22 @@ returned. When a message has been received, the location and size of the data with the message can be determined by calling:: - void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5, - enum krb5_crypto_mode mode, - size_t *_offset, size_t *_len); + int crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5, + enum krb5_crypto_mode mode, + size_t *_offset, size_t *_len); The caller provides the offset and length of the message to the function, which then alters those values to indicate the region containing the data (plus any -padding). It is up to the caller to determine how much padding there is. +padding). It is up to the caller to determine how much padding there is. The +function returns an error if the length is too small or if the mode is +unsupported. An additional function:: + + int crypto_krb5_check_data_len(const struct krb5_enctype *krb5, + enum krb5_crypto_mode mode, + size_t len, size_t min_content); + +is provided to just do a basic check that the decrypted/verified message would +have a sufficient minimum payload. Preparation Functions --------------------- diff --git a/Documentation/crypto/libcrypto-auth-encryption.rst b/Documentation/crypto/libcrypto-auth-encryption.rst new file mode 100644 index 000000000000..1e527685a42f --- /dev/null +++ b/Documentation/crypto/libcrypto-auth-encryption.rst @@ -0,0 +1,20 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Authenticated encryption +======================== + +These APIs provide support for authenticated encryption and decryption. + +AES-CCM +------- + +This API provides support for AES in the CCM mode of operation. + +.. kernel-doc:: include/crypto/aes-ccm.h + +AES-GCM +------- + +This API provides support for AES in the GCM mode of operation. + +.. kernel-doc:: include/crypto/aes-gcm.h diff --git a/Documentation/crypto/libcrypto-blockcipher.rst b/Documentation/crypto/libcrypto-blockcipher.rst new file mode 100644 index 000000000000..fd85e27fab8d --- /dev/null +++ b/Documentation/crypto/libcrypto-blockcipher.rst @@ -0,0 +1,19 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Block ciphers +============= + +AES +--- + +This API provides support for the AES block cipher. + +.. kernel-doc:: include/crypto/aes.h + +DES +--- + +This API provides support for the DES block cipher. This algorithm is obsolete +and is supported only for backwards compatibility. + +.. kernel-doc:: include/crypto/des.h diff --git a/Documentation/crypto/libcrypto-hash.rst b/Documentation/crypto/libcrypto-hash.rst new file mode 100644 index 000000000000..fa4c54236af6 --- /dev/null +++ b/Documentation/crypto/libcrypto-hash.rst @@ -0,0 +1,88 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Hash functions, MACs, and XOFs +============================== + +AES-CMAC and AES-XCBC-MAC +------------------------- + +This API provides support for the AES-CMAC and AES-XCBC-MAC message +authentication codes. + +.. kernel-doc:: include/crypto/aes-cbc-macs.h + +BLAKE2b +------- + +This API provides support for the BLAKE2b cryptographic hash function. + +.. kernel-doc:: include/crypto/blake2b.h + +BLAKE2s +------- + +This API provides support for the BLAKE2s cryptographic hash function. + +.. kernel-doc:: include/crypto/blake2s.h + +GHASH and POLYVAL +----------------- + +This API provides support for the GHASH and POLYVAL universal hash functions. +These algorithms are used only as internal components of other algorithms. + +.. kernel-doc:: include/crypto/gf128hash.h + +MD5 +--- + +This API provides support for the MD5 cryptographic hash function and HMAC-MD5. +This algorithm is obsolete and is supported only for backwards compatibility. + +.. kernel-doc:: include/crypto/md5.h + +NH +-- + +This API provides support for the NH universal hash function. This algorithm is +used only as an internal component of other algorithms. + +.. kernel-doc:: include/crypto/nh.h + +Poly1305 +-------- + +This API provides support for the Poly1305 universal hash function. This +algorithm is used only as an internal component of other algorithms. + +.. kernel-doc:: include/crypto/poly1305.h + +SHA-1 +----- + +This API provides support for the SHA-1 cryptographic hash function and +HMAC-SHA1. This algorithm is obsolete and is supported only for backwards +compatibility. + +.. kernel-doc:: include/crypto/sha1.h + +SHA-2 +----- + +This API provides support for the SHA-2 family of cryptographic hash functions, +including SHA-224, SHA-256, SHA-384, and SHA-512. This also includes their +corresponding HMACs: HMAC-SHA224, HMAC-SHA256, HMAC-SHA384, and HMAC-SHA512. + +.. kernel-doc:: include/crypto/sha2.h + +SHA-3 +----- + +The SHA-3 API is documented in :ref:`sha3`. + +SM3 +--- + +This API provides support for the SM3 cryptographic hash function. + +.. kernel-doc:: include/crypto/sm3.h diff --git a/Documentation/crypto/libcrypto-signature.rst b/Documentation/crypto/libcrypto-signature.rst new file mode 100644 index 000000000000..2a6dc793f0de --- /dev/null +++ b/Documentation/crypto/libcrypto-signature.rst @@ -0,0 +1,11 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Digital signature algorithms +============================ + +ML-DSA +------ + +This API provides support for the ML-DSA digital signature algorithm. + +.. kernel-doc:: include/crypto/mldsa.h diff --git a/Documentation/crypto/libcrypto-unauth-encryption.rst b/Documentation/crypto/libcrypto-unauth-encryption.rst new file mode 100644 index 000000000000..b4639b8927c6 --- /dev/null +++ b/Documentation/crypto/libcrypto-unauth-encryption.rst @@ -0,0 +1,49 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Unauthenticated encryption +========================== + +These APIs provide support for unauthenticated encryption and decryption, +including bare stream ciphers and other length-preserving algorithms such as +block ciphers in XTS mode. The legitimate use cases for these algorithms are: + +- Support for legacy protocols that really should have chosen an authenticated + mode (or even another primitive entirely) but didn't. + +- Internal components of authenticated modes. For example, AES-CTR is used by + AES-GCM and AES-CCM internally. + +- Storage encryption that cannot accommodate ciphertext expansion. Usually + AES-XTS is used for this. + +- Stream ciphers for key derivation and random number generation. + +Besides the above, these shouldn't be used. + +AES-CBC and AES-CBC-CTS +----------------------- + +This API provides support for AES in the CBC and CBC-CTS modes of operation. + +.. kernel-doc:: include/crypto/aes-cbc.h + +AES-CTR and AES-XCTR +-------------------- + +This API provides support for AES in the CTR and XCTR modes of operation. + +.. kernel-doc:: include/crypto/aes-ctr.h + +AES-ECB +------- + +This API provides support for AES in the ECB mode of operation. + +.. kernel-doc:: include/crypto/aes-ecb.h + +AES-XTS +------- + +This API provides support for AES in the XTS mode of operation. + +.. kernel-doc:: include/crypto/aes-xts.h diff --git a/Documentation/crypto/libcrypto-utils.rst b/Documentation/crypto/libcrypto-utils.rst new file mode 100644 index 000000000000..9d833f47ed39 --- /dev/null +++ b/Documentation/crypto/libcrypto-utils.rst @@ -0,0 +1,6 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Utility functions +================= + +.. kernel-doc:: include/crypto/utils.h diff --git a/Documentation/crypto/libcrypto.rst b/Documentation/crypto/libcrypto.rst new file mode 100644 index 000000000000..e911e0521597 --- /dev/null +++ b/Documentation/crypto/libcrypto.rst @@ -0,0 +1,168 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +============== +Crypto library +============== + +The Linux kernel's crypto library (``lib/crypto/``) provides kernel-internal +users of cryptographic algorithms with faster and easier access to those +algorithms than the traditional kernel crypto API. + +Each cryptographic algorithm is supported via a set of dedicated functions. +"Crypto agility", where needed, is left to calling code. + +The crypto library functions are intended to be boring and straightforward, and +to follow familiar conventions. Their primary documentation is their (fairly +extensive) kernel-doc. This page just provides some extra high-level context. + +Note that the crypto library isn't entirely new. ``lib/`` has contained some +crypto functions since 2005. Rather, it's just an approach that's been expanded +over time as it's been found to work well. It also largely just matches how the +kernel already does things elsewhere. + +Scope and intended audience +=========================== + +The crypto library documentation is primarily meant for kernel developers who +need to use a particular cryptographic algorithm(s) in kernel code. For +example, "I just need to compute a SHA-256 hash." A secondary audience is +developers working on the crypto algorithm implementations themselves. + +If you're looking for more general information about cryptography, like the +differences between the different crypto algorithms or how to select an +appropriate algorithm, you should refer to external sources which cover that +type of information much more comprehensively. If you need help selecting +algorithms for a new kernel feature that doesn't already have its algorithms +predefined, please reach out to ``linux-crypto@vger.kernel.org`` for advice. + +Code organization +================= + +- ``lib/crypto/*.c``: the crypto algorithm implementations + +- ``lib/crypto/$(SRCARCH)/``: architecture-specific code for crypto algorithms. + It is here rather than somewhere in ``arch/`` partly because this allows + generic and architecture-optimized code to be easily built into a single + loadable module (when the algorithm is set to 'm' in the kconfig). + +- ``lib/crypto/tests/``: KUnit tests for the crypto algorithms + +- ``include/crypto/``: crypto headers, for both the crypto library and the + traditional crypto API + +Generally, there is one kernel module per algorithm. Sometimes related +algorithms are grouped into one module. There is intentionally no common +framework, though there are some utility functions that multiple algorithms use. + +Each algorithm module is controlled by a tristate kconfig symbol +``CRYPTO_LIB_$(ALGORITHM)``. As is the norm for library functions in the +kernel, these are hidden symbols which don't show up in the kconfig menu. +Instead, they are just selected by all the kconfig symbols that need them. + +Many of the algorithms have multiple implementations: a generic implementation +and architecture-optimized implementation(s). Each module initialization +function, or initcall in the built-in case, automatically enables the best +implementation based on the available CPU features. + +Note that the crypto library doesn't use the ``crypto/``, +``arch/$(SRCARCH)/crypto/``, or ``drivers/crypto/`` directories. These +directories are used by the traditional crypto API. When possible, algorithms +in the traditional crypto API are implemented by calls into the library. + +Advantages +========== + +Some of the advantages of the library over the traditional crypto API are: + +- The library functions tend to be much easier to use. For example, a hash + value can be computed using only a single function call. Most of the library + functions always succeed and return void, eliminating the need to write + error-handling code. Most also accept standard virtual addresses, rather than + scatterlists which are difficult and less efficient to work with. + +- The library functions are usually faster, especially for short inputs. They + call the crypto algorithms directly without inefficient indirect calls, memory + allocations, string parsing, lookups in an algorithm registry, and other + unnecessary API overhead. Architecture-optimized code is enabled by default. + +- The library functions use standard link-time dependencies instead of + error-prone dynamic loading by name. There's no need for workarounds such as + forcing algorithms to be built-in or adding module soft dependencies. + +- The library focuses on the approach that works the best on the vast majority + of systems: CPU-based implementations of the crypto algorithms, utilizing + on-CPU acceleration (such as AES instructions) when available. + +- The library uses standard KUnit tests, rather than custom ad-hoc tests. + +- The library tends to have higher assurance implementations of the crypto + algorithms. This is both due to its simpler design and because more of its + code is being regularly tested. + +- The library supports features that don't fit into the rigid framework of the + traditional crypto API, for example interleaved hashing and XOFs. + +When to use it +============== + +In-kernel users should use the library (rather than the traditional crypto API) +whenever possible. Many subsystems have already been converted. It usually +simplifies their code significantly and improves performance. + +Some kernel features allow userspace to provide an arbitrary string that selects +an arbitrary algorithm from the traditional crypto API by name. These features +generally will have to keep using the traditional crypto API for backwards +compatibility. + +Note: new kernel features shouldn't support every algorithm, but rather make a +deliberate choice about what algorithm(s) to support. History has shown that +making a deliberate, thoughtful choice greatly simplifies code maintenance, +reduces the chance for mistakes (such as using an obsolete, insecure, or +inappropriate algorithm), and makes your feature easier to use. + +Testing +======= + +The crypto library uses standard KUnit tests. Like many of the kernel's other +KUnit tests, they are included in the set of tests that is run by +``tools/testing/kunit/kunit.py run --alltests``. + +A ``.kunitconfig`` file is also provided to run just the crypto library tests. +For example, here's how to run them in user-mode Linux: + +.. code-block:: sh + + tools/testing/kunit/kunit.py run --kunitconfig=lib/crypto/ + +Many of the crypto algorithms have architecture-optimized implementations. +Testing those requires building an appropriate kernel and running the tests +either in QEMU or on appropriate hardware. Here's one example with QEMU: + +.. code-block:: sh + + tools/testing/kunit/kunit.py run --kunitconfig=lib/crypto/ --arch=arm64 --make_options LLVM=1 + +Depending on the code being tested, flags may need to be passed to QEMU to +emulate the correct type of hardware for the code to be reached. + +Since correctness is essential in cryptographic code, new architecture-optimized +code is accepted only if it can be tested in QEMU. + +Note: the crypto library also includes FIPS 140 self-tests. These are +lightweight, are designed specifically to meet FIPS 140 requirements, and exist +*only* to meet those requirements. Normal testing done by kernel developers and +integrators should use the much more comprehensive KUnit tests instead. + +API documentation +================= + +.. toctree:: + :maxdepth: 2 + + libcrypto-auth-encryption + libcrypto-blockcipher + libcrypto-hash + libcrypto-signature + libcrypto-unauth-encryption + libcrypto-utils + sha3 diff --git a/Documentation/crypto/sha3.rst b/Documentation/crypto/sha3.rst index 37640f295118..250669c98f6b 100644 --- a/Documentation/crypto/sha3.rst +++ b/Documentation/crypto/sha3.rst @@ -1,5 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0-or-later +.. _sha3: + ========================== SHA-3 Algorithm Collection ========================== diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst index 8158b363cd98..d6194346e366 100644 --- a/Documentation/crypto/userspace-if.rst +++ b/Documentation/crypto/userspace-if.rst @@ -1,29 +1,98 @@ +.. _crypto_userspace_interface: + User Space Interface ==================== Introduction ------------ -The concepts of the kernel crypto API visible to kernel space is fully -applicable to the user space interface as well. Therefore, the kernel -crypto API high level discussion for the in-kernel use cases applies -here as well. - -The major difference, however, is that user space can only act as a -consumer and never as a provider of a transformation or cipher -algorithm. - -The following covers the user space interface exported by the kernel -crypto API. A working example of this description is libkcapi that can -be obtained from [1]. That library can be used by user space -applications that require cryptographic services from the kernel. - -Some details of the in-kernel kernel crypto API aspects do not apply to -user space, however. This includes the difference between synchronous -and asynchronous invocations. The user space API call is fully -synchronous. - -[1] https://www.chronox.de/libkcapi.html +AF_ALG provides unprivileged userspace programs access to arbitrary hash, +symmetric cipher, AEAD, and RNG algorithms that are implemented in kernel-mode +code. + +AF_ALG is insecure and is deprecated. Originally added to the kernel in 2010, +most kernel developers now consider it to be a mistake. Support for hardware +accelerators, which was the original purpose of AF_ALG, has been removed. + +AF_ALG continues to be supported only for backwards compatibility. + +Starting in Linux v7.3, the set of algorithms supported by AF_ALG is limited by +default. See :ref:`/proc/sys/crypto/af_alg_restrict <af_alg_restrict>`. + +On systems where no programs using AF_ALG remain, the support for it should be +disabled entirely by setting ``/proc/sys/crypto/af_alg_restrict`` to 2 or by +disabling ``CONFIG_CRYPTO_USER_API_*`` in the kernel configuration. + +Deprecation +----------- + +AF_ALG was originally intended to provide userspace programs access to crypto +accelerators that they wouldn't otherwise have access to. + +However, that capability turned out to not be useful on very many systems. More +significantly, the actual implementation exposes a vastly greater amount of +functionality than that. It actually provides access to all software algorithms. + +This includes arbitrary compositions of different algorithms created via a +complex template system, as well as algorithms that only make sense as internal +implementation details of other algorithms. In the past, it also included full +zero-copy support, which was difficult for the kernel to implement securely. + +Ultimately, these algorithms are just math computations. They use the same +instructions that userspace programs already have access to, just accessed in a +much more convoluted and less efficient way. + +Indeed, userspace code is nearly always what is being used anyway. These same +algorithms are widely implemented in userspace crypto libraries. + +Even when zero-copy and off-CPU accelerators were supported, AF_ALG was usually +much slower than optimized software cryptography in userspace. This was +especially true for the small message sizes usually seen in performance-critical +workloads. While it was possible to demonstrate performance wins for hashing +large files on embedded devices, it is hard to imagine a situation where this +would be performance-critical. + +Nowadays, AF_ALG no longer supports zero-copy or off-CPU accelerators. +Therefore, it is *always* slower than an optimized userspace implementation, +even for large messages. The only possible advantage left is that it avoids +duplicating code between kernel and userspace. However, userspace +implementations, especially hardware-accelerated ones, do not need to be large. +Just because OpenSSL is huge does not mean that all userspace cryptography +libraries are. + +Meanwhile, AF_ALG hasn't been withstanding modern vulnerability discovery tools +such as syzbot and large language models. It receives a steady stream of CVEs. +Some of the examples include: + +- CVE-2026-31677 +- CVE-2026-31431 (https://copy.fail) +- CVE-2025-38079 +- CVE-2025-37808 +- CVE-2024-26824 +- CVE-2022-48781 +- CVE-2019-8912 +- CVE-2018-14619 +- CVE-2017-18075 +- CVE-2017-17806 +- CVE-2017-17805 +- CVE-2016-10147 +- CVE-2015-8970 +- CVE-2015-3331 +- CVE-2014-9644 +- CVE-2013-7421 +- CVE-2011-4081 + +Hardware accelerator drivers are frequently buggy. To reduce attack surface, +AF_ALG now only provides access to algorithms implemented in software. This +means that AF_ALG no longer fulfills its original purpose. + +It is recommended that, whenever possible, userspace programs be migrated to +userspace crypto code (which again, is what is normally used anyway) and +``CONFIG_CRYPTO_USER_API_*`` be disabled. On systems that use SELinux, SELinux +can also be used to restrict the use of AF_ALG to trusted programs. + +The remainder of this documentation provides the historical documentation for +the deprecated AF_ALG interface. User Space API General Remarks ------------------------------ @@ -297,7 +366,7 @@ follows: struct sockaddr_alg sa = { .salg_family = AF_ALG, .salg_type = "rng", /* this selects the random number generator */ - .salg_name = "drbg_nopr_sha256" /* this is the RNG name */ + .salg_name = "stdrng" /* this is the RNG name */ }; @@ -327,33 +396,10 @@ CRYPTO_USER_API_RNG_CAVP option: Zero-Copy Interface ------------------- -In addition to the send/write/read/recv system call family, the AF_ALG -interface can be accessed with the zero-copy interface of -splice/vmsplice. As the name indicates, the kernel tries to avoid a copy -operation into kernel space. - -The zero-copy operation requires data to be aligned at the page -boundary. Non-aligned data can be used as well, but may require more -operations of the kernel which would defeat the speed gains obtained -from the zero-copy interface. - -The system-inherent limit for the size of one zero-copy operation is 16 -pages. If more data is to be sent to AF_ALG, user space must slice the -input into segments with a maximum size of 16 pages. - -Zero-copy can be used with the following code example (a complete -working example is provided with libkcapi): - -:: - - int pipes[2]; - - pipe(pipes); - /* input data in iov */ - vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT); - /* opfd is the file descriptor returned from accept() system call */ - splice(pipes[0], NULL, opfd, NULL, ret, 0); - read(opfd, out, outlen); +AF_ALG used to have zero-copy support, but it was removed due to it being a +frequent source of vulnerabilities. For backwards compatibility the splice() +and sendfile() system calls are still supported, but the kernel will make an +internal copy of the data before passing it to the crypto code. Setsockopt Interface @@ -406,4 +452,4 @@ Please see [1] for libkcapi which provides an easy-to-use wrapper around the aforementioned Netlink kernel interface. [1] also contains a test application that invokes all libkcapi API calls. -[1] https://www.chronox.de/libkcapi.html +[1] https://www.chronox.de/libkcapi/index.html |
