Linux C语言调用OpenSSL: RSA非对称加解密(填充模式PKCS1)

一、概述

OpenSSL支持多种非对称加密算法,包括RSA、DH、DSA、ECC和SM2等。本文主讲RSA非对称加解密的PKCS1填充模式。

1. RSA非对称加解密流程

  1. 生成密钥对
    生成私钥:使用OpenSSL提供的命令行工具可以生成一对RSA密钥,包括一个私钥和一个公钥。生成私钥的命令是openssl genrsa -out rsa_private_key.pem 1024,其中1024是密钥的长度,可以根据安全需求选择不同的长度。
    提取公钥:有了私钥文件后,可以通过命令openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem从私钥中提取出公钥。
    密钥格式:在C/C++开发中,私钥和公钥通常以PEM格式存储,这种格式的密钥文件包含了起始和结束的标识,以及每64个字节的换行符,方便阅读和管理。
  2. 公钥加密过程
    读取公钥文件:在进行加密操作前,需要通过fopen()函数打开公钥文件,并使用PEM_read_RSA_PUBKEY函数读入并初始化公钥。
    执行加密操作:利用RSA_public_encrypt函数可以实现公钥加密,该函数需要指定明文的长度和密文的存储空间。加密过程中可能需要对明文进行适当的填充,以确保加密的正确性。
    加密数据限制:由于RSA算法的限制,每次加密的数据长度不能超过密钥长度减去一定数值(如RSA_PKCS1_PADDING),对于较大的数据需要进行分块加密或采用其他策略。
  3. 私钥解密过程
    读取私钥文件:与加密过程类似,解密前需要打开私钥文件,使用PEM_read_RSAPrivateKey函数读入私钥并进行初始化。
    执行解密操作:通过RSA_private_decrypt函数可以实现私钥解密,解密过程中同样需要注意数据长度和填充规范,以确保解密的正确性。
    解密数据限制:解密过程中也受到数据长度的限制,需要确保每次解密的数据块符合RSA算法的要求。

2. RSA非对称加解密的填充模式

以下是对每种填充模式的介绍:

  1. RSA_PKCS1_PADDING
    特点: RSA_PKCS1_PADDING是RSA加密中一种传统的填充方式,它遵循PKCS#1标准。这种模式在数据块前添加了必要的填充字节,以确保数据符合RSA密钥长度的要求。
    安全性分析: 虽然PKCS1填充广泛使用,但它可能受到选择密文攻击(CCA)的威胁。在某些情况下,不恰当的实现可能会暴露出安全漏洞。
    适用场景: RSA_PKCS1_PADDING适用于那些不需要最高安全性的应用,或者在能够确保加密过程中其他环节安全性的情况下使用。
  2. RSA_PKCS1_OAEP_PADDING
    特点: RSA_PKCS1_OAEP_PADDING是一种基于最优非对称加密填充(Optimal Asymmetric Encryption Padding, OAEP)的模式。它不仅提供数据填充,还加强了算法的整体安全性,通过在加密前对数据进行预处理来防止某些类型的攻击。
    安全性分析: OAEP设计用于提高RSA加密的安全性,可以有效防御CCA和其他类型的攻击。它引入了额外的随机性和编码步骤,使得加密过程更难以被攻击者利用。
    适用场景: RSA_PKCS1_OAEP_PADDING适用于需要较高安全性的应用场景,如敏感数据的加密传输和数字签名。
  3. RSA_NO_PADDING
    特点: 如其名,RSA_NO_PADDING不使用任何填充。这意味着加密的数据必须严格符合RSA密钥的长度要求,否则将无法正确加密或解密。
    安全性分析: 由于没有填充,这种模式容易受到多种攻击,特别是当处理未经过适当验证的数据时。因此,除非特殊情况,通常不推荐使用无填充模式。
    适用场景: 应避免使用RSA_NO_PADDING,除非在非常特定的、已经充分考虑并管理了所有潜在风险的场景下。
  4. 注意事项
    确保在实施加密时,密钥的长度和填充模式相匹配,以避免数据丢失或错误。
    在选择填充模式时,应考虑到数据的特性和安全需求,合理选择最合适的加密策略。
    对于涉及高安全性需求的场合,建议使用RSA_PKCS1_OAEP_PADDING以增强整体安全性。

