admin管理员组文章数量:1566998
蓝牙数据是可以通过空中抓包而被抓取到的,因此需要将通信数据进行加密,即使别人截获了加密后的数据,也无法利用该数据。
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)实现源码
/****************************************************************
* 名 称: Aes128EncryptAndDecrypTest()
*
* 功 能: 测试AES-128 加解密,注意我们加密时需要key,
* 加密后的数据用于通信;同样解密的时候也
* 需要用同一个key进行解密,这样,如果对方
* 没有key 就无法解密出原始数据,进而保护了
* 用户数据不被截取。
*
* 入口参数: 无
* 出口参数: 无
****************************************************************/
static void Aes128EncryptAndDecrypTest(void)
{
int i = 0;
// 加密秘钥 16个字节也就是128 bit
uint8 key[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
// 需要加密的数据(保证16个字节,不够的自己填充)
uint8 source_buf[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
// 加密后数据存放区
uint8 encrypted_buf[16];
// 解密后数据存放区
uint8 deccrypted_buf[16];
// 开始加密,加密后的数据存放到 encrypted_buf
LL_Encrypt( key, source_buf, encrypted_buf );
// 开始解密,将解密后的数据存到deccrypted_buf
LL_EXT_Decrypt( key, encrypted_buf, deccrypted_buf );
//打印原始数据
tx_printf("source:");
for(i = 0;i < 16;i++)
{
txprintf("0x%02x ",source_buf[i]);
}
tx_printf("");
//打印加密后的数据
tx_printf("encrypte:");
for(i = 0;i < 16;i++)
{
txprintf("0x%02x ",encrypted_buf[i]);
}
tx_printf("");
//打印解密后的数据
tx_printf("deccrypte:");
for(i = 0;i < 16;i++)
{
txprintf("0x%02x ",deccrypted_buf[i]);
}
tx_printf("");
}
上述测试方法放到“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)测试源码:
package com.zzfenglin.aes;
import java.util.Formatter;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AesEntryDetry {
// 加密秘钥 ,16个字节也就是128 bit
private static final byte[] AES_KEY = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16 };
// 需要加密的数据(保证16个字节,不够的自己填充)
private static final byte[] SOURCE_BUF = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16 };
// Java测试工程入口方法,在这个方法中调用加解密方法并打印结果
public static void main(String[] args) throws Exception {
// 需要加密的原始数据转化成字符串并打印到控制台
String strSource = BytetohexString(SOURCE_BUF);
System.out.println("source:\n" + strSource);
// 调用加密方法,对数据进行加密,加密后的数据存放到encryBuf字节数组中
byte[] encryBuf = encrypt(AES_KEY, SOURCE_BUF);
// 将加密后的字节数组数据转成字符串并打印到控制台
String strEncry = BytetohexString(encryBuf).toLowerCase();
System.out.println("encrypte:\n" + strEncry);
// 调用解密方法,对数据进行解密,解密后的数据存放到decryBuf字节数组中
byte[] decryBuf = decrypt(AES_KEY, encryBuf);
// 将解密后的字节数组数据转成字符串并打印到控制台
String strDecry = BytetohexString(decryBuf);
System.out.println("decrypte:\n" + strDecry);
}
// 加密方法
private static byte[] encrypt(byte[] key, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
// 解密方法
private static byte[] decrypt(byte[] key, byte[] encrypted)
throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
// 字节数组按照一定格式转换拼装成字符串用于打印显示
private static String BytetohexString(byte[] b) {
int len = b.length;
StringBuilder sb = new StringBuilder(b.length * (2 + 1));
Formatter formatter = new Formatter(sb);
for (int i = 0; i < len; i++) {
if (i < len - 1)
formatter.format("0x%02X:", b[i]);
else
formatter.format("0x%02X", b[i]);
}
formatter.close();
return sb.toString();
}
}
3、如何使用 MAC 生成 AES 秘钥
例子:该方式可以保证每个设备的 AES 秘钥不同,但如果他人知道了秘钥的获取方式,则该加密方式将不再安全。
CC254x 将温度值放在广播数据中发送给手机 app:
1)CC254x 使用 mac 形成 AES 秘钥;
2)CC254x 将温度值利用 AES 秘钥进行加密;
3)CC254x 将加密后的温度值动态广播出来;
4)手机 app 使用 mac 形成 AES 秘钥。
5)手机app获取CC2541的广播数据,并解析出温度数据字段。
6)将加密后的温度值利用AES秘钥进行解密。
//******************************************************************************
//name: GUA_AES.c
//introduce: AES驱动
//author:
//******************************************************************************
#include <ioCC2540.h>
#include "LL.h"
#include "GUA_AES.h"
/*********************内部变量************************/
static GUA_U8 sbGUA_AES_Key[16] = {0}; //AES的秘钥
/*********************内部函数************************/
static void GUA_Get_LocalMac(GUA_U8 *pGUA_LocalMac);
static void GUA_AES_GetKey(GUA_U8 *pGUA_AES_LocalMac, GUA_U8 *pGUA_AES_Key);
//******************************************************************************
//name: GUA_Get_LocalMac
//introduce: 获取本机mac
//parameter: pGUA_LocalMac:mac需要保存到的位置,需要6个字节大小
//return: none
//******************************************************************************
static void GUA_Get_LocalMac(GUA_U8 *pGUA_LocalMac)
{
pGUA_LocalMac[5] = *(GUA_U8 *)(0x780E); //直接指向指针内容
pGUA_LocalMac[4] = *(GUA_U8 *)(0x780F);
pGUA_LocalMac[3] = *(GUA_U8 *)(0x7810);
pGUA_LocalMac[2] = XREG(0x7811); //define函数直接读出数据
pGUA_LocalMac[1] = XREG(0x7812);
pGUA_LocalMac[0] = XREG(0x7813);
}
//******************************************************************************
//name: GUA_AES_GetKey
//introduce: 通过mac形成自定义秘钥
//parameter: pGUA_AES_LocalMac:mac地址
// pGUA_AES_Key:秘钥存放位置,需要16字节大小
//return: none
//author: 甜甜的大香瓜
//email: 897503845@qq
//QQ group: 香瓜BLE之CC2541(127442605)
//changetime: 2017.03.29
//******************************************************************************
static void GUA_AES_GetKey(GUA_U8 *pGUA_AES_LocalMac, GUA_U8 *pGUA_AES_Key)
{
pGUA_AES_Key[0] = 'G';
pGUA_AES_Key[1] = 'U';
pGUA_AES_Key[2] = 'A';
pGUA_AES_Key[3] = '#';
pGUA_AES_Key[4] = pGUA_AES_LocalMac[0];
pGUA_AES_Key[5] = pGUA_AES_LocalMac[1];
pGUA_AES_Key[6] = pGUA_AES_LocalMac[2];
pGUA_AES_Key[7] = pGUA_AES_LocalMac[3];
pGUA_AES_Key[8] = pGUA_AES_LocalMac[4];
pGUA_AES_Key[9] = pGUA_AES_LocalMac[5];
pGUA_AES_Key[10] = pGUA_AES_LocalMac[0] + pGUA_AES_LocalMac[1];
pGUA_AES_Key[11] = pGUA_AES_LocalMac[2] + pGUA_AES_LocalMac[3];
pGUA_AES_Key[12] = pGUA_AES_LocalMac[4] + pGUA_AES_LocalMac[5];
pGUA_AES_Key[13] = pGUA_AES_LocalMac[0] - pGUA_AES_LocalMac[1];
pGUA_AES_Key[14] = pGUA_AES_LocalMac[2] - pGUA_AES_LocalMac[3];
pGUA_AES_Key[15] = pGUA_AES_LocalMac[4] - pGUA_AES_LocalMac[5];
}
//******************************************************************************
//name: GUA_AES_Encrypted
//introduce: 加密16字节的数据
//parameter: pGUA_AES_Data:要加密的数据缓存区,必须16字节
// pGUA_AES_EncryptedData:加密后的数据缓存区,必须16字节
//return: none
//******************************************************************************
void GUA_AES_Encrypted(GUA_U8 *pGUA_AES_Data, GUA_U8 *pGUA_AES_EncryptedData)
{
LL_Encrypt(sbGUA_AES_Key, pGUA_AES_Data, pGUA_AES_EncryptedData);
}
//******************************************************************************
//name: GUA_AES_Deccrypted
//introduce: 解密16字节以内的数据
//parameter: pGUA_AES_EncryptedData:加密后的数据缓存区,必须16字节
// pGUA_AES_DeccryptedData:解密后的数据缓存区,必须16字节
//return: none
//author: 甜甜的大香瓜
//email: 897503845@qq
//QQ group: 香瓜BLE之CC2541(127442605)
//changetime: 2017.03.29
//******************************************************************************
void GUA_AES_Deccrypted(GUA_U8 *pGUA_AES_EncryptedData, GUA_U8 *pGUA_AES_DeccryptedData)
{
LL_EXT_Decrypt(sbGUA_AES_Key, pGUA_AES_EncryptedData, pGUA_AES_DeccryptedData);
}
//******************************************************************************
//name: GUA_AES_Init
//introduce: AES初始化
//parameter: none
//return: none
//******************************************************************************
void GUA_AES_Init(void)
{
GUA_U8 nbGUA_LocalMac[6] = {0};
//获取mac
GUA_Get_LocalMac(nbGUA_LocalMac);
//通过mac获取秘钥
GUA_AES_GetKey(nbGUA_LocalMac, sbGUA_AES_Key);
}
refer:
https://blog.csdn/zzfenglin/article/details/51729300
https://blog.csdn/feilusia/article/details/68070791
https://blog.csdn/feilusia/article/details/50085225
版权声明:本文标题:【IoT】加密与安全:CC254x 低功耗蓝牙 BLE 之 AES-128 加密算法 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dongtai/1727572492a1121386.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论