词典的加密

一、问题需求。

我们的软件是使用星际译王的开源软件进行词典处理。可以使用它提供的stardict-tool工具,对用户提供的词典(DRAE.tab),转换成星际译王所需的文件(转换成三个文件,idx,ifo,dict.dz)。只要tab文件按照星际译王的格式要求,即可进行转换(单词与解释在一行,使用/t分割)。

由于用户提供的词典具有版权等问题,所以,需要实现对tab进行加密。

二、处理方法。

使用QCA。

编写一个dictionary_encrypt的工具,以后每次运行这个工具,就可以对tab进行加密,存储成另一个tab文件,供stardict-editor进行转换。

编写一个crypto_util的library,在其他的地方只要使用了这个library,就支持相关的加密解密工作。

三、遇到问题及尝试的改进。

1.编码问题

在tab文件中,有各种西班牙的字母,所以,需要注意设置读取文件的格式是utf-8。其次,读入文件,写文件,相关的操作方法要对应起来,才能保证格式的一致。如使用QFile提供的方法来读文件,则对应地,要使用QFile的方法来写新文件。如果用QTextStream或其他方法来写文件,则在实际操作中发现格式会不一致,导致后面的操作出错。

2.大小问题及模糊检索

对单词进行加密,使用的是aes-128加密方法,会增加文件的大小。(比如,原来是word,加密后会是asdfasfdasdf1221341423等一长串字符。)

对于tab文件,示例形式是:

word-a      explanation-a

