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();
}