当前位置:   article > 正文

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

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

目录

一、前言

二、TEA算法

三、AES算法

四、加解密测试

五、安全性保障


一、前言

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

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

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

二、TEA算法

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

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

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

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

  1. /*
  2. ================================================================================
  3. 描述 : TEA加密单元
  4. 输入 :
  5. 输出 :
  6. ================================================================================
  7. */
  8. void EncryptTEA(u32 *firstChunk, u32 *secondChunk, u32* key)
  9. {
  10. u32 y = *firstChunk;
  11. u32 z = *secondChunk;
  12. u32 sum = 0;
  13. u32 delta = 0x9e3779b9;
  14. for (int i = 0; i < 32; i++)//32轮运算(需要对应下面的解密核心函数的轮数一样)
  15. {
  16. sum += delta;
  17. y += ((z << 4) + key[0]) ^ (z + sum) ^ ((z >> 5) + key[1]);
  18. z += ((y << 4) + key[2]) ^ (y + sum) ^ ((y >> 5) + key[3]);
  19. }
  20. *firstChunk = y;
  21. *secondChunk = z;
  22. }
  23. /*
  24. ================================================================================
  25. 描述 : TEA解密单元
  26. 输入 :
  27. 输出 :
  28. ================================================================================
  29. */
  30. void DecryptTEA(u32 *firstChunk, u32 *secondChunk, u32* key)
  31. {
  32. u32 sum = 0;
  33. u32 y = *firstChunk;
  34. u32 z = *secondChunk;
  35. u32 delta = 0x9e3779b9;
  36. sum = delta << 5; //32轮运算,所以是2的5次方;16轮运算,所以是2的4次方;8轮运算,所以是2的3次方
  37. for (int i = 0; i < 32; i++) //32轮运算
  38. {
  39. z -= (y << 4) + key[2] ^ y + sum ^ (y >> 5) + key[3];
  40. y -= (z << 4) + key[0] ^ z + sum ^ (z >> 5) + key[1];
  41. sum -= delta;
  42. }
  43. *firstChunk = y;
  44. *secondChunk = z;
  45. }

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

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

  1. /*
  2. ================================================================================
  3. 描述 :TEA数据加密函数
  4. 输入 : buff的长度必须是8的整数倍
  5. 输出 :
  6. ================================================================================
  7. */
  8. u16 tea_encrypt_buff(u8 *buff, u16 len, u32* key)
  9. {
  10. u8 *p = buff;
  11. u16 i,counts;
  12. if(len%8!=0)
  13. {
  14. printf("Encrypt buff len err!\n");
  15. return 0;
  16. }
  17. counts=len/8;
  18. for(i=0;i<counts;i++)
  19. {
  20. EncryptTEA((u32 *)p, (u32 *)(p + 4), key);
  21. p+=8;
  22. }
  23. return len;
  24. }
  25. /*
  26. ================================================================================
  27. 描述 : TEA数据解密函数
  28. 输入 : buff的长度必须是8的整数倍
  29. 输出 :
  30. ================================================================================
  31. */
  32. u16 tea_decrypt_buff(u8 *buff, u16 len, u32* key)
  33. {
  34. u8 *p = buff;
  35. u16 i,counts;
  36. if(len%8!=0)
  37. {
  38. printf("Decryp buff len err!\n");
  39. return 0;
  40. }
  41. counts=len/8;
  42. for(i=0;i<counts;i++)
  43. {
  44. DecryptTEA((u32 *)p, (u32 *)(p + 4), key);
  45. p+=8;
  46. }
  47. return len;
  48. }

        这是自己封装的,主要是检测输入的数据长度有没有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) - 知乎

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

  1. /*
  2. ================================================================================
  3. 描述 :AES-CBC模式加密
  4. 输入 :
  5. 输出 :
  6. ================================================================================
  7. */
  8. int aes_encrypt_buff(u8 *in_buff, u16 in_len,u8 *out_buff, u16 out_size,u8 *passwd)
  9. {
  10. static mbedtls_aes_context aes_ctx;
  11. u16 loop_cnts=0;//循环加密次数
  12. u8 temp_buff[20]={0};
  13. u8 iv[17]={0},key[17]={0};
  14. loop_cnts=in_len/16;
  15. if(in_len%16>0)
  16. loop_cnts++;
  17. if(loop_cnts*16>out_size)
  18. return 0;
  19. if(strlen((char*)passwd)>16)
  20. {
  21. memcpy(key, passwd, 16);
  22. }
  23. else
  24. {
  25. strcpy((char*)key, (char*)passwd);
  26. }
  27. mbedtls_aes_init(&aes_ctx);
  28. mbedtls_aes_setkey_enc(&aes_ctx, key, 128);
  29. memset(iv,'0',sizeof(iv));
  30. for(int i=0;i<loop_cnts;i++)
  31. {
  32. if(i==loop_cnts-1 && in_len%16>0)//最后一组
  33. {
  34. memset(temp_buff, 0, sizeof(temp_buff));
  35. memcpy(temp_buff, &in_buff[i*16], in_len%16);//用0填充
  36. }
  37. else
  38. {
  39. memcpy(temp_buff, &in_buff[i*16], 16);
  40. }
  41. mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, 16, iv, temp_buff, &out_buff[i*16]);
  42. }
  43. return loop_cnts*16;
  44. }
  45. /*
  46. ================================================================================
  47. 描述 :AES-CBC模式解密
  48. 输入 :
  49. 输出 :
  50. ================================================================================
  51. */
  52. int aes_decrypt_buff(u8 *in_buff, u16 in_len,u8 *out_buff, u16 out_size,u8 *passwd)
  53. {
  54. mbedtls_aes_context aes_ctx;
  55. u16 loop_cnts=0;//循环加密次数
  56. u8 temp_buff[16]={0};
  57. u8 iv[16]={0},key[17]={0};
  58. loop_cnts=in_len/16;
  59. if(in_len%16>0)
  60. return 0; //密文长度必须是16的整数倍
  61. if(loop_cnts*16>out_size)
  62. return 0;
  63. if(strlen((char*)passwd)>16)
  64. {
  65. memcpy(key, passwd, 16);
  66. }
  67. else
  68. {
  69. strcpy((char*)key, (char*)passwd);
  70. }
  71. mbedtls_aes_init(&aes_ctx);
  72. mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
  73. memset(iv,'0',sizeof(iv));
  74. for(int i=0;i<loop_cnts;i++)
  75. {
  76. memcpy(temp_buff, &in_buff[i*16], 16);
  77. mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, 16, iv, temp_buff, &out_buff[i*16]);
  78. }
  79. return loop_cnts*16;
  80. }

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

四、加解密测试

        测试环境如下所示:

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

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

  1. u8 in_buff[32]={"0123456789ABCDEF0123456789ABCDEF"};
  2. u8 out_buff[32]={0};
  3. u8 passwd[16]={"0123456789123456"};
  4. //TEA加解密测试
  5. printf("*****start tea test!\n");
  6. printf("000 in_buff=%s\n", in_buff);
  7. tea_encrypt_buff(in_buff, 32, (u32*)passwd);//TEA加密
  8. printf_hex("out_buff=", in_buff, 32);//打印密文
  9. tea_decrypt_buff(in_buff, 32, (u32*)passwd);//TEA解密
  10. printf("111 in_buff=%s\n", in_buff);//打印解密明文
  11. //AES加解密测试
  12. printf("\n*****start aes test!\n");
  13. printf("000 in_buff=%s\n", in_buff);
  14. aes_encrypt_buff(in_buff, 32, out_buff, 32, passwd);//AES加密
  15. printf_hex("out_buff=", out_buff, 32);//打印密文
  16. memset(in_buff, 0, 32);//清空明文区
  17. aes_decrypt_buff(out_buff, 32, in_buff, 32, passwd);//AES解密
  18. 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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/414918
推荐阅读
相关标签
  

闽ICP备14008679号