(开始的要求是只需对explanation-a进行加密。后来客户觉得word-a也需加密。我们认为,对word-a的加密,导致的增加会是翻倍的。因为word-a不仅存在与词典(.dict.dz)中,还存在于词典的索引文件(.idx)中。就是说,加密后的word部分,会在词典里有两份表示。

但这样子,文件太大。

所以,考虑使用折中的方法处理。

使用两次的start-dict。

一是存储word的对:

word-a 1

word-b 2

..... 

一是存储explanation的对:

1 explanation-a

2 explanation-b

.....

但是这样子,其实word-a还是存在了两次啊。为什么会减少空间?这不科学!

但是实际就是这样的。。如果是 word-encrypted explanation-encrypted 这样的对,那么总大小是500M。如果分开word-encrypted 1 和1 explanation-encrypted,则两个词典总大小是180M。

应该是与dict.dz文件的存储形式有关。并不是线性的增加。

后来,与客户进行沟通,放弃了对word的加密。

其实对word加密,发现还有问题,就是fuzzy的查询方式不能支持。查阅 有关资料,对于加密的其实也可以建立索引。具体可参考如下:

http://www.cnki.com.cn/Article/CJFDTotal-JSJA2011S1030.htm

四、代码。

使用QT的QCA进行加密,示例如下。

1.配置QCA:

自行解决...

2.头文件:

#ifndef TEST_AES_CRYPTO_H
#define TEST_AES_CRYPTO_H

#include <QtCore/QtCore>
#include <QtCrypto/QtCrypto>

class TestAESCrypto: public QObject
{
    Q_OBJECT

public:
    TestAESCrypto(QObject *parent = 0);
    ~TestAESCrypto();

    QString encryptData(const QString & source);
    QString decryptData(const QString & source);
    void encryptFile(const QString & in_file_name, const QString & out_file_name);

private:
    QCA::Initializer init_;
    QCA::SymmetricKey key_;
    QCA::InitializationVector iv_;

};

#endif // TEST_AES_CRYPTO_H

3.源文件:

#include "test_aes_crypto.h"
#include <QtCrypto/QtCrypto>

const static QString KEY = "aff400e117304202a660442fd2dc9172";
const static QString IV  = "156b68e397a54a2f8aa68b2be2f4eb11";

TestAESCrypto::TestAESCrypto(QObject *parent)
    : QObject(parent)
{
    //initialize QCA
    init_ = QCA::Initializer();
    key_ = QCA::SymmetricKey(KEY.toAscii());
    iv_ = QCA::InitializationVector(IV.toAscii());
}

TestAESCrypto::~TestAESCrypto()
{

}

QString TestAESCrypto::encryptData(const QString &source)
{
    //initialize the cipher for aes128 algorithm, using CBC mode,
    //with padding enabled (by default), in encoding mode,
    //using the given key and initialization vector
    QCA::Cipher cipher = QCA::Cipher(QString("aes128"), QCA::Cipher::CBC,
                                         QCA::Cipher::DefaultPadding, QCA::Encode,
                                         key_, iv_);
    //check if aes128 is available
    if (!QCA::isSupported("aes128-cbc-pkcs7"))
    {
        qDebug() << "AES128 CBC PKCS7 not supported - "
                    "please check if qca-ossl plugin"
                    "installed correctly !";
        return "";
    }
    QCA::SecureArray secureData = source.toUtf8();
    //we encrypt the data
    QCA::SecureArray encrypted_data = cipher.process(secureData);
    //check if encryption succeded
    if (!cipher.ok())
    {
        qDebug() << "Encryption failed !";
        return "";
    }

    return QCA::arrayToHex(encrypted_data.toByteArray());
}

QString TestAESCrypto::decryptData(const QString &source)
{
    //initialize the cipher for aes128 algorithm, using CBC mode,
    //with padding enabled (by default), in decoding mode,
    //using the given key and initialization vector
    QCA::Cipher cipher = QCA::Cipher(QString("aes128"), QCA::Cipher::CBC,
                                     QCA::Cipher::DefaultPadding, QCA::Decode,
                                     key_, iv_);
    QCA::SecureArray encrypted_data = QCA::SecureArray(QCA::hexToArray(source));
    QCA::SecureArray decrypted_data = cipher.process(encrypted_data);
    //check if decryption succeded
    if (!cipher.ok())
    {
        qDebug() << "Decryption failed !";
        return "";
    }
    return QString::fromUtf8(decrypted_data.data());
}

//跟具体应用场景有关。我所需的加密文件是以/t为分隔符的字典
void TestAESCrypto::encryptFile(const QString &in_file_name, const QString &out_file_name)
{
    QFile in_file(in_file_name);
    QFile out_file(out_file_name);
    QTextStream in_stream;
    QTextStream out_stream;
    if(!in_file.open(QIODevice::ReadOnly|QIODevice::Text))
    {
        qDebug() << " Cannot open file to read";
        return;
    }
    if(!out_file.open(QIODevice::WriteOnly|QIODevice::Truncate))
    {
        qDebug() << " Cannot open file to write";
        return;
    }
    in_stream.setDevice(&in_file);
    in_stream.setCodec("UTF-8");
    out_stream.setDevice(&out_file);
    out_stream.setCodec("UTF-8");
    QString line_string = in_stream.readLine();
    QStringList string_list;

    int line_count = 1;
    //使用map来判断这个单词是否已经出现过
    QMap<QString,bool> map;
    while(!line_string.isNull())
    {
        string_list = line_string.split("\t");
        if(string_list.size() != 2)
        {
            qDebug() << "The input file doesn't contain two elements in line "<<line_count;
        }else if(string_list.at(0).isEmpty() || string_list.at(0).isNull()){
            qDebug() << "The word is empty in line "<<line_count;
        }else if(map.contains(string_list.at(0))) {
            qDebug() << "The word " <<string_list.at(0)<<" is duplicate in line "<<line_count;
            qDebug() << "whole string is "<< line_string;
        }else{
            map.insert(string_list.at(0), true);
            out_stream << string_list.at(0);
            out_stream << "\t";
            out_stream << encryptData(string_list.at(1));
            out_stream << "\n";
        }
        line_count++;
        line_string = in_stream.readLine();
    }

    in_file.close();
    out_file.close();
}

4.用于加密的main.cpp。

#include <QApplication>
#include "test_aes_crypto.h"

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        qDebug() << "Need to input two file names! " << argc;
        return 0;
    }
    qDebug() << "Encryption begins..";
    TestAESCrypto crypto;
    crypto.encryptFile(QString(argv[1]), QString(argv[2]));
    qDebug() << "Encryption ends.";
    return 1;
}

5.在makefile里的示例:

ENABLE_QT()
 
INCLUDE_DIRECTORIES(.)
 
# Header files.
FILE(GLOB MOC_HDRS *.h)
QT4_WRAP_CPP(MOC_SRCS ${MOC_HDRS})
 
# Source files.
FILE(GLOB SRCS *.cpp)
SET(SRCS  ${MOC_HDRS}  ${SRCS}  ${MOC_SRCS})
 
ADD_LIBRARY(crypto_util ${SRCS})
TARGET_LINK_LIBRARIES(crypto_util qca ${QT_LIBRARIES} ${ADD_LIB})
 
ADD_EXECUTABLE(dictionary_encrypt main.cpp ${SRCS})

makefile主要的是

ADD_LIBRARY(crypto_util ${SRCS})

在其他的地方可以使用到crypto_util这个library

ADD_EXECUTABLE(dictionary_encrypt main.cpp ${SRCS})

生成了dictionary_encrypt这个bin文件,进行加密



参考

http://www.essentialunix.org/index.php?option=com_content&view=article&id=48:qcatutorial&catid=34:qttutorials&Itemid=53



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值