使用mbedtls加解密(RSA AES)

 

tg_rsa.hios

 

// 注意: 編譯mbedtls時, 添加宏 MBEDTLS_RSA_NO_CRT (基於 mbedtls 2.16.1)
#ifndef _BVR_OPENSSL_H_ #define _BVR_OPENSSL_H_ #include <iostream> #include <string> typedef struct mbedtls_rsa_context RSA; bool tg_rsa_init(); bool tg_rsa_deinit(); // 生成密鑰 bits >= 512
bool tg_rsa_key_generate(RSA** rsa, int bits); // 密鑰轉爲字符串
bool tg_rsa_key_string(RSA* rsa, std::string& n, std::string& e, std::string& d); // 字符串轉換爲密鑰
bool tg_rsa_key_get(RSA** rsa, const std::string& n, const std::string& e, const std::string& d = ""); // 釋放rsa
bool tg_rsa_key_free(RSA* rsa); // 密鑰加密 usePubKey: 是否使用公鑰加密
bool tg_rsa_encrypt(bool usePubKey, RSA* encrypt, std::string src, std::string& dst); // 密鑰解密 usePriKey: 是否使用私鑰加密
bool tg_rsa_decrypt(bool usePriKey, RSA* decrypt, std::string src, std::string& dst); /** base64 編碼 */ std::string tg_base64_encode(const std::string& str_data); /** base64 解碼 */ std::string tg_base64_decode(const std::string& str_encoded); /** aes cbc 加密 */
int tg_aes_cbc_encrypt(const std::string& plaintext, const std::string& key, const std::string& iv, std::string& ciphertext); /** aes cbc 解密 */
int tg_aes_cbc_decrypt(const std::string& ciphertext, const std::string& key, const std::string& iv, std::string& plaintext); /** 計算數據MD5值*/ std::string tg_md5_encode(const std::string& data); #endif //_BVR_OPENSSL_H_
View Code

 

 

tg_rsa.cppapp

 

#include "tg_rsa.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include "mbedtls/config.h" #include "mbedtls/platform.h" #include "mbedtls/rsa.h" #include "mbedtls/entropy.h" #include "mbedtls/ctr_drbg.h" #include "mbedtls/error.h" #include "mbedtls/base64.h" #include "mbedtls/md5.h" #ifdef _MSC_VER #include <Windows.h>

#pragma comment(lib, "mbedcrypto.lib")
#pragma comment(lib, "mbedtls.lib")
#pragma comment(lib, "mbedx509.lib")
#endif

#define EXPONENT 65537 mbedtls_entropy_context m_entropy; mbedtls_ctr_drbg_context m_ctr_drbg; bool tg_rsa_init() { const char *pers = "rsa_encrypt"; int ret = -1; mbedtls_ctr_drbg_init(&m_ctr_drbg); mbedtls_entropy_init(&m_entropy); ret = mbedtls_ctr_drbg_seed(&m_ctr_drbg, mbedtls_entropy_func, &m_entropy, (const unsigned char *)pers, strlen(pers)); return true; } bool tg_rsa_deinit() { mbedtls_ctr_drbg_free(&m_ctr_drbg); mbedtls_entropy_free(&m_entropy); return true; } bool tg_rsa_key_generate(RSA** pp_rsa, int bits) { mbedtls_rsa_context* p_rsa = NULL; int ret = -1; if (NULL == pp_rsa) { return false; } p_rsa = (mbedtls_rsa_context*)malloc(sizeof(mbedtls_rsa_context)); mbedtls_rsa_init(p_rsa, MBEDTLS_RSA_PKCS_V15, 0); ret = mbedtls_rsa_gen_key(p_rsa, mbedtls_ctr_drbg_random, &m_ctr_drbg, bits, EXPONENT); if (0 == ret) { *pp_rsa = p_rsa; } return true; } bool tg_rsa_key_string(RSA* p_rsa, std::string& p_n, std::string& p_e, std::string& p_d) { int ret = -1; int radix = 16; mbedtls_mpi N, D, E, P, Q; size_t olen_N = 0, olen_D = 0, olen_E = 0, olen_P = 0, olen_Q = 0; mbedtls_mpi_init(&N); mbedtls_mpi_init(&E); mbedtls_mpi_init(&D); mbedtls_mpi_init(&P); mbedtls_mpi_init(&Q); mbedtls_rsa_context* rsa = (mbedtls_rsa_context*)p_rsa; ret = mbedtls_rsa_export(rsa, &N, &P, &Q, &D, &E); int n = mbedtls_mpi_bitlen(&N); if (radix >= 4) n >>= 1; if (radix >= 16) n >>= 1; n += 3 + ((n + 1) & 1); p_n.resize(n); p_e.resize(n); p_d.resize(n); ret = mbedtls_mpi_write_string(&N, radix, (char*)p_n.data(), p_n.size(), &olen_N); ret = mbedtls_mpi_write_string(&E, radix, (char*)p_e.data(), p_e.size(), &olen_E); ret = mbedtls_mpi_write_string(&D, radix, (char*)p_d.data(), p_d.size(), &olen_D); p_n.resize(olen_N); p_e.resize(olen_E); p_d.resize(olen_D); mbedtls_mpi_free(&N); mbedtls_mpi_free(&E); mbedtls_mpi_free(&D); mbedtls_mpi_free(&P); mbedtls_mpi_free(&Q); return true; } bool tg_rsa_key_get(RSA** pp_rsa, const std::string& p_n, const std::string& p_e, const std::string& p_d /*= ""*/) { bool rc = false; int radix = 16; int ret = -1; mbedtls_mpi N, D, E, P, Q; mbedtls_rsa_context* p_rsa = NULL; if (NULL == pp_rsa) { return false; } p_rsa = (mbedtls_rsa_context*)::malloc(sizeof(mbedtls_rsa_context)); mbedtls_mpi_init(&N); mbedtls_mpi_init(&E); mbedtls_mpi_init(&D); mbedtls_mpi_init(&P); mbedtls_mpi_init(&Q); ret = mbedtls_mpi_read_string(&N, radix, p_n.data()); ret = mbedtls_mpi_read_string(&E, radix, p_e.data()); ret = mbedtls_mpi_read_string(&D, radix, p_d.data()); ret = mbedtls_mpi_read_string(&P, radix, "1"); ret = mbedtls_mpi_read_string(&Q, radix, "1"); mbedtls_rsa_init(p_rsa, MBEDTLS_RSA_PKCS_V15, 0); ret = mbedtls_rsa_import(p_rsa, &N, &P, &Q, &D, &E); if (0 == ret) { *pp_rsa = p_rsa; rc = true; } mbedtls_mpi_free(&N); mbedtls_mpi_free(&E); mbedtls_mpi_free(&D); mbedtls_mpi_free(&P); mbedtls_mpi_free(&Q); return rc; } bool tg_rsa_key_free(RSA* p_rsa) { mbedtls_rsa_context* rsa = (mbedtls_rsa_context*)p_rsa; if (rsa) { mbedtls_rsa_free(rsa); ::free(rsa); } return true; } /** padding: 1)RSA_PKCS1_PADDING 填充模式,最經常使用的模式 要求: 輸入 必須 比 RSA 鑰模長(modulus) 短至少11個字節, 也就是 RSA_size(rsa) – 11。若是輸入的明文過長,必須切割, 而後填充 輸出 和modulus同樣長 根據這個要求,對於1024bit的密鑰, block length = 1024/8 – 11 = 117 字節 2) RSA_PKCS1_OAEP_PADDING 要求:RSA_size(rsa) – 41 3)for RSA_NO_PADDING 不填充 RSA_size(rsa) */


bool tg_rsa_encrypt(bool usePubKey, RSA* p_encrypt, std::string src, std::string& dst) { mbedtls_rsa_context* encrypt = (mbedtls_rsa_context*)p_encrypt; /** 說明: rsa加密, 是將加密數據看作一個數字(大數), 進行加密。 源數據的長度要小於密鑰位數(FLEN_MAX), 加密後的長度是RSA_LEN。 解密是將若干個RSA_LEN的塊解密 */
    int RSA_LEN = mbedtls_rsa_get_len(encrypt); // 512 = 4096 / 8
    int FLEN_MAX = RSA_LEN - 11; if (FLEN_MAX <= 0) { return false; } int count = src.size() / FLEN_MAX; int remain = src.size() % FLEN_MAX; size_t reserveSize = count * RSA_LEN + (remain > 0 ? RSA_LEN : 0); // 預留空間
 dst.reserve(reserveSize); std::string cipper; cipper.resize(RSA_LEN); unsigned char* from = (unsigned char*)src.data(); unsigned char* to = (unsigned char*)cipper.data(); int mode = MBEDTLS_RSA_PRIVATE; if (usePubKey) { mode = MBEDTLS_RSA_PUBLIC; } for (int i = 0; i < count; i++) { int ret = mbedtls_rsa_pkcs1_encrypt(encrypt, mbedtls_ctr_drbg_random, &m_ctr_drbg, mode, FLEN_MAX, (const unsigned char*)from + i * FLEN_MAX, to); if (ret != 0) { char pTmp[1024]; mbedtls_strerror(ret, pTmp, 1024); #ifdef _MSC_VER OutputDebugStringA(pTmp); #endif printf("%s\n", pTmp); return false; } if (0 == ret){ dst.append(cipper.data(), cipper.size()); } } if (remain > 0) { int ret = mbedtls_rsa_pkcs1_encrypt(encrypt, mbedtls_ctr_drbg_random, &m_ctr_drbg, mode, remain, (const unsigned char*)from + count * FLEN_MAX, to); if (ret != 0) { char pTmp[1024]; mbedtls_strerror(ret, pTmp, 1024); #ifdef _MSC_VER OutputDebugStringA(pTmp); #endif printf("%s\n", pTmp); return false; } dst.append(cipper.data(), cipper.size()); } return true; } bool tg_rsa_decrypt(bool usePriKey, RSA* p_decrypt, std::string src, std::string& dst) { mbedtls_rsa_context* decrypt = (mbedtls_rsa_context*)p_decrypt; int RSA_LEN = mbedtls_rsa_get_len(decrypt); // 512 = 4096 / 8

    int count = src.size() / RSA_LEN; int remain = src.size() % RSA_LEN; if (remain != 0) { return false; } size_t reserveSize = count * RSA_LEN; // 預留空間
 dst.reserve(reserveSize); std::string cipper; cipper.resize(RSA_LEN); unsigned char* from = (unsigned char*)src.data(); unsigned char* to = (unsigned char*)cipper.data(); int mode = MBEDTLS_RSA_PUBLIC; if (usePriKey) { mode = MBEDTLS_RSA_PRIVATE; } size_t elen = 0; for (int i = 0; i < count; i++) { // 解密
        int ret = mbedtls_rsa_pkcs1_decrypt(decrypt, mbedtls_ctr_drbg_random, &m_ctr_drbg, mode, &elen, from + i * RSA_LEN, to, cipper.size()); // output_max_len >= modulus_len - 11

        if (ret != 0) { char pTmp[1024]; mbedtls_strerror(ret, pTmp, 1024); #ifdef _MSC_VER OutputDebugStringA(pTmp); #endif printf("%s\n", pTmp); return false; } dst.append(cipper.data(), elen); } return true; } std::string tg_base64_encode(const std::string& str_data) { std::string result; size_t slen = str_data.size(); size_t n = slen / 3 + (slen % 3 != 0); size_t dlen = 4 * n + 1; result.resize(dlen); unsigned char buffer[1024]; memset(buffer, 0, sizeof(buffer)); size_t olen = 0; int ret = mbedtls_base64_encode((unsigned char*)result.data(), result.size(), &olen, (const unsigned char*)str_data.data(), str_data.size()); if (ret != 0) { char pTmp[1024]; mbedtls_strerror(ret, pTmp, 1024); #ifdef _MSC_VER OutputDebugStringA(pTmp); #endif printf("%s\n", pTmp); } result.resize(olen); return result; } std::string tg_base64_decode(const std::string& str_encoded) { std::string result; result.resize(str_encoded.size()); size_t olen = 0; int ret = mbedtls_base64_decode((unsigned char*)result.data(), result.size(), &olen, (const unsigned char*)str_encoded.data(), str_encoded.size()); if (ret != 0) { char pTmp[1024]; mbedtls_strerror(ret, pTmp, 1024); #ifdef _MSC_VER OutputDebugStringA(pTmp); #endif printf("%s\n", pTmp); } result.resize(olen); return result; } int tg_aes_cbc_encrypt(const std::string& plaintext, const std::string& key, const std::string& iv, std::string& ciphertext) { int rc = -1; size_t src_len = plaintext.size(); size_t newsize = (src_len / 16) * 16; if (src_len % 16) { newsize += 16; } if (ciphertext.size() < newsize) { ciphertext.resize(newsize); } std::string src_data(plaintext); if (src_data.size() != newsize) { src_data.resize(newsize); // 兼容openssl, 填充位填充的數據爲填充的長度
        int fill_len = newsize - src_len; for (size_t i = src_len; i < newsize; i++) { ((char*)src_data.data())[i] = (char)fill_len; // (0, 16)
 } } std::string tmp_iv(iv); const unsigned char* input = (const unsigned char*)src_data.data(); unsigned char* output = (unsigned char*)ciphertext.data(); mbedtls_aes_context ctx; mbedtls_aes_init(&ctx); rc = mbedtls_aes_setkey_enc(&ctx, (const unsigned char*)key.data(), key.size() * 8); rc = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, newsize, (unsigned char*)tmp_iv.data(), input, output); mbedtls_aes_free(&ctx); return 0; } int tg_aes_cbc_decrypt(const std::string& ciphertext, const std::string& key, const std::string& iv, std::string& plaintext) { int rc = -1; if (plaintext.size() < ciphertext.size()) { plaintext.resize(ciphertext.size()); } size_t newsize = ciphertext.size(); std::string tmp_iv(iv); const unsigned char* input = (const unsigned char*)ciphertext.data(); unsigned char* output = (unsigned char*)plaintext.data(); mbedtls_aes_context ctx; mbedtls_aes_init(&ctx); rc = mbedtls_aes_setkey_dec(&ctx, (const unsigned char*)key.data(), key.size() * 8); rc = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, newsize, (unsigned char*)tmp_iv.data(), input, output); // 兼容openssl, 填充位填充的數據爲填充的長度
 { int fill_len = output[plaintext.size() - 1]; if (fill_len > 0 && fill_len < 16) { bool is_ok = true; for (size_t i = plaintext.size() - fill_len; i < plaintext.size(); i++) { if (output[i] != fill_len) { is_ok = false; break; } } if (is_ok) { plaintext.resize(plaintext.size() - fill_len); } else { rc = -2; } } } mbedtls_aes_free(&ctx); return rc; } std::string tg_md5_encode(const std::string& src) { std::string result; unsigned char output[17]; memset(output, 0, sizeof(output)); int rc = mbedtls_md5_ret((const unsigned char *)src.data(), src.size(), output); if (0 == rc) { char buffer[33]; memset(buffer, 0, sizeof(buffer)); for (int i = 0; i < 16; i++) { sprintf(buffer + i * 2, "%02x", output[i]); } result.assign(buffer, 32); } return result; } void test_tg_rsa() { int rc = -1; tg_rsa_init(); RSA* p_rsa = NULL; int bits = 2048; tg_rsa_key_generate(&p_rsa, bits); std::string n, e, d; tg_rsa_key_string(p_rsa, n, e, d); tg_rsa_key_free(p_rsa); RSA* tmp_rsa = NULL; tg_rsa_key_get(&tmp_rsa, n, e, d); std::string src = "視258頻提供了功能強大的方法幫助您證實您的觀點。當您單擊聯機視頻時,能夠在想要添加的視頻的嵌入代碼中進行粘貼。您也能夠鍵入一個關鍵字以聯機搜索最適合您的文檔的視頻。爲使您的文檔具備專業外觀,Word 提供了頁眉、頁腳、封面和文本框設計,這些設計可互爲補充。例如,您能夠添加匹配的封面、頁眉和提要欄。單擊「插入」,而後從不一樣庫中選擇所需元素。主題和樣式也有助於文檔保持協調。當您單擊設計並選擇新的主題時,圖片、圖表或 SmartArt 圖形將會更改以匹配新的主題。當應用樣式時,您的標題會進行更改以匹配新的主題。使用在須要位置出現的新按鈕在 Word 中保存時間。若要更改圖片適應文檔的方式,請單擊該圖片,圖片旁邊將會顯示佈局選項按鈕。當處理表格時,單擊要添加行或列的位置,而後單擊加號。在新的閱讀視圖中閱讀更加容易。能夠摺疊文檔某些部分並關注所需文本。若是在達到結尾處以前須要中止讀取,Word 會記住您的中止位置 - 即便在另外一個設備上。123視258頻提供了功能強大的方法幫助您證實您的觀點。當您單擊聯機視頻時,能夠在想要添加的視頻的嵌入代碼中進行粘貼。您也能夠鍵入一個關鍵字以聯機搜索最適合您的文檔的視頻。爲使您的文檔具備專業外觀,Word 提供了頁眉、頁腳、封面和文本框設計,這些設計可互爲補充。例如,您能夠添加匹配的封面、頁眉和提要欄。單擊「插入」,而後從不一樣庫中選擇所需元素。主題和樣式也有助於文檔保持協調。當您單擊設計並選擇新的主題時,圖片、圖表或 SmartArt 圖形將會更改以匹配新的主題。當應用樣式時,您的標題會進行更改以匹配新的主題。使用在須要位置出現的新按鈕在 Word 中保存時間。若要更改圖片適應文檔的方式,請單擊該圖片,圖片旁邊將會顯示佈局選項按鈕。當處理表格時,單擊要添加行或列的位置,而後單擊加號。在新的閱讀視圖中閱讀更加容易。能夠摺疊文檔某些部分並關注所需文本。若是在達到結尾處以前須要中止讀取,Word 會記住您的中止位置 - 即便在另外一個設備上。1234視258頻提供了功能強大的方法幫助您證實您的觀點。當您單擊聯機視頻時,能夠在想要添加的視頻的嵌入代碼中進行粘貼。您也能夠鍵入一個關鍵字以聯機搜索最適合您的文檔的視頻。爲使您的文檔具備專業外觀,Word 提供了頁眉、頁腳、封面和文本框設計,這些設計可互爲補充。例如,您能夠添加匹配的封面、頁眉和提要欄。單擊「插入」,而後從不一樣庫中選擇所需元素。主題和樣式也有助於文檔保持協調。當您單擊設計並選擇新的主題時,圖片、圖表或 SmartArt 圖形將會更改以匹配新的主題。當應用樣式時,您的標題會進行更改以匹配新的主題。使用在須要位置出現的新按鈕在 Word 中保存時間。若要更改圖片適應文檔的方式,請單擊該圖片,圖片旁邊將會顯示佈局選項按鈕。當處理表格時,單擊要添加行或列的位置,而後單擊加號。在新的閱讀視圖中閱讀更加容易。能夠摺疊文檔某些部分並關注所需文本。若是在達到結尾處以前須要中止讀取,Word 會記住您的中止位置 - 即便在另外一個設備上。123視258頻提供了功能強大的方法幫助您證實您的觀點。當您單擊聯機視頻時,能夠在想要添加的視頻的嵌入代碼中進行粘貼。您也能夠鍵入一個關鍵字以聯機搜索最適合您的文檔的視頻。爲使您的文檔具備專業外觀,Word 提供了頁眉、頁腳、封面和文本框設計,這些設計可互爲補充。例如,您能夠添加匹配的封面、頁眉和提要欄。單擊「插入」,而後從不一樣庫中選擇所需元素。主題和樣式也有助於文檔保持協調。當您單擊設計並選擇新的主題時,圖片、圖表或 SmartArt 圖形將會更改以匹配新的主題。當應用樣式時,您的標題會進行更改以匹配新的主題。使用在須要位置出現的新按鈕在 Word 中保存時間。若要更改圖片適應文檔的方式,請單擊該圖片,圖片旁邊將會顯示佈局選項按鈕。當處理表格時,單擊要添加行或列的位置,而後單擊加號。在新的閱讀視圖中閱讀更加容易。能夠摺疊文檔某些部分並關注所需文本。若是在達到結尾處以前須要中止讀取,Word 會記住您的中止位置 - 即便在另外一個設備上。12345"; std::string dst, dst2; tg_rsa_encrypt(true, tmp_rsa, src, dst); tg_rsa_decrypt(true, tmp_rsa, dst, dst2); std::string base64 = tg_base64_encode("this is test"); std::string debase64 = tg_base64_decode(base64); { int32_t key_rand = 128; int32_t iv_rand = 5; std::string key;/* A 256 bit key */  // 256/8=32 "01234567890123456789012345678901"
        std::string iv;/* A 128 bit IV */ // 128/8=16 "0123456789012345"
 { const int KEY_SIZE_256_BIT = 32; key.resize(KEY_SIZE_256_BIT); for (int i = 0; i < KEY_SIZE_256_BIT; i++) { key[i] = (2 * i * i * i + 7 * i + key_rand) % 256; } const int IV_SIZE_128_BIT = 16; iv.resize(IV_SIZE_128_BIT); for (int i = 0; i < IV_SIZE_128_BIT; i++) { iv[i] = (6 * i * i * i + 8 * i + iv_rand) % 256; } } unsigned char output[100]; unsigned char output2[100]; mbedtls_aes_context ctx_encrypt, ctx_decrypt; memset(output, 0x00, 100); memset(output2, 0x00, 100); unsigned char src_str[1024]; memset(src_str, 0, sizeof(src_str)); strcpy((char*)src_str, "this is"); size_t len = strlen((char*)src_str); if (len % 16) { len = len / 16 * 16 + 16; } mbedtls_aes_init(&ctx_encrypt); mbedtls_aes_init(&ctx_decrypt); rc = mbedtls_aes_setkey_enc(&ctx_encrypt, (const unsigned char*)key.data(), key.size() * 8); rc = mbedtls_aes_setkey_dec(&ctx_decrypt, (const unsigned char*)key.data(), key.size() * 8); rc = mbedtls_aes_crypt_cbc(&ctx_encrypt, MBEDTLS_AES_ENCRYPT, len, (unsigned char*)iv.data(), (const unsigned char*)src_str, output); { const int IV_SIZE_128_BIT = 16; iv.resize(IV_SIZE_128_BIT); for (int i = 0; i < IV_SIZE_128_BIT; i++) { iv[i] = (6 * i * i * i + 8 * i + iv_rand) % 256; } } rc = mbedtls_aes_crypt_cbc(&ctx_decrypt, MBEDTLS_AES_DECRYPT, 16, (unsigned char*)iv.data(), (const unsigned char*)output, output2); mbedtls_aes_free(&ctx_encrypt); mbedtls_aes_free(&ctx_decrypt); } { int32_t key_rand = 128; int32_t iv_rand = 5; std::string key;/* A 256 bit key */  // 256/8=32 "01234567890123456789012345678901"
        std::string iv;/* A 128 bit IV */ // 128/8=16 "0123456789012345"
 { const int KEY_SIZE_256_BIT = 32; key.resize(KEY_SIZE_256_BIT); for (int i = 0; i < KEY_SIZE_256_BIT; i++) { key[i] = (2 * i * i + 5 * i + key_rand) % 256; } const int IV_SIZE_128_BIT = 16; iv.resize(IV_SIZE_128_BIT); for (int i = 0; i < IV_SIZE_128_BIT; i++) { iv[i] = (6 * i * i + 20 * i + iv_rand) % 256; } } std::string plaintext = "1234567890123456789012345678901234567"; std::string ciphertext, src; tg_aes_cbc_encrypt(plaintext, key, iv, ciphertext); const char* ptr = ciphertext.data(); std::string base64 = tg_base64_encode(ciphertext); std::string debase64 = tg_base64_decode("0D7z6lI1x8SRMtLBk6jBiGAEZdazu/9ZkZhNGjaZC7DeABaboX33F885Otlh/mt8"); tg_aes_cbc_decrypt(debase64, key, iv, src); const char* ptr2 = src.data(); printf(""); } { std::string data = "this is hello"; std::string md5 = tg_md5_encode(data); printf(""); std::string str1 = set_cert_txt_openssl("this is hello 中文"); std::string str2 = get_cert_txt_openssl(str1); printf(""); } tg_rsa_key_free(tmp_rsa); tg_rsa_deinit(); }
View Code
相關文章
相關標籤/搜索