mbedtls移植之RSA签名验签算法(数字签名) 您所在的位置:网站首页 rsa密钥对验证 mbedtls移植之RSA签名验签算法(数字签名)

mbedtls移植之RSA签名验签算法(数字签名)

2024-07-10 20:26| 来源: 网络整理| 查看: 265

一、 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.非对称算法性能远低于对称算法

三、签名验签简介

签名验签机制被称为数字签名,通过该机制可实现完整性(Integrity)、认证性(Authenticity)、不和否认性(Non-Repudiation)的保护。通过使用私钥对原始数据进行签名,并同步将签名信息传递给接收者。接受者收到后,使用对应的公钥对签名进行验签,以确认接收到的原始数据是否有效。 原则为:私钥签名,公钥验签 详细请见RFC3447 总体流程如下图: 在这里插入图片描述

四、实现

demo代码:https://download.csdn.net/download/anjiyufei/88863376

4.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_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 4.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" 4.3 填充方式

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

4.3.1 PKCS#V2.1说明

在使用PK库时,mbedtls已提示默认使用PKCS#V1.5,无接口去调用PKCS#V2.1的填充方式 在这里插入图片描述

但实际测试发现,可通过mbedtls_rsa_set_padding(private_rsa_context,MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256)去实现PKCS#V2.1的填充 当添加如上代码后,跟踪到mbedtls_rsa_pkcs1_sign函数,可发现ctx的padding为1 在这里插入图片描述 在这里插入图片描述

4.4 公私钥和熵源

详见之前博客《mbedtls移植之RSA加解密算法》的3.4章节,此处不额外说明

4.5 读取密钥

从文件中读取pem格式的公私钥

//获取公钥 int get_public_key_from_file( mbedtls_pk_context *public_pk_context,const char *public_pem_file){ char error[100]; int result = mbedtls_pk_parse_public_keyfile(public_pk_context,public_pem_file); if(result != 0){ printf("failed to parse public key from file:"); mbedtls_strerror(result,error,sizeof(error)); printf("%s\n",error); return -1; }else{ printf("succeeded to parse public key from file!\n"); } return 0; } //获取私钥 int get_private_key_from_file(mbedtls_pk_context *private_pk_context,const char *private_pem_file){ char error[100]; int result = mbedtls_pk_parse_keyfile(private_pk_context,private_pem_file,NULL); if(result != 0){ printf("failed to parse private key from file:"); mbedtls_strerror(result,error,sizeof(error)); printf("%s\n",error); return -1; }else{ printf("succeeded to parse private key from file!\n"); } return 0; } 4.6 计算HASH

在对文件进行签名时,需先计算文件的HASH,再使用RSA私钥进行签名。使用SHA256计算HASH过程如下:

