之前二篇文章介绍了QCA框架的安装和配置,在这篇文章中我将开始编写一个基于数字证书的加密例程,用来讲解QCA框架的使用。其实QCA的应用是非常简单的,且在源代码发行包中也附带了大量的例子(在qca-2.0.3\examples目录中),基本上可以解决我们日常的加解密编程工作。
照例先介绍一下开发环境:
首先用OpenSSL生成一张测试用的数字证书,网上有一坨介绍OpenSSL生成数字证书的文章,所以我就不再重复介绍了,如果你很懒,不愿意去看文章自己生成数字证书,我这里提供了一个测试用的数字证书,以便你可以正常的运行本例程,在文章的最后我提供了整个例程的源代码,其中就包含了测试用的数字证书(在etc目录中)。接着我们打开NetBeans,新建一个Qt类型的应用程序项目。在我之前的一篇文章中介绍了使用NetBeans进行C/C++开发的文章,有兴趣的同学可以去看看,总体来说,在C/C++ IDE方面,NetBeans比Qt Creator和Eclipse要强点(VC++除外,因为我们用的gcc编译器)。
项目创建好之后大致的目录结构如下图所示:
(图一)
这里我们关注的是certificatecrypto.h和certificatecrypto.cpp文件,如下所示:
#ifndef CERTIFICATECRYPTO_H #define CERTIFICATECRYPTO_H #include <QtCore/qdir.h> #include <QtCore/qstring.h> #include <QtCore/qbytearray.h> const QString CERT_FILE_DIR = "etc"; class CertificateCrypto { public: explicit CertificateCrypto(); virtual ~CertificateCrypto(); bool encrypt(const QByteArray &in, QByteArray *out); QString toHex(const QByteArray &in); private: QDir m_certFileDir; }; #endif /* CERTIFICATECRYPTO_H */
#include "certificatecrypto.h" #include <QtCore/qdatetime.h> #include <QDebug> #include <QtCrypto/qca.h> /** * 构造函数 */ CertificateCrypto::CertificateCrypto() : m_certFileDir(CERT_FILE_DIR) { } /** * 析构函数 */ CertificateCrypto::~CertificateCrypto() { } /** * 证书加密 * @param in * @param out * @return */ bool CertificateCrypto::encrypt(const QByteArray& in, QByteArray* out) { //1. 初始化QCA QCA::Initializer qca_init; QCA::SecureArray encrypt; //2. 检查系统是否支持QCA插件 if (!QCA::isSupported("cert")) { qDebug("对不起,当前系统不支持数字证书!"); } else { QString cert_file = m_certFileDir.absoluteFilePath("server.cer"); //3. 加载数字证书 QCA::ConvertResult result; QCA::Certificate cert = QCA::Certificate::fromPEMFile(cert_file, &result); if (result == QCA::ConvertGood) { //4. 检查数字证书有效期 QDateTime before = cert.notValidBefore(); QDateTime after = cert.notValidAfter(); QDateTime now = QDateTime::currentDateTime(); if (now >= before && now <= after) { //5. 获取数字证书中的公钥 QCA::PublicKey pub_key = cert.subjectPublicKey(); if (pub_key.canEncrypt()) { //6. 用公钥加密 encrypt = pub_key.encrypt(in, QCA::EME_PKCS1v15); out->clear(); out->append(encrypt.toByteArray()); return true; } else { qDebug("对不起,当前数字证书不支持加密!"); } } else { qDebug("对不起,当前数字证书已过期!"); } } else { qDebug("对不起,加载数字证书失败!"); } } return false; } /** * 转换成16进制字符串 * @param encrypt * @return */ QString CertificateCrypto::toHex(const QByteArray& in) { return QCA::arrayToHex(in); }
1. 在使用QCA之前,必须要对其进行初始化调用,否则QCA将无法工作,就是代码中的“QCA::Initializer qca_init”。
2. 在调用QCA相关加密算法之前最好做一次检查,看当前提供者实现是否支持该加密算法,例如代码中:if (!QCA::isSupported("cert")),就是检查一下是否支持数字证书,有同学肯定会问,如何知道isSupported函数中的那个算法字符串参数呢?其实在之前的文章中我们已经讲到过了,就是使用qcatool2工具,在命令行中输入“qcatool2 plugins --debug”,然后会显示中一大堆算法名称,isSupported函数中就是使用这个算法名称的字符串。如在我的开发环境中如下图所示:
(图二)
3. qca-ossl提供者的数字证书算法实现是支持多种方法加载证书的,在我的代码中是使用了文件加载方式,另外还支持字符串加载方式和字节数组加载方式,根据实际的应用环境可以选择不同的证书加载函数。
4. QCA返回的密文是QCA::SecureArray对象,所以要将其转换成字节数组(QByteArray)之后才能进行后续的处理。
5. 要编译并链接QCA库必须进行一些必要的设置,如下图所示:
(图三)
在项目属性对话框中点击“Qt”,在右边的框中选择“定制定义”旁的按钮,弹出定制定义对话框,点击“添加”按钮,输入“CONFIG += crypto”,最后点击保存。
大家是否还记得,在本系列的第一篇文章中我们定义过的crypto.prf文件(在%%QTDIR%\mkspecs\features目录中)。在这个文件中定义了QCA的头文件目录以及库文件目录。Qt在编译应用程序时会读取该配置文件,从而获取编译及链接的相关信息。
好了,现在我们可以运行程序了(其他的相关代码不再介绍了,都是一些Qt GUI的基础编程),如下图所示:
(图四)
程序显示一个主窗体和一个确定按钮,点击确定按钮,会在文本框中显示加密的字符串(明文为:“hello world!”),如下图所示:
(图五)
至此,我们的应用程序开发完成了,总体来说QCA的开发不是很困难,基本上API的设计是很友好的。非常适合从Java转型的Qt开发人员(包括我自己)。下一篇文章我们将介绍如何将QCA例程打包发布成脱离Qt开发环境的应用程序安装包,敬请关注。
提供本例程源代码的打包下载,共学习参考:qca_demo.rar