c++下RSA和BLOWFISH加解密-使用Crypto库

工作需要使用RSA和BLOWFISH加密,主要使用CRYPTO库,但是CRYPTO并不是很方便使用,封装的有点复杂。我整理CRYPTO的文档,简单的封装了主要的加密和解密方法。代码如下:

代码需要配置boost和crypto才能运行。

首先是 data_package_t.hpp 这个类和加解密没有关系,只是简单的封装了shared_array, 添加了一个_size_datalen,能够直接获取数组的长度。方法也很简单,只有一个构造函数和 reset_data。构造函数只有一个参数,传入数组的长度。reset_data 的作用是把数据的数据全部清0.


#ifndef UNIT_TEST_DATA_PACKAGE_T_H
#define UNIT_TEST_DATA_PACKAGE_T_H

#include <iostream>
#include <cstring>
#include <boost/shared_array.hpp>

namespace my_utils {
    namespace types {
        template<typename data_type>
        class package {
        public:
            inline package(std::size_t _init_datalen = 0)
                    : _arr_data(new data_type[_init_datalen]), _size_datalen(_init_datalen) {
                reset_data();
            }

            inline void reset_data() {
                memset(_arr_data.get(), 0x0, sizeof(data_type) * _size_datalen);
            }

            boost::shared_array <data_type> _arr_data;
            std::size_t _size_datalen;
        };

        typedef unsigned char data_t;
        typedef package<data_t> data_package_t;
    }
}

#endif //UNIT_TEST_DATA_PACKAGE_T_H

接下来是主要的头文件 encryption_utils.h 里面定义了主要的方法,包含了主要的密钥创建和初始换,和加解密的方法。每个方法都加了注释,这里就不详细解释了。

#ifndef ACCP_SERVER_SDK_LIBS_ENCRYPTION_UTILS_H
#define ACCP_SERVER_SDK_LIBS_ENCRYPTION_UTILS_H

#include <string>
#include <rsa.h>
#include <cryptlib.h>
#include <osrng.h>
#include <assert.h>
#include <blowfish.h>
#include <filters.h>
#include <modes.h>
#include <boost/shared_ptr.hpp>
#include "data_package_t.hpp"

namespace my_utils {
    namespace utils {
        /**
         * 存放 blowfish 的密钥
         * data_key 为 key
         * data_iv 为 iv
         */
        struct blowfish_key_value {
            blowfish_key_value(std::size_t key_len = 0, std::size_t iv_len = 0)
                    : data_key(key_len), data_iv(iv_len) {}
            types::data_package_t data_key;
            types::data_package_t data_iv;
        };

        /**
         * 从数组导入rsa的 private key
         * @param private_key 需要导入的private key
         * @param _key_data   导入的数组
         * @return 执行是否成功
         */
        bool import_rsa_private_key_from_byte(CryptoPP::RSA::PrivateKey &private_key,
                                              const types::data_package_t &_key_data);

        /**
         * 从数组导入rsa的 public key
         * @param public_key 需要 导入的 public key
         * @param _key_data 导入的数组
         * @return 执行是否成功
         */
        bool import_rsa_public_key_from_byte(CryptoPP::RSA::PublicKey &public_key,
                                             const types::data_package_t &_key_data);

        /**
         * 导出rsa的private_key到数组
         * @param private_key 需要导出的private key
         * @param _key_data   导出的数组
         * @return 执行是否成功
         */
        bool export_rsa_private_key_to_byte(const CryptoPP::RSA::PrivateKey &private_key,
                                            types::data_package_t &_key_data);

        /**
         * 导出rsa的public_key到数组
         * @param public_key 需要导出的public_key
         * @param _key_data  导出的数组
         * @return 执行是否成功
         */
        bool export_rsa_public_key (const CryptoPP::RSA::PublicKey &public_key,
                                     types::data_package_t &_key_data);

