mbedtls移植之RSA加解密算法

一、 mbedtls简介

MbedTLS是一个开源、可移植、易使用、可读性高的SSL库,实现了常所用的加解密算法、X.509证书操作以及TLS协议操作。MbedTLS各功能模块独立性高、耦合度低,可以通过配置宏定义进行功能裁剪,非常适合对空间和效率要求高的嵌入式系统。

二、RSA算法简介

1978年,由Ron Rivest、Adi Shamir和Reonard Adleman共同发表了公钥密码算法RSA,RSA目前是使用广泛的非对称加解密和签名验签算法。RSA密钥由公钥和私钥组成,基本特性如下:
1.公钥和私钥是成对出现的,一个公钥必然对应一个固定的私钥。同理,一个私钥也必然对应一个固定的公钥;
2.在加解密缓解,公钥用于加密,私钥用于解密;
3.在签名验签环节,私钥用于签名,公钥用于验签;
4.公钥通常是公开的,任何人都可以获取到,但私钥必须严格保密;
5.RSA按分组进行,若分组长度不足(例如1024bits或2048bits),则需要填充。填充方式分为PKCS#V1.5和PKCS#V2.1
6.非对称算法性能远低于对称算法

三、实现

3.1 移植MbedTLS代码

移植自mbedTLS 2.16版本
需移植的文件如下:
在这里插入图片描述
在这里插入图片描述

修改config.h文件

#ifndef MBEDTLS_CONFIG_H
#define MBEDTLS_CONFIG_H

#define MBEDTLS_ERROR_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_OID_C
#define MBEDTLS_RSA_C
#define MBEDTLS_AES_C
#define MBEDTLS_MD_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_GENPRIME
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_PK_C
#define MBEDTLS_SHA256_C

//写pem证书时需要
#define MBEDTLS_PK_WRITE_C
#define MBEDTLS_PEM_WRITE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BASE64_C

//读pem证书
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_BASE64_C
#define MBEDTLS_FS_IO

//填充方式,V15或V21两种模式必须二选一
#define MBEDTLS_PKCS1_V21
//#define MBEDTLS_PKCS1_V15

//不使用平台默认熵源,mbedtls在windows和linux下已实现熵源
#define MBEDTLS_NO_PLATFORM_ENTROPY
//#include "check_config.h"

#endif

3.2 引入头文件

引入相应的头文件

#include <stdio.h>
#include <time.h>
#include <string.h>
#include "../crypto/mbedtls/rsa.h"
#include "../crypto/mbedtls/ctr_drbg.h"
#include "../crypto/mbedtls/entropy.h"
#include "../crypto/mbedtls/entropy_poll.h"
#include "../crypto/mbedtls/sha256.h"
#include "../crypto/mbedtls/pk.h"
#include "../crypto/mbedtls/error.h"

3.3 填充方式

RSA加解密时存在两种填充方式:PKCS#V1.5、PKCS#V2.1,必须在config.h中指定填充方式。
mbedtls的RSA中默认使用PKCS#V1.5的填充方式,若在代码中使用PKCS#V2.1,代码中需额外设置,具体设置见后续代码备注。
两种填充方式的差异此处不展开介绍。

3.4 生成RSA公私钥对

3.4.1 添加熵源

假定无本地熵源的情况下,需添加熵源(mbedtls在windows和linux已支持默认熵源,但其他嵌入式平台无熵源,需手动添加)
示例使用当前时间作为熵源,实际应选择强度更高的熵源

//添加熵源
int get_clock_for_entropy( void *data,unsigned char *output, size_t len, size_t *olen ) {
    time_t now_time;
    time(&now_time);
    unsigned long timer = now_time;
    ((void) data);
    *olen = 0;

    if (len < sizeof(unsigned long))
        return (0);

    memcpy(output, &timer, sizeof(unsigned long));
    *olen = sizeof(unsigned long);
    return 0;
}

3.4.2 生成RSA密钥对

生成密钥对,可选择生成多少位的密钥,例如1024或者2048,通常推荐生成2048的密钥

int generate_keypair(){

    //个性化初始值:用于初始化伪随机数生成器,可设置为任意值
    const char *personalization = "Fr789jj-ikrkjfjs@";
    char error[100];

    mbedtls_rsa_context  rsa_context;
    mbedtls_entropy_context entropy_context;
    mbedtls_ctr_drbg_context ctr_drbg_context;

    mbedtls_entropy_init(&entropy_context);
    mbedtls_ctr_drbg_init(&ctr_drbg_context);
    //使用V15填充时,hash_id不是必选
    mbedtls_rsa_init(&rsa_context,MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256);

    //添加熵源,若在嵌入式平台,需添加熵源
    mbedtls_entropy_add_source(&entropy_context,get_clock_for_entropy,NULL,MBEDTLS_ENTROPY_MIN_PLATFORM,MBEDTLS_ENTROPY_SOURCE_STRONG);
    int result = mbedtls_ctr_drbg_seed(&ctr_drbg_context, mbedtls_entropy_func, &entropy_context, personalization,strlen(personalization));
    if(result !=0 ){
        printf("failed to set ctr_drbg seed\n");
        mbedtls_rsa_free(&rsa_context);
        mbedtls_entropy_free(&entropy_context);
        mbedtls_ctr_drbg_free(&ctr_drbg_context);
        return -1;
    }
    //生成RSA密钥,若要修改密钥长度,则修改nbits参数
    result = mbedtls_rsa_gen_key(&rsa_context,mbedtls_ctr_drbg_random,&ctr_drbg_context,2048,65537);
    if(result == 0){
        printf("succeeded to generate RSA key pair\n");
    }else{
        printf("failed to generate RSA key pair\n");
        mbedtls_strerror(result,error,sizeof(error));
        printf("%s\n",error);
        mbedtls_rsa_free(&rsa_context);
        mbedtls_entropy_free(&entropy_context);
        mbedtls_ctr_drbg_free(&ctr_drbg_context);
        return -2;
    }
    get_key_from_rsa_context(&rsa_context);

    mbedtls_rsa_free(&rsa_context);
    mbedtls_entropy_free(&entropy_context);
    mbedtls_ctr_drbg_free(&ctr_drbg_context);

    return 0;
}

3.4.3 获取PEM格式证书

若需要将证书保存到文件,需额外添加写文件操作即可。

