1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
| #include <string> #include <openssl/rsa.h> #include <openssl/pem.h> #include <openssl/err.h>
namespace openssl_rsa_3_x { // 官方文档 https://www.openssl.org/docs/man3.1/man7/EVP_PKEY-RSA.html // 下面的 GenerateKeys1/2/3, 都能用, 1和2效果是一样的, 3可以设置参数生成密钥
// 从EVP_PKEY对象中提取公钥和私钥 inline void GenerateKeysForEvp(EVP_PKEY* pkey, std::string& pri_key, std::string& pub_key) { BIO* pri = BIO_new(BIO_s_mem()); BIO* pub = BIO_new(BIO_s_mem());
PEM_write_bio_PrivateKey(pri, pkey, NULL, NULL, 0, NULL, NULL); PEM_write_bio_PUBKEY(pub, pkey);
size_t pri_len = BIO_pending(pri); size_t pub_len = BIO_pending(pub);
pri_key.resize(pri_len); pub_key.resize(pub_len); BIO_read(pri, &pri_key[0], pri_len); BIO_read(pub, &pub_key[0], pub_len);
// 内存释放 BIO_free_all(pub); BIO_free_all(pri); }
// 生成密钥对, 返回是否成功 // pri_key = 接收私钥结果 // pub_key = 接收公钥结果 // bits = 密钥长度 inline bool GenerateKeys1(std::string& pri_key, std::string& pub_key, UINT bits = 2048) { EVP_PKEY* pkey = EVP_RSA_gen(bits); if (!pkey) return false;
GenerateKeysForEvp(pkey, pri_key, pub_key);
EVP_PKEY_free(pkey); return true; }
// 生成密钥对, 返回是否成功 // pri_key = 接收私钥结果 // pub_key = 接收公钥结果 // bits = 密钥长度 inline bool GenerateKeys2(std::string& pri_key, std::string& pub_key, UINT bits = 2048) { EVP_PKEY* pkey = NULL; EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); EVP_PKEY_keygen_init(pctx); EVP_PKEY_generate(pctx, &pkey); if (!pkey) return false;
GenerateKeysForEvp(pkey, pri_key, pub_key);
EVP_PKEY_CTX_free(pctx); return true; }
// 生成密钥对, 返回是否成功 // pri_key = 接收私钥结果 // pub_key = 接收公钥结果 // bits = 密钥长度 inline bool GenerateKeys3(std::string& pri_key, std::string& pub_key, UINT bits = 2048) { unsigned int primes = 3; OSSL_PARAM params[3]; EVP_PKEY* pkey = NULL; EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
EVP_PKEY_keygen_init(pctx);
// 设置参数生成密钥 // 官方文档 https://www.openssl.org/docs/man3.0/man3/OSSL_PARAM_construct_uint.html params[0] = OSSL_PARAM_construct_uint("bits", &bits); params[1] = OSSL_PARAM_construct_uint("primes", &primes); params[2] = OSSL_PARAM_construct_end(); EVP_PKEY_CTX_set_params(pctx, params);
EVP_PKEY_generate(pctx, &pkey);
if (!pkey) { EVP_PKEY_CTX_free(pctx); return false; }
GenerateKeysForEvp(pkey, pri_key, pub_key);
EVP_PKEY_CTX_free(pctx); return true; }
// 一般情况下都是公钥加密, 私钥解密, 如果是私钥加密的话, 私钥也可以解密 // 所以只写公钥加密和私钥解密的函数 // 需要私钥解密公钥解密的话, 可以改 PEM_read_bio_PUBKEY/PEM_read_bio_PrivateKey // 看名字就能看出来, 一个是读取公钥, 一个是读取私钥 // 后续的加解密操作都是根据 PEM_read_bio_PUBKEY/PEM_read_bio_PrivateKey 返回的对象操作的
// 公钥加密 // pData = 要加密的数据 // nSize = 要加密的数据长度 // pub_key = 公钥 inline std::string rsa_encrypt(LPCVOID pData, size_t nSize, LPCSTR pub_key) { std::string en_data; if (!pData || nSize == 0) return en_data; // 没有数据, 直接返回空字符串
EVP_PKEY_CTX* ctx = 0; BIO* keybio = BIO_new_mem_buf(pub_key, -1); EVP_PKEY* pKey = PEM_read_bio_PUBKEY(keybio, 0, NULL, NULL); while (pKey) { ctx = EVP_PKEY_CTX_new(pKey, NULL); if (!ctx) break;
if (EVP_PKEY_encrypt_init(ctx) <= 0) // 初始化加密 break;
const int key_len = EVP_PKEY_size(pKey); char* buf = new char[key_len];
LPCBYTE ptr = reinterpret_cast<LPCBYTE>(pData); LPCBYTE pEnd = ptr + nSize; const int block_len = key_len - 11; int len = block_len;
// 计算结果长度, 预先分配这么大的内存, 计算方式为: // 每次加密最大尺寸 = block_len // 加密次数 = 总尺寸 / block_len // 每次加密得到的长度 = key_len // 总尺寸 = 每次加密得到的长度 * 总次数 const size_t reserve_size = ((nSize / block_len + ((nSize % block_len == 0) ? 0 : 1)) * key_len); en_data.reserve(reserve_size);
while (ptr < pEnd) { if ((ptr + len) > pEnd) len = pEnd - ptr;
size_t outl = block_len; int ret = EVP_PKEY_encrypt(ctx, reinterpret_cast<LPBYTE>(buf), &outl, ptr, len); if (ret > 0) { en_data.append(buf, outl); } ptr += len; } delete[] buf;
break; }
if (pKey) EVP_PKEY_free(pKey); if (ctx) EVP_PKEY_CTX_free(ctx);
return en_data;
}
// 私钥解密 // pData = 要加密的数据 // nSize = 要加密的数据长度 // pub_key = 私钥 inline std::string rsa_decrypt(LPCVOID pData, size_t nSize, LPCSTR pri_key) { std::string de_data; if (!pData || nSize == 0) return de_data; // 没有数据, 直接返回空字符串
EVP_PKEY_CTX* ctx = 0; BIO* keybio = BIO_new_mem_buf(pri_key, -1); EVP_PKEY* pKey = PEM_read_bio_PrivateKey(keybio, 0, NULL, NULL);
while (pKey) { ctx = EVP_PKEY_CTX_new(pKey, NULL); if (!ctx) break;
if (EVP_PKEY_decrypt_init(ctx) <= 0) // 初始化解密 break;
// 解密的长度就不计算了, 直接使用数据长度, 解密的尺寸肯定小于数据长度 de_data.reserve(nSize); LPCBYTE ptr = reinterpret_cast<LPCBYTE>(pData); LPCBYTE pEnd = ptr + nSize; const int key_len = EVP_PKEY_size(pKey); int len = key_len; char* buf = new char[key_len + 1];
while (ptr < pEnd) { if ((ptr + len) > pEnd) len = pEnd - ptr;
size_t outl = key_len; int ret = EVP_PKEY_decrypt(ctx, reinterpret_cast<LPBYTE>(buf), &outl, ptr, len); #if defined(_DEBUG) || defined(DEBUG) if (ret <= 0) { unsigned long err = ERR_get_error(); //获取错误号 char err_msg[1024] = { 0 }; ERR_error_string(err, err_msg); // 格式:error:errId:库:函数:原因 printf("err msg: err:%ld, msg:%s\n", err, err_msg); } #endif if (ret > 0) { de_data.append(buf, outl); } ptr += len; } delete[] buf;
break; }
if (pKey) EVP_PKEY_free(pKey); if (ctx) EVP_PKEY_CTX_free(ctx);
return de_data; }
}
|