Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP 8266; Mbedtls Libary #1

Closed
doli08 opened this issue Nov 4, 2022 · 19 comments
Closed

ESP 8266; Mbedtls Libary #1

doli08 opened this issue Nov 4, 2022 · 19 comments

Comments

@doli08
Copy link

doli08 commented Nov 4, 2022

first of all thank you for effort pushing this project to GH (!)

I am struggling loading the project to a Lolin Wemos D1 Mini (ESP 8266).
I cannot activate the Mbedtls libary in the arduino IDE.

what I have tried (but not solved):

  • find the libary in the libary manager (not found the correct one, just "Seeed_Arduino_mbedtls"
  • install the mbedtls lib from github via zip file -> faulted
  • copy the unzipped folders to: install folder or to the project folder

error msg:

C:~~\SmartMeterSchnittstelle\esp32-smartmeter-reader-main\esp32-smartmeter-reader-main\esp32-smartmeter-reader\esp32-smartmeter-reader.ino:2:10: fatal error: mbedtls/aes.h: No such file or directory
2 | #include "mbedtls/aes.h" //=> not found :(
| ^~~~~~~~~~~~~~~
compilation terminated.

exit status 1

Compilation error: mbedtls/aes.h: No such file or directory

@aldadic
Copy link
Owner

aldadic commented Nov 5, 2022

Hi @doli08!

I have never questioned how I got the mbedtls library in the Arduino IDE. It was simply available when I needed it, which is why I thought that this might be always the case. But it seems I was wrong on this assumption 😅. After a bit of googling I found out that the library was probably installed as a part of the Arduino core for the ESP32 (see here). Therefore I would suggest that you install the ESP32 board in your Arduino IDE by adding

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

as "Additional Board Manager URL".

@leecher1337
Copy link

leecher1337 commented Dec 20, 2022

Otherwise, crypto library should also work, I guess..

#include <AES.h>
#include <CTR.h>

    // Initialisation Vector zusammenbaun:
    uint8_t iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02};
    // 8 Bytes von 13 (=system-title)
    memcpy(&iv[0], fullData->sys_t, 8);
    // 4 Bytes von 23 (=nonce). INFO: Nonce wird bei jedem Paket um 1 größer (=increment counter)
    memcpy(&iv[8], &fullData->inv_cnt, 4);

    // Entschlüsseln
    uint8_t plainText[sizeof(fullData->data)];
    CTR<AES128> ctr;
    ctr.setKey(Key, sizeof(Key));
    ctr.setIV(iv, sizeof(iv));
    ctr.decrypt(plainText, (unsigned char*)&fullData->data, sizeof(fullData->data));

image

@aldadic
Copy link
Owner

aldadic commented Dec 26, 2022

Thanks a lot for sharing @leecher1337! I was unfamiliar with that library. As soon as i have time i will try your code with an ESP8266 and probably update the repository accordingly.

@curtosvienna
Copy link

first of all thank you for effort pushing this project to GH (!)

I am struggling loading the project to a Lolin Wemos D1 Mini (ESP 8266). I cannot activate the Mbedtls libary in the arduino IDE.

