mbedtls rsa使用pem文件

最近有个项目需要用到rsa加密和解密,平台是cortex-m4单片机,于是我想用炒的比较火的mbedtls库实现。既然这玩意炒的比较火,资料应该不少才对,上手以后才发现资料少的可怜,仅有的资料基本都是在注水,参考意义不大,pem格式的秘钥操作这一块基本相当于没有资料,只能自己硬着头皮搞了。搞了两天以后终于搞出来了。

关于pem相关知识这里不做介绍,我就直接贴代码。

#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif

#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#include <stdlib.h>
#define mbedtls_printf       printf
#define mbedtls_exit         exit
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
#endif /* MBEDTLS_PLATFORM_C */


#include "mbedtls/rsa.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/pk.h"
#include <stdio.h>
#include <string.h>

int rsa_encrypt()
{
    FILE* f = NULL;
    long size;
    size_t n;
    unsigned char* publickey = NULL;
    mbedtls_pk_context ctx_pk;

/*********************************************/
    int ret = 1;

    size_t i;
    mbedtls_rsa_context rsa;
    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
    unsigned char input[1024];
    unsigned char buf[512];
    const char* pers = "rsa_encrypt";
    mbedtls_mpi N, E;       //定义一个大数,也就是公钥
/*****************************************************/
    mbedtls_pk_init(&ctx_pk);

    if ((f = fopen("rsa4096_pub.pem", "rb")) == NULL)      //打开pem格式的公钥文件
    {
        mbedtls_printf("\n  .  Open public key file failed!");
        return(-1);
    }
    fseek(f, 0, SEEK_END);
    if ((size = ftell(f)) == -1)
    {
        fclose(f);
        return(-1);
    }
    fseek(f, 0, SEEK_SET);

    n = (size_t)size;    //

    if (n + 1 == 0 || (publickey = mbedtls_calloc(1, n + 1)) == NULL)
    {
        fclose(f);
        return(-1);
    }

    if (fread(publickey, 1, n, f) != n)
    {
        fclose(f);
        free(publickey);
        publickey = NULL;
        return(-1);
    }
    fclose(f);

    /*从pem文件里获得公钥*/
    if (0 != mbedtls_pk_parse_public_key(&ctx_pk, publickey, n + 1))
    {
        mbedtls_printf("\n  . Can't import public key");
    }
    else
    {
        mbedtls_printf("\n  . Import public key successfully");
    }

    free(publickey);
    publickey = NULL;
    /*****************************************************************/

    mbedtls_printf("\n  . Seeding the random number generator...");

    memset(input, 0, 1024);
    fflush(stdout);

    mbedtls_mpi_init(&N);
    mbedtls_mpi_init(&E);
    mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
    mbedtls_ctr_drbg_init(&ctr_drbg);      //初始化ctr drbg结构体,用于随机数的生成
    mbedtls_entropy_init(&entropy);       //初始化熵源

    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers));     //生成随机数

    if (ret != 0)
    {
        mbedtls_printf(" failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret);
        goto exit;
    }
    /*导入pem内的公钥*/
    rsa = *(mbedtls_rsa_context*)ctx_pk.pk_ctx;      

    input[0] = 'H';
    input[1] = 'E';
    input[2] = 'L';
    input[3] = 'L';
    input[4] = 'O';
    input[5] = ',';
    input[6] = 'W';
    input[7] = 'O';
    input[8] = 'R';
    input[9] = 'L';
    input[10] = 'D';
    input[11] = '!';
    input[12] = '\0';

    /*
     * Calculate the RSA encryption of the hash.
     */
    mbedtls_printf("\n  . Generating the RSA encrypted value");
    fflush(stdout);
    /*加密操作,利用公钥加密*/
    ret = mbedtls_rsa_pkcs1_encrypt(&rsa, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, 12, input, buf);
    if (ret != 0)
    {
        mbedtls_printf(" failed\n  ! mbedtls_rsa_pkcs1_encrypt returned %d\n\n", ret);
        goto exit;
    }

    /*
     * Write the signature into result-enc.txt
     */
    if ((f = fopen("result-enc.txt", "wb+")) == NULL)      //将加密文件写入到result-enc.txt
    {
        mbedtls_printf(" failed\n  ! Could not create %s\n\n", "result-enc.txt");
        goto exit;
    }

    for (i = 0; i < rsa.len; i++)
    {
        mbedtls_fprintf(f, "%02X%s", buf[i], (i + 1) % 16 == 0 ? "\r\n" : " ");
    }
    fclose(f);

    mbedtls_printf("\n  . Done (created \"%s\")\n\n", "result-enc.txt");  

exit:
    /*释放资源*/
    mbedtls_mpi_free(&N);
    mbedtls_mpi_free(&E);
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);
    mbedtls_rsa_free(&rsa);
    return 0;
}

