一、 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中开启的一致文章来源:https://www.toymoban.com/news/detail-834213.html
//加密方式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 运行效果
文章来源地址https://www.toymoban.com/news/detail-834213.html
到了这里,关于mbedtls移植之RSA加解密算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!