        /**
         * 生成rsa密钥对
         * @param public_key  公钥
         * @param private_key 私钥
         * @param key_size    密钥的长度
         * @return 执行是否成功
         */
        bool generate_rsa_key(CryptoPP::RSA::PublicKey &public_key,
                              CryptoPP::RSA::PrivateKey &private_key,
                              unsigned int key_size);

        /**
         * RSA加密函数
         * @param public_key  公钥
         * @param str_data    需要加密的数据
         * @param cipher_data 加密后的数据
         * @return 执行是否成功
         */
        bool rsa_encrypt_std_string(CryptoPP::RSA::PublicKey &public_key,
                                    const std::string &str_data,
                                    my_utils::types::data_package_t &cipher_data);

        /**
         * RSA解密函数
         * @param private_key 私钥
         * @param raw_data    需要解密的数据
         * @param plain       解密后的数据
         * @return 执行是否成功
         */
        bool rsa_decrypt_byte_data(CryptoPP::RSA::PrivateKey &private_key,
                                   const my_utils::types::data_package_t &raw_data,
                                   std::string &plain);

        /**
         * 生成Blowfish 的密钥和iv
         * @param _key_value 密钥和iv
         * @return 执行是否成功
         */
        bool generate_blowfish_key(my_utils::utils::blowfish_key_value &_key_value);

        /**
         * 使用blowfish 加密数据
         * @param _key_value 密钥
         * @param plain      加密前的数据
         * @param cipher     加密后的数据
         * @return 执行是否成功
         */
        bool blowfish_encrypt_std_string(const blowfish_key_value &_key_value,
                                         const std::string &plain,
                                         std::string &cipher);

        /**
         * 使用blowfish 解密数据
         * @param _key_value 密钥
         * @param cipher     解密前的数据
         * @param plain      解密后的数据
         * @return 执行是否成功
         */
        bool blowfish_decrypt_byte_data(const blowfish_key_value &_key_value,
                                        const std::string &cipher,
                                        std::string &plain);
    }
}


#endif //ACCP_SERVER_SDK_LIBS_ENCRYPTION_UTILS_H

encryption_utils.cpp 加解密的实现文件,主要参考了crypto的文档。


#include "../include/encryption_utils.h"


static CryptoPP::AutoSeededRandomPool g_rng;

using namespace CryptoPP;

bool my_utils::utils::import_rsa_private_key_from_byte(CryptoPP::RSA::PrivateKey &private_key,
                                                       const my_utils::types::data_package_t &_key_data) {
    try {
        CryptoPP::ByteQueue byte_queue;
        byte_queue.Put2(_key_data._arr_data.get(), _key_data._size_datalen, 0, false);
        private_key.Load(byte_queue.Ref());
        return true;
    } catch (const CryptoPP::Exception &e) {
        return false;
    }
}

bool ::my_utils::utils::import_rsa_public_key_from_byte(CryptoPP::RSA::PublicKey &public_key,
                                                        const my_utils::types::data_package_t &_key_data) {

    try {
        CryptoPP::ByteQueue byte_queue;
        byte_queue.Put2(_key_data._arr_data.get(), _key_data._size_datalen, 0, false);
        public_key.Load(byte_queue.Ref());
        return true;
    } catch (const CryptoPP::Exception &e) {
        return false;
    }
}

bool my_utils::utils::export_rsa_private_key_to_byte(const CryptoPP::RSA::PrivateKey &private_key,
                                                     my_utils::types::data_package_t &_key_data) {
    try {
        CryptoPP::ByteQueue byte_queue;
        private_key.Save(byte_queue);
        _key_data = my_utils::types::data_package_t(byte_queue.CurrentSize());
        byte_queue.Get(_key_data._arr_data.get(), _key_data._size_datalen);
        return true;
    } catch (const CryptoPP::Exception &) {
        return false;
    }
}

bool my_utils::utils::export_rsa_public_key(const CryptoPP::RSA::PublicKey &public_key,
                                            my_utils::types::data_package_t &_key_data) {
    try {
        CryptoPP::ByteQueue byte_queue;
        public_key.Save(byte_queue);
        _key_data = my_utils::types::data_package_t(byte_queue.CurrentSize());
        byte_queue.Get(_key_data._arr_data.get(), _key_data._size_datalen);
        return true;
    } catch (const CryptoPP::Exception &) {
        return false;
    }
}