int rsa_decrypt()
{
    FILE* f = NULL;
    long size;
    size_t n;
    unsigned char* privatekey = NULL;
    mbedtls_pk_context ctx_pk;
    /*******************************/
    int ret = 1;
    int c;
    size_t i;
    mbedtls_rsa_context rsa;
    mbedtls_mpi N, P, Q, D, E, DP, DQ, QP;      //定义大数
    mbedtls_entropy_context entropy;
    mbedtls_ctr_drbg_context ctr_drbg;
    unsigned char result[1024];
    unsigned char buf[512];
    const char* pers = "rsa_decrypt";
    memset(result, 0, sizeof(result));
    /*********************************/
    mbedtls_pk_init(&ctx_pk);
    
    if ((f = fopen("rsa4096_prv.pem", "rb")) == NULL)      //打开pem格式的公钥文件
    {
        mbedtls_printf("\n  . Open private key file failed!");
        return(-1);
    }

    fseek(f, 0, SEEK_END);

    if ((size = ftell(f)) == -1)
    {
        fclose(f);
        return(-1);
    }
    fseek(f, 0, SEEK_SET);

    n = (size_t)size;    //

    if (n + 1 == 0 || (privatekey = mbedtls_calloc(1, n + 1)) == NULL)
    {
        fclose(f);
        return(-1);
    }

    if (fread(privatekey, 1, n, f) != n)
    {
        fclose(f);
        free(privatekey);
        privatekey = NULL;
        return(-1);
    }
    fclose(f);

    /*从pem文件里获得私钥*/
    if (0 != mbedtls_pk_parse_key(&ctx_pk, privatekey, n + 1, NULL, 0))
    {
        mbedtls_printf("\n  . Can't import private key");
    }
    else
    {
        mbedtls_printf("\n  . Import private key successfully");
    }

    free(privatekey);
    privatekey = NULL;

    mbedtls_printf("\n  . Seeding the random number generator...");
    fflush(stdout);

    mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
    mbedtls_ctr_drbg_init(&ctr_drbg);
    mbedtls_entropy_init(&entropy);
    mbedtls_mpi_init(&N);
    mbedtls_mpi_init(&P);
    mbedtls_mpi_init(&Q);
    mbedtls_mpi_init(&D);
    mbedtls_mpi_init(&E);
    mbedtls_mpi_init(&DP);
    mbedtls_mpi_init(&DQ);
    mbedtls_mpi_init(&QP);

    ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
        &entropy, (const unsigned char*)pers,
        strlen(pers));
    if (ret != 0)
    {
        mbedtls_printf(" failed\n  ! mbedtls_ctr_drbg_seed returned %d\n",
            ret);
        goto exit;
    }

    /*导入pem内的私钥*/
    rsa = *(mbedtls_rsa_context*)ctx_pk.pk_ctx;

    if ((ret = mbedtls_rsa_complete(&rsa)) != 0)
    {
        mbedtls_printf(" failed\n  ! mbedtls_rsa_complete returned %d\n\n", ret);
        goto exit;
    }

    /*
     * Extract the RSA encrypted value from the text file
     */
    if ((f = fopen("result-enc.txt", "rb")) == NULL)
    {
        mbedtls_printf("\n  ! Could not open %s\n\n", "result-enc.txt");
        goto exit;
    }

    i = 0;

    while (fscanf(f, "%02X", &c) > 0 && i < (int)sizeof(buf))
        buf[i++] = (unsigned char)c;

    fclose(f);

    if (i != rsa.len)
    {
        mbedtls_printf("\n  ! Invalid RSA signature format\n\n");
        goto exit;
    }

    /*
     * Decrypt the encrypted RSA data and print the result.
     */
    mbedtls_printf("\n  . Decrypting the encrypted data");
    fflush(stdout);

    ret = mbedtls_rsa_pkcs1_decrypt(&rsa, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PRIVATE, &i, buf, result, 1024);
    if (ret != 0)
    {
        mbedtls_printf(" failed\n  ! mbedtls_rsa_pkcs1_decrypt returned %d\n\n", ret);      
        goto exit;
    }

    mbedtls_printf("\n  . OK\n\n");

    mbedtls_printf("The decrypted result is: '%s'\n\n", result);