what I have tried (but not solved):

  • find the libary in the libary manager (not found the correct one, just "Seeed_Arduino_mbedtls"
  • install the mbedtls lib from github via zip file -> faulted
  • copy the unzipped folders to: install folder or to the project folder

error msg:

C:~~\SmartMeterSchnittstelle\esp32-smartmeter-reader-main\esp32-smartmeter-reader-main\esp32-smartmeter-reader\esp32-smartmeter-reader.ino:2:10: fatal error: mbedtls/aes.h: No such file or directory 2 | #include "mbedtls/aes.h" //=> not found :( | ^~~~~~~~~~~~~~~ compilation terminated.

exit status 1

Compilation error: mbedtls/aes.h: No such file or directory

Hallo @doli08 !

habe hier selbes Problem.
Hast du eine Lösung gefunden.?
stehe hier komplett an, komme nicht weiter

@leecher1337
Copy link

leecher1337 commented Feb 10, 2023

Hallo, ich hab meine eigene Variante von dem Code geschrieben. Soll ich sie auf Github stellen?
Ich konnte sie nur noch nicht verifizieren, weil der Netzbetreiber mir wahrscheinlich den falschen Schlüssel geschickt hat o.Ä., jedenfalls kann ich die Pakete von meinem Smartmeter nicht entschlüsseln, aber in meinem Code selbst hab ich keinen Fehler gefunden.
Eigentlich wollte ich den erst online stellen, wenn ich ihn verifiziert habe, ob er auch funktioniert, aber das kann bei dem Netzbetreiber noch Monate dauern, bis der mal irgendwas macht, wenn er überhaupt was macht :(

@curtosvienna
Copy link

Hallo @leecher1337,

ich hätte nichts dagegen. ;-) Dann könnte ich deine Version mit meinem Schlüssel testen ob es funktioniert und hier Rückmeldung geben.

@aldadic
Copy link
Owner

aldadic commented Feb 10, 2023

Hi @curtosvienna!

Ich habe meinen Code mit der library, die @leecher1337 vorgeschlagen hat, umgeschrieben. Hier ist der Code:

https://gist.github.com/aldadic/31abea0001c0a231c59814a3e0c68146

Auf meinem ESP32 klappt es tadellos.

@aldadic
Copy link
Owner

aldadic commented Feb 10, 2023

Update: Der Code läuft nun erfolgreich auf meinem ESP8266. Im obigen Code musste ich dafür noch die Wifi library ändern (#include <ESP8266WiFi.h> um genau zu sein; ich habe das GitHub gist entsprechend angepasst). Den Lesekopf habe ich wie folgt angeschlossen:

IR reader ESP8266
VCC 3.3V
GND GND
RX GPIO3 (RX)
TX GPIO1 (TX)

Im config.h musste ich daher die letzte Zeile zu

HardwareSerial *smart_meter = &Serial;

ändern. Ich würde mich freuen zu hören, ob das auch bei dir klappt @curtosvienna. Dann könnte ich das nämlich im repository entsprechend ergänzen.

@curtosvienna
Copy link

curtosvienna commented Feb 10, 2023 via email

@curtosvienna
Copy link

Hallo @leecher1337 @aldadic @,

alles zusammengebaut, konfiguriert, ......
Funktioniert einwandfrei,
Daten werden an den MQTT Server übertragen.
MQTT werd ich mich noch spielen bzw. in influxdb schieben und in Grafana visualisieren
Danke für eure Hilfe.
falls noch von Interesse .... Hichie Lesekopf(Clon) > ESB8266NodeMCU > RaspberryPI4 > Mosquitto Broker
habe es auch mit einem Wemos ESP-Wroom-02 D1 Mini WiFi Module ESP8266 + 18650 mit Akku versucht, da ist aber die WLAN Verbindung nicht ausrreichend.

Grüße
Kurt

@aldadic
Copy link
Owner

aldadic commented Feb 11, 2023

Super! Freut mich zu hören, dass der Code auch bei dir funktioniert @curtosvienna. Dann werde ich den Code bzw. die Anleitung im repository demnächst entsprechend aktualisieren.

@leecher1337
Copy link

Hallo @curtosvienna

Prima, dass es funzt! Was mich noch interessieren würde, weil ichs mit meinem Cryptoschlüssel ja nicht entschlüsseln kann:
Korrespondiert der SystemTitle eigentlich mit der Zählernummer im Portal (die Wiener Netze haben so ein Portal, da steht eine Zählernummer und da kann man sich auch den zugehörigen Cryptoschlüssel anzeigen lassen)?
Ich hab nen Landis&Gyr, da beginnt die Zählernummer mit LGZ... Und auch das SystemTitle beginnt so:

Beispiel:

0x4C,0x47,0x5A,0x68,0x71,0x69,0xA4,0x2A
L   ,G   ,Z   ,103 ,113 ,105 ,164 ,42

Aber die Nummer hinter dem LGZ passt nicht mit dem Zähler zusammen, von dem ich auslese, daher die Frage, ob das korrespondieren sollte?

@curtosvienna
Copy link

curtosvienna commented Feb 11, 2023 via email

@leecher1337
Copy link

Hallo @curtosvienna Ich meine nicht den Schlüssel, sondern den SystemTitle!
Also die ersten 8 Bytes, die Du in den IV kopierst.

@aldadic
Copy link
Owner

aldadic commented Feb 11, 2023

@leecher1337 Ich habe mal bei mir nachgesehen. Bei mir beginnt der SystemTitle ebenfalls mit 0x4C, 0x47, 0x5A, 0x67. Die nächsten vier Stellen stimmen aber nicht mit der Zählernummer überein, die ich Smartmeter Portal sehe.

@leecher1337
Copy link

Danke, war bei mir auch so.
Ok, dann ist das auch kein Hinweis darauf, warum ich offensichtlich einen Schlüssel habe, der nicht richtig entschlüsselt.
Habe neben meiner eigenen Implementierung in C auch dieses Python-Script probiert: https://gist.github.com/pocki80/941fa090a8d6269a9b3b68c195f8750f
Kommt exakt dasselbe raus bei dem Python Script, Rahmen-Prüfsumme ist OK, Inhalt ist wirr.
Dann kann ich nur hoffen, dass die Wiener Netze rausfinden, warum mein Schlüssel nicht passt. :-(

@curtosvienna
Copy link

Also ich gebe in der config.h folgendes ein:
const byte KEY[] = ( 0x2a, 0x47, 0xf8, 0xa4, 0x9d, 0xaa, 0x37…….
Das sind doch genau die Daten aus dem Schlüssel.
2a 47 f8 a4 9d aa 37 ( 2A47 F8A4 9DAA)

@leecher1337
Copy link

leecher1337 commented Feb 11, 2023

Ich auch, nur bei mir kommt eben dann Schrott :(
landis.c ist mein eigenes Entschlüssler, der dasselbe macht wie bei diesem Projekt hier und das og. Python-Script.

$ gcc -o landis -lssl landis.c
$ ./landis
Rahmen-Pruefsumme des Pakets ist gueltig
Entschluesseltes Datenpaket: 52 F6 AA ED 3F A6 C9 E6 C8 39 C5 91 EB D5 02 01 D9 C1 42 6A 54 76 BE E6 CB E5 A5 FF 82 DA B7 22 34 5F 93 9F F8 8E 45 8E CD 40 57 99 0B AC C4 A1 F8 EF 72 EB 01 36 0F E5 23 E7 6A 83 A1 80 4F EE 4A 9B 9A 8F D4 6B B9 2C 5E 4D

Entschluesselung fehlgeschlagen? Falscher Paketstart

Mir sieht das nach Schrott aus...

Mein Code, wenns wen interessiert:

//
// Smartmeter Datenpaket Entschluesselungs Testprogramm
//
#include <stdio.h>
#include <stdint.h>
#include <memory.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/hmac.h>
#include <openssl/buffer.h>

// Schluessel aus dem Kundenportal der Wiener Netze
uint8_t Key[16] = {0x30, 0xCF, 0x95, ....};

// Beispiel
unsigned char MBusData[] = {
	0x7E,
	0xA0,
	0x67,
	0xCE,
	0xFF,
	0x03,
	0x13,
	0x38,0xBD,
	0xE6,
	0xE7,
	0x00,
	0xDB,
	0x08,
	0x4C,0x47,0x5A,0x??,0x??,0x??,0x??,0x??,
	0x4F,
	0x20,
	0x00,0x20,0xE4,0x10,
	0x27,0xDE,0xCF,0x3D,0x4D,0x8D,0xA8,0x00,0xF3,0x20,0x6C,0x16,0x04,0xA0,0xEC,0x9B,0xB0,0x32,0x56,0x10,0x28,0x48,0x72,0x69,0xAF,0x53,0x05,0xE0,0x1A,0x9E,0x1E,0xE1,0x67,0x73,0xD9,0x7C,0x48,0xC5,0x83,0xF1,0x7F,0x7D,0x3D,0x8C,0xAC,0xDF,0x58,0x35,0x5A,0x8B,0x74,0xE8,0x54,0xFA,0xFB,0x37,0x53,0x9F,0xE5,0x2B,0x68,0x95,0xAE,0xBE,0x23,0x8A,0x71,0x0C,0x80,0xF0,0xC6,0xB5,0x60,0x6B,
	0x5D,0xBB,
	0x7E};

// Strukturen der Datenpakete
#pragma pack(1)
typedef uint32_t  TYP_PacketNumber;
typedef struct
{
    uint16_t Year;
    uint8_t Month;
    uint8_t Day;
    uint8_t DayOfWeek;
    uint8_t Hour;
    uint8_t Minute;
    uint8_t Second;
    uint32_t Unknown;
} TYP_TimeStamp;
typedef uint16_t TYP_Unk1;
typedef uint32_t TYP_32BitVal;
typedef uint8_t TYPID;

enum
{
    TYPID_Unk1 = 0x02,
    TYPID_32BitVal = 0x06,
    TYPID_TimeStamp = 0x0C,
    TYPID_PacketNumber = 0x0F
};

typedef struct
{
    TYPID Type;
    TYP_PacketNumber Data;
} DS_PacketNumber;

typedef struct
{
    TYPID Type;
    TYP_TimeStamp Data;
} DS_TimeStamp;

typedef struct
{
    TYPID Type;
    TYP_Unk1 Data;
} DS_Unk1;

typedef struct
{
    TYPID Type;
    TYP_32BitVal Data;
} DS_32BitVal;

// Variante 3
// https://oesterreichsenergie.at/fileadmin/user_upload/Smart_Meter-Plattform/20200201_Konzept_Kundenschnittstelle_SM.pdf
typedef struct
{
    DS_PacketNumber PacketNumber;
    DS_TimeStamp TimeStamp1;
    DS_Unk1 Unk1;
    DS_TimeStamp TimeStamp2;
    DS_32BitVal pA;    // Wirkenergie +A Wh
    DS_32BitVal nA;   // Wirkenergie -A Wh
    DS_32BitVal pR;   // Blindenergie +R varh
    DS_32BitVal nR;   // Blindenergie -R varh
    DS_32BitVal pP;   // Momentanleistung +P W
    DS_32BitVal nP;   // Momentanleistung -P W
    DS_32BitVal pQ;   // Momentanleistung +Q var
    DS_32BitVal nQ;   // Momentanleistung -Q var
} PAYLOAD_PACKET;

typedef struct {

    uint8_t flag;               // Opening flag (0x7E)
    uint8_t type;               // Frame format type
    uint8_t length;             // Length of packet
    uint8_t client_nr;          // Client number?
    uint8_t dst_address;        // Destination address
    uint8_t src_address;        // Source address
    uint8_t control;            // Control field
    uint16_t hcs;               // Header check sequence, CRC-16/X25 (Byte 2-7)
    uint8_t dst_lsap;           // Destination LSAP
    uint8_t src_lsap;           // Source LSAP
    uint8_t llc_quality;        // LLC quality
    uint8_t llc_sdu;            // LLC service data unit
    uint8_t len_sys_t;          // Length of system title
    uint8_t sys_t[8];           // System title
    uint8_t len_content;        // Length of ciphered content
    uint8_t sc_e;               // SC-E: bit 5=1 = Encryption only
    uint32_t inv_cnt;           // Invocation counter
    PAYLOAD_PACKET data;        // Crypted payload (74 bytes)
    uint16_t fcs;               // Frame check sequence
    uint8_t end;                // End flag (0x7E)
} DATA_FRAME;

#pragma pack()


//
// CRC validierung der Pakete
//
uint16_t HdlcCrcReflect(uint16_t crc, int bitnum)
{

  // reflects the lower 'bitnum' bits of 'crc'

  uint16_t i, j = 1, crcout = 0;

  for (i = (uint16_t)1 << (bitnum - 1); i; i >>= 1)
  {
    if (crc & i)
      crcout |= j;
    j <<= 1;
  }
  return (crcout);
}

#define order 16
#define polynom 0x1021
#define crcinit 0xffff
#define crcxor 0xffff

// http://www.zorc.breitbandkatze.de/crc.html
// http://www.zorc.breitbandkatze.de/crctester.c
uint16_t HdlcCrcBitByBit(unsigned char *p, uint16_t len)
{
  uint16_t crchighbit;
  uint16_t i, j, c, bit, crc;
  uint16_t crcmask;

  crcmask = ((((uint16_t)1 << (order - 1)) - 1) << 1) | 1;
  crchighbit = (uint16_t)1 << (order - 1);

  crc = crcinit;
  for (i = 0; i < order; i++)
  {

    bit = crc & 1;
    if (bit)
      crc ^= polynom;
    crc >>= 1;
    if (bit)
      crc |= crchighbit;
  }

  // bit by bit algorithm with augmented zero bytes.
  // does not use lookup table, suited for polynom orders between 1...32.

  for (i = 0; i < len; i++)
  {

    c = (uint16_t)*p++;
    c = HdlcCrcReflect(c, 8);

    for (j = 0x80; j; j >>= 1)
    {

      bit = crc & crchighbit;
      crc <<= 1;
      if (c & j)
        crc |= 1;
      if (bit)
        crc ^= polynom;
    }
  }

  for (i = 0; i < order; i++)
  {
    bit = crc & crchighbit;
    crc <<= 1;
    if (bit)
      crc ^= polynom;
  }

  crc = HdlcCrcReflect(crc, order);
  crc ^= crcxor;
  crc &= crcmask;

  return (crc);
}

int CheckValues(uint8_t *data, size_t dataSize)
{
  uint16_t crc = HdlcCrcBitByBit(data, dataSize - 2); // -2 because last 2 bytes are the checksum I have to compare it to
  uint8_t hiByte = (crc & 0xff00) >> 8;
  uint8_t loByte = (crc & 0xff);

  return hiByte == data[dataSize - 1] && loByte == data[dataSize - 2];
}




int main(int argc, char **argv)
{
	AES_KEY key;
	unsigned char ecount_buf[AES_BLOCK_SIZE] = {0};
	int num = 0;
	unsigned int i;
	DATA_FRAME *fullData = (DATA_FRAME*)MBusData;
    // Initialisation Vector zusammenbaun:
    uint8_t iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02};
    uint8_t plainText[sizeof(fullData->data)]={0};

	// Rahmen-CRC pruefen
	printf ("Rahmen-Pruefsumme des Pakets ist %s\n", (CheckValues((unsigned char*)&fullData->type, sizeof(DATA_FRAME)-2)?"gueltig":"UNGUELTIG!!!"));

    // 8 Bytes von 13 (=system-title)
    memcpy(&iv[0], fullData->sys_t, 8);
    // 4 Bytes von 23 (=nonce). INFO: Nonce wird bei jedem Paket um 1 groesser (=increment counter)
    memcpy(&iv[8], &fullData->inv_cnt, 4);

    // Entschluesseln
	AES_set_encrypt_key(Key, 128, &key);
    AES_ctr128_encrypt((unsigned char*)&fullData->data, plainText, sizeof(fullData->data), &key, iv, ecount_buf, &num);
	//memcpy(plainText, &fullData->data, sizeof(fullData->data));

	printf ("Entschluesseltes Datenpaket: ");
	for (i=0; i<sizeof(plainText); i++) printf ("%02X ", plainText[i]);
	printf("\n\n");

	if (fullData->data.PacketNumber.Type != TYPID_PacketNumber)
		fprintf(stderr, "Entschluesselung fehlgeschlagen? Falscher Paketstart\n");

} 

@aldadic
Copy link
Owner

aldadic commented Aug 27, 2023

The changes from the GitHub gist were integrated into esp-smartmeter-reader.ino. This sketch now compiles for both ESP32 and ESP8266.

@aldadic aldadic closed this as completed Aug 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants