使用mbedtls加解密(RSA AES)
tg_rsa.h
// 注意: 编译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_
tg_rsa.cpp
#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(); }