本文代码示例中,使用RSA_PKCS1_PADDING举例。

二、调用函数介绍

本文主要使用EVP打头的函数,关于EVP函数的介绍,可参考我的博客: Linux C语言调用OpenSSL:EVP 接口概述

1. EVP_PKEY_new

动态地分配并初始化一个 EVP_PKEY 结构体。这个结构体通常与特定的密钥类型(如 RSA、DSA、EC 等)关联,并且包含密钥的实际数据。

#include <openssl/evp.h>
EVP_PKEY *EVP_PKEY_new(void);

返回值:
如果成功,返回一个指向新分配的 EVP_PKEY 结构体的指针。如果失败,返回 NULL。

注意:
(1)通常不会直接使用 EVP_PKEY_new 来生成密钥。应该使用特定于密钥类型的函数(如 RSA_generate_key_ex、EC_KEY_generate_key 等)来生成密钥,并将生成的密钥设置为 EVP_PKEY 结构体的内容。
(2)当使用完 EVP_PKEY 结构体后,应该使用 EVP_PKEY_free 函数来释放它,以避免内存泄漏。
(3)如果在创建 EVP_PKEY 结构体后没有设置其密钥类型或内容,那么它就是一个“空”的或“未初始化”的 EVP_PKEY 结构体,并且可能无法用于任何有意义的操作。

2. EVP_PKEY_set1_RSA

用于将RSA密钥(RSA *类型)设置为EVP密钥(EVP_PKEY *类型)的RSA部分。

#include <openssl/evp.h>
#include <openssl/rsa.h>
int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key)

参数:
*EVP_PKEY pkey:这是一个指向EVP_PKEY结构的指针,该结构表示一个公钥或私钥。这个指针指向的EVP_PKEY结构将被设置为包含提供的RSA密钥。
*RSA key:这是一个指向RSA结构的指针,该结构包含RSA密钥的具体信息。这个密钥将被复制到EVP_PKEY结构中。

返回值:
成功时返回1,表示密钥已成功设置。如果发生错误,则返回0,并可以通过OpenSSL的错误处理函数(如ERR_get_error)来获取更详细的错误信息。

注意:
EVP_PKEY_set1_RSA函数会增加key的引用计数(如果它尚未被设置为自动释放),并在不再需要时自动释放它。这有助于管理密钥的生命周期,并确保在不再需要密钥时正确地释放它。

3. EVP_PKEY_CTX_new

用于初始化一个密钥上下文 (EVP_PKEY_CTX)。这个上下文用于存储与特定公钥或私钥相关的操作(如签名、验证、加密、解密等)的状态和参数。

#include <openssl/evp.h>
EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);

参数:
EVP_PKEY *pkey:这是一个指向 EVP_PKEY 结构的指针,该结构包含了公钥或私钥的信息。这个参数通常是非空的,除非要在不涉及具体密钥的情况下设置某些通用的上下文选项。
ENGINE *e:这是一个指向 ENGINE 结构的指针,该结构用于硬件加速或实现特定的加密算法。在大多数情况下,可以将此参数设置为 NULL,除非正在使用特定的加密硬件或需要特定的算法实现。

返回值:
如果成功,EVP_PKEY_CTX_new 将返回一个指向新创建的 EVP_PKEY_CTX 结构的指针。如果失败,它将返回 NULL。

4. EVP_PKEY_encrypt_init

用于初始化一个公钥加密操作。使用公钥进行加密时(例如,在公钥密码体制如 RSA 或 ECC 中),需要首先使用这个函数来设置加密操作的上下文。

#include <openssl/evp.h>
int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);

参数:
EVP_PKEY_CTX *ctx:这是一个指向 EVP_PKEY_CTX 结构的指针,该结构用于存储加密操作的上下文。这个上下文通常是通过 EVP_PKEY_CTX_new 函数创建的。
EVP_PKEY *pkey:这是一个指向 EVP_PKEY 结构的指针,该结构包含了公钥的信息。公钥用于加密数据。

返回值:
如果初始化成功,函数返回 1(真)。如果失败,它返回 0(假)并设置错误代码,可以通过 ERR_get_error 来获取这个错误代码。

5. EVP_PKEY_CTX_set_rsa_padding

用于在 RSA 加密或签名操作中设置填充模式(padding mode)。RSA 加密和签名操作通常需要某种形式的填充来确保安全性,因为 RSA 算法本身并不直接支持对任意长度的数据进行加密或签名。

#include <openssl/evp.h>
int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int pad);

参数:
EVP_PKEY_CTX *ctx:这是一个指向 EVP_PKEY_CTX 结构的指针,该结构用于存储密钥操作的上下文。这个上下文通常是通过 EVP_PKEY_CTX_new 函数创建的,并且已经与 RSA 密钥相关联。
int pad:这是一个整数,指定了 RSA 操作的填充模式。OpenSSL 支持多种 RSA 填充模式,包括但不限于:
RSA_PKCS1_PADDING:传统的 PKCS#1 v1.5 填充模式。
RSA_PKCS1_OAEP_PADDING:PKCS#1 OAEP(Optimal Asymmetric Encryption Padding)填充模式,通常与 SHA-1、SHA-256 等哈希算法一起使用。
RSA_NO_PADDING:不进行填充(注意:这通常是不安全的,并且仅用于某些特定的、非标准的用途)。
其他填充模式可能也受支持,但上述是最常见的。

返回值:
如果设置成功,函数返回 1(真)。如果失败,它返回 0(假)并设置错误代码,可以通过 ERR_get_error 来获取这个错误代码。

6. EVP_PKEY_encrypt

用于执行公钥加密操作的函数。

#include <openssl/evp.h>
int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx,  unsigned char *out, size_t *outlen,  
                     const unsigned char *in, size_t inlen);

参数:
EVP_PKEY_CTX *ctx:这是一个指向 EVP_PKEY_CTX 结构的指针,它包含了加密操作的所有上下文信息,包括公钥、填充模式、加密算法等。
unsigned char *out:这是一个指向输出缓冲区的指针,加密后的数据将被写入这个缓冲区。
size_t *outlen:这是一个指向 size_t 类型的指针,它包含了输出缓冲区 out 的大小。在函数调用后,它将被设置为实际写入输出缓冲区的字节数。
const unsigned char *in:这是一个指向输入数据的指针,即需要被加密的数据。
size_t inlen:这是输入数据的长度(以字节为单位)。

返回值:
如果加密操作成功,函数返回 1(真)。如果失败,它返回 0(假)并设置错误代码,可以通过 ERR_get_error 来获取这个错误代码。

7. EVP_PKEY_CTX_free

用于释放由EVP_PKEY_CTX_new创建的EVP_PKEY_CTX结构的内存。当使用完一个EVP_PKEY_CTX上下文后,应该调用这个函数来释放它占用的资源,以防止内存泄漏。

#include <openssl/evp.h>
void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);

参数:
EVP_PKEY_CTX *ctx:指向要释放的EVP_PKEY_CTX结构的指针。这个指针必须是之前通过EVP_PKEY_CTX_new或相关函数(如EVP_PKEY_sign_init、EVP_PKEY_encrypt_init等)成功创建的。

返回值:
此函数没有返回值,因为它执行的是一个简单的内存释放操作。

8. EVP_PKEY_decrypt_init

用于初始化解密操作的函数。它设置了一个 EVP_PKEY_CTX 上下文,以便进行后续的解密操作