int get_hash_from_file_by_sha256(const char *sign_file,unsigned char *hash){ FILE *input_file = fopen(sign_file,"rb"); unsigned char input_buffer[1024]; size_t read_num = 0; mbedtls_sha256_context sha256_context; mbedtls_sha256_init(&sha256_context); mbedtls_sha256_starts(&sha256_context,0); while(1){ read_num = fread(input_buffer,sizeof(char ),1024,input_file); if( read_num > 0){ if(read_num == 1024){ mbedtls_sha256_update(&sha256_context,input_buffer,read_num); }else{ //文件尾 mbedtls_sha256_update(&sha256_context,input_buffer,read_num); break; } }else{ printf("failed to read file\n"); mbedtls_sha256_free(&sha256_context); fclose(input_file); return -1; } } mbedtls_sha256_finish(&sha256_context,hash); /* printf("sha256 info:\n"); for(int i=0;i printf("failed to get drbg seed\n"); free_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context); return -1; } result = get_private_key_from_file(&private_pk_context,private_pem_file); if(result != 0){ printf("failed to get private key!\n"); return -2; } //对文件进行签名 //计算待加密文件HASH result = get_hash_from_file_by_sha256(sign_verify_file,hash_buffer); if(result != 0){ printf("failed to get hash from file\n"); } mbedtls_rsa_context *private_rsa_context = mbedtls_pk_rsa(private_pk_context); //因PK默认填充方式为V15,若需要使用V21填充方式,需添加如下代码。若使用V15,则无需添加。若使用V21填充方式,需同步在config.h中启用#define MBEDTLS_PKCS1_V21 //mbedtls_rsa_set_padding(private_rsa_context,MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256); result = mbedtls_rsa_pkcs1_sign(private_rsa_context,mbedtls_ctr_drbg_random,&ctr_drbg_context,MBEDTLS_RSA_PRIVATE,MBEDTLS_MD_SHA256,sizeof(hash_buffer),hash_buffer,signature_info); if(result != 0){ printf("failed to signature:"); mbedtls_strerror(result,error,sizeof(error)); printf("%s\n",error); return -3; }else{ printf("succeeded to signature!\n"); printf("signature info:\n"); for(int i=0;i printf("failed to write signature to file\n"); } fclose(sign_file); } //修改签名信息,查看验签是否失败 //memset(signature_info+255,0xFF,1); //验签 //从文件中读取公钥 result = get_public_key_from_file(&public_pk_context,public_pem_file); if(result != 0){ printf("failed to get public key!\n"); free_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context); return -4; } //计算待加密文件HASH result = get_hash_from_file_by_sha256(sign_verify_file,hash_buffer); if(result != 0){ printf("failed to get hash from file\n"); } mbedtls_rsa_context *public_rsa_context = mbedtls_pk_rsa(public_pk_context); //因PK默认填充方式为V15,若需要使用V21填充方式,需添加如下代码。若使用V15,则无需添加。若使用V21填充方式,需同步在config.h中启用#define MBEDTLS_PKCS1_V21 //mbedtls_rsa_set_padding(public_rsa_context,MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256); result = mbedtls_rsa_pkcs1_verify(public_rsa_context,mbedtls_ctr_drbg_random,&ctr_drbg_context,MBEDTLS_RSA_PUBLIC,MBEDTLS_MD_SHA256,sizeof(hash_buffer),hash_buffer,signature_info); if(result == 0){ printf("succeeded to verify signature!\n"); }else{ printf("failed to verify signature:"); mbedtls_strerror(result,error,sizeof(error)); printf("%s\n",error); free_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context); return -5; } free_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context); return 0; } 4.7.1.1 运行效果

1.正常运行效果 在这里插入图片描述

2.篡改签名信息后验证 代码中启用注释掉的代码memset(signature_info+255,0xFF,1); 最终提示验签失败 在这里插入图片描述

3.使用openssl验签 上述代码中,成功后的签名信息会保存到D:\tmp\crypto\rsa\mbedtls_sign-rsa.bin 使用openssl命令进行验签,也可以验签通过(openssl使用PKCS#V1.5填充进行验签。若使用PKCS#V2.1签名,因填充方式不一致,会导致验签失败) 在这里插入图片描述 在这里插入图片描述

4.7.2 调用PK库

1.读取私钥和公钥信息 2.对待签名文件使用SHA256算法得到文件的HASH值 3.签名:使用私钥对文件HASH值进行签名,得到签名值。签名使用函数mbedtls_pk_sign 4.验签:使用对应的公钥对签名值进行验证,得到验签结果。验签使用函数mbedtls_pk_verify

注意: 默认使用PKCS#V1.5填充算法,若需使用PKCS#V2.1填充算法,请参考代码中注释部分

int sign_verify_by_pk(){ //个性化初始值:用于初始化伪随机数生成器,可设置为任意值 const char *personalization = "Fr789jj-ikrkjfjs@"; mbedtls_pk_context public_pk_context; mbedtls_pk_context private_pk_context; const char *public_pem_file = "D:\\tmp\\crypto\\rsa\\public.pem"; const char *private_pem_file = "D:\\tmp\\crypto\\rsa\\private.pem"; const char *sign_verify_file = "D:\\tmp\\crypto\\rsa\\music.mp3"; char error[100]; unsigned char signature_info[256]; unsigned char hash_buffer[32]; 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_pk_init(&public_pk_context); mbedtls_pk_init(&private_pk_context); 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_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context); return -1; } //对文件进行签名 //从文件读取私钥 result = get_private_key_from_file(&private_pk_context,private_pem_file); if(result != 0){ printf("failed to get private key!\n"); free_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context); return -2; } //计算待加密文件HASH result = get_hash_from_file_by_sha256(sign_verify_file,hash_buffer); if(result != 0){ printf("failed to get hash from file\n"); } //因PK默认填充方式为V15,若需要使用V21填充方式,需添加如下代码。若使用V15,则无需添加。若使用V21填充方式,需同步在config.h中启用#define MBEDTLS_PKCS1_V21 //mbedtls_rsa_set_padding(mbedtls_pk_rsa(private_pk_context),MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256); size_t signature_length; result = mbedtls_pk_sign(&private_pk_context,MBEDTLS_MD_SHA256,hash_buffer,sizeof(hash_buffer),signature_info,&signature_length,mbedtls_ctr_drbg_random,&ctr_drbg_context); if(result != 0){ printf("failed to signature:"); mbedtls_strerror(result,error,sizeof(error)); printf("%s\n",error); free_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context); return -3; }else{ printf("succeeded to signature!\n"); printf("signature info:\n"); for(int i=0;i printf("failed to write signature to file\n"); } fclose(sign_file); } //修改签名信息,查看验签是否失败 //memset(signature_info+255,0xFF,1); //验签 //从文件中读取公钥 result = get_public_key_from_file(&public_pk_context,public_pem_file); if(result != 0){ printf("failed to get public key!\n"); free_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context); return -4; } //计算待加密文件HASH result = get_hash_from_file_by_sha256(sign_verify_file,hash_buffer); if(result != 0){ printf("failed to get hash from file\n"); } //因PK默认填充方式为V15,若需要使用V21填充方式,需添加如下代码。若使用V15,则无需添加。若使用V21填充方式,需同步在config.h中启用#define MBEDTLS_PKCS1_V21 //mbedtls_rsa_set_padding(mbedtls_pk_rsa(private_pk_context),MBEDTLS_RSA_PKCS_V21,MBEDTLS_MD_SHA256); //最后一个参数为签名长度,RSA-2048为256Bytes(先HASH在签名) result = mbedtls_pk_verify(&public_pk_context,MBEDTLS_MD_SHA256,hash_buffer,sizeof(hash_buffer),signature_info,256); if(result == 0){ printf("succeeded to verify signature!\n"); }else{ printf("failed to verify signature:"); mbedtls_strerror(result,error,sizeof(error)); printf("%s\n",error); free_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context); return -5; } free_context(&public_pk_context,&private_pk_context,&entropy_context,&ctr_drbg_context); return 0; } 4.7.2.1 运行效果

1.正常运行效果 在这里插入图片描述

2.篡改签名信息后验证 代码中启用注释掉的代码memset(signature_info+255,0xFF,1); 最终提示验签失败 在这里插入图片描述

3.使用openssl验签 上述代码中,成功后的签名信息会保存到D:\tmp\crypto\rsa\mbedtls_sign-pk.bin 使用openssl命令进行验签,也可以验签通过(openssl使用PKCS#V1.5填充进行验签。若使用PKCS#V2.1签名,因填充方式不一致,会导致验签失败) 在这里插入图片描述 在这里插入图片描述



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有