QNX Cryptography Library
The QNX cryptography library (qcrypto library) is a generic cryptographic shim layer that provides a consistent API to the various cryptographic primitives offered by third-party libraries.
The library's unified API provides a configurable plugin system that allows a system integrator to choose a cryptography provider without re-writing software. It is designed to maximize interoperability between library implementations by providing configuration parameters that allow systems to switch to the cryptographic backend of their choice.
The qcrypto library also enforces a certain level of security by following best practices where possible to ensure that users of the library use appropriate security parameters and key lengths. The sources for security best practices include the following information:
- National Institute of Standards and Technology (NIST Guidelines) — http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
- Key length and strength recommendations — https://www.keylength.com/en/
Using qcrypto
The following components are needed to run qcrypto on a system:
- libqcrypto.so.1
- a system configuration file that allows the system integrator to configure which cryptography providers the system uses (see
Configuration file
) - one of the qcrypto plugin binaries listed below
Features that use qcrypto
- QNX Trusted Disk (see the entry for fs-qtd.so in the Utilities Reference)
- Power-Safe filesystem (see the entry for fs-qnx6.so in the Utilities Reference)
- random (see the entry for random in the Utilities Reference)
Dynamically loading the qcrypto library
If you need to support dynamically loading the cryptography library at runtime instead of linking to it directly, link your binary with libqcrypto_dyn.so and call qcrypto_load() to safely load the library before calling the other APIs. (The qcrypto_unload() function unloads it.) This dynamic shim layer is transparent and the API calls are identical in both libraries.
Supported algorithms
The qcrypto library framework allows you to add newer algorithms to a system using plugins. The algorithms that each plugin supports depends entirely on which algorithms the third-party cryptography library supports. In some cases, to encourage users to avoid using insecure primitives, qcrypto has purposefully avoided adding support for algorithms that are considered obsolete and unsafe. Some other algorithms require careful consideration when you define certain values, such as the initialization vector in many AES modes.Algorithm naming
The qcrypto library tries to use uniform and unambiguous naming for algorithms. All algorithm names are lowercase ASCII strings and, where possible, the common naming used by RFCs. For example:- AES 128 CBC Cipher — aes-128-cbc
- SHA512 Digest — sha512
- RSA with SHA256 digest — rsa-with-sha256
Plugins
The qcrypto library uses plugins to interface with different cryptographic providers. Currently, the library provides the following plugins. See the documentation for each plugin for details:Plugins are provided by libraries that use the following naming format:qcrypto-plugin.so
For example, qcrypto-openssl-3.so and qcrypto-certicom.so.
The qcrypto library
allows you to create custom plugins. For more information, see Adding cryptographic primitives.
Supported cryptographic primitives
The qcrypto library APIs include functions for working with the following cryptographic primitives:
Initialization
You need to initialize the library before you can successfully call any other algorithm functions. Use qcrypto_init() to initialize the qcrypto library and qcrypto_uninit() to un-initialize it.Using algorithms
After the library is initialized, the following steps are the usual work flow for using cryptographic primitives:- Use a qcrypto_*_request() function to get an instance of the desired algorithm (e.g., qcrypto_cipher_request()).
- Manipulate the primitive using the qcrypto functions defined for it.
- Call qcrypto_release_ctx() when you no longer need the algorithm.
Reusing an algorithm instance
An instance of an algorithm (a context) can be reused if the caller reinitializes it using its initialization function. Reinitializing allows you to reuse an instance without clearing memory all the time and may improve performance.Requesting an algorithm
When you call qcrypto_*_request(), the function searches for the specified algorithm.- If a tag value is specified, it searches plugins in the order they are defined (first the plugin with the internal tag value that qcrypto_init() creates, then plugins in the configuration file) for a matching tag value (wildcard tags (*) match anything).
- If a tag value is not provided (tag = NULL), it searches plugins in the order they are defined using the tag value __progname (see the __progname entry in the C Library Reference).
For more information on how tags work with requests, see Tags
in the
Configuration file
section.
Error handling and logging
Use qcrypto_strerror() to retrieve the textual representation of qcrypto library error codes.
By default, logging prints errors and other conditions to slogger2 and is handled by QNX helper logging functionality (libqh). For additional logging options, see the QNX Helpers Developer's Guide.
Error codes
For the error codes that the qcrypto library uses and returns, seeQNX cryptography library error codes.
General functions
The qcrypto library provides the following general-purpose and cryptography-related functions:- qcrypto_memcmp() (fixed-time memory comparison)
- qcrypto_memclear() (set the cryptography safe memory to zero)
Selecting the buffer size
The qcrypto_*_final() functions (e.g., qcrypto_cipher_final()) take pointers to a buffer for a value and its size. When buffer is NULL, the function returns the size of the data it wants to write in size and allows the caller to allocate a buffer large enough for the data. This type of call is useful for data like key values, which can vary widely in size, unlike digests, which have known, fixed lengths.