#include <openssl/evp.h>
int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx);

参数:
EVP_PKEY_CTX *ctx:指向 EVP_PKEY_CTX 结构的指针,该结构将包含解密操作的上下文信息。

返回值:
如果初始化成功,函数返回 1(真)。如果失败,它返回 0(假)并设置错误代码。

9. EVP_PKEY_decrypt

用于执行私钥解密操作。EVP_PKEY_decrypt函数是一个通用的接口,它可以用于支持多种算法(如RSA、EC等)的解密操作。

#include <openssl/evp.h>
int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx,  unsigned char *out, size_t *outlen,  
                     const unsigned char *in, size_t inlen);

参数:
EVP_PKEY_CTX *ctx:指向已初始化解密操作的EVP_PKEY_CTX结构的指针。
unsigned char *out:指向输出缓冲区的指针,用于存放解密后的数据。
size_t *outlen:解密后数据的长度(以字节为单位)。这是一个输入/输出参数。在调用函数之前,它应该被设置为输出缓冲区out的大小。在函数返回后,它将被设置为实际解密数据的长度。
const unsigned char *in:指向要解密的密文的指针。
size_t inlen:密文的长度(以字节为单位)。

返回值:
如果解密操作成功,函数返回1(真)。如果失败,它返回0(假)并设置错误代码。

示例

代码

#include <stdio.h>
#include <stdlib.h>

#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>

#define WK_OK            0
#define WK_ERR           (-1)
#define ANSI_COLOR_RESET   "\x1b[0m"
#define ANSI_COLOR_RED     "\x1b[31m"
#define log_err(...)        (printf("[" ANSI_COLOR_RED "%s-%s-%d" ANSI_COLOR_RESET "]: ", __FILE__, __FUNCTION__, __LINE__), printf(__VA_ARGS__))


//打印
void my_printf(char* str, unsigned char* data, unsigned int len)
{
    if(NULL != str)
    {
        printf("%s\n", str);
    }
    for(int i=0; i<len; i++)
    {
        printf("0x%02x, ", data[i]);
        if(0 == (i+1)%32)
        {
            printf("\n");
        }
    }
    printf("\n");
}

//生成RSA私钥
RSA* my_generate_rsa_key(int key_bit, unsigned long e_value)
{
    RSA* r = RSA_new();//存放rsa密钥对
    if(NULL == r)
    {
        return NULL;
    }
    BIGNUM* e = BN_new();
    BN_set_word(e, e_value); //公钥指数 使用默认值RSA_F4 65537;  也可以采用随机数,性能不可控
    RSA_generate_key_ex(r, key_bit, e, NULL);//生成私钥指数D 和 模数N(N=p*q)

    BN_free(e);//释放空间
    return r;
}

//提取公钥
//prikey:私钥
RSA* my_get_pub_form_pri(RSA* prikey)
{
    BIGNUM *n_in_pri = NULL;//私钥中的模数
    BIGNUM *e_in_pri = NULL;//私钥中的公钥指数
    BIGNUM *n_in_pub = NULL;
    BIGNUM *e_in_pub = NULL;

    //存放rsa公钥
    RSA* pubkey = RSA_new();
    if(NULL == pubkey)
    {
        return NULL;
    }

    //获取私钥中的N和e(公钥由模数N和公钥指数E决定,所以只需要获取这两个参数)
    RSA_get0_key(prikey, &n_in_pri, &e_in_pri, NULL);
    //复制大数。注意:(1)不能直接使用memcpy,容易造成内存泄漏;(2)若使用BN_copy,需要提前给目标BINNUM申请空间
    n_in_pub = BN_dup(n_in_pri);
    e_in_pub = BN_dup(e_in_pri);

    //设置公钥(pubkey会继承n_in_pub和e_in_pub空间,所以无需单独释放n_in_pub和e_in_pub空间)
    RSA_set0_key(pubkey, n_in_pub, e_in_pub, NULL);

    return pubkey;
}


