1、生成pem格式的密钥,并写入文件。
1)创建RSA公钥加密的上下文,id可以指定国密、RSA、椭圆曲线等算法,e为加密对象,可以传NULL,表示默认值
EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e);
2)对上下文进行初始化
int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
3)设置密钥长度
int EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits)
4)生成密钥,密钥放在ppkey中,这个ppkey需要手动释放;
int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
5)将公私钥写入文件中
//从EVP_PKEY中获取RSA对象 struct rsa_st *EVP_PKEY_get0_RSA(EVP_PKEY *pkey); //将公钥写入文件 int PEM_write_RSAPublicKey(FILE*fp,const RSA*x); //将私钥写入文件 int PEM_write_RSAPrivateKey(FILE*fp, const RSA* x, const EVP_CIPHER*enc//加密上下文, unsigned char*kstr//密钥, int klen//密钥长度, pem_password_cb*cb//加密回调, void*u//回调用的参数);
生成公私钥,并写入文件代码实现
EVP_PKEY*GenerKey() { //1、创建RSA公钥加密上下文,参数1为算法类型 EVP_PKEY_CTX *ctx= EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); if (!ctx) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(ctx); return NULL; } //2、初始化密钥对生成上下文 int ret=EVP_PKEY_keygen_init(ctx); if (!ret) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(ctx); return NULL; } //设置参数,RSA的密钥位数1024位 if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 1024) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(ctx); return NULL; } //4、密钥生成 EVP_PKEY *pkey=NULL; //内部有malloc申请的空间 if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(ctx); return NULL; } EVP_PKEY_CTX_free(ctx); FILE *fp1 = fopen("./public.pem", "w"); if(!fp1) { //出错处理 } PEM_write_RSAPublicKey(fp1, EVP_PKEY_get0_RSA(pkey)); FILE *fp2 = fopen("./private.pem", "w"); if(!fp2) { //出错处理 } //以明文方式存储 PEM_write_RSAPrivateKey(fp2, EVP_PKEY_get0_RSA(pkey), NULL,//加密的上下文 NULL,//key 0,//密钥长度 NULL,//回调 NULL //回调参数 ); fclose(fp1); fclose(fp2); return pkey; }
2、加密或者解密
1)把文件中公钥写入RSA对象中;
int PEM_read_RSAPublicKey(FILE*fp, RSA**r, pem_password_cb *cb, void *arg);
2)通过EVP_PKEY生成EVP_PKEY_CTX上下文
//产生EVP_PKEY对象 EVP_PKEY *EVP_PKEY_new(void); //给EVP_PKEY设置RSA密钥 int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key); //生成EVP_PKEY上下文 EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
3)加密
int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx);//加密初始化 int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out//输出空间 , size_t *outlen, //传入传出参数,传入预留空间大小,传出实际大小 const unsigned char *in,//输入数据 size_t inlen /*输入数据大小*/);
加密代码实现
int Encrypto(const unsigned char *in, int in_len, unsigned char *out) { //1、读取公钥 FILE *fp = fopen("./public.pem", "r"); RSA *r = NULL; if (NULL == fp) { fclose(fp); return -1; } //把文件中公钥写入到RSA结构体中 PEM_read_RSAPublicKey(fp, &r, NULL, NULL); fclose(fp); if (!r) { ERR_print_errors_fp(stderr); return -1; } //2、 //密钥长度 int key_size = RSA_size(r); //2通过EVP_PKEY生成EVP_PKEY_CTX上下文 EVP_PKEY *pkey = EVP_PKEY_new(); //设置为RSA的密钥 EVP_PKEY_set1_RSA(pkey, r); auto ctx = EVP_PKEY_CTX_new(pkey, NULL); //3加密初始化 EVP_PKEY_encrypt_init(ctx); //数据块大小 int block_size = key_size - RSA_PKCS1_PADDING_SIZE; int out_size = 0; int i; //4加密,分块加密 for (i = 0; i < in_len; i += block_size) { size_t out_len = key_size; size_t ensize = block_size; if (in_len - i < block_size) ensize = in_len - i; int ret=EVP_PKEY_encrypt(ctx, out+out_size, &out_len, in+i, ensize); if (ret <= 0) { ERR_print_errors_fp(stderr); break; } out_size += out_len; } EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(ctx); RSA_free(r); return out_size; }
解密代码实现
int Decrypto(const unsigned char *in, int in_len, unsigned char *out) { //打开pem文件获取私钥 FILE *fp = fopen("./private.pem", "r"); if (!fp) { fclose(fp); return -1; } RSA *r = NULL; //拿私钥 PEM_read_RSAPrivateKey(fp, &r, NULL, NULL); if (!r) { fclose(fp); RSA_free(r); } int key_size = RSA_size(r); //生成PKEY并创建上下文 EVP_PKEY*pkey = EVP_PKEY_new(); EVP_PKEY_set1_RSA(pkey, r); auto ctx = EVP_PKEY_CTX_new(pkey,NULL); EVP_PKEY_free(pkey); RSA_free(r); fclose(fp); //解密 int out_size = 0; EVP_PKEY_decrypt_init(ctx); int block_size = key_size; for (int i = 0; i < in_len; i += block_size) { size_t outlen = key_size;//设置输出空间大小; if (EVP_PKEY_decrypt(ctx, out+out_size, &outlen, in + i, block_size) <= 0) { ERR_print_errors_fp(stderr); return -1; } out_size += outlen; } EVP_PKEY_CTX_free(ctx); return out_size; }
测试
int test01() unsigned char data[] = "how are you?hello world!i am fine and you"; unsigned char out[512] = { 0 }; unsigned char out2[512] = { 0 }; int data_size = sizeof(data); auto pkey = GenerKey(); EVP_PKEY_free(pkey); int outsize = Encrypto(data, data_size, out); cout << "密文长度:" << outsize << endl; cout << "密文:" << out << endl; int out2size = Decrypto(out, outsize, out2); cout << "解密后的数据:" << out2<<endl; return 0; }