bool my_utils::utils::generate_rsa_key(CryptoPP::RSA::PublicKey &public_key,
                                       CryptoPP::RSA::PrivateKey &private_key,
                                       unsigned int key_size) {
    try {
        CryptoPP::InvertibleRSAFunction parameters;
        parameters.GenerateRandomWithKeySize(g_rng, key_size);

        public_key = CryptoPP::RSA::PublicKey(parameters);
        private_key = CryptoPP::RSA::PrivateKey(parameters);
        return true;
    } catch (const CryptoPP::Exception &e) {
        return false;
    }
}

bool my_utils::utils::generate_blowfish_key(my_utils::utils::blowfish_key_value &_key_value) {
    try {
        _key_value = my_utils::utils::blowfish_key_value((std::size_t) CryptoPP::Blowfish::DEFAULT_KEYLENGTH,
                                                         (std::size_t) CryptoPP::Blowfish::BLOCKSIZE);
        g_rng.GenerateBlock(_key_value.data_key._arr_data.get(), _key_value.data_key._size_datalen);
        g_rng.GenerateBlock(_key_value.data_iv._arr_data.get(), _key_value.data_key._size_datalen);
        return true;
    } catch (const CryptoPP::Exception &e) {
        return false;
    }
}


bool my_utils::utils::rsa_encrypt_std_string(CryptoPP::RSA::PublicKey &public_key,
                                             const std::string &str_data,
                                             my_utils::types::data_package_t &cipher_data) {
    try {

        CryptoPP::SecByteBlock plaintext(str_data.length());
        memcpy(plaintext.data(), str_data.c_str(), str_data.length());

        CryptoPP::RSAES_OAEP_SHA_Encryptor encryptor(public_key);

        assert(0 != encryptor.FixedMaxPlaintextLength());
        assert(str_data.length() <= encryptor.FixedMaxPlaintextLength());

        size_t ecl = encryptor.CiphertextLength(plaintext.size());
        CryptoPP::SecByteBlock ciphertext(ecl);

        encryptor.Encrypt(g_rng, plaintext, plaintext.size(), ciphertext);

        cipher_data = my_utils::types::data_package_t(ecl);

        memcpy(cipher_data._arr_data.get(), ciphertext.data(), ciphertext.size());

        return true;
    } catch (const CryptoPP::Exception &e) {
        return false;
    }
}

bool my_utils::utils::rsa_decrypt_byte_data(CryptoPP::RSA::PrivateKey &private_key,
                                            const my_utils::types::data_package_t &raw_data,
                                            std::string &plain) {

    try {
        CryptoPP::SecByteBlock ciphertext(raw_data._size_datalen);
        assert(raw_data._size_datalen <= ciphertext.size());
        memcpy(ciphertext.data(), raw_data._arr_data.get(), raw_data._size_datalen);

        // Decrypt
        CryptoPP::RSAES_OAEP_SHA_Decryptor decryptor(private_key);

        // Now that there is a concrete object, we can validate
        assert(0 != decryptor.FixedCiphertextLength());
        assert(ciphertext.size() <= decryptor.FixedCiphertextLength());

        size_t dpl = decryptor.MaxPlaintextLength(ciphertext.size());
        assert(0 != dpl);
        CryptoPP::SecByteBlock recovered(dpl);

        // Paydirt
        CryptoPP::DecodingResult result = decryptor.Decrypt(g_rng,
                                                            ciphertext, ciphertext.size(), recovered);

        // More sanity checks
        assert(result.isValidCoding);
        assert(result.messageLength <=
               decryptor.MaxPlaintextLength(ciphertext.size()));

        plain = std::string((char *) recovered.data(), result.messageLength);
        return true;
    } catch (const CryptoPP::Exception &e) {
        return false;
    }
}