//RSA加密
int my_RSA_en(EVP_PKEY *evpKey, unsigned char* src, unsigned int src_len, unsigned char* dst, unsigned int* dst_len)
{
    int ret = 0;
    char err[128] = {0};
    EVP_PKEY_CTX *ctx = NULL;
    int encrypted_len = 0;

    ctx = EVP_PKEY_CTX_new(evpKey, NULL);
    if (ctx == NULL) 
    {
        log_err("err: EVP_PKEY_CTX_new\n");
        goto err_handle;
    }

    //初始化加密上下文
    ret = EVP_PKEY_encrypt_init(ctx);
    if (ret <= 0) 
    {
        log_err("err: EVP_PKEY_encrypt_init\n");
        goto err_handle;
    }
    //设置填充模式
    ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING);
    if (ret <= 0) 
    {
        log_err("err: EVP_PKEY_CTX_set_rsa_padding\n");
        goto err_handle;
    }
    //加密
    ret = EVP_PKEY_encrypt(ctx, dst, dst_len, src, src_len);
    if (ret <= 0) 
    {
        log_err("err: EVP_PKEY_encrypt\n");
        goto err_handle;
    }

    EVP_PKEY_CTX_free(ctx);
    return WK_OK;

err_handle:
    ERR_error_string(ERR_get_error(), err);
    log_err("err: [%s]\n", err);
    if(ctx)
    {
        EVP_PKEY_CTX_free(ctx);
    }
    return WK_ERR; 
}


//RSA解密
int my_RSA_de(EVP_PKEY *evpKey, unsigned char* src, unsigned int src_len, unsigned char* dst, unsigned int* dst_len)
{
    int ret = 0;
    char err[128] = {0};
    EVP_PKEY_CTX *ctx = NULL;

    ctx = EVP_PKEY_CTX_new(evpKey, NULL);
    if (ctx == NULL) 
    {
        log_err("err: EVP_PKEY_CTX_new\n");
        goto err_handle;
    }

    //初始化加密上下文
    ret = EVP_PKEY_decrypt_init(ctx);
    if (ret <= 0) 
    {
        log_err("err: EVP_PKEY_decrypt_init\n");
        goto err_handle;
    }
    //设置填充模式
    ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING);
    if (ret <= 0) 
    {
        log_err("err: EVP_PKEY_CTX_set_rsa_padding\n");
        goto err_handle;
    }

    //解密
    ret = EVP_PKEY_decrypt(ctx, dst, dst_len, src, src_len);
    if (ret <= 0) 
    {
        log_err("err: EVP_PKEY_decrypt\n");
        goto err_handle;
    }

    EVP_PKEY_CTX_free(ctx);
    return WK_OK;

err_handle:
    ERR_error_string(ERR_get_error(), err);
    log_err("err: [%s]\n", err);
    if(ctx)
    {
        EVP_PKEY_CTX_free(ctx);
    }
    return WK_ERR; 
}