int get_key_from_rsa_context(mbedtls_rsa_context *rsa_context){
    mbedtls_pk_context pk_context;
    unsigned char public_key_pem[2048];
    unsigned char private_key_pem[2048];

    mbedtls_pk_init(&pk_context);
    //设置PK上下文的类型为RSA
    mbedtls_pk_setup(&pk_context,mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
    //获取PK context的RSA字段并设置rsa context
    mbedtls_rsa_copy(mbedtls_pk_rsa(pk_context),rsa_context);

    //获取公钥
    int result = mbedtls_pk_write_pubkey_pem(&pk_context,public_key_pem,sizeof(public_key_pem));
    if( result == 0){
        printf("%s\n", public_key_pem);
    }else{
        printf("failed to get public key\n");
        mbedtls_pk_free(&pk_context);
        return -1;
    }

    //获取私钥
    result = mbedtls_pk_write_key_pem(&pk_context,private_key_pem,sizeof(private_key_pem));
    if( result == 0){
        printf("%s\n", private_key_pem);
    }else{
        printf("failed to get private key\n");
        mbedtls_pk_free(&pk_context);
        return -2;
    }

    mbedtls_pk_free(&pk_context);
    return 0;
}

3.4.4 运行效果

在这里插入图片描述

3.5 RSA加解密

int encrypt_and_decrypt_data(){
    //个性化初始值:用于初始化伪随机数生成器,可设置为任意值
    const char *personalization = "Fr789jj-ikrkjfjs@";
    mbedtls_pk_context public_pk_context;
    mbedtls_pk_context private_pk_context;
    unsigned char public_key_buffer[2048];
    unsigned char private_key_buffer[2048];
    const char *public_pem_file = "D:\\tmp\\crypto\\rsa\\public.pem";
    const char *private_pem_file = "D:\\tmp\\crypto\\rsa\\private.pem";
    const unsigned char *plain = "hello world";
    unsigned char encrypt_text[256];
    unsigned char decrypt_text[256];
    unsigned char pk_encrypt_text[256];
    unsigned char pk_decrypt_text[256];
    char error[100];

    //mbedtls_rsa_context  rsa_context;
    mbedtls_entropy_context entropy_context;
    mbedtls_ctr_drbg_context ctr_drbg_context;

    mbedtls_entropy_init(&entropy_context);
    mbedtls_ctr_drbg_init(&ctr_drbg_context);
    //mbedtls_rsa_init(&rsa_context,MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256);
    mbedtls_pk_init(&public_pk_context);
    mbedtls_pk_init(&private_pk_context);
    //mbedtls_pk_setup(&pk_context,mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));

    mbedtls_entropy_add_source(&entropy_context,get_clock_for_entropy,NULL,MBEDTLS_ENTROPY_MIN_PLATFORM,MBEDTLS_ENTROPY_SOURCE_STRONG);
    int result = mbedtls_ctr_drbg_seed(&ctr_drbg_context, mbedtls_entropy_func, &entropy_context, personalization,strlen(personalization));
    if(result){
        printf("failed to get drbg seed\n");
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -1;
    }

    //加密
    //获取公钥
    result = mbedtls_pk_parse_public_keyfile(&public_pk_context,public_pem_file);
    if(result != 0){
        printf("failed to parse public key from file!\n");
        mbedtls_strerror(result,error,sizeof(error));
        printf("%s\n",error);
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -2;
    }else{
        printf("succeeded to parse public key from file!\n");
    }

    //加密方式1:直接调用RSA加密函数
    mbedtls_rsa_context *public_rsa_context = mbedtls_pk_rsa(public_pk_context);
    //设置填充方式,默认为V15,若使用V21则必须显式设置
    mbedtls_rsa_set_padding(public_rsa_context,MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256);
    result = mbedtls_rsa_pkcs1_encrypt(public_rsa_context,mbedtls_ctr_drbg_random,&ctr_drbg_context,MBEDTLS_RSA_PUBLIC,strlen(plain),plain,encrypt_text);
    if(result == 0){
        //获取密文长度
        size_t encrypt_text_len = mbedtls_rsa_get_len(public_rsa_context);
        printf("succeeded to encrypt data by rsa\n");
        printf("encrypt data:\n");
        for(int i=0;i<encrypt_text_len;i++){
            printf("%02x",encrypt_text[i]);
        }
        printf("\n");
    }else{
        printf("failed to encrypt data by rsa!\n");
        mbedtls_strerror(result,error,sizeof(error));
        printf("%s\n",error);
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -3;
    }

    //加密方式2:调用PK中的加密函数(PK是对整个公钥加密算法做了个封装,PK里包含RSA和ECC)
    size_t pk_encrypt_len = 0;
    //因PK默认填充方式为V15,若需要使用V21填充方式,需添加如下代码。若使用V15,则无需添加
    mbedtls_rsa_set_padding(mbedtls_pk_rsa(public_pk_context),MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256);
    //end
    result = mbedtls_pk_encrypt(&public_pk_context,plain,strlen(plain),pk_encrypt_text,&pk_encrypt_len,sizeof(pk_encrypt_text),mbedtls_ctr_drbg_random,&ctr_drbg_context);
    if(result == 0){
        printf("succeeded to encrypt data by pk\n");
        //printf("encrypt len:%zu\n",pk_encrypt_len);
        printf("encrypt data:\n");
        for(int i=0;i<pk_encrypt_len;i++){
            printf("%02x",pk_encrypt_text[i]);
        }
        printf("\n");
    }else{
        printf("failed to encrypt data by pk!\n");
        mbedtls_strerror(result,error,sizeof(error));
        printf("%s\n",error);
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -3;
    }

    //解密
    //获取私钥
    result = mbedtls_pk_parse_keyfile(&private_pk_context,private_pem_file,NULL);
    if(result != 0){
        printf("failed to parse private key from file!\n");
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -4;
    }else{
        printf("succeeded to parse private key from file!\n");
    }


    //解密方式1:直接调用RSA解密函数
    mbedtls_rsa_context *private_rsa_context = mbedtls_pk_rsa(private_pk_context);
    //明文长度
    size_t decrypt_len = 0;
    //设置填充方式,默认为V15,故若使用V21则必须显式设置
    mbedtls_rsa_set_padding(private_rsa_context,MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256);
    result = mbedtls_rsa_pkcs1_decrypt(private_rsa_context,mbedtls_ctr_drbg_random,&ctr_drbg_context,MBEDTLS_RSA_PRIVATE,&decrypt_len,encrypt_text,decrypt_text,sizeof(decrypt_text));
    if(result == 0){
        //解密成功
        printf("succeeded to decrypt data by rsa\n");
        printf("after decryption data:\n");
        for(int i=0;i<decrypt_len;i++){
            printf("%c",decrypt_text[i]);
        }
        printf("\n");
    }else{
        printf("failed to decrypt data by rsa!\n");
        mbedtls_strerror(result,error,sizeof(error));
        printf("%s\n",error);
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -5;
    }

    //解密方式2:调用PK解密函数,mbedtls_pk_decrypt的ilen必须为当前密文的真实长度,不是密文buffer长度。
    size_t pk_decrypt_len = 0;
    //因PK默认填充方式为V15,若需要使用V21填充方式,需添加如下代码。若使用V15,则无需添加
    mbedtls_rsa_set_padding(mbedtls_pk_rsa(private_pk_context),MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256);
    //end
    result = mbedtls_pk_decrypt(&private_pk_context,pk_encrypt_text,sizeof(pk_encrypt_text),pk_decrypt_text,&pk_decrypt_len,sizeof(pk_decrypt_text),mbedtls_ctr_drbg_random,&ctr_drbg_context);
    if(result == 0){
        //解密成功
        printf("succeeded to decrypt data by pk\n");
        //printf("pk_decrypt_len:%zu\n",pk_decrypt_len);
        printf("after decryption data:\n");
        for(int i=0;i<pk_decrypt_len;i++){
            printf("%c",pk_decrypt_text[i]);
        }
        printf("\n");
    }else{
        printf("failed to decrypt data by pk!\n");
        mbedtls_strerror(result,error,sizeof(error));
        printf("%s\n",error);
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -5;
    }

    free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
    return 0;
}

void free_crypto_context(mbedtls_pk_context *public_pk_context,mbedtls_pk_context *private_pk_context,mbedtls_entropy_context *entropy_context,mbedtls_ctr_drbg_context *ctr_drbg_context){
    mbedtls_pk_free(private_pk_context);
    mbedtls_pk_free(public_pk_context);
    mbedtls_ctr_drbg_free(ctr_drbg_context);
    mbedtls_entropy_free(entropy_context);
}

总体实现代码如上,下面简单做下分析

3.5.1 读取密钥

读取密钥的函数如下:

  • mbedtls_pk_parse_public_keyfile从文件中读取PEM公钥
  • mbedtls_pk_parse_public_Key从buffer或数组中读取PEM公钥
  • mbedtls_pk_parse_keyfile从文件中读取PEM私钥
  • mbedtls_pk_parse_key从buffer或数组中读取PEM私钥

示例代码为从文件中读取

//获取公钥
    result = mbedtls_pk_parse_public_keyfile(&public_pk_context,public_pem_file);
    if(result != 0){
        printf("failed to parse public key from file!\n");
        mbedtls_strerror(result,error,sizeof(error));
        printf("%s\n",error);
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -2;
    }else{
        printf("succeeded to parse public key from file!\n");
    }
//获取私钥
    result = mbedtls_pk_parse_keyfile(&private_pk_context,private_pem_file,NULL);
    if(result != 0){
        printf("failed to parse private key from file!\n");
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -4;
    }else{
        printf("succeeded to parse private key from file!\n");
    }

3.5.2 加密

可通过两种方式进行加密:
1.直接调用RSA中的加密函数
2.调用PK中的加密函数(最终还是调用到RSA的加密函数)
mbedtls的PK库为整个公钥算法库,在RSA基础上进一步封装,并将ECC算法封装进去

备注:需注意填充方式为V15还是V21,此处填充方式需保持和config.h中开启的一致

//加密方式1:直接调用RSA加密函数
    mbedtls_rsa_context *public_rsa_context = mbedtls_pk_rsa(public_pk_context);
    //设置填充方式,默认为V15,若使用V21则必须显式设置
    mbedtls_rsa_set_padding(public_rsa_context,MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256);
    result = mbedtls_rsa_pkcs1_encrypt(public_rsa_context,mbedtls_ctr_drbg_random,&ctr_drbg_context,MBEDTLS_RSA_PUBLIC,strlen(plain),plain,encrypt_text);
    if(result == 0){
        //获取密文长度
        size_t encrypt_text_len = mbedtls_rsa_get_len(public_rsa_context);
        printf("succeeded to encrypt data by rsa\n");
        printf("encrypt data:\n");
        for(int i=0;i<encrypt_text_len;i++){
            printf("%02x",encrypt_text[i]);
        }
        printf("\n");
    }else{
        printf("failed to encrypt data by rsa!\n");
        mbedtls_strerror(result,error,sizeof(error));
        printf("%s\n",error);
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -3;
    }
//加密方式2:调用PK中的加密函数(PK是对整个公钥加密算法做了个封装,PK里包含RSA和ECC)
    size_t pk_encrypt_len = 0;
    //因PK默认填充方式为V15,若需要使用V21填充方式,需添加如下代码。若使用V15,则无需添加
    mbedtls_rsa_set_padding(mbedtls_pk_rsa(public_pk_context),MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256);
    //end
    result = mbedtls_pk_encrypt(&public_pk_context,plain,strlen(plain),pk_encrypt_text,&pk_encrypt_len,sizeof(pk_encrypt_text),mbedtls_ctr_drbg_random,&ctr_drbg_context);
    if(result == 0){
        printf("succeeded to encrypt data by pk\n");
        //printf("encrypt len:%zu\n",pk_encrypt_len);
        printf("encrypt data:\n");
        for(int i=0;i<pk_encrypt_len;i++){
            printf("%02x",pk_encrypt_text[i]);
        }
        printf("\n");
    }else{
        printf("failed to encrypt data by pk!\n");
        mbedtls_strerror(result,error,sizeof(error));
        printf("%s\n",error);
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -3;
    }

3.5.3 解密

解密同样有两种方式:
1.直接调用RSA中的解密函数
2.调用PK中的解密函数(最终仍然是调用到RSA中的解密函数)

备注:需注意填充方式为V15还是V21,此处填充方式需保持和config.h中开启的一致

//解密方式1:直接调用RSA解密函数
    mbedtls_rsa_context *private_rsa_context = mbedtls_pk_rsa(private_pk_context);
    //明文长度
    size_t decrypt_len = 0;
    //设置填充方式,默认为V15,故若使用V21则必须显式设置
    mbedtls_rsa_set_padding(private_rsa_context,MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256);
    result = mbedtls_rsa_pkcs1_decrypt(private_rsa_context,mbedtls_ctr_drbg_random,&ctr_drbg_context,MBEDTLS_RSA_PRIVATE,&decrypt_len,encrypt_text,decrypt_text,sizeof(decrypt_text));
    if(result == 0){
        //解密成功
        printf("succeeded to decrypt data by rsa\n");
        printf("after decryption data:\n");
        for(int i=0;i<decrypt_len;i++){
            printf("%c",decrypt_text[i]);
        }
        printf("\n");
    }else{
        printf("failed to decrypt data by rsa!\n");
        mbedtls_strerror(result,error,sizeof(error));
        printf("%s\n",error);
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -5;
    }
//解密方式2:调用PK解密函数,mbedtls_pk_decrypt的ilen必须为当前密文的真实长度,不是密文buffer长度。
    size_t pk_decrypt_len = 0;
    //因PK默认填充方式为V15,若需要使用V21填充方式,需添加如下代码。若使用V15,则无需添加
    mbedtls_rsa_set_padding(mbedtls_pk_rsa(private_pk_context),MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256);
    //end
    result = mbedtls_pk_decrypt(&private_pk_context,pk_encrypt_text,sizeof(pk_encrypt_text),pk_decrypt_text,&pk_decrypt_len,sizeof(pk_decrypt_text),mbedtls_ctr_drbg_random,&ctr_drbg_context);
    if(result == 0){
        //解密成功
        printf("succeeded to decrypt data by pk\n");
        //printf("pk_decrypt_len:%zu\n",pk_decrypt_len);
        printf("after decryption data:\n");
        for(int i=0;i<pk_decrypt_len;i++){
            printf("%c",pk_decrypt_text[i]);
        }
        printf("\n");
    }else{
        printf("failed to decrypt data by pk!\n");
        mbedtls_strerror(result,error,sizeof(error));
        printf("%s\n",error);
        free_crypto_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context);
        return -5;
    }

3.5.4 运行效果

在这里插入图片描述

  • 19
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值