ESP-C3入门19. RSA算法加密、解密的实现

news2024/11/24 22:28:50

ESP-C3入门19. RSA算法加密、解密的实现

  • 一、概述
  • 二、重要函数
    • 1. mbedtls_pk_parse_public_key和mbedtls_pk_parse_key
      • 函数原型:
      • 函数参数:
    • 2. mbedtls_pk_encrypt
      • 函数原型:
      • 函数参数:
      • 函数功能:
  • 三、实现过程
    • 1. CMakeLists.txt 引用Mbed TLS
    • 2. rsa_utils.h 头文件定义
    • 3. rsa_utils.c 函数体
    • 4. 使用demo
  • 三、注意要点

在这里插入图片描述

一、概述

官方文档地址:
https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/migration-guides/release-5.x/5.0/protocols.html?highlight=mbed

ESP-IDFv5里集成了 Mbed TLSv3.1.0版本。

实现RSA加密与解密主要是以下步骤:

  1. 生成RSA密钥对:RSA加密算法需要一个公钥和一个私钥。在ESP-IDF提供的加密库中有生成RSA密钥对的函数。本文重点放在加密、解密,生成RSA密钥对的过程本文不作介绍。

  2. 加密数据:要加密数据,需要使用公钥对数据进行加密。我们使用mbedtls_rsa_pkcs1_encrypt()函数来实现RSA加密。这个函数接受明文数据、公钥和输出缓冲区作为参数,并将加密后的数据存储在输出缓冲区中。

  3. 解密数据:要解密数据,需要使用私钥对加密数据进行解密。我们使用mbedtls_rsa_pkcs1_decrypt()函数来实现RSA解密。这个函数接受加密的数据、私钥和输出缓冲区作为参数,并将解密后的数据存储在输出缓冲区中。

在实现这些步骤之前,需要在ESP-IDF项目中包含相关的头文件和库,并根据项目的需要进行配置。

二、重要函数

1. mbedtls_pk_parse_public_key和mbedtls_pk_parse_key

以 mbedtls_pk_parse_public_key为例:

函数原型:

int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen);

该函数用于解析给定的公钥数据,将其加载到mbedtls_pk_context结构体中。

函数参数:

  • ctx:指向要填充的mbedtls_pk_context结构体的指针。
  • key:指向包含公钥数据的缓冲区的指针。
  • keylen:公钥数据的长度。

该函数将从key缓冲区中解析并填充mbedtls_pk_context结构体,以便后续可以使用该结构体进行公钥相关操作,如加密或验证。

2. mbedtls_pk_encrypt

函数原型:

int mbedtls_pk_encrypt(mbedtls_pk_context *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, size_t osize, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);

函数参数:

  • ctx:指向包含公钥的mbedtls_pk_context结构体的指针。
  • input:指向要加密的输入数据的缓冲区的指针。
  • ilen:要加密的输入数据的长度。
  • output:指向用于存储加密结果的输出缓冲区的指针。
  • olen:指向size_t类型的变量的指针,用于输入输出缓冲区的长度。加密后,olen将包含实际加密数据的长度。
  • osize:输出缓冲区的大小。如果输出缓冲区不足以容纳加密结果,将返回MBEDTLS_ERR_RSA_BUFFER_TOO_SMALL错误。
  • f_rng:指向随机数生成函数的指针,用于生成加密过程中所需的随机数。可以使用默认的mbedtls_ctr_drbg_random作为参数。
  • p_rng:指向随机数生成函数上下文的指针。可以使用默认的mbedtls_ctr_drbg_context上下文作为参数。

函数功能:

  • mbedtls_pk_encrypt()函数使用指定的公钥对输入数据进行加密,并将加密结果存储在输出缓冲区中。
  • 在加密过程中,函数使用给定的随机数生成函数生成必要的随机数。
  • 函数返回值为0表示加密成功,非零值表示加密过程中发生错误。
  • 使用mbedtls_pk_encrypt()函数时,需要确保已经成功解析了有效的公钥并填充了mbedtls_pk_context结构体。

三、实现过程

1. CMakeLists.txt 引用Mbed TLS

# 递归查找所有c文件
file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
idf_component_register(SRCS ${SOURCES}
                       INCLUDE_DIRS "." 
        REQUIRES   "nvs_flash" "esp_http_client" "esp-tls" "json" "driver" "esp_event" "esp_wifi"
           
)

重点是其中的esp-tls

2. rsa_utils.h 头文件定义

//
// 
//

#ifndef WIFI_ESP32_RSA_UTILS_H
#define WIFI_ESP32_RSA_UTILS_H




