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