目录结构:
1.项目目标及意义
2.硬件准备和硬件驱动实现
3.软件和服务器实现
4.通信安全设计
5.总结
视频如下:
1.项目目标及意义
- 基于TencentOS Tiny系统,实现门禁与考勤的二合一设备开发,
- 与设备交互方式多样,蓝牙,wifi,人脸等多方式用来开门和考勤
- 采用加密算法与服务器通讯,将所有原始数据存储在设备内部,服务器仅能获得秘文和部分明文,解密后用于验证用户身份。
- 加密算法,保护了用户个人隐私和设备OT安全
- 关键个人隐私数据保存在本地避免用户对于个人隐私泄露的焦虑。
项目目标:
识别功能: | 蓝牙开发,WIFI开发,人脸识别开发, |
---|---|
网络功能: | 网络连接,加密通信 |
本地存储功能: | 设备端保护用户个人信息,服务器只能收到密文或部分明文 |
安全功能: | 加密算法,用户隐私保护 |
2.硬件准备和硬件驱动实现
包括蓝牙模块(TB03F)、wifi模块(esp8266)、门禁控制器(电插锁 继电器),RT1062开发板(带摄像头),
2.1蓝牙模块(TB03F)
用于RT1062开发板和手机微信小程序的直接通信,传输开门指令。
代码使用了安信可提供的模块透传代码,即蓝牙接收到的数据直接发送给RT1062开发板。数据传输逻辑如下图所示
模块烧录软件TB-TOOL和透传固件从安信可官网获取
https://docs.ai-thinker.com/blue_tooth
2.2 Wi-Fi
Wi-Fi模块(esp8266)
用途:Wi-Fi模块与路由器连接,实现RT1062开发板上云,实现网络连接,方便后续通过微信小程序与服务器控制开发板。
Wi-Fi模块如下图所示:
Wi-Fi模块开发方式:
通过VSCODE和PlatformIO插件的方式,实现了对Wi-Fi模块二次开发,
PlatformIO的框架地址:
https://github.com/platformio
PlatformIO的下载安装方式:
在VSCODE的插件市场下载即可。
基础的使用教程查看官网:
https://docs.platformio.org/en/latest/
Wi-Fi模块开发功能
在Wi-Fi模块上实现MQTT协议,和透传功能,具体流程如下图所示
Wi-Fi模块主要代码
代码语言:c复制/*
Basic ESP8266 MQTT example
This sketch demonstrates the capabilities of the pubsub library in combination
with the ESP8266 board/library.
It connects to an MQTT server then:
- publishes "hello world" to the topic "outTopic" every two seconds
- subscribes to the topic "inTopic", printing out any messages
it receives. NB - it assumes the received payloads are strings not binary
- If the first character of the topic "inTopic" is an 1, switch ON the ESP Led,
else switch it off
It will reconnect to the server if the connection is lost using a blocking
reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
achieve the same result without blocking the main loop.
To install the ESP8266 board, (using Arduino 1.6.4 ):
- Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
http://arduino.esp8266.com/stable/package_esp8266com_index.json
- Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
- Select your ESP8266 in "Tools -> Board"
*/
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
//mqtt连接历程
// const char *ssid = "babybed";
// const char *password = "babybed123";
const char *ssid = "access_control";
const char *password = "access123!@#";
const char *mqtt_server = "118.178.180.56";
// const char *pub_topic = "/babybed_status";
// const char *sub_topic = "/babybed_command";
const char *pub_topic = "/Access_control_system_device";
const char *sub_topic = "/Access_control_system_command";
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (80)
char msg[MSG_BUFFER_SIZE];
int value = 0;
#define LED_BUILTIN 0
void setup_wifi()
{
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
//randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char *topic, byte *payload, int length)
{
// Serial.print("Message arrived [");
// Serial.print(sub_topic);
// Serial.print("] ");
for (int i = 0; i < length; i )
{
Serial.print((char)payload[i]);
}
Serial.println();
}
void reconnect()
{
// Loop until we're reconnected
while (!client.connected())
{
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId = String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str()))
{
Serial.println("connected");
// Once connected, publish an announcement...
client.publish(pub_topic, "hello world");
// ... and resubscribe
client.subscribe(sub_topic);
}
else
{
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup()
{
//pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
//client.subscribe("/test1");此处订阅没用,因为未连接mqtt服务器。
client.setCallback(callback);
//test
}
String RXString = "";
int count = 0;
int flag = 0;
char c[80]="";
void loop()
{
if (!client.connected())
{
reconnect();
}
client.loop();
while (Serial.available() > 0) //判断
{
RXString = char(Serial.read()); //https://www.cnblogs.com/anandexuechengzhangzhilu/p/10719546.html
delay(2);
wdt_reset();//feed watchdog https://www.cnblogs.com/Mysterious/p/4817054.html
}
if (RXString.length() > 0)
{
//Serial.println(RXString); //打印接收到的字符
strcpy(c,RXString.c_str());//https://blog.csdn.net/dagjj/article/details/108185706
//snprintf(msg, MSG_BUFFER_SIZE, "head%s", c); //client.publish的payload不能为string,通过snprintf处理即可。添加了报头报尾
snprintf(msg, MSG_BUFFER_SIZE, "%s", c);
client.publish(pub_topic, msg);
RXString = "";
wdt_reset();
}
}
通过上述代码,实现了80位字节大小以内的数据透传任务。
代码
代码语言:javascript复制#defineMSG_BUFFER_SIZE(80)
用来控制数据透传的长度,设置为变量可以节约空间,可以根据数据和指令长度灵活修改。
2.3 RT1062开发板(带摄像头)
- 核心板采用的RT1062处理器属于i.MX RT 系列 MCU,是由 NXP 推出的跨界处理器,既具备高频率(最高主频600M)、高处理性能,也具备中断响应迅速、实时性高的特点。
- 1M RAM 16M SDRAM 64MB qspi flash 128MB spi flash。
开发方式使用MCUXpressoIDE,按照教程移植了TencentOS Tiny内核。
项目工程代码如下
https://share.weiyun.com/P3PhAyxI
使用了SM4.c文件对来自蓝牙和串口的数据加密
SM4代码如下
代码语言:javascript复制#include "string.h"
#include <stdio.h>
#include <stdlib.h>
#include "sm4.h"
#define u32 unsigned long
const u32 TBL_SYS_PARAMS[4] = {
0xa3b1bac6,
0x56aa3350,
0x677d9197,
0xb27022dc};
/******************************??????CK???****************************************/
const u32 TBL_FIX_PARAMS[32] = {
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279};
/******************************SBox????****************************************/
const u8 TBL_SBOX[256] = {
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48};
//4???????????long?
void four_uCh2uLong(u8 *in, u32 *out)
{
int i = 0;
*out = 0;
for (i = 0; i < 4; i )
*out = ((u32)in[i] << (24 - i * 8)) ^ *out;
}
//???long??4???????
void uLong2four_uCh(u32 in, u8 *out)
{
int i = 0;
//?32?unsigned long??????
for (i = 0; i < 4; i )
*(out i) = (u32)(in >> (24 - i * 8));
}
//??,?????????
u32 move(u32 data, int length)
{
u32 result = 0;
result = (data << length) ^ (data >> (32 - length));
return result;
}
//??????,???Sbox???????,??????L???L'
u32 func_key(u32 input)
{
int i = 0;
u32 ulTmp = 0;
u8 ucIndexList[4] = {0};
u8 ucSboxValueList[4] = {0};
uLong2four_uCh(input, ucIndexList);
for (i = 0; i < 4; i )
{
ucSboxValueList[i] = TBL_SBOX[ucIndexList[i]];
}
four_uCh2uLong(ucSboxValueList, &ulTmp);
ulTmp = ulTmp ^ move(ulTmp, 13) ^ move(ulTmp, 23);
return ulTmp;
}
//?????????,???Sbox???????,???????L
u32 func_data(u32 input)
{
int i = 0;
u32 ulTmp = 0;
u8 ucIndexList[4] = {0};
u8 ucSboxValueList[4] = {0};
uLong2four_uCh(input, ucIndexList);
for (i = 0; i < 4; i )
{
ucSboxValueList[i] = TBL_SBOX[ucIndexList[i]];
}
four_uCh2uLong(ucSboxValueList, &ulTmp);
ulTmp = ulTmp ^ move(ulTmp, 2) ^ move(ulTmp, 10) ^ move(ulTmp, 18) ^ move(ulTmp, 24);
return ulTmp;
}
//????(??????????,16???????,?????0??16??????)
//len:????(??????) key:??(16??) input:??????? output:???????
void encode_fun(u8 len, u8 *key, u8 *input, u8 *output)
{
int i = 0, j = 0;
u8 *p = (u8 *)malloc(50); //????50?????
u32 ulKeyTmpList[4] = {0}; //?????u32??
u32 ulKeyList[36] = {0}; //?????????????FK????????
u32 ulDataList[36] = {0}; //????????
/***************************???????********************************************/
four_uCh2uLong(key, &(ulKeyTmpList[0]));
four_uCh2uLong(key 4, &(ulKeyTmpList[1]));
four_uCh2uLong(key 8, &(ulKeyTmpList[2]));
four_uCh2uLong(key 12, &(ulKeyTmpList[3]));
ulKeyList[0] = ulKeyTmpList[0] ^ TBL_SYS_PARAMS[0];
ulKeyList[1] = ulKeyTmpList[1] ^ TBL_SYS_PARAMS[1];
ulKeyList[2] = ulKeyTmpList[2] ^ TBL_SYS_PARAMS[2];
ulKeyList[3] = ulKeyTmpList[3] ^ TBL_SYS_PARAMS[3];
for (i = 0; i < 32; i ) //32???????
{
//5-36?32????
ulKeyList[i 4] = ulKeyList[i] ^ func_key(ulKeyList[i 1] ^ ulKeyList[i 2] ^ ulKeyList[i 3] ^ TBL_FIX_PARAMS[i]);
}
/***********************************??32?32???????**********************************/
for (i = 0; i < len; i ) //????????p???
*(p i) = *(input i);
for (i = 0; i < 16 - len % 16; i ) //???16??0??16????
*(p len i) = 0;
for (j = 0; j < len / 16 ((len % 16) ? 1 : 0); j ) //??????,?????????(????????16???????,????,??16???????,17???0?32?????????,????)
{
/*????????*/
four_uCh2uLong(p 16 * j, &(ulDataList[0]));
four_uCh2uLong(p 16 * j 4, &(ulDataList[1]));
four_uCh2uLong(p 16 * j 8, &(ulDataList[2]));
four_uCh2uLong(p 16 * j 12, &(ulDataList[3]));
//??
for (i = 0; i < 32; i )
{
ulDataList[i 4] = ulDataList[i] ^ func_data(ulDataList[i 1] ^ ulDataList[i 2] ^ ulDataList[i 3] ^ ulKeyList[i 4]);
}
/*????????*/
uLong2four_uCh(ulDataList[35], output 16 * j);
uLong2four_uCh(ulDataList[34], output 16 * j 4);
uLong2four_uCh(ulDataList[33], output 16 * j 8);
uLong2four_uCh(ulDataList[32], output 16 * j 12);
}
free(p);
}
//????(?????????,???????????,???????????)
//len:???? key:?? input:???????? output:????????
void decode_fun(u8 len, u8 *key, u8 *input, u8 *output)
{
int i = 0, j = 0;
u32 ulKeyTmpList[4] = {0}; //?????u32??
u32 ulKeyList[36] = {0}; //?????????????FK????????
u32 ulDataList[36] = {0}; //????????
/*???????*/
four_uCh2uLong(key, &(ulKeyTmpList[0]));
four_uCh2uLong(key 4, &(ulKeyTmpList[1]));
four_uCh2uLong(key 8, &(ulKeyTmpList[2]));
four_uCh2uLong(key 12, &(ulKeyTmpList[3]));
ulKeyList[0] = ulKeyTmpList[0] ^ TBL_SYS_PARAMS[0];
ulKeyList[1] = ulKeyTmpList[1] ^ TBL_SYS_PARAMS[1];
ulKeyList[2] = ulKeyTmpList[2] ^ TBL_SYS_PARAMS[2];
ulKeyList[3] = ulKeyTmpList[3] ^ TBL_SYS_PARAMS[3];
for (i = 0; i < 32; i ) //32???????
{
//5-36?32????
ulKeyList[i 4] = ulKeyList[i] ^ func_key(ulKeyList[i 1] ^ ulKeyList[i 2] ^ ulKeyList[i 3] ^ TBL_FIX_PARAMS[i]);
}
/*??32?32???????*/
for (j = 0; j < len / 16; j ) //??????,?????????
{
/*????????*/
four_uCh2uLong(input 16 * j, &(ulDataList[0]));
four_uCh2uLong(input 16 * j 4, &(ulDataList[1]));
four_uCh2uLong(input 16 * j 8, &(ulDataList[2]));
four_uCh2uLong(input 16 * j 12, &(ulDataList[3]));
//??
for (i = 0; i < 32; i )
{
ulDataList[i 4] = ulDataList[i] ^ func_data(ulDataList[i 1] ^ ulDataList[i 2] ^ ulDataList[i 3] ^ ulKeyList[35 - i]); //??????????????????
}
/*????????*/
uLong2four_uCh(ulDataList[35], output 16 * j);
uLong2four_uCh(ulDataList[34], output 16 * j 4);
uLong2four_uCh(ulDataList[33], output 16 * j 8);
uLong2four_uCh(ulDataList[32], output 16 * j 12);
}
}
//????????16????
void print_hex(u8 *data, int len)
{
int i = 0;
char alTmp[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
for (i = 0; i < len; i )
{
printf("%c", alTmp[data[i] / 16]);
printf("%c", alTmp[data[i] % 16]);
putchar(' ');
}
putchar('n');
}
char HexToChar(uint8_t hex)
{
char ch = 0;
if (hex > 0x0f)
return -1;
if ((hex >= 0) && (hex <= 0x09))
ch = hex '0';
else if ((hex >= 0x0a) && (hex <= 0x0f))
ch = (hex & 0x0f) ('a' - 0x0a);
return ch;
}
void ArryToString(uint8_t *data, uint8_t data_len, uint8_t *string)
{
uint8_t *p_string = string;
for (uint8_t i = 0; i < data_len; i )
{
*(p_string ) = HexToChar(data[i] >> 4);
*(p_string ) = HexToChar(data[i] & 0x0f);
}
*p_string = '