当前位置:   article > 正文

【IoT】加密与安全:CC254x 低功耗蓝牙 BLE 之 AES-128 加密算法_蓝牙 aes-128 加密解密

蓝牙 aes-128 加密解密

蓝牙数据是可以通过空中抓包而被抓取到的,因此需要将通信数据进行加密,即使别人截获了加密后的数据,也无法利用该数据。

AES 加密原理

CC254x 支持对称加密 AES:

加密过程:

需要加密的数据 A 与秘钥 KEY 进行一定的算法,获得加密过的数据 B。

解密过程:

加密过的数据 B 与秘钥 KEY 进行一定的逆运算算法,获得加密前的数据 A。

因此,在 BLE 连接交互数据时,可以对明文数据进行加密,确保数据的机密性,从而抵御攻击者。机密性是指第三方“攻击者”由于没有加密链路的共享密钥,因此无法拦截、破译或读取消息的原始内容。

1、BLE AES-128 加密算法简介

低功耗蓝牙 BLE 中的所有加密和认证都基于同一个加密引擎,称为高级加密系统(AES)。

BLE 使用 128(16 字节) 位的密钥和 128 位的数据块。也就是说,所有密钥的长度均为 128 位,每次加密生成的密文长度为 16 个字节。

AES 加密块非常简单,它包含两个输入和一个输出。

两个输入分别为 128 位的密钥值和 128 位的纯文本数据块,输出则为 128 位的加密数据块。

密钥和纯文本在使用上有一些不同:

纯文本可以直接为加密块使用,但密钥必须经过处理后才能使用。

在 BLE 中 AES 加密引擎被用于下列四个基本功能:

1)加密净荷数据

2)计算消息完整性校验值

3)数据签名

4)生成私有地址

数据签名在安全管理器中定义,生成私有地址在通用访问规范中定义。

2、BLE AES-128 加解密方法源码

2.1、BLE 设备端

1)测试环境

开发环境:

IAR8.20版本,Windows XP系统

测试设备:

CC2541/CC2540 开发板

测试例程:

1.4.0 协议栈中 simpleBLEPeripheral 例程