exit:
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);
    mbedtls_rsa_free(&rsa);
    mbedtls_mpi_free(&N);
    mbedtls_mpi_free(&P);
    mbedtls_mpi_free(&Q);
    mbedtls_mpi_free(&D); 
    mbedtls_mpi_free(&E);
    mbedtls_mpi_free(&DP);
    mbedtls_mpi_free(&DQ);
    mbedtls_mpi_free(&QP);

    return 0;


}
int main()
{
    int exit_code = 0;
    rsa_encrypt();     //加密
    rsa_decrypt();     //解密

#if defined(_WIN32)
    mbedtls_printf("  + Press Enter to exit this program.\n");
    fflush(stdout); 
    getchar();
#endif

    return(exit_code);
}

mbedtls库:https://github.com/ARMmbed/mbedtls

开发环境:visual studio 2019

ps:我使用的公钥和私钥的在tests/data_files内,也可以使用自己生成的

2021.02.03补充宏定义

/* System support */
#define MBEDTLS_PLATFORM_C                       //启用平台抽象接口,重新定义printf,sprintf 和malloc,free
#define MBEDTLS_PLATFORM_MEMORY                  //启用内存分配接口,需要自己实现malloc,free
//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C          //启用mbedtls自带的内存分配接口,适用于没有动态内存分配的平台
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS        //不使用标准的库函数,如malloc,free
//#define MBEDTLS_PLATFORM_EXIT_ALT              //允许使用平台exit接口
#define MBEDTLS_NO_PLATFORM_ENTROPY              //不使用内置熵源,需要自己实现熵 ,不定义该宏,使用内置熵,只有window和linux才可以注释掉,其他平台不支持内置熵
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES       //取消默认熵,不定义该宏,就会使用默认熵
#define MBEDTLS_PLATFORM_PRINTF_ALT              //使能printf替换
#define MBEDTLS_PLATFORM_SNPRINTF_ALT            //使能sprintf替换


#define MBEDTLS_AES_C        //AES
#define MBEDTLS_SHA256_C     //SHA256
#define MBEDTLS_ENTROPY_C    //使能熵源
#define MBEDTLS_CTR_DRBG_C   //随机数模块
#define MBEDTLS_BIGNUM_C     //大数模块
//#define MBEDTLS_GENPRIME     //使能素数生成,如果生成RSA的公钥和私钥需要定义此宏
#define MBEDTLS_MD_C         //使能MD通用接口,计算消息摘要
#define MBEDTLS_OID_C        //必须定义  
#define MBEDTLS_RSA_C        //RSA
#define MBEDTLS_PKCS1_V15    //RSA填充方案
//#define MBEDTLS_RSA_NO_CRT    //是否通过中国剩余定理加速
#define MBEDTLS_AES_ROM_TABLES    //预定义s盒,可节约部分内存空间

#define MBEDTLS_ERROR_C        //错误代码解析
#define MBEDTLS_BASE64_C       //使能Base64编码
//#define MBEDTLS_SHA256_SMALLER
#define MBEDTLS_FS_IO        //txt格式的秘钥文件
/*pem格式秘钥需要定义的宏*/
#define MBEDTLS_PK_PARSE_C   
#define MBEDTLS_PK_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_PEM_PARSE_C

 

  • 5
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值