一、 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#include #include #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;iprintf("%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 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 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 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
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
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
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
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 运行效果