物联网实战--驱动篇之(五)TEA和AES加密算法

目录

一、前言

二、TEA算法

三、AES算法

四、加解密测试

五、安全性保障


一、前言

        物联网的安全性是经常被提及的一个点,如果你的设备之间通讯没有加密的话,那么攻击者很容易就能获取并解析出报文的协议,从而根据攻击者的需要进行设备操控和敏感信息获取。举个例子,现在有很多的WiFi插座,连接WIFI后用户就能通过手机去控制插座开关,如果设计者对安全不重视,所有报文都是明文,那么攻击者只要设局让用户连在同一个局域网WiFi,获取一些身份信息,即可自己组合相关报文对插座进行控制了,是一件比较危险的事情。

        对于设备端,处理器性能有好有差的,所以对于加密算法要根据实际情况去选配,在这里,我们主要介绍TEA和AES两种加密算法,具体的算法原理属于加密学的内容,还是挺难懂的,有兴趣可以自己深入研究,我们这里主要讲下如何封装和使用这两种加密算法。

        加解密的流程如下图所示,我们这里都是对称加密,加解密用的同一个密钥,没什么太复杂的流程。

二、TEA算法

        TEA是一个非常轻量级的加解密算法,效率高、强度好,很多游戏类有实时性要求的都是用TEA算法,QQ好像也是,它的基本介绍百科里有TEA加密算法_百度百科。对于我们使用者而言,主要有几个点注意下就行了。

1、TEA采用对称加密,数据是8字节一组,密钥是16字节一组,所以对用户层的数据有要求,数据需要8字节对齐,不够的自己补齐再输入;密码要16字节。

2、TEA算法的加密强度跟算法本身关系不大,主要还是加密轮次,建议是32轮,所以驱动库里就写死了,加解密算法轮次要对应。

        下面先展现每组的加密单元,代码如下所示:


/*		
================================================================================
描述 :  TEA加密单元
输入 : 
输出 : 
================================================================================
*/
void EncryptTEA(u32 *firstChunk, u32 *secondChunk, u32* key)
{
	u32 y = *firstChunk;
	u32 z = *secondChunk;
	u32 sum = 0;
	u32 delta = 0x9e3779b9;

	for (int i = 0; i < 32; i++)//32轮运算(需要对应下面的解密核心函数的轮数一样)
	{
		sum += delta;
		y += ((z << 4) + key[0]) ^ (z + sum) ^ ((z >> 5) + key[1]);
		z += ((y << 4) + key[2]) ^ (y + sum) ^ ((y >> 5) + key[3]);
	}

	*firstChunk = y;
	*secondChunk = z;
 }

/*		
================================================================================
描述 : TEA解密单元
输入 : 
输出 : 
================================================================================
*/
void DecryptTEA(u32 *firstChunk, u32 *secondChunk, u32* key)
{
	u32  sum = 0;
	u32  y = *firstChunk;
	u32  z = *secondChunk;
	u32  delta = 0x9e3779b9;

	sum = delta << 5; //32轮运算,所以是2的5次方;16轮运算,所以是2的4次方;8轮运算,所以是2的3次方

	for (int i = 0; i < 32; i++) //32轮运算
	{
		z -= (y << 4) + key[2] ^ y + sum ^ (y >> 5) + key[3];
		y -= (z << 4) + key[0] ^ z + sum ^ (z >> 5) + key[1];
		sum -= delta;
	}

	*firstChunk = y;
	*secondChunk = z;
}

        具体核心函数的内部原理我们就不考究了,简单的观察就是4字节+4字节数据与16字节的密码做相关运算。

        接下来看下如何调用这个核心加解密函数,具体代码如下:


/*		
================================================================================
描述 :TEA数据加密函数
输入 : buff的长度必须是8的整数倍
输出 : 
================================================================================
*/
u16 tea_encrypt_buff(u8 *buff, u16 len, u32* key)
{
	u8 *p = buff; 
	u16 i,counts;

	if(len%8!=0)
	{
		printf("Encrypt buff len err!\n");
		return 0;
	}
	counts=len/8;	
	for(i=0;i<counts;i++)
	{
		EncryptTEA((u32 *)p, (u32 *)(p + 4), key);
		p+=8;
	}
	return len;
}

/*		
================================================================================
描述 : TEA数据解密函数
输入 : buff的长度必须是8的整数倍
输出 : 
================================================================================
*/
u16 tea_decrypt_buff(u8 *buff, u16 len, u32* key)  
{
	u8 *p = buff; 
	u16 i,counts;

	if(len%8!=0)
	{
		printf("Decryp buff len err!\n");
		return 0;
	}	
	counts=len/8;	
	for(i=0;i<counts;i++)
	{
		DecryptTEA((u32 *)p, (u32 *)(p + 4), key);
		p+=8;
	}
	
	return len;
}

        这是自己封装的,主要是检测输入的数据长度有没有8字节对齐,然后调用加解密函数对每个单元的数据一次操作,由于是指针传递,所以明文和密文都是在同一个缓冲区内。

三、AES算法

        AES算法是当今使用最多的对称加密算法了,效率高、安全性好,它的实现比较复杂,我们用的是mbedtls库,把其中的AES相关部分拿出来,因为整个库对于单片机来讲着实有点大了GitHub - Mbed-TLS/mbedtls: An open source, portable, easy to use, readable and flexible TLS library, and reference implementation of the PSA Cryptography API. Releases are on a varying cadence, typically around 3 - 6 months between releases.

        AES内部还分了5中加密模式,具体看这里介绍,我们选择的是cbc模式,密码16字节,其它模式自己也可以尝试。AES五种加密模式(CBC、ECB、CTR、OCF、CFB) - 知乎

        下面具体看下驱动库封装后的程序,代码如下:


/*		
================================================================================
描述 :AES-CBC模式加密
输入 : 
输出 : 
================================================================================
*/
int aes_encrypt_buff(u8 *in_buff, u16 in_len,u8 *out_buff, u16 out_size,u8 *passwd)
{
	static mbedtls_aes_context aes_ctx;
	u16 loop_cnts=0;//循环加密次数
	u8 temp_buff[20]={0};
	u8 iv[17]={0},key[17]={0};
	loop_cnts=in_len/16;
	if(in_len%16>0)
		loop_cnts++;

	if(loop_cnts*16>out_size)
		return 0;

	if(strlen((char*)passwd)>16)
	{
		memcpy(key, passwd, 16);
	}
	else
	{
		strcpy((char*)key, (char*)passwd);
	}
	mbedtls_aes_init(&aes_ctx);
	mbedtls_aes_setkey_enc(&aes_ctx, key, 128);
	memset(iv,'0',sizeof(iv));
	for(int i=0;i<loop_cnts;i++)
	{
		if(i==loop_cnts-1 && in_len%16>0)//最后一组
		{
			memset(temp_buff, 0, sizeof(temp_buff));
			memcpy(temp_buff, &in_buff[i*16], in_len%16);//用0填充
		}
		else
		{
			memcpy(temp_buff, &in_buff[i*16], 16);
		}
		mbedtls_aes_crypt_cbc(&aes_ctx,  MBEDTLS_AES_ENCRYPT, 16, iv, temp_buff,  &out_buff[i*16]);
	}

	return loop_cnts*16;
}

/*		
================================================================================
描述 :AES-CBC模式解密
输入 : 
输出 : 
================================================================================
*/
int aes_decrypt_buff(u8 *in_buff, u16 in_len,u8 *out_buff, u16 out_size,u8 *passwd)
{
	mbedtls_aes_context aes_ctx;
	u16 loop_cnts=0;//循环加密次数
	u8 temp_buff[16]={0};
	u8 iv[16]={0},key[17]={0};
	loop_cnts=in_len/16;
	if(in_len%16>0)
		return 0;   //密文长度必须是16的整数倍

	if(loop_cnts*16>out_size)
		return 0;

	if(strlen((char*)passwd)>16)
	{
		memcpy(key, passwd, 16);
	}
	else
	{
		strcpy((char*)key, (char*)passwd);
	}
	mbedtls_aes_init(&aes_ctx);
	mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
	memset(iv,'0',sizeof(iv));
	for(int i=0;i<loop_cnts;i++)
	{
		memcpy(temp_buff, &in_buff[i*16], 16);
		mbedtls_aes_crypt_cbc(&aes_ctx,  MBEDTLS_AES_DECRYPT, 16, iv, temp_buff,  &out_buff[i*16]);
	}
	return loop_cnts*16;
}

        CBC模式需要初始化向量,这里全部初始化为‘0’,核心还是调用mbedtls的库函数,代码自行阅读,接下来做一些测试,看下如何使用。

四、加解密测试

        测试环境如下所示:

        如果采用的是净化器项目的工程代码,那么user_opt.h和rtconfig.h文件参数修改下,不然RAM不够用,任务无法运行,AES算法有点吃内存,对于小身板来讲比较够呛。

        下面是测试代码,放在user_app.c文件里,代码如下:

  
  u8 in_buff[32]={"0123456789ABCDEF0123456789ABCDEF"};
  u8 out_buff[32]={0};
  u8 passwd[16]={"0123456789123456"};
  
  //TEA加解密测试
  printf("*****start tea test!\n");
  printf("000 in_buff=%s\n", in_buff); 
  tea_encrypt_buff(in_buff, 32, (u32*)passwd);//TEA加密
  printf_hex("out_buff=", in_buff, 32);//打印密文

  tea_decrypt_buff(in_buff, 32, (u32*)passwd);//TEA解密
  
  printf("111 in_buff=%s\n", in_buff);//打印解密明文  
  
  //AES加解密测试
  printf("\n*****start aes test!\n");
  printf("000 in_buff=%s\n", in_buff); 
  aes_encrypt_buff(in_buff, 32, out_buff, 32, passwd);//AES加密
  printf_hex("out_buff=", out_buff, 32);//打印密文
  
  memset(in_buff, 0, 32);//清空明文区
  aes_decrypt_buff(out_buff, 32, in_buff, 32, passwd);//AES解密
  
  printf("222 in_buff=%s\n", in_buff);   

        测试结果如下图所示,密文用16进制的方式打印,不然是乱码:

        从结果上看,加解密算法没什么问题,速度也还可以,不过AES算法对于STM32F103C8T6可能还是有点大了,芯片的RAM是20KB,单纯AES文件就要用掉10KB左右,所以对于前端小型设备,可能还是TEA算法比较合适,这个自行选择。

五、安全性保障

        现在回到物联网本身,有哪些我们可以采用加密传输呢?像购买的从机设备一般是没办法的,比如485温湿度传感器,这种厂家已经固定程序了,不会为你去做适配的,不过这一类传感器也不必要加密通讯了,因为它是有线局部传输,物理环境本身比较安全。备端的加密一般放在无线组网方面和主机与服务器通讯方面。

        首先无线组网数据容易被截获,如果内容是加密的,对方破解需要代价和时间,如果你在内容里加上时间戳等信息,可以有效防止重放攻击,以后会讲的LoRa自组网就会用到加密算法了。

        主机跟服务器方面就不用多说了,这部分如果没有加密的话很容易被攻击,因为数据一般是发往互联网的,攻击者的操作手段太多了,我们只能尽可能得做好数据加密,防止一些常规手段的攻击。

        安全性不单单是加密算法的事,更重要的是密钥的存放,如果密钥很容易就被获取了,那么跟没加密是一样的。对于单片机设备,如果有一定价值,攻击者可以通过非正常手段读取单片机内部flash的所有内容,如果你的密钥是明文写在程序内的,对方很快就能获悉了,所以一个高可靠性产品的代码写起来确实不容易,至于要如何防止,只能在后续项目实操中融入了。

代码链接:https://download.csdn.net/download/ypp240124016/89110489

文件中的drv_common.c和drv_common.h直接替换掉原来的就行。

本项目的交流QQ群:701889554

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c# refc# substring c# 反射c# split c# websocket c# datatable使用

在C#编程中&#xff0c;ref关键字、Substring方法、反射&#xff08;Reflection&#xff09;、Split方法、WebSocket通信以及DataTable的使用都是常见的技术和方法。下面我将逐一为您详解这些内容。 1. C# ref关键字 ref关键字在C#中用于按引用传递参数。这意味着当您将变量作…

当你的项目体积比较大?你如何做性能优化

在前端开发中&#xff0c;项目体积优化是一个重要的环节&#xff0c;它直接影响到网页的加载速度和用户体验。随着前端项目越来越复杂&#xff0c;引入的依赖也越来越多&#xff0c;如何有效地减少最终打包文件的大小&#xff0c;成为了前端工程师需要面对的挑战。以下是一些常…

vim卡死了,没有反应怎么办?

解决办法&#xff1a; 很有可能是你有个在window下的好习惯&#xff0c;没事儿就ctrl s保存文件。但是在vim里&#xff0c;ctrl s默认是发送一种流控制信号&#xff0c;通常用于停止终端的输出&#xff0c;所以你的屏幕就卡死了。 解决办法也很简单&#xff0c;按下ctrl q即…

机器学习前导——PyCharm PyTorch Python3 机器学习

机器学习前导——PyCharm & pytorch & Python3 & 机器学习 文章目录 前言PyCharmPyTorchPython3机器学习联系 前言 这学期选了《机器学习》&#xff0c;第一次接触&#xff0c;对一些专有名词很陌生。 PyCharm PyCharm是一款由JetBrains开发的软件&#xff0c…

python--递归算法篇

1、给定一个包含n1个整数的数组nums&#xff0c;其数字在1到n之间&#xff08;包含1和n&#xff09;&#xff0c; 可知至少存在一个重复的整数&#xff0c;假设只有一个重复的整数&#xff0c;请找出这个重复的数 def repeat(ls:list) -> list:#把个数超过1的数&#xff0c…

ppt技巧:如何将Word文档大纲中导入到幻灯片中?

在PowerPoint中&#xff0c;将Word文档的大纲导入到新的幻灯片是一种非常实用的技巧。以下是详细的步骤&#xff1a; 首先&#xff0c;需要打开PowerPoint软件并打开原始的幻灯片文件。 在PowerPoint的顶部【开始】菜单栏中&#xff0c;找到并点击“新建幻灯片”按钮&#xff0…

OSPF中配置VLAN通信(单臂路由)

OSPF中配置VLAN通信&#xff08;单臂路由&#xff09; 单臂路由&#xff08;One-Arm Routing&#xff09;是一种网络路由配置方式&#xff0c;常用于解决网络中的特定问题。在传统的网络架构中&#xff0c;路由器通常需要连接到多个子网或网络段&#xff0c;每个子网都需要一个…

数学知识——欧几里得算法(辗转相除法)

欧几里得算法用来求最大公约数 int gcd(int a, int b) {if(b 0) return a;else return gcd(b, a % b); } 例题&#xff1a;洛谷p1029 #include<iostream>using namespace std;#define int long long #define endl \nint x, y; int ans;int gcd(int x, int y) {if(y 0)…

Bytebase 2.15.0 - GitOps 整体升级

&#x1f514; GitOps 整体升级 新版 GitOps 和之前版本不兼容&#xff0c;如果需要升级协助&#xff0c;请联系我们。 使用访问令牌进行身份验证。支持项目中配置多个 VCS 连接器。支持在 VCS 连接器中指定数据库分组为目标&#xff08;默认情况下应用于项目中的所有数据库&…

俄罗斯yandex广告推广如何投放?

俄罗斯作为欧亚大陆的重要经济体&#xff0c;拥有庞大的互联网用户基数&#xff0c;其中Yandex作为该地区最主要的搜索引擎&#xff0c;无疑是触及目标客户群的关键渠道。云衔科技凭借专业优势与实战经验&#xff0c;为企业提供一站式Yandex广告开户及全程代运营解决方案&#…

抽象工厂模式:深入探索面向对象设计的多样性

在软件开发中&#xff0c;正确地应用设计模式对于构建可扩展、可维护和高效的系统至关重要。抽象工厂模式作为创建型设计模式之一&#xff0c;提供了一个高层接口&#xff0c;用于创建一系列相关或依赖对象&#xff0c;而无需指定它们具体的类。本文将详细介绍抽象工厂模式的概…

Ubuntu日常配置

目录 修改网络配置 xshell连不上怎么办 解析域名失败 永久修改DNS方法 临时修改DNS方法 修改网络配置 1、先ifconfig确认本机IP地址&#xff08;刚装的机子没有ifconfig&#xff0c;先apt install net-tools&#xff09; 2、22.04版本的ubuntu网络配置在netplan目录下&…

【随笔】Git 高级篇 -- 管理多分支 git rebase(二十二)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

WSL访问adb usb device

1.Windows上用PowerShell运行&#xff1a; winget install --interactive --exact dorssel.usbipd-win 2.在WSLUbuntu上终端运行&#xff1a; sudo apt install linux-tools-generic hwdata sudo update-alternatives --install /usr/local/bin/usbip usbip /usr/lib/linux-too…

数据结构的魅力

数据结构这块越学越敬佩 博大精深 统计大文件中相同年龄的人的个数 public static void main(String[] args) throws Exception {String str "";String fileName "";InputStreamReader isr new InputStreamReader(new FileInputStream(fileName), Stan…

蓝桥杯嵌入式(G431)备赛笔记——RTC

// RTC time// 声明一个变量 rtc_tick 用于记录上次 RTC 处理的时间 u32 rtc_tick 0;// 声明结构体变量 D 用于存储 RTC 的日期信息 RTC_DateTypeDef D;// 声明结构体变量 T 用于存储 RTC 的时间信息 RTC_TimeTypeDef T;// RTC_proc 函数&#xff0c;用于处理 RTC 时间 void R…

【单片机毕业设计8-基于stm32c8t6的RFID校园门禁系统】

【单片机毕业设计8-基于stm32c8t6的RFID校园门禁系统】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇8基于stm32的RFID校园门禁系统 &#x1f9ff;创作不易&#xff0c;拒绝白嫖可私 一、功能介绍 -----------…

Spark-Scala语言实战(15)

在之前的文章中&#xff0c;我们学习了如何在spark中使用键值对中的学习键值对方法中的lookup&#xff0c;cogroup两种方法。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#…

5. @Autowired与@Resource的区别

在上一节我们使用Autowired进行了bean的装配&#xff0c;Autowired与Resource都可以用来装配bean&#xff0c;但它们之前还是有一些区别&#xff0c;它们的区别具体体现为以下几点&#xff1a; 来源不同对Constructor注入的支持不同查找顺序不同支持参数不同 1. 来源不同 Re…

事务隔离级别(图文详解)

事务隔离级别(图文详解) 什么是事务? 事务是逻辑上的一组操作&#xff0c;要么都执行&#xff0c;要么都不执行。 事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账1000元&#xff0c;这个转账会涉及到两个关键操作就是&#xff1a;将小明的余额减少1000元…