/**
\mainpage Qt Cryptographic Architecture
Taking a hint from the similarly-named
Java
Cryptography Architecture, %QCA aims to provide a
straightforward and cross-platform cryptographic API, using Qt
datatypes and conventions. %QCA separates the API from the
implementation, using plugins known as Providers. The advantage
of this model is to allow applications to avoid linking to or
explicitly depending on any particular cryptographic library.
This allows one to easily change or upgrade Provider
implementations without even needing to recompile the
application!
%QCA should work everywhere %Qt does, including Windows/Unix/MacOSX. This
version of %QCA is for Qt4 or Qt5, and requires no Qt3 compatibility code.
\section features Features
This library provides an easy API for the following features:
- Secure byte arrays (QCA::SecureArray)
- Arbitrary precision integers (QCA::BigInteger)
- Random number generation (QCA::Random)
- SSL/TLS (QCA::TLS)
- X509 certificates (QCA::Certificate and QCA::CertificateCollection)
- X509 certificate revocation lists (QCA::CRL)
- Built-in support for operating system certificate root storage (QCA::systemStore)
- Simple Authentication and Security Layer (SASL) (QCA::SASL)
- Cryptographic Message Syntax (e.g., for S/MIME) (QCA::CMS)
- PGP messages (QCA::OpenPGP)
- Unified PGP/CMS API (QCA::SecureMessage)
- Subsystem for managing Smart Cards and PGP keyrings (QCA::KeyStore)
- Simple but flexible logging system (QCA::Logger)
- RSA (QCA::RSAPrivateKey and QCA::RSAPublicKey)
- DSA (QCA::DSAPrivateKey and QCA::DSAPublicKey)
- Diffie-Hellman (QCA::DHPrivateKey and QCA::DHPublicKey)
- Hashing (QCA::Hash) with
- SHA-0
- SHA-1
- MD2
- MD4
- MD5
- RIPEMD160
- SHA-224
- SHA-256
- SHA-384
- SHA-512
- Whirlpool
- Ciphers (QCA::Cipher) using
- BlowFish
- Triple DES
- DES
- AES (128, 192 and 256 bit)
- CAST5 (also known as CAST-128)
- Message Authentication Code (QCA::MessageAuthenticationCode), using
- HMAC with SHA-1
- HMAC with MD5
- HMAC with RIPEMD160
- HMAC with SHA-224
- HMAC with SHA-256
- HMAC with SHA-384
- HMAC with SHA-512
- Encoding and decoding of hexadecimal (QCA::Hex) and
Base64 (QCA::Base64) strings.
Functionality is supplied via plugins. This is useful for avoiding
dependence on a particular crypto library and makes upgrading easier,
as there is no need to recompile your application when adding or
upgrading a crypto plugin. Also, by pushing crypto functionality into
plugins, your application is free of legal issues, such as export
regulation.
And of course, you get a very simple crypto API for Qt, where you can
do things like:
\code
QString hash = QCA::Hash("sha1").hashToString(blockOfData);
\endcode
\section using Using QCA
The application simply includes <QtCrypto> and links to
libqca, which provides the 'wrapper API' and plugin loader. Crypto
functionality is determined during runtime, and plugins are loaded
from the 'crypto' subfolder of the %Qt library paths. There are additional examples available.
\subsection tute1 Introduction
Using %QCA is much like using Qt, and if you are familiar with
Qt, then it should feel "natural". There are a few things you
do need to know though, to build reliable applications:
- %QCA needs to be initialized before you use any class that
requires plugin support, or uses secure memory. That is most
of %QCA, so you should assume that you need to perform
initialization. The easiest way to do this is to instantiate
a QCA::Initializer object and ensure it is not deleted (or
allowed to go out of scope) until you have finished using
%QCA.
- Most features/algorithms are provided by plugins/\ref providers.
You should check that the required feature is actually
available (using QCA::isSupported()) before trying to create
it. If you try to create a class and suitable provider support
is not available, you will get back a null object, and when
you try to use one of the methods, your application will
segfault. Also, for features that take algorithm names (e.g.
QCA::Hash, which takes the name of the hashing algorithm such
as "md5" or "sha256"), the name is looked up at run-time, so
if you make a typographical error (e.g. "md56") it will compile
correctly, but segfault at run-time.
\subsection tute2 Thoughts on security
%QCA tries to be flexible in what it supports. That does not mean that
every possible combination of features makes sense though.
We strongly recommend against coming up with your own design made up
of low-level cryptographic primitives (e.g. QCA::Hash, QCA::Cipher and
similar features) and trying to use higher level capabilities. In particular,
we recommend looking at QCA::TLS, QCA::SASL, QCA::CMS and QCA::OpenPGP
as starting points.
When selecting a particular cryptographic feature, you should make sure
that you understand what sort of threats your application is likely
to be exposed to, and how that threat can be effectively countered. In
addition, you should consider whether you can avoid adding cryptographic
features directly to your application (e.g. for secure transport, you
may be able to tunnel your application over SSH).
Also, you may need to look beyond %QCA for some security needs (e.g.
for authentication, your situation may be more suited to using
Kerberos than SASL or TLS).
\subsection intro-design Design
The architecture of %QCA is shown below:
\image html qca-arch.png "QCA Architecture"
\image latex qca-arch.eps "QCA Architecture" width=\textwidth
Application authors normally only need to use the User API. The
provider API is available for plugin authors, but can also
be used by application authors to provide very specific capabilities.
For more information on the design of %QCA, you might like to review
the \ref architecture description.
\section availability Availability
\subsection qca2code Releases
The latest release packages can be found in the
%QCA 2.x download area.
See the project web site for
further information about %QCA releases.
\subsection qca2dev Current development
The latest version of the code is available from the KDE Git server
(there is no formal release of the current version at this time).
Naturally you will need %Qt properly set up and configured in order
to build and use %QCA.
The Git code can be browsed
via the web
Use
\verbatim
git clone https://invent.kde.org/libraries/qca.git
\endverbatim
to get the latest sources.
*/
/** \page architecture Architecture
\note You don't need to understand any of this to use %QCA - it is
documented for those who are curious, and for anyone planning to
extend or modify %QCA.
The design of %QCA is based on the Bridge design pattern. The intent of
the Bridge pattern is to "Decouple an abstraction from its
implementation so that the two can vary independently." [Gamma et.al,
pg 151].
To understand how this decoupling works in the case of %QCA, is is
easiest to look at an example - a cryptographic Hash. The API is
pretty simple (although I've left out some parts that aren't required
for this example):
\code
class QCA_EXPORT Hash : public Algorithm, public BufferedComputation
{
public:
Hash(const QString &type, const QString &provider);
virtual void clear();
virtual void update(const QCA::SecureArray &a);
virtual QCA::SecureArray final();
}
\endcode
The implementation for the Hash class is almost as simple:
\code
Hash::Hash(const QString &type, const QString &provider)
:Algorithm(type, provider)
{
}
void Hash::clear()
{
static_cast(context())->clear();
}
void Hash::update(const QCA::SecureArray &a)
{
static_cast(context())->update(a);
}
QCA::SecureArray Hash::final()
{
return static_cast(context())->final();
}
\endcode
The reason why it looks so simple is that the various methods in Hash
just call out to equivalent routines in the context() object. The
context comes from a call (getContext()) that is made as part of the
Algorithm constructor. That getContext() call causes %QCA to work
through the list of providers (generally plugins) that it knows about,
looking for a provider that can produce the right kind of context (in
this case, a HashContext).
The code for a HashContext doesn't need to be linked into %QCA - it can
be varied in its implementation, including being changed at run-time. The
application doesn't need to know how HashContext is implemented, because
it just has to deal with the Hash class interface. In fact, HashContext
may not be implemented, so the application should check (using
QCA::isSupported()) before trying to use features that are implemented
with plugins.
The code for one implementation (in this case, calling OpenSSL) is shown
below.
\code
class opensslHashContext : public HashContext
{
public:
opensslHashContext(const EVP_MD *algorithm, Provider *p, const QString &type) : HashContext(p, type)
{
m_algorithm = algorithm;
EVP_DigestInit( &m_context, m_algorithm );
};
~opensslHashContext()
{
EVP_MD_CTX_cleanup(&m_context);
}
void clear()
{
EVP_MD_CTX_cleanup(&m_context);
EVP_DigestInit( &m_context, m_algorithm );
}
void update(const QCA::SecureArray &a)
{
EVP_DigestUpdate( &m_context, (unsigned char*)a.data(), a.size() );
}
QCA::SecureArray final()
{
QCA::SecureArray a( EVP_MD_size( m_algorithm ) );
EVP_DigestFinal( &m_context, (unsigned char*)a.data(), 0 );
return a;
}
Provider::Context *clone() const
{
return new opensslHashContext(*this);
}
protected:
const EVP_MD *m_algorithm;
EVP_MD_CTX m_context;
};
\endcode
This approach (using an Adapter pattern) is very common in %QCA backends,
because the plugins are often based on existing libraries.
In addition to the various Context objects, each provider also has
a parameterised Factory class that has a createContext() method, as
shown below:
\code
Context *createContext(const QString &type)
{
//OpenSSL_add_all_digests();
if ( type == "sha1" )
return new opensslHashContext( EVP_sha1(), this, type);
else if ( type == "sha0" )
return new opensslHashContext( EVP_sha(), this, type);
else if ( type == "md5" )
return new opensslHashContext( EVP_md5(), this, type);
else if ( type == "aes128-cfb" )
return new opensslCipherContext( EVP_aes_128_cfb(), 0, this, type);
else if ( type == "aes128-cbc" )
return new opensslCipherContext( EVP_aes_128_cbc(), 0, this, type);
else
return 0;
}
\endcode
The resulting effect is that %QCA can ask the provider to provide an appropriate
Context object without worrying about how it is implemented.
For features that are implemented with variable algorithms (for example, HashContext can
support a wide range of algorithms - MD5, SHA0, and SHA1 in the example above; and
CipherContext and MACContext can also do this), we need to be able to let applications
determine which algorithms are supported. This is handled through the InfoContext class.
A typical example is shown below:
\code
class opensslInfoContext : public InfoContext
{
Q_OBJECT
public:
opensslInfoContext(Provider *p) : InfoContext(p)
{
}
Context *clone() const
{
return new opensslInfoContext(*this);
}
QStringList supportedHashTypes() const
{
QStringList list;
list += "sha1";
list += "sha0";
list += "md5";
return list;
}
// MAC and Cipher types can go in here
};
\endcode
Note that InfoContext is itself a feature, so you have to add it to the createContext()
method for the provider, as shown below:
\code
Context *createContext(const QString &type)
{
if ( type == "sha1" )
return new opensslHashContext( EVP_sha1(), this, type);
else if ( type == "sha0" )
return new opensslHashContext( EVP_sha(), this, type);
else if ( type == "md5" )
return new opensslHashContext( EVP_md5(), this, type);
else if ( type == "info" )
return new opensslInfoContext( this );
else
return 0;
}
\endcode
*/
/** \page providers Providers
%QCA works on the concept of a "provider". There is a limited
internal provider (named "default"), but most of the work is
done in plugin modules.
The logic to selection of a provider is fairly simple. The user can
specify a provider name - if that name exists, and the provider supports
the requested feature, then the named provider is used. If that
didn't work, then the available plugins are searched (based on a
priority order) for the requested feature. If that doesn't work,
then the default provider is searched for the requested feature.
So the only way to get the default provider is to either have no other support
whatsoever, or to specify the default provider directly (this goes for the
algorithm constructors as well as setGlobalRNG()).
You can add your own provider in two ways - as a shared object plugin,
and as a part of the client code.
The shared object plugin needs to be able to be found using the
built-in scan logic - this normally means you need to install it into
the plugins/crypto subdirectory within the directory that Qt is
installed to. This will make it available for all applications.
If you have a limited application domain (such as a specialist
algorithm, or a need to be bug-compatible), you may find it easier to
create a client-side provider, and add it using the
QCA::insertProvider call. There is an example of this - see
the AES-CMAC example.
*/