2007-04-02 07:16:13 +00:00
|
|
|
/**
|
|
|
|
\mainpage Qt Cryptographic Architecture
|
|
|
|
|
|
|
|
Taking a hint from the similarly-named
|
|
|
|
<a href="http://java.sun.com/j2se/1.5.0/docs/guide/security/CryptoSpec.html">Java
|
|
|
|
Cryptography Architecture</a>, %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, and requires no Qt3 compatibility code.
|
|
|
|
|
|
|
|
\section features Features
|
|
|
|
|
|
|
|
This library provides an easy API for the following features:
|
2007-04-13 19:04:16 +00:00
|
|
|
- Secure byte arrays (QCA::SecureArray)
|
|
|
|
- Arbitrary precision integers (QCA::BigInteger)
|
2007-04-02 07:16:13 +00:00
|
|
|
- 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
|
|
|
|
- Ciphers (QCA::Cipher) using
|
|
|
|
- BlowFish
|
|
|
|
- Triple DES
|
|
|
|
- DES
|
|
|
|
- AES (128, 192 and 256 bit)
|
2007-04-02 07:57:36 +00:00
|
|
|
- Message Authentication Code (QCA::MessageAuthenticationCode), using
|
2007-04-02 07:16:13 +00:00
|
|
|
- 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
|
2007-08-10 11:12:54 +00:00
|
|
|
Base64 (QCA::Base64) strings.
|
2007-04-02 07:16:13 +00:00
|
|
|
|
|
|
|
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 <a
|
|
|
|
href="examples.html">additional examples available</a>.
|
|
|
|
|
2007-08-10 11:12:54 +00:00
|
|
|
\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).
|
|
|
|
|
2007-08-29 15:58:39 +00:00
|
|
|
\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"
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
2007-04-02 07:16:13 +00:00
|
|
|
\section availability Availability
|
|
|
|
|
|
|
|
\subsection qca2code Current development
|
|
|
|
|
|
|
|
The latest version of the code is available from the KDE Subversion
|
|
|
|
server (there is no formal release of the current version at this time). See
|
|
|
|
<a href="http://developer.kde.org/source/anonsvn.html">
|
|
|
|
http://developer.kde.org/source/anonsvn.html
|
|
|
|
</a> for general instructions. You do <i>not</i> need kdelibs or
|
|
|
|
arts modules for %QCA - just pull down kdesupport/qca. The plugins
|
|
|
|
are in the same tree. Naturally you will need %Qt properly set up
|
|
|
|
and configured in order to build and use %QCA.
|
|
|
|
|
|
|
|
The Subversion code can also be browsed
|
|
|
|
<a href="http://websvn.kde.org/trunk/kdesupport/qca/">
|
|
|
|
via the web</a>
|
|
|
|
|
|
|
|
\subsection qca1code Previous versions
|
|
|
|
|
|
|
|
A previous version of %QCA (sometimes referred to as QCA1) which
|
|
|
|
works with Qt3, is still available.
|
|
|
|
You will need to get the main library
|
2007-08-29 17:31:50 +00:00
|
|
|
(<a href="http://delta.affinix.com/download/qca/qca-1.0.tar.bz2">qca-1.0.tar.bz2</a>)
|
|
|
|
and one or more providers
|
|
|
|
(<a href="http://delta.affinix.com/download/qca/qca-tls-1.0.tar.bz2">qca-tls-1.0.tar.bz2</a>
|
|
|
|
for the OpenSSL based provider, or
|
|
|
|
<a href="http://delta.affinix.com/download/qca/qca-sasl-1.0.tar.bz2">qca-sasl-1.0.tar.bz2</a>
|
|
|
|
for the SASL based provider). Note that development of QCA1 has basically
|
2007-04-02 07:16:13 +00:00
|
|
|
stopped.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** \page architecture Architecture
|
|
|
|
|
2007-08-28 21:23:43 +00:00
|
|
|
\note You don't need to understand any of this to use %QCA - it is
|
2007-04-02 07:16:13 +00:00
|
|
|
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();
|
2007-04-16 10:45:26 +00:00
|
|
|
virtual void update(const QCA::SecureArray &a);
|
|
|
|
virtual QCA::SecureArray final();
|
2007-04-02 07:16:13 +00:00
|
|
|
}
|
|
|
|
\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<HashContext *>(context())->clear();
|
|
|
|
}
|
|
|
|
|
2007-04-16 10:45:26 +00:00
|
|
|
void Hash::update(const QCA::SecureArray &a)
|
2007-04-02 07:16:13 +00:00
|
|
|
{
|
|
|
|
static_cast<HashContext *>(context())->update(a);
|
|
|
|
}
|
|
|
|
|
2007-04-16 10:45:26 +00:00
|
|
|
QCA::SecureArray Hash::final()
|
2007-04-02 07:16:13 +00:00
|
|
|
{
|
|
|
|
return static_cast<HashContext *>(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 );
|
|
|
|
}
|
|
|
|
|
2007-04-16 10:45:26 +00:00
|
|
|
void update(const QCA::SecureArray &a)
|
2007-04-02 07:16:13 +00:00
|
|
|
{
|
|
|
|
EVP_DigestUpdate( &m_context, (unsigned char*)a.data(), a.size() );
|
|
|
|
}
|
|
|
|
|
2007-04-16 10:45:26 +00:00
|
|
|
QCA::SecureArray final()
|
2007-04-02 07:16:13 +00:00
|
|
|
{
|
2007-04-16 10:45:26 +00:00
|
|
|
QCA::SecureArray a( EVP_MD_size( m_algorithm ) );
|
2007-04-02 07:16:13 +00:00
|
|
|
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;
|
2007-08-28 21:23:43 +00:00
|
|
|
}
|
2007-04-02 07:16:13 +00:00
|
|
|
\endcode
|
|
|
|
|
|
|
|
The resulting effect is that %QCA can ask the provider to provide an appropriate
|
|
|
|
Context object without worrying about how it is implemented.
|
|
|
|
|
2007-08-28 21:23:43 +00:00
|
|
|
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
|
|
|
|
|
2007-04-02 07:16:13 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/** \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
|
|
|
|
<a href="aes-cmac_8cpp-example.html">the AES-CMAC example</a>.
|
|
|
|
*/
|
|
|
|
|