bool my_utils::utils::blowfish_encrypt_std_string(const my_utils::utils::blowfish_key_value &_key_value,
                                                  const std::string &plain,
                                                  std::string &cipher) {


    try {
        CBC_Mode<Blowfish>::Encryption e;
        e.SetKeyWithIV(_key_value.data_key._arr_data.get(),
                       _key_value.data_key._size_datalen,
                       _key_value.data_iv._arr_data.get());


        StringSource(plain, true,
                     new StreamTransformationFilter(e,
                                                    new StringSink(cipher)
                     )
        );

        return true;
    } catch (const CryptoPP::Exception &e) {
        return false;
    }
}

bool my_utils::utils::blowfish_decrypt_byte_data(const my_utils::utils::blowfish_key_value &_key_value,
                                                 const std::string &cipher,
                                                 std::string &plain) {
    try {
        CBC_Mode<Blowfish>::Decryption d;
        d.SetKeyWithIV(_key_value.data_key._arr_data.get(),
                       _key_value.data_key._size_datalen,
                       _key_value.data_iv._arr_data.get());

        StringSource s(cipher, true,
                       new StreamTransformationFilter(d,
                                                      new StringSink(plain)
                       )
        );

        return true;
    } catch (const CryptoPP::Exception &e) {
        return false;
    }
}


下面是测试代码:

#include "../include/encryption_utils.h"

using namespace std;
using namespace my_utils;
using namespace my_utils::utils;
using namespace my_utils::types;
using namespace boost;

/**
 * RSA加密解密测试代码
 */
void rsa_encrypt_test() {

    bool b_result = false;
    CryptoPP::RSA::PublicKey _rsa_publickey;
    CryptoPP::RSA::PrivateKey _rsa_privatekey;
    // 生成密钥
    generate_rsa_key(_rsa_publickey, _rsa_privatekey, 1024);

    data_package_t cipher_data;
    // 加密前的数据
    std::string str_data("Hello World");
    // 执行加密操作
    b_result = rsa_encrypt_std_string(_rsa_publickey, str_data, cipher_data);
    assert(b_result);
    // 导出加密数据
    std::string outdata((char *) cipher_data._arr_data.get(), cipher_data._size_datalen);
    data_package_t cipher_data_1(outdata.size());
    memcpy(cipher_data_1._arr_data.get(), outdata.c_str(), outdata.size());
    // 测试密钥的导出和导入
    data_package_t _output_private_key;
    b_result = export_rsa_private_key_to_byte(_rsa_privatekey, _output_private_key);
    assert(b_result);
    data_package_t _output_public_key;
    b_result = export_rsa_public_key(_rsa_publickey, _output_public_key);
    assert(b_result);

    CryptoPP::RSA::PublicKey _rsa_second_publickey;
    CryptoPP::RSA::PrivateKey _rsa_second_privatekey;

    b_result = import_rsa_private_key_from_byte(_rsa_second_privatekey, _output_private_key);
    assert(b_result);

    b_result = import_rsa_public_key_from_byte(_rsa_second_publickey, _output_public_key);
    assert(b_result);

    std::string plain;
    // 执行解密操作
    b_result = rsa_decrypt_byte_data(_rsa_second_privatekey, cipher_data_1, plain);
    assert(b_result);
    assert(plain == str_data);
}

/**
 * blowfish 加密解密测试
 */
void blowfish_encrtpt_test() {
    bool b_result = false;
    blowfish_key_value _key_value;
    // 生成密钥
    b_result = generate_blowfish_key(_key_value);
    assert (b_result);
    // 加密前的密钥
    std::string plain_1("Hello World");
    std::string cipher_1;
    // 执行加密操作
    b_result = blowfish_encrypt_std_string(_key_value, plain_1, cipher_1);
    assert(b_result);
    std::string plain_2;
    // 执行解密操作
    b_result = blowfish_decrypt_byte_data(_key_value, cipher_1, plain_2);
    assert(b_result);
    assert(plain_2 == plain_1);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容