EVP接口生成pem格式的RSA密鑰


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM