工作需要使用RSA和BLOWFISH加密,主要使用CRYPTO庫,但是CRYPTO并不是很方便使用,封裝的有點復(fù)雜。我整理CRYPTO的文檔,簡單的封裝了主要的加密和解密方法。代碼如下:
代碼需要配置boost和crypto才能運行。
首先是 data_package_t.hpp 這個類和加解密沒有關(guān)系,只是簡單的封裝了shared_array, 添加了一個_size_datalen,能夠直接獲取數(shù)組的長度。方法也很簡單,只有一個構(gòu)造函數(shù)和 reset_data。構(gòu)造函數(shù)只有一個參數(shù),傳入數(shù)組的長度。reset_data 的作用是把數(shù)據(jù)的數(shù)據(jù)全部清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 里面定義了主要的方法,包含了主要的密鑰創(chuàng)建和初始換,和加解密的方法。每個方法都加了注釋,這里就不詳細解釋了。
#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; }; /** * 從數(shù)組導(dǎo)入rsa的 PRivate key * @param private_key 需要導(dǎo)入的private key * @param _key_data 導(dǎo)入的數(shù)組 * @return 執(zhí)行是否成功 */ bool import_rsa_private_key_from_byte(CryptoPP::RSA::PrivateKey &private_key, const types::data_package_t &_key_data); /** * 從數(shù)組導(dǎo)入rsa的 public key * @param public_key 需要 導(dǎo)入的 public key * @param _key_data 導(dǎo)入的數(shù)組 * @return 執(zhí)行是否成功 */ bool import_rsa_public_key_from_byte(CryptoPP::RSA::PublicKey &public_key, const types::data_package_t &_key_data); /** * 導(dǎo)出rsa的private_key到數(shù)組 * @param private_key 需要導(dǎo)出的private key * @param _key_data 導(dǎo)出的數(shù)組 * @return 執(zhí)行是否成功 */ bool export_rsa_private_key_to_byte(const CryptoPP::RSA::PrivateKey &private_key, types::data_package_t &_key_data); /** * 導(dǎo)出rsa的public_key到數(shù)組 * @param public_key 需要導(dǎo)出的public_key * @param _key_data 導(dǎo)出的數(shù)組 * @return 執(zhí)行是否成功 */ 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 執(zhí)行是否成功 */ bool generate_rsa_key(CryptoPP::RSA::PublicKey &public_key, CryptoPP::RSA::PrivateKey &private_key, unsigned int key_size); /** * RSA加密函數(shù) * @param public_key 公鑰 * @param str_data 需要加密的數(shù)據(jù) * @param cipher_data 加密后的數(shù)據(jù) * @return 執(zhí)行是否成功 */ bool rsa_encrypt_std_string(CryptoPP::RSA::PublicKey &public_key, const std::string &str_data, my_utils::types::data_package_t &cipher_data); /** * RSA解密函數(shù) * @param private_key 私鑰 * @param raw_data 需要解密的數(shù)據(jù) * @param plain 解密后的數(shù)據(jù) * @return 執(zhí)行是否成功 */ 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 執(zhí)行是否成功 */ bool generate_blowfish_key(my_utils::utils::blowfish_key_value &_key_value); /** * 使用blowfish 加密數(shù)據(jù) * @param _key_value 密鑰 * @param plain 加密前的數(shù)據(jù) * @param cipher 加密后的數(shù)據(jù) * @return 執(zhí)行是否成功 */ bool blowfish_encrypt_std_string(const blowfish_key_value &_key_value, const std::string &plain, std::string &cipher); /** * 使用blowfish 解密數(shù)據(jù) * @param _key_value 密鑰 * @param cipher 解密前的數(shù)據(jù) * @param plain 解密后的數(shù)據(jù) * @return 執(zhí)行是否成功 */ 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_Hencryption_utils.cpp 加解密的實現(xiàn)文件,主要參考了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; // 加密前的數(shù)據(jù) std::string str_data("Hello World"); // 執(zhí)行加密操作 b_result = rsa_encrypt_std_string(_rsa_publickey, str_data, cipher_data); assert(b_result); // 導(dǎo)出加密數(shù)據(jù) 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()); // 測試密鑰的導(dǎo)出和導(dǎo)入 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; // 執(zhí)行解密操作 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; // 執(zhí)行加密操作 b_result = blowfish_encrypt_std_string(_key_value, plain_1, cipher_1); assert(b_result); std::string plain_2; // 執(zhí)行解密操作 b_result = blowfish_decrypt_byte_data(_key_value, cipher_1, plain_2); assert(b_result); assert(plain_2 == plain_1);}
|
新聞熱點
疑難解答
圖片精選