/**
 * @brief RSA公钥加密
 *
 * @param public_key_pem 公钥PEM字符串
 * @param plaintext 待加密的数据
 * @param plaintext_len 待加密数据的长度
 * @param ciphertext 加密后的数据缓冲区
 * @param ciphertext_len 加密后的数据长度缓冲区
 * @return int 加密结果长度,失败返回负数
 */
int rsa_public_encrypt(const unsigned char* public_key_pem, const unsigned char* plaintext,
                       size_t plaintext_len, unsigned char* ciphertext, size_t* ciphertext_len);

/**
 * @brief RSA私钥解密
 *
 * @param private_key_pem 私钥PEM字符串
 * @param ciphertext 待解密的数据
 * @param ciphertext_len 待解密数据的长度
 * @param plaintext 解密后的数据缓冲区
 * @param plaintext_len 解密后的数据长度缓冲区
 * @return int 解密结果长度,失败返回负数
 */
int rsa_private_decrypt(const unsigned char* private_key_pem, const unsigned char* ciphertext,
                        size_t ciphertext_len, unsigned char* plaintext, size_t* plaintext_len);


#endif //WIFI_ESP32_RSA_UTILS_H

3. rsa_utils.c 函数体

//
// Created by Xundh on 2023/6/19.
//
#include <mbedtls/pk.h>
#include <mbedtls/ctr_drbg.h>
#include <string.h>
#include <esp_log.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include "include/rsa_utils.h"

const char *TAG = "[rsa_utils]";

int rsa_public_encrypt(const unsigned char *public_key_pem, const unsigned char *plaintext,
                       size_t plaintext_len, unsigned char *ciphertext, size_t *ciphertext_len) {

    int ret;

    mbedtls_ctr_drbg_context ctr_drbg;
    mbedtls_entropy_context entropy;

    mbedtls_ctr_drbg_init(&ctr_drbg);
    mbedtls_entropy_init(&entropy);

    if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0) != 0) {
        // Handle error
        ESP_LOGI(TAG, "random init error");
        ret = -1;
    } else {
        mbedtls_pk_context pk;
        mbedtls_pk_init(&pk);
        size_t keylen = strlen((const char *) public_key_pem);
        // 解析公钥
        ret = mbedtls_pk_parse_public_key(&pk, public_key_pem, keylen + 1);
        if (ret != 0) {
            ESP_LOGI(TAG, "pass public key error");
        } else {
            ESP_LOGI(TAG, "pass public key success");

            // 执行RSA加密
            ret = mbedtls_pk_encrypt(&pk, plaintext, plaintext_len, ciphertext, ciphertext_len,
                                     1024, mbedtls_ctr_drbg_random, &ctr_drbg);
            if (ret != 0) {
                char error_buf[100];
                mbedtls_strerror(ret, error_buf, sizeof(error_buf));
                ESP_LOGI(TAG, "rsa public encrypt error:%s", error_buf);
            }
        }
        mbedtls_pk_free(&pk);
    }
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);
    return ret;
}

int rsa_private_decrypt(const unsigned char *private_key_pem, const unsigned char *ciphertext,
                        size_t ciphertext_len, unsigned char *plaintext, size_t *plaintext_len) {
    int ret;

    mbedtls_ctr_drbg_context ctr_drbg;
    mbedtls_entropy_context entropy;

    mbedtls_ctr_drbg_init(&ctr_drbg);
    mbedtls_entropy_init(&entropy);

    if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0) != 0) {
        // Handle error
        ESP_LOGI(TAG, "random init error");
        ret = -1;
    } else {
        mbedtls_pk_context pk;
        mbedtls_pk_init(&pk);
        size_t keylen = strlen((char *) private_key_pem);
        // 解析私钥
        ret = mbedtls_pk_parse_key(&pk, private_key_pem, keylen+1, NULL, 0, NULL, NULL);

        if (ret != 0) {
            ESP_LOGI(TAG, "pass private key error");
        } else {
            ESP_LOGI(TAG, "pass private key success");
            // 执行RSA解密
            ret = mbedtls_pk_decrypt(&pk, ciphertext, ciphertext_len, plaintext, plaintext_len,
                                     512, mbedtls_ctr_drbg_random, &ctr_drbg);
            if (ret != 0) {
                char error_buf[100];
                mbedtls_strerror(ret, error_buf, sizeof(error_buf));
                ESP_LOGI(TAG, "rsa public decrypt error:%s", error_buf);
            }else{
                ESP_LOG_BUFFER_HEXDUMP(TAG, plaintext, *plaintext_len,ESP_LOG_INFO);
            }
        }
        mbedtls_pk_free(&pk);
    }
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);
    return ret;
}

4. 使用demo



static const char *TAG = "[main]";