int main()
{
    unsigned long long e_value = RSA_F4;//65537,rsa.h中的宏定义,加密指数(或称:公共指数)
    int key_bit = 2048;
    RSA* rsa_key = NULL;//私钥
    RSA* rsa_pub = NULL;//公钥
    unsigned char data[512] = {0};
    unsigned int datalen = 245;
    unsigned char cipher[512] = {0};
    unsigned int cipher_len = 0;
    unsigned char plain[512] = {0};
    unsigned int plain_len = 0;
    int ret = 0, i = 0;
    char err[128] = {0};
    EVP_PKEY *evpKey = EVP_PKEY_new();//EVP KEY结构体变量(私钥)
    EVP_PKEY *evpKey_pub = EVP_PKEY_new();//EVP KEY结构体变量(公钥)

    for(i=0; i<datalen; i++)
    {
        data[i] = i%100;
    }
    printf("data len [%d]\n", datalen);
    my_printf("data:", data, datalen);

    OpenSSL_add_all_algorithms();
/*===================================================================================================*/
    //获取密钥(也可从文件中读取)
    rsa_key = my_generate_rsa_key(key_bit, e_value);
    if(NULL == rsa_key)
    {
        log_err("err: my_generate_rsa_key\n");
        return WK_ERR;
    }
    rsa_pub = my_get_pub_form_pri(rsa_key);//提取公钥
    if(NULL == rsa_pub)
    {
        log_err("err: my_get_pub_form_pri\n");
        return WK_ERR;
    }
    //保存rsa密钥结构体,到EVP_PKEY 结构体中
    ret = EVP_PKEY_set1_RSA(evpKey, rsa_key);
    if(1 != ret)
    {
        log_err("err: EVP_PKEY_set1_RSA\n");
        goto err_handle;
    }    
    ret = EVP_PKEY_set1_RSA(evpKey_pub, rsa_pub);
    if(1 != ret)
    {
        log_err("err: EVP_PKEY_set1_RSA\n");
        goto err_handle;
    }    
/*==============================================================================================*/
//注意:对于RSA加解密,单包有长度限制,单包加密最大长度 = 私钥长度 - 填充长度
//比如:私钥的size = 2048,即256字节,选择RSA_PKCS1_PADDING填充模式,RSA_PKCS1_PADDING_SIZE = 11;于是单包加密最大长度 = 256 - 11 = 245
//若需对长报文进行非对称加解密,可以分包加密,然后依次解密后拼接
    //加密
    ret = my_RSA_en(evpKey_pub, data, datalen, cipher, &cipher_len);
    if(WK_OK != ret)
    {
        log_err("err: my_RSA_PSS_sign\n");
        goto err_handle;
    }
    printf("en result len [%d]\n", cipher_len);
    my_printf("en result:", cipher, cipher_len);

    //解密
    ret = my_RSA_de(evpKey, cipher, cipher_len, plain, &plain_len);
    if(WK_OK != ret)
    {
        log_err("err: my_RSA_PSS_ver\n");
        goto err_handle;
    }
    printf("de result len [%d]\n", plain_len);
    my_printf("de result:", plain, plain_len);
    if(0 == memcmp(plain, data, datalen))
    {
        printf("succ: ========en and de========\n");
    }
    else
    {
        printf("err:  ========en and de========\n");
    }

    EVP_PKEY_free(evpKey);
    EVP_PKEY_free(evpKey_pub);
    RSA_free(rsa_key);
    RSA_free(rsa_pub);
    return WK_OK;  

err_handle:
    ERR_error_string(ERR_get_error(), err);
    log_err("err: [%s]\n", err);
    if(NULL != evpKey)
    {
        EVP_PKEY_free(evpKey);
    }
    if(NULL != evpKey_pub)
    {
        EVP_PKEY_free(evpKey_pub);
    }
    if(NULL != rsa_key)
    {
        RSA_free(rsa_key);
    }
    if(NULL != rsa_pub)
    {
        RSA_free(rsa_pub);
    }
    return WK_ERR;  
}

makefile

