Merge pull request #9588 from Staars/MI32

MI_ESP32: use BEARSSL for decryption, revert to old TELEPERIOD style as default
This commit is contained in:
Theo Arends 2020-10-20 15:53:38 +02:00 committed by GitHub
commit 9a21dc864f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 109 additions and 68 deletions

View File

@ -14,6 +14,7 @@
extern "C" {
#endif
#ifndef ESP32
#ifndef ICACHE_RODATA_ATTR
#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
#endif
@ -29,6 +30,7 @@ extern "C" {
// Place each progmem object into its own named section, avoiding conflicts
#define PROGMEM __attribute__((section( "\".irom.text." __FILE__ "." __STRINGIZE(__LINE__) "." __STRINGIZE(__COUNTER__) "\"")))
#endif
#endif //ESP32
#ifndef PGM_P
#define PGM_P const char *
#endif

View File

@ -140,6 +140,24 @@ seeder_win32(const br_prng_class **ctx)
#endif
#if BR_USE_ESP8266_RAND
#ifdef ESP32
extern uint32_t esp_random(void);
static int
seeder_esp8266(const br_prng_class **ctx) //TODO: rename/refactor it to ESP32
{
uint32_t tmp[32 / sizeof(uint32_t)];
size_t i;
for (i=0; i<sizeof(tmp)/sizeof(tmp[0]); i++) {
tmp[i] = esp_random();
}
(*ctx)->update(ctx, tmp, sizeof tmp);
return 1;
}
#else
extern uint32_t phy_get_rand(void); // From the ESP8266 SDK
static int
@ -157,6 +175,7 @@ seeder_esp8266(const br_prng_class **ctx)
return 1;
}
#endif
#endif
/* see bearssl_rand.h */

View File

@ -33,7 +33,11 @@ br_chacha20_ct_run(const void *key,
uint32_t kw[8], ivw[3];
size_t u;
#ifdef ESP32
static const uint32_t CW[] = {
#else
static const uint32_t CW[] PROGMEM = {
#endif
0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
};

View File

@ -7,13 +7,19 @@
#define __ets__
#endif
#ifndef ESP32
#ifndef ICACHE_FLASH
#define ICACHE_FLASH
#endif
#ifndef ESP8266
#define ESP8266
#else
#ifndef PROGMEM
#define PROGMEM
#endif
#endif
// #ifndef ESP8266
// #define ESP8266
// #endif
#ifndef BR_SLOW_MUL15
#define BR_SLOW_MUL15 1 // shrinks EC code by 8.5k

View File

@ -132,7 +132,7 @@
* Set BR_LOMUL on platforms where it makes sense.
*/
#ifndef BR_LOMUL
#if BR_ARMEL_CORTEXM_GCC || (defined(ESP8266) && !defined(ESP8266M32))
#if BR_ARMEL_CORTEXM_GCC || ((defined(ESP8266) || defined(ESP32)) && !defined(ESP8266M32))
#define BR_LOMUL 1
#endif
#endif
@ -315,7 +315,7 @@
* Use ESP8266 hardware random generator when possible.
*/
#ifndef BR_USE_ESP8266_RAND
#if defined(ESP8266)
#if (defined(ESP8266) || defined(ESP32))
#define BR_USE_ESP8266_RAND 1
#endif
#endif
@ -433,7 +433,7 @@
*/
#ifndef BR_USE_UNIX_TIME
#if defined __unix__ || defined __linux__ || defined ESP8266 \
#if defined __unix__ || defined __linux__ || defined ESP8266 || defined ESP32\
|| defined _POSIX_SOURCE || defined _POSIX_C_SOURCE \
|| (defined __APPLE__ && defined __MACH__)
#define BR_USE_UNIX_TIME 1
@ -2568,7 +2568,7 @@ br_cpuid(uint32_t mask_eax, uint32_t mask_ebx,
#endif
#ifdef ESP8266
#if (defined(ESP8266)|| defined(ESP32))
#ifdef __cplusplus
extern "C" {

View File

@ -20,6 +20,8 @@
--------------------------------------------------------------------------------------------
Version yyyymmdd Action Description
--------------------------------------------------------------------------------------------
0.9.1.4 20201020 changed - use BearSSL for decryption, revert to old TELEPERIOD-cycle as default
-------
0.9.1.3 20200926 changed - Improve HA discovery, make key+MAC case insensitive
-------
0.9.1.3 20200916 changed - add ATC (custom FW for LYWSD03MMC), API adaption for NimBLE-Arduino 1.0.2
@ -47,7 +49,7 @@
#include <NimBLEDevice.h>
#include <vector>
#ifdef USE_MI_DECRYPTION
#include <mbedtls/ccm.h>
#include <t_bearssl.h>
#endif //USE_MI_DECRYPTION
void MI32scanEndedCB(NimBLEScanResults results);
@ -81,11 +83,12 @@ struct {
uint8_t sensor; // points to to the number 0...255
} state;
struct {
uint32_t allwaysAggregate:1;
uint32_t allwaysAggregate:1; // always show all known values of one sensor in brdigemode
uint32_t noSummary:1; // no sensor values at TELE-period
uint32_t minimalSummary:1; // DEPRECATED!!
uint32_t directBridgeMode:1; // send every received BLE-packet as a MQTT-message in real-time
uint32_t showRSSI:1;
uint32_t ignoreBogusBattery:1;
uint32_t noSummary:1;
uint32_t minimalSummary:1;
} option;
} MI32;
@ -465,77 +468,71 @@ void MI32KeyMACStringToBytes(char* _string,uint8_t _keyMAC[]) { //uppercase
* @brief Decrypts payload in place
*
* @param _buf - pointer to the buffer at position of PID
* @param _bufSize - buffersize (last position is last byte of TAG)
* @param _bufSize - buffersize (last position is two bytes behind last byte of TAG)
* @param _type - sensor type
* @return int - error code, 0 for success
*/
int MI32_decryptPacket(char *_buf, uint16_t _bufSize, uint32_t _type){
encPacket_t *packet = (encPacket_t*)_buf;
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("to decrypt: %02x %02x %02x %02x %02x %02x %02x %02x"),(uint8_t)_buf[0],(uint8_t)_buf[1],(uint8_t)_buf[2],(uint8_t)_buf[3],(uint8_t)_buf[4],(uint8_t)_buf[5],(uint8_t)_buf[6],(uint8_t)_buf[7]);
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR(" : %02x %02x %02x %02x %02x %02x %02x %02x"),(uint8_t)_buf[8],(uint8_t)_buf[9],(uint8_t)_buf[10],(uint8_t)_buf[11],(uint8_t)_buf[12],(uint8_t)_buf[13],(uint8_t)_buf[14],(uint8_t)_buf[15]);
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR(" : %02x %02x %02x %02x %02x %02x %02x %02x"),(uint8_t)_buf[16],(uint8_t)_buf[17],(uint8_t)_buf[18],(uint8_t)_buf[19],(uint8_t)_buf[20],(uint8_t)_buf[21],(uint8_t)_buf[22],(uint8_t)_buf[23]);
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("as packet: MAC: %02x %02x %02x %02x %02x %02x"), packet->MAC[0], packet->MAC[1], packet->MAC[2], packet->MAC[3], packet->MAC[4], packet->MAC[5]);
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Decrypt Size of Buffer: %u"), _bufSize);
uint8_t payload[8];
size_t data_len = _bufSize - 9 - 4 - 3 - 1 - 1 ; // _bufsize - header - tag - ext.counter - RSSI - spare(?)
int ret = 0;
unsigned char output[10] = {0};
uint8_t nonce[12];
uint8_t tag[4 ];
uint32_t tag;
const unsigned char authData[1] = {0x11};
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Decrypt Size of Buffer: %u, payload length: %u"), _bufSize, data_len);
// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*)_buf, _bufSize);
// nonce: device MAC, device type, frame cnt, ext. cnt
for (uint32_t i = 0; i<6; i++){
nonce[i] = packet->MAC[i];
}
memcpy((uint8_t*)&nonce+6,(uint8_t*)&packet->PID,2);
nonce[8] = packet->frameCnt;
memcpy((uint8_t*)&nonce+9,(char*)&_buf[_bufSize-9],3);
memcpy((uint8_t*)&nonce+9,(uint8_t*)&_buf[_bufSize-9],3);
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("nonceCnt1 and 2: %02x %02x %02x"),nonce[9],nonce[10],nonce[11]);
memcpy((uint8_t*)&tag,(char*)&_buf[_bufSize-6],4);
memcpy((uint8_t*)&tag,(uint8_t*)&_buf[_bufSize-6],4);
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("tag: %02x %02x %02x %02x"),tag[0],tag[1],tag[2],tag[3]);
MI32_ReverseMAC(packet->MAC);
uint8_t _bindkey[16] = {0x0};
bool foundNoKey = true;
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MI32: search key for MAC: %02x %02x %02x %02x %02x %02x"), packet->MAC[0], packet->MAC[1], packet->MAC[2], packet->MAC[3], packet->MAC[4], packet->MAC[5]);
for(uint32_t i=0; i<MIBLEbindKeys.size(); i++){
if(memcmp(packet->MAC,MIBLEbindKeys[i].MAC,sizeof(packet->MAC))==0){
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("have key"));
memcpy(_bindkey,MIBLEbindKeys[i].key,sizeof(_bindkey));
}
else{
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mac in packet: %02x %02x %02x %02x %02x %02x"), packet->MAC[0], packet->MAC[1], packet->MAC[2], packet->MAC[3], packet->MAC[4], packet->MAC[5]);
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mac in vector: %02x %02x %02x %02x %02x %02x"), MIBLEbindKeys[i].MAC[0], MIBLEbindKeys[i].MAC[1], MIBLEbindKeys[i].MAC[2], MIBLEbindKeys[i].MAC[3], MIBLEbindKeys[i].MAC[4], MIBLEbindKeys[i].MAC[5]);
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MI32: decryption Key found"));
foundNoKey = false;
break;
}
}
if(foundNoKey){
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MI32: no Key found !!"));
return -2;
}
// init
mbedtls_ccm_context ctx;
mbedtls_ccm_init(&ctx);
// set bind key
ret = mbedtls_ccm_setkey(&ctx,
MBEDTLS_CIPHER_ID_AES,
_bindkey,
16 * 8 //bits
);
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("set key: %i, MAC: %02x %02x %02x %02x %02x %02x"),ret, packet->MAC[0], packet->MAC[1], packet->MAC[2], packet->MAC[3], packet->MAC[4], packet->MAC[5]);
br_aes_small_ctrcbc_keys keyCtx;
br_aes_small_ctrcbc_init(&keyCtx, _bindkey, sizeof(_bindkey));
/*int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len )
*/
ret = mbedtls_ccm_auth_decrypt(&ctx,_bufSize-18,
(const unsigned char*)&nonce, sizeof(nonce),
authData, sizeof(authData),
(const unsigned char*)packet->payload, output,
tag,sizeof(tag));
br_ccm_context ctx;
br_ccm_init(&ctx, &keyCtx.vtable);
br_ccm_reset(&ctx, nonce, sizeof(nonce), sizeof(authData), data_len, sizeof(tag));
br_ccm_aad_inject(&ctx, authData, sizeof(authData));
br_ccm_flip(&ctx);
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Decrypted %i: %02x %02x %02x %02x %02x %02x %02x"), ret, output[0],output[1],output[2],output[3],output[4],output[5],output[6]);
// put decrypted data in place
memcpy((uint8_t*)(packet->payload)+1,output,_bufSize-18);
// clean up
mbedtls_ccm_free(&ctx);
return ret;
memcpy(payload,packet->payload,data_len); //we want to be sure about 4-byte alignement
br_ccm_run(&ctx, 0, payload, data_len);
memcpy((uint8_t*)packet->payload+1,payload,data_len); //back to the packet
// br_ccm_get_tag(&ctx, &checkTag);
ret = br_ccm_check_tag(&ctx, &tag);
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("packetTag: %08x"),tag);
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("computedTag: %08x"),checkTag);
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MI32: Err:%i, Decrypted : %02x %02x %02x %02x %02x "), ret, packet->payload[1],packet->payload[2],packet->payload[3],packet->payload[4],packet->payload[5]);
return ret-1;
}
#endif // USE_MI_DECRYPTION
@ -651,6 +648,9 @@ void MI32triggerTele(void){
\*********************************************************************************************/
void MI32Init(void) {
MIBLEsensors.reserve(10);
MIBLEbindKeys.reserve(10);
MI32.mode.init = false;
if (!MI32.mode.init) {
NimBLEDevice::init("");
@ -661,10 +661,11 @@ void MI32Init(void) {
//test section for options
MI32.option.allwaysAggregate = 1;
MI32.option.noSummary = 0;
MI32.option.minimalSummary = 0;
MI32.option.directBridgeMode = 0;
MI32.option.showRSSI = 1;
MI32.option.ignoreBogusBattery = 1; // from advertisements
MI32.option.noSummary = 0;
MI32.option.minimalSummary = 1;
MI32StartScanTask(); // Let's get started !!
}
@ -1125,10 +1126,12 @@ void MI32parseMiBeacon(char * _buf, uint32_t _slot, uint16_t _bufSize){
MIBLEsensors[_slot].lastCnt = _beacon.counter;
#ifdef USE_MI_DECRYPTION
int decryptRet = 0;
switch(MIBLEsensors[_slot].type){
case LYWSD03MMC: case MHOC401:
if (_beacon.frame == 0x5858){
int decryptRet = MI32_decryptPacket((char*)&_beacon.productID,_bufSize, LYWSD03MMC); //start with PID
decryptRet = MI32_decryptPacket((char*)&_beacon.productID,_bufSize, LYWSD03MMC); //start with PID
// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*)&_beacon.productID,_bufSize);
}
break;
case MJYD2S:
@ -1138,9 +1141,10 @@ void MI32parseMiBeacon(char * _buf, uint32_t _slot, uint16_t _bufSize){
memcpy((uint8_t*)&_beacon.MAC,MIBLEsensors[_slot].MAC,6); // now insert the real MAC from our internal vector
_bufSize+=6; // the packet has grown
MI32_ReverseMAC(_beacon.MAC); // payload MAC is always reversed
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MJYD2S: special packet"));
}
if (_beacon.frame != 0x5910){
int decryptRet = MI32_decryptPacket((char*)&_beacon.productID,_bufSize,MJYD2S); //start with PID
decryptRet = MI32_decryptPacket((char*)&_beacon.productID,_bufSize,MJYD2S); //start with PID
}
else{
// This seems to be some kind of wake-up packet only, as it shows up before all kinds of messages, not only motion
@ -1156,22 +1160,22 @@ void MI32parseMiBeacon(char * _buf, uint32_t _slot, uint16_t _bufSize){
}
break;
}
#endif //USE_MI_DECRYPTION
if (MIBLEsensors[_slot].type==NLIGHT){
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MiBeacon type:%02x: %02x %02x %02x %02x %02x %02x %02x %02x"),_beacon.type, (uint8_t)_buf[0],(uint8_t)_buf[1],(uint8_t)_buf[2],(uint8_t)_buf[3],(uint8_t)_buf[4],(uint8_t)_buf[5],(uint8_t)_buf[6],(uint8_t)_buf[7]);
AddLog_P2(LOG_LEVEL_DEBUG,PSTR(" type:%02x: %02x %02x %02x %02x %02x %02x %02x %02x"),_beacon.type, (uint8_t)_buf[8],(uint8_t)_buf[9],(uint8_t)_buf[10],(uint8_t)_buf[11],(uint8_t)_buf[12],(uint8_t)_buf[13],(uint8_t)_buf[14],(uint8_t)_buf[15]);
if(decryptRet!=0){
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MI32: decryption failed with error: %d"),decryptRet);
return;
}
#endif //USE_MI_DECRYPTION
if(MIBLEsensors[_slot].type==6){
DEBUG_SENSOR_LOG(PSTR("CGD1 no support for MiBeacon, type %u"),MIBLEsensors[_slot].type);
return;
}
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s at slot %u"), kMI32DeviceType[MIBLEsensors[_slot].type-1],_slot);
AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s at slot %u with payload type: %02x"), kMI32DeviceType[MIBLEsensors[_slot].type-1],_slot,_beacon.type);
switch(_beacon.type){
case 0x01:
MIBLEsensors[_slot].Btn=_beacon.Btn.num + (_beacon.Btn.longPress/2)*6;
MIBLEsensors[_slot].eventType.Btn = 1;
MI32.mode.shallTriggerTele = 1;
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode 1: U16: %u Button"), MIBLEsensors[_slot].Btn );
break;
case 0x04:
@ -1247,12 +1251,14 @@ if (MIBLEsensors[_slot].type==NLIGHT){
MIBLEsensors[_slot].events++;
MIBLEsensors[_slot].lux = _beacon.lux;
MIBLEsensors[_slot].eventType.lux = 1;
MIBLEsensors[_slot].NMT = 0;
MIBLEsensors[_slot].NMT = 0;
MI32.mode.shallTriggerTele = 1;
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("PIR: primary"),MIBLEsensors[_slot].lux );
break;
case 0x17:
MIBLEsensors[_slot].NMT = _beacon.NMT;
MIBLEsensors[_slot].eventType.NMT = 1;
MI32.mode.shallTriggerTele = 1;
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode 17: NMT: %u seconds"), _beacon.NMT);
break;
#endif //USE_MI_DECRYPTION
@ -1262,13 +1268,17 @@ if (MIBLEsensors[_slot].type==NLIGHT){
MIBLEsensors[_slot].events++;
MIBLEsensors[_slot].NMT = 0;
MIBLEsensors[_slot].lastTime = millis();
MI32.mode.shallTriggerTele = 1;
// AddLog_P2(LOG_LEVEL_DEBUG,PSTR("PIR: primary"),MIBLEsensors[_slot].lux );
}
else{
AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*)_buf,_bufSize);
}
break;
}
if(MIBLEsensors[_slot].eventType.raw == 0) return;
MIBLEsensors[_slot].shallSendMQTT = 1;
MI32.mode.shallTriggerTele = 1;
if(MI32.option.directBridgeMode) MI32.mode.shallTriggerTele = 1;
}
void MI32ParseATCPacket(char * _buf, uint32_t length, uint8_t addr[6], int rssi){
@ -1286,7 +1296,7 @@ void MI32ParseATCPacket(char * _buf, uint32_t length, uint8_t addr[6], int rssi)
MIBLEsensors[_slot].eventType.bat = 1;
MIBLEsensors[_slot].shallSendMQTT = 1;
MI32.mode.shallTriggerTele = 1;
if(MI32.option.directBridgeMode) MI32.mode.shallTriggerTele = 1;
}
@ -1328,7 +1338,7 @@ void MI32parseCGD1Packet(char * _buf, uint32_t length, uint8_t addr[6], int rssi
}
if(MIBLEsensors[_slot].eventType.raw == 0) return;
MIBLEsensors[_slot].shallSendMQTT = 1;
MI32.mode.shallTriggerTele = 1;
if(MI32.option.directBridgeMode) MI32.mode.shallTriggerTele = 1;
}
void MI32ParseResponse(char *buf, uint16_t bufsize, uint8_t addr[6], int rssi) {