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:
Using qcrypto
The following components are needed to run qcrypto on a system:
- libqcrypto.so
- 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:
For example, qcrypto-openssl.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.
The same work flow applies to handling cryptographic keys, whether you are generating
them for the first time or loading them from memory or files. See the section that discusses
each of the various supported cryptographic primitives for examples of how to use
them.
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).
If a matching tag isn't found or the algorithm is not found in a matching plugin, the
algorithm resolution fails.
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.
General functions
The
qcrypto
library provides the following
general-purpose and cryptography-related functions:
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.