Files
fastbee/sdk/Arduino/WumeiArduino/Auth.cpp
2023-03-24 14:30:22 +08:00

178 lines
5.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*********************************************************************
* function 设备认证
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#include "Auth.h"
/*
* 连接MQTT加密认证
*/
void connectMqtt()
{
printMsg("连接Mqtt服务器...");
mqttClient.setClient(wifiClient);
mqttClient.setServer(mqttHost, mqttPort);
mqttClient.setBufferSize(1024);
mqttClient.setKeepAlive(5);
// 设置Mqtt回调函数
mqttClient.setCallback(mqttCallback);
// 生成mqtt加密密码
String aesPassword = generationAESPwd();
// 连接 设备mqtt客户端Id格式为认证类型(E=加密、S=简单) & 设备编号 & 产品ID & 用户ID
String clientId = "E&" + (String)deviceNum + "&" + (String)productId + "&" + (String)userId;
printMsg("客户端ID" + clientId);
bool connectResult = mqttClient.connect(clientId.c_str(), mqttUserName, aesPassword.c_str());
if (connectResult)
{
printMsg("连接Mqtt成功");
// 订阅系统主题
subscribeTopic();
// 发布设备信息,设备上电都需要发布一次
publishInfo();
}
else
{
printMsg("连接失败, rc=");
Serial.print(mqttClient.state());
}
}
/*
* 生成加密密码
*/
String generationAESPwd()
{
// 获取NTP时间
String jsonTime = getTime();
StaticJsonDocument<128> doc;
DeserializationError error = deserializeJson(doc, jsonTime);
if (error)
{
printMsg("Json解析失败");
Serial.print(error.f_str());
return "";
}
// 获取NTP时间=(设备发送消息时间 + 服务器接收消息时间 + 服务器发送消息时间 - 设备接收时间 最后除于2
float deviceSendTime = doc["deviceSendTime"];
float serverSendTime = doc["serverSendTime"];
float serverRecvTime = doc["serverRecvTime"];
float deviceRecvTime = millis();
float now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2;
// 过期时间 = 当前时间 + 1小时
float expireTime = now + 1 * 60 * 60 * 1000;
// 加密认证密码格式为mqtt密码 & 过期时间 & 授权码(可选),如果产品启用了授权码就必须加上
String password = "";
if (authCode == "")
{
password = (String)mqttPwd + "&" + String(expireTime, 0);
}
else
{
password = (String)mqttPwd + "&" + String(expireTime, 0) + "&" + authCode;
}
// 密码加密
printMsg("密码(未加密):" + password);
String encryptPassword = encrypt(password, mqttSecret, wumei_iv);
printMsg("密码(已加密)" + encryptPassword);
return encryptPassword;
}
/*
* 通过HTTP获取NTP时间
*/
String getTime()
{
while (WiFi.status() == WL_CONNECTED)
{
HTTPClient http;
printMsg("获取时间...");
if (http.begin(wifiClient, (ntpServer + (String)millis()).c_str()))
{
// 发送请求
int httpCode = http.GET();
if (httpCode > 0)
{
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY)
{
printMsg("获取时间成功data:");
Serial.print(http.getString());
return http.getString();
}
}
else
{
printMsg("获取时间失败error:");
Serial.printf(http.errorToString(httpCode).c_str());
}
http.end();
}
else
{
printMsg("连接Http失败");
}
delay(500);
}
return "";
}
/*
* AES加密 (AES-CBC-128-pkcs5padding)
*/
String encrypt(String plain_data, char *wumei_key, char *wumei_iv)
{
int i;
// pkcs7padding填充 Block Size : 16
int len = plain_data.length();
int n_blocks = len / 16 + 1;
uint8_t n_padding = n_blocks * 16 - len;
uint8_t data[n_blocks * 16];
memcpy(data, plain_data.c_str(), len);
for (i = len; i < n_blocks * 16; i++)
{
data[i] = n_padding;
}
uint8_t key[16], iv[16];
memcpy(key, wumei_key, 16);
memcpy(iv, wumei_iv, 16);
// 加密
br_aes_big_cbcenc_keys encCtx;
br_aes_big_cbcenc_init(&encCtx, key, 16);
br_aes_big_cbcenc_run(&encCtx, iv, data, n_blocks * 16);
// Base64编码
len = n_blocks * 16;
char encoded_data[base64_enc_len(len)];
base64_encode(encoded_data, (char *)data, len);
return String(encoded_data);
}
/*
* AES解密 (AES-CBC-128-pkcs5padding)
*/
String decrypt(String encoded_data_str, char *wumei_key, char *wumei_iv)
{
int input_len = encoded_data_str.length();
char *encoded_data = const_cast<char *>(encoded_data_str.c_str());
int len = base64_dec_len(encoded_data, input_len);
uint8_t data[len];
base64_decode((char *)data, encoded_data, input_len);
uint8_t key[16], iv[16];
memcpy(key, wumei_key, 16);
memcpy(iv, wumei_iv, 16);
int n_blocks = len / 16;
br_aes_big_cbcdec_keys decCtx;
br_aes_big_cbcdec_init(&decCtx, key, 16);
br_aes_big_cbcdec_run(&decCtx, iv, data, n_blocks * 16);
// PKCS#7 Padding 填充
uint8_t n_padding = data[n_blocks * 16 - 1];
len = n_blocks * 16 - n_padding;
char plain_data[len + 1];
memcpy(plain_data, data, len);
plain_data[len] = '\0';
return String(plain_data);
}