SRC := $(wildcard ./*.c)

#paramter
CC := gcc
target := app_openssl

#头文件和库路径(修改成安装openssl的路径)
DIR_LIB := -L /xxxxxxx/openssl/lib64
DIR_INCLUDE := -I /xxxxxx/openssl/include/

$(target):$(SRC)
        $(CC) $(SRC) $(DIR_INCLUDE) $(DIR_LIB) -lssl -lcrypto -o $@

clean:
        rm -rf $(target)

执行结果

在这里插入图片描述
每次的加密结果不一样。

参考链接:https://www.openssl.org/source/old/index.html

  • 21
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是使用C语言OpenSSL编写RSA加密解密算法的代码及注释: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <openssl/bio.h> #include <openssl/evp.h> #include <openssl/rsa.h> #define KEY_LENGTH 2048 // RSA密钥长度 #define PUB_EXP 3 // RSA公钥指数 // RSA密钥对结构体 typedef struct _rsa_keys { RSA *public_key; RSA *private_key; } rsa_keys; // 生成RSA密钥对函数 int generate_rsa_keys(rsa_keys *keys) { int ret = 0; BIGNUM *bn = NULL; BIO *bio = NULL; // 生成RSA密钥对 keys->public_key = RSA_new(); keys->private_key = RSA_new(); bn = BN_new(); ret = BN_set_word(bn, PUB_EXP); ret = RSA_generate_key_ex(keys->public_key, KEY_LENGTH, bn, NULL); ret = RSA_generate_key_ex(keys->private_key, KEY_LENGTH, bn, NULL); // 清除内存 BN_free(bn); return ret; } // RSA加密函数 int rsa_encrypt(char *input, int input_len, char *output, rsa_keys *keys) { int ret = 0; BIO *bio = NULL; EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; size_t output_len = 0; // 获取RSA公钥 pkey = EVP_PKEY_new(); ret = EVP_PKEY_set1_RSA(pkey, keys->public_key); // 创建RSA加密上下文 ctx = EVP_PKEY_CTX_new(pkey, NULL); // 初始化RSA加密上下文 ret = EVP_PKEY_encrypt_init(ctx); // 设置RSA加密填充模式 ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING); // 执行RSA加密 ret = EVP_PKEY_encrypt(ctx, NULL, &output_len, input, input_len); // 申请内存 output = (char*) malloc(output_len); // 执行RSA加密 ret = EVP_PKEY_encrypt(ctx, output, &output_len, input, input_len); // 清除内存 EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return ret; } // RSA解密函数 int rsa_decrypt(char *input, int input_len, char *output, rsa_keys *keys) { int ret = 0; BIO *bio = NULL; EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; size_t output_len = 0; // 获取RSA私钥 pkey = EVP_PKEY_new(); ret = EVP_PKEY_set1_RSA(pkey, keys->private_key); // 创建RSA解密上下文 ctx = EVP_PKEY_CTX_new(pkey, NULL); // 初始化RSA解密上下文 ret = EVP_PKEY_decrypt_init(ctx); // 设置RSA解密填充模式 ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING); // 执行RSA解密 ret = EVP_PKEY_decrypt(ctx, NULL, &output_len, input, input_len); // 申请内存 output = (char*) malloc(output_len); // 执行RSA解密 ret = EVP_PKEY_decrypt(ctx, output, &output_len, input, input_len); // 清除内存 EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey); return ret; } int main() { rsa_keys keys; char *input = "Hello, RSA!"; char *encrypted = NULL; char *decrypted = NULL; int ret = 0; // 生成RSA密钥对 ret = generate_rsa_keys(&keys); // RSA加密 ret = rsa_encrypt(input, strlen(input), encrypted, &keys); // RSA解密 ret = rsa_decrypt(encrypted, strlen(encrypted), decrypted, &keys); // 输出结果 printf("Input: %s\n", input); printf("Encrypted: %s\n", encrypted); printf("Decrypted: %s\n", decrypted); // 清除内存 free(encrypted); free(decrypted); return 0; } ``` 注释已经标注在代码中,主要分为以下几个部分: - 生成RSA密钥对 - RSA加密 - RSA解密 代码中使用了OpenSSL库提供的RSA相关函数。首先使用`RSA_new()`函数创建RSA密钥对结构体,然后使用`RSA_generate_key_ex()`函数生成RSA密钥对。生成RSA密钥对后,使用`EVP_PKEY_set1_RSA()`函数获取RSA公钥或私钥,使用`EVP_PKEY_CTX_new()`函数创建RSA加密或解密上下文,使用`EVP_PKEY_encrypt()`或`EVP_PKEY_decrypt()`函数执行RSA加密或解密,最后使用`EVP_PKEY_CTX_free()`和`EVP_PKEY_free()`函数清除内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值