void app_main() {
    // 公钥加密,私钥解密
    const unsigned char *public_key_pem = (const unsigned char *) "-----BEGIN PUBLIC KEY-----\n"
                                                                  "放置一个公钥"
                                                                  "-----END PUBLIC KEY-----\n";

    const unsigned char *private_key_pem = (const unsigned char *) "-----BEGIN PRIVATE KEY-----\n"
                                                                   "放置一个私钥"
                                                                   "-----END PRIVATE KEY-----\n";

    int ret;
    mbedtls_platform_setup(NULL);
    // 加密和解密的数据
    const unsigned char *plaintext = (const unsigned char *) "Hello, RSA!";
    size_t plaintext_len = strlen((const char *) plaintext);

    unsigned char encrypted[256];
    size_t encrypted_len = 0;

    ret = rsa_public_encrypt(public_key_pem, plaintext, plaintext_len, encrypted, &encrypted_len);

    if (ret != 0) {
        ESP_LOGI(TAG, "mbedtls_pk_encrypt error ");
    } else {
        ESP_LOG_BUFFER_HEXDUMP(TAG, encrypted, encrypted_len, ESP_LOG_INFO);
    }

    unsigned char decrypted[256];
    size_t decrypted_len = 256;
//     // 使用私钥解密
     ret = rsa_private_decrypt(private_key_pem, encrypted, encrypted_len, decrypted, &decrypted_len);
     if (ret < 0) {
         ESP_LOGI(TAG, "Failed to decrypt data.");
     }
    // 清理Mbed TLS库
    mbedtls_platform_teardown(NULL);
}

三、注意要点

由于单片机的栈比较小,在使用rsa时,定义的数组大小不要太大,否则容易造成栈溢出。
运行示例:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/667153.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

@Param注解的用法

1、使用Param注解的原因 在 Mapper接口中&#xff0c;当方法的参数为多个字面量类型&#xff0c;此时mybatis会将这些参数存储在一个Map集合中&#xff0c;以两种方式进行存储 1、以arg0.arg1…为键&#xff0c;以参数为值2、以param1&#xff0c;param2…为键&#xff0c;以…

解读Linux常用命令使用方法

文章目录 1.前言1.1 定义1.2 特点 2.常用命令介绍2.1 ls2.2 pwd2.3 cd2.4 touch2.5 cat2.6 mkdir2.7 rm2.8 cp2.9 mv2.10 man&#xff08;联机手册&#xff09;2.11 vim2.12 grep2.13 ps2.14 netstat 1.前言 1.1 定义 Linux是一套免费使用和自由传播的类Unix操作系统&#xf…

【百套源码】HTML5期末大作业 - 各类网页作业源码合集

文章目录 持续更新文章记录1️⃣ 个人介绍类相关源码1.1 html实现个人简历1.2 科技风个人简历1.3 网站风个人简历1.4 多种风格个人主页模板1.5 html好看的个人简历明星版1.6 专属个人主页-系列11.7 专属个人主页-系列21.8 专属个人主页-系列31.9 专属个人主页-系列41.10 专属个…

uniapp和springboot微信小程序开发实战:前端架构之微信小程序主页实现

文章目录 主页效果前端代码后端实现主页效果 前端代码 具体代码实现如下: <template><view><!--首页轮播图--><view class="uni-banner-wrap"><swiper class="swiper" circular :indicator-dots="indicatorDots" …

数字信号处理11:变换

之前好长一段时间都在写软著、写一些结课作业&#xff0c;就断断续续的在学&#xff0c;很少有时间把东西串起来&#xff0c;前些博文主要就是讲的说&#xff0c;做这个Z变换&#xff0c;今天就主要来看看其他的变换&#xff0c;当然&#xff0c;最重要的还是傅里叶变换&#x…

有哪些优秀好用的网站SEO文章采集软件?

有哪些优秀好用的网站SEO文章采集软件?Ai智能采集文章操作教程及txt转Word教程#资源变现 #资源采集 我为什么会死磕seo并利用采集站seo赚到了第一个100W&#xff1f; 两个原因&#xff1a; 第一就是seo就是目前网络上免费的获取精准用户最牛逼&#xff0c;最有效的引流吸粉手…

linux下express+puppeteer安装部署并用PM2守护进程

背景 承上篇 puppeteer-不需重构&#xff0c;无痛加强vue单页面应用的SEO&#xff0c;提升百度收录排名,是在本地nginx部署前端&#xff0c;本地另起express服务进行测试&#xff0c;下面我们来讲讲如何部署express到linux服务器&#xff0c;并用PM2守护进程。 node 16.14.1 p…

java 学习交流社区平台系统Myeclipse开发mysql数据库web结构jsp编程计算机servlet网页项目

一、源码特点 JSP 学习交流社区平台系统 是一套完善的系统源码&#xff0c;对理解JSP java serlvet dao bean MVC编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;以及相应配套的设计文档&#xff0c;系统主要采用B/S模式开发。 研究的基本内…

wsl中docker自启动

前言 wsl -l -v # 查看 wsl 的状态 wsl -t Ubuntu # 关闭指定版本 wsl -d Ubuntu # 启动指定版本 启动 docker 通过命令 ps -p 1 -o comm 我们知道我们用的是 init&#xff0c;故我们将 systemd 命令修改为 SysV init命令。 ps -p 1 -o comm 更换命令&#xff0c;用SysV in…

NLP作业02:课程设计报告

作业头 这个作业属于哪个课程自然语言处理这个作业要求在哪里NLP作业02&#xff1a;课程设计报告我在这个课程的目标实现基于Seq2Seq注意力机制的聊天机器人这个作业在哪个具体方面帮助我实现目标问题的提出&#xff0c;资料的查找参考文献1.简说Seq2Seq原理以及实现 2.序列到…

Android加载大图策略,防止OOM

前言 Android中图片以位图&#xff08;Bitmap&#xff09;的形式存在&#xff0c;位图常见的格式有.png、.jgp、.bmp、.gif。在加载图片的过程中常见的就是OOM&#xff08;Out of Memory&#xff09;内存溢出。 内存溢出是系统会给APP分配内存也就是Heap Size值。当APP占用的内…

含多类型充电桩的电动汽车充电站优化配置方法(matlab代码)

目录 1 主要内容 目标函数 约束条件 程序亮点 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序复现博士文章《互动环境下分布式电源与电动汽车充电站的优化配置方法研究》第三章《含多类型充电桩的电动汽车充电站优化配置方法》&#xff0c;本章选择3种典型的电动汽…

乐鑫创客沙龙精彩回顾|激发创新、共享技术

近期&#xff0c;乐鑫科技在全国多个城市举办了 ESP Friends 创客沙龙活动&#xff0c;吸引了来自物联网各个领域的企业家、开发者、创客和学生的参与&#xff0c;包含智能硬件企业家、技术自媒体、教育从业者、博士生、高校学生等。他们与乐鑫资深应用工程师和技术专家面对面深…

冯诺依曼体系结构和操作系统的工作方式

目录 一. 冯诺依曼体系结构 1.1 什么是冯诺依曼体系结构 1.2 为什么冯诺依曼体系结构这样设计 1.3 冯诺依曼体系结构与现实问题的结合 二. 操作系统的工作方式 2.1 操作系统的功能 2.2 操作系统对下进行软硬件管理的方式 2.3 操作系统对上提供使用环境的方式 三. 总结…

泛微E-Office前台文件上传漏洞

0x01 阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&…

史上最全Hadoop面试题:尼恩大数据面试宝典专题1

说在前面&#xff1a; 《尼恩 大数据 面试宝典》 是 《尼恩Java面试宝典》 姊妹篇。 这里特别说明一下&#xff1a;《尼恩Java面试宝典》41个专题 PDF &#xff08;请在文末获取&#xff09;自发布以来&#xff0c; 已经收集了 好几千题&#xff0c; 足足4000多页&#xff0c…

android 如何分析应用的内存(八)——Android 7.0以后的malloc debug

android 如何分析应用的内存&#xff08;八&#xff09; 接上文&#xff0c;介绍六大板块中的第三个————malloc调试和libc回调 上一篇文章中&#xff0c;仅仅是在分配和释放的时候&#xff0c;拦截对应的操作。而不能进一步的去检查内存问题。比如&#xff1a;释放之后再…

卖家必看,要做好独立站,一定要知道的八件事!

如何打造并运营你的跨境独立站&#xff1f;如何吸引更多的流量并促使他们在你的网站下单&#xff1f;在你决定开设独立站之前&#xff0c;以下这些方面是你必须要考虑的&#xff0c;否则你的独立站可能会面临失败的风险。 一、定义目标受众 你是B2B业务还是B2C独立站&#xff…

小区物业电瓶车充电桩收费管理系统 支持扫码刷卡

电动车火灾事故频频发生&#xff0c;毫不起眼的电动车屡次引发夺命大火&#xff0c;电动车已然成为火灾“重灾区”。为预防和遏制电动自行车火灾事故发生&#xff0c;国家三令五申各种政策&#xff0c;为此公安部安委会曾出台《电动自行车集中停放和充电治理方案》。 大部分充电…

visionOS:理想的UI设计竟要考虑这么多细节

拥有对macOS、iPadOS、watchOS、iOS等系统的开发经验&#xff0c;苹果在XR操作系统设计上也具有先天优势&#xff0c;相比于其他公司从头开始构建XR系统界面&#xff0c;苹果可直接借鉴已经过验证的设计美学。 与此同时&#xff0c;WWDC 2023上公布的一系列开发者教程来看&…