2)实现源码

  1. /****************************************************************
  2. * 名 称: Aes128EncryptAndDecrypTest()
  3. *
  4. * 功 能: 测试AES-128 加解密,注意我们加密时需要key
  5. * 加密后的数据用于通信;同样解密的时候也
  6. * 需要用同一个key进行解密,这样,如果对方
  7. * 没有key 就无法解密出原始数据,进而保护了
  8. * 用户数据不被截取。
  9. *
  10. * 入口参数: 无
  11. * 出口参数: 无
  12. ****************************************************************/
  13. static void Aes128EncryptAndDecrypTest(void)
  14. {
  15. int i = 0;
  16. // 加密秘钥 16个字节也就是128 bit
  17. uint8 key[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
  18. // 需要加密的数据(保证16个字节,不够的自己填充)
  19. uint8 source_buf[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
  20. // 加密后数据存放区
  21. uint8 encrypted_buf[16];
  22. // 解密后数据存放区
  23. uint8 deccrypted_buf[16];
  24. // 开始加密,加密后的数据存放到 encrypted_buf
  25. LL_Encrypt( key, source_buf, encrypted_buf );
  26. // 开始解密,将解密后的数据存到deccrypted_buf
  27. LL_EXT_Decrypt( key, encrypted_buf, deccrypted_buf );
  28. //打印原始数据
  29. tx_printf("source:");
  30. for(i = 0;i < 16;i++)
  31. {
  32. txprintf("0x%02x ",source_buf[i]);
  33. }
  34. tx_printf("");
  35. //打印加密后的数据
  36. tx_printf("encrypte:");
  37. for(i = 0;i < 16;i++)
  38. {
  39. txprintf("0x%02x ",encrypted_buf[i]);
  40. }
  41. tx_printf("");
  42. //打印解密后的数据
  43. tx_printf("deccrypte:");
  44. for(i = 0;i < 16;i++)
  45. {
  46. txprintf("0x%02x ",deccrypted_buf[i]);
  47. }
  48. tx_printf("");
  49. }

上述测试方法放到“simpleBLEPeripheral.c”文件中,在初始化函数“SimpleBLEPeripheral_Init”里面最后的地方调用上述测试方法“Aes128EncryptAndDecrypTest();”。

通过上述测试方法,我们看到设备端加密用的是“LL_Encrypt”方法,解密用的是“LL_EXT_Decrypt”方法,这两个方法的声明在“Ll.h”头文件中,这个头文件被“hci.h”头文件引用,所以如果提示找不到这两个方法的时候,我们引用“hci.h”头文件即可。

2.2、安卓手机端

1)测试环境:

开发环境:

Eclipse 开发工具,Windows XP 系统。

测试设备:

Eclipse 开发工具编译 java 工程可以在控制台输出结果。

2)测试源码:

  1. package com.zzfenglin.aes;
  2. import java.util.Formatter;
  3. import javax.crypto.Cipher;
  4. import javax.crypto.spec.SecretKeySpec;
  5. public class AesEntryDetry {
  6. // 加密秘钥 ,16个字节也就是128 bit
  7. private static final byte[] AES_KEY = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
  8. 12, 13, 14, 15, 16 };
  9. // 需要加密的数据(保证16个字节,不够的自己填充)
  10. private static final byte[] SOURCE_BUF = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
  11. 11, 12, 13, 14, 15, 16 };
  12. // Java测试工程入口方法,在这个方法中调用加解密方法并打印结果
  13. public static void main(String[] args) throws Exception {
  14. // 需要加密的原始数据转化成字符串并打印到控制台
  15. String strSource = BytetohexString(SOURCE_BUF);
  16. System.out.println("source:\n" + strSource);
  17. // 调用加密方法,对数据进行加密,加密后的数据存放到encryBuf字节数组中
  18. byte[] encryBuf = encrypt(AES_KEY, SOURCE_BUF);
  19. // 将加密后的字节数组数据转成字符串并打印到控制台
  20. String strEncry = BytetohexString(encryBuf).toLowerCase();
  21. System.out.println("encrypte:\n" + strEncry);
  22. // 调用解密方法,对数据进行解密,解密后的数据存放到decryBuf字节数组中
  23. byte[] decryBuf = decrypt(AES_KEY, encryBuf);
  24. // 将解密后的字节数组数据转成字符串并打印到控制台
  25. String strDecry = BytetohexString(decryBuf);
  26. System.out.println("decrypte:\n" + strDecry);
  27. }
  28. // 加密方法
  29. private static byte[] encrypt(byte[] key, byte[] clear) throws Exception {
  30. SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
  31. Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
  32. cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
  33. byte[] encrypted = cipher.doFinal(clear);
  34. return encrypted;
  35. }
  36. // 解密方法
  37. private static byte[] decrypt(byte[] key, byte[] encrypted)
  38. throws Exception {
  39. SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
  40. Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
  41. cipher.init(Cipher.DECRYPT_MODE, skeySpec);
  42. byte[] decrypted = cipher.doFinal(encrypted);
  43. return decrypted;
  44. }
  45. // 字节数组按照一定格式转换拼装成字符串用于打印显示
  46. private static String BytetohexString(byte[] b) {
  47. int len = b.length;
  48. StringBuilder sb = new StringBuilder(b.length * (2 + 1));
  49. Formatter formatter = new Formatter(sb);
  50. for (int i = 0; i < len; i++) {
  51. if (i < len - 1)
  52. formatter.format("0x%02X:", b[i]);
  53. else
  54. formatter.format("0x%02X", b[i]);
  55. }
  56. formatter.close();
  57. return sb.toString();
  58. }
  59. }

3、如何使用 MAC 生成 AES 秘钥

例子:该方式可以保证每个设备的 AES 秘钥不同,但如果他人知道了秘钥的获取方式,则该加密方式将不再安全。

CC254x 将温度值放在广播数据中发送给手机 app:

1)CC254x 使用 mac 形成 AES 秘钥;

2)CC254x 将温度值利用 AES 秘钥进行加密;

3)CC254x 将加密后的温度值动态广播出来;

4)手机 app 使用 mac 形成 AES 秘钥。

5)手机app获取CC2541的广播数据,并解析出温度数据字段。

6)将加密后的温度值利用AES秘钥进行解密。

  1. //******************************************************************************
  2. //name: GUA_AES.c
  3. //introduce: AES驱动
  4. //author:
  5. //******************************************************************************
  6. #include <ioCC2540.h>
  7. #include "LL.h"
  8. #include "GUA_AES.h"
  9. /*********************内部变量************************/
  10. static GUA_U8 sbGUA_AES_Key[16] = {0}; //AES的秘钥
  11. /*********************内部函数************************/
  12. static void GUA_Get_LocalMac(GUA_U8 *pGUA_LocalMac);
  13. static void GUA_AES_GetKey(GUA_U8 *pGUA_AES_LocalMac, GUA_U8 *pGUA_AES_Key);
  14. //******************************************************************************
  15. //name: GUA_Get_LocalMac
  16. //introduce: 获取本机mac
  17. //parameter: pGUA_LocalMac:mac需要保存到的位置,需要6个字节大小
  18. //return: none
  19. //******************************************************************************
  20. static void GUA_Get_LocalMac(GUA_U8 *pGUA_LocalMac)
  21. {
  22. pGUA_LocalMac[5] = *(GUA_U8 *)(0x780E); //直接指向指针内容
  23. pGUA_LocalMac[4] = *(GUA_U8 *)(0x780F);
  24. pGUA_LocalMac[3] = *(GUA_U8 *)(0x7810);
  25. pGUA_LocalMac[2] = XREG(0x7811); //define函数直接读出数据
  26. pGUA_LocalMac[1] = XREG(0x7812);
  27. pGUA_LocalMac[0] = XREG(0x7813);
  28. }
  29. //******************************************************************************
  30. //name: GUA_AES_GetKey
  31. //introduce: 通过mac形成自定义秘钥
  32. //parameter: pGUA_AES_LocalMac:mac地址
  33. // pGUA_AES_Key:秘钥存放位置,需要16字节大小
  34. //return: none
  35. //author: 甜甜的大香瓜
  36. //email: 897503845@qq.com
  37. //QQ group: 香瓜BLE之CC2541(127442605)
  38. //changetime: 2017.03.29
  39. //******************************************************************************
  40. static void GUA_AES_GetKey(GUA_U8 *pGUA_AES_LocalMac, GUA_U8 *pGUA_AES_Key)
  41. {
  42. pGUA_AES_Key[0] = 'G';
  43. pGUA_AES_Key[1] = 'U';
  44. pGUA_AES_Key[2] = 'A';
  45. pGUA_AES_Key[3] = '#';
  46. pGUA_AES_Key[4] = pGUA_AES_LocalMac[0];
  47. pGUA_AES_Key[5] = pGUA_AES_LocalMac[1];
  48. pGUA_AES_Key[6] = pGUA_AES_LocalMac[2];
  49. pGUA_AES_Key[7] = pGUA_AES_LocalMac[3];
  50. pGUA_AES_Key[8] = pGUA_AES_LocalMac[4];
  51. pGUA_AES_Key[9] = pGUA_AES_LocalMac[5];
  52. pGUA_AES_Key[10] = pGUA_AES_LocalMac[0] + pGUA_AES_LocalMac[1];
  53. pGUA_AES_Key[11] = pGUA_AES_LocalMac[2] + pGUA_AES_LocalMac[3];
  54. pGUA_AES_Key[12] = pGUA_AES_LocalMac[4] + pGUA_AES_LocalMac[5];
  55. pGUA_AES_Key[13] = pGUA_AES_LocalMac[0] - pGUA_AES_LocalMac[1];
  56. pGUA_AES_Key[14] = pGUA_AES_LocalMac[2] - pGUA_AES_LocalMac[3];
  57. pGUA_AES_Key[15] = pGUA_AES_LocalMac[4] - pGUA_AES_LocalMac[5];
  58. }
  59. //******************************************************************************
  60. //name: GUA_AES_Encrypted
  61. //introduce: 加密16字节的数据
  62. //parameter: pGUA_AES_Data:要加密的数据缓存区,必须16字节
  63. // pGUA_AES_EncryptedData:加密后的数据缓存区,必须16字节
  64. //return: none
  65. //******************************************************************************
  66. void GUA_AES_Encrypted(GUA_U8 *pGUA_AES_Data, GUA_U8 *pGUA_AES_EncryptedData)
  67. {
  68. LL_Encrypt(sbGUA_AES_Key, pGUA_AES_Data, pGUA_AES_EncryptedData);
  69. }
  70. //******************************************************************************
  71. //name: GUA_AES_Deccrypted
  72. //introduce: 解密16字节以内的数据
  73. //parameter: pGUA_AES_EncryptedData:加密后的数据缓存区,必须16字节
  74. // pGUA_AES_DeccryptedData:解密后的数据缓存区,必须16字节
  75. //return: none
  76. //author: 甜甜的大香瓜
  77. //email: 897503845@qq.com
  78. //QQ group: 香瓜BLE之CC2541(127442605)
  79. //changetime: 2017.03.29
  80. //******************************************************************************
  81. void GUA_AES_Deccrypted(GUA_U8 *pGUA_AES_EncryptedData, GUA_U8 *pGUA_AES_DeccryptedData)
  82. {
  83. LL_EXT_Decrypt(sbGUA_AES_Key, pGUA_AES_EncryptedData, pGUA_AES_DeccryptedData);
  84. }
  85. //******************************************************************************
  86. //name: GUA_AES_Init
  87. //introduce: AES初始化
  88. //parameter: none
  89. //return: none
  90. //******************************************************************************
  91. void GUA_AES_Init(void)
  92. {
  93. GUA_U8 nbGUA_LocalMac[6] = {0};
  94. //获取mac
  95. GUA_Get_LocalMac(nbGUA_LocalMac);
  96. //通过mac获取秘钥
  97. GUA_AES_GetKey(nbGUA_LocalMac, sbGUA_AES_Key);
  98. }

refer:

https://blog.csdn.net/zzfenglin/article/details/51729300

https://blog.csdn.net/feilusia/article/details/68070791

https://blog.csdn.net/feilusia/article/details/50085225

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

闽ICP备14008679号