之前二篇文章介紹了QCA架構的安裝和配置,在這篇文章中我將開始編寫一個基於數位憑證的加密常式,用來講解QCA架構的使用。其實QCA的應用是非常簡單的,且在原始碼發行包中也附帶了大量的例子(在qca-2.0.3\examples目錄中),基本上可以解決我們日常的加解密編程工作。
照例先介紹一下開發環境: 作業系統:windows7 32位版本。 Qt SDK:4.8.5版本(安裝路徑:C:\Qt\4.8.5)。 QCA SDK:2.0.3版本。 OpenSSL:1.0.0g版本,QCA依賴庫,並且用於產生一張數位憑證檔案。 IDE:NetBeans IDE 7.3.1 C/C++版本。
首先用OpenSSL產生一張測試用的數位憑證,網上有一坨介紹OpenSSL產生數位憑證的文章,所以我就不再重複介紹了,如果你很懶,不願意去看文章自己產生數位憑證,我這裡提供了一個測試用的數位憑證,以便你可以正常的運行本常式,在文章的最後我提供了整個常式的原始碼,其中就包含了測試用的數位憑證(在etc目錄中)。接著我們開啟NetBeans,建立一個Qt類型的應用程式項目。在我之前的一篇文章中介紹了使用NetBeans進行C/C++開發的文章,有興趣的同學可以去看看,總體來說,在C/C++ IDE方面,NetBeans比Qt Creator和Eclipse要強點(VC++除外,因為我們用的gcc編譯器)。
項目建立好之後大致的目錄結構如下圖所示:
(圖一)
這裡我們關注的是certificatecrypto.h和certificatecrypto.cpp檔案,如下所示:
#ifndef CERTIFICATECRYPTO_H#defineCERTIFICATECRYPTO_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提供者的數位憑證演算法實現是支援多種方法載入認證的,在My Code中是使用了檔案載入方式,另外還支援字串載入方式和位元組數組載入方式,根據實際的應用環境可以選擇不同的認證載入函數。
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