EnOcean Rolling Code PoC Implementierung

Begonnen von JanS, 11 Mai 2014, 19:44:38

Vorheriges Thema - Nächstes Thema

JanS

Hallo,

ich hätte eine EnOcean Rolling Code Implementierung in Perl abzugeben. Wohlgemerkt nur ein PoC der bei Tests entstanden ist. Bei Interesse bitte kurze Rückmeldung hier, da ich dazu sicher noch ein paar Erklärungen abgeben müsste (Stichwort eigene EUL Firmware mit HEX Output). ;-)


Grüße,
Jan

klaus.schauer

Die Ideen rund um die neuen Security Optionen würden mich sehr interessieren.

JanS

Gut, dann schau ich mal, dass ich evtl. den Code die Tage -zumindest ein wenig- salongfähiger mache, kann aber nicht zur viel versprechen, da ich dass in einem anders gelagerten Projekt noch in der Mache habe. ;-)

Voraussetzungen für Tests sind außer einem EnOcean Empfänger noch ein PTM215 oder kompatibles Modul, z.B. Eltako FMH4. Ich tue mir so spontan etwas schwer Einlerntelegramme von meinem PTM215 zur Verfügung zu stellen, da mit der Vertraulichkeit dieser das System steht und fällt. ;)
Ich helfe auch gerne beim Integrieren in dein FHEM Modul mit, möchte mich aber aus Zeitmangel nicht zu tief in die Details der FHEM Schnittstellen oder Deines Moduls einarbeiten.

Vorschlag meinerseits: Besorg dir ein PTM215 und dann gehts los. ;-)
Der Code hat mich ca. 1,5 Tage gekostet mit Tests. Wenn du ein PTM215 verfügbar hast, dann schätze ich den Integrationsaufwand in Dein Modul auch so in der Größenordnung von 1-2 Tagen ein. Wichtigste Neuerung dürfte ein persistenter Speicherort für die Crpytoparameter (Sender ID, Rolling code counter, private Key und ein paar Parameter sein).

Grüße,
Jan

klaus.schauer

An dem Schalter scheitert es nicht. Der liegt hier rum. Dann bin ich ja mal gespannt.

Zephyr

Würde mich ebenfalls interessieren, da bei mir in den nächsten zwei Wochen etliches Equipment von EnOcean ankommt.
Ich will auf dieses System u.a. weil es eine Verschlüsselung bietet.

Viele Grüße
Zephyr
FHEM 5.5 auf Fritz!Box 7390 und Beagle Bone black mit RFXtrx433

JanS

Ok :-)
Bin dran es etwas aufzuhübschen und werde dann hier eine Funktion nach der anderen als Perl Source abliefern. Bin leider etwas landunter und will nicht einfach eine Ladung Code hier abkippen die keiner blickt ;-) Abgesehen davon hab ich ja auch ein bisschen Stolz ;-)

Generell schon mal eine Zusammenfassung für diejenigen die sich nicht das Whitepaper von EnOcean antun wollen.

Soweit imir bekannt gibt es an Rolling Code fähigen Sendern bislang nur das PTM215 Modul, welches z.B. in den Tastern von Eltako verbaut. Andere Module sind mir nicht bekannt, jedoch gibt die Spezifikation deutlich mehr her, als derzeit genutzt wird. Rolling Code fähige Fenster/Türkontakte habe ich sowohl bei Eltako also auch EnOcean einfach mal angefragt. Antwort war in etwa: "Mhja geplant, aber keine Ahnung wann."

So was geht also mit den PTM215 Modulen und was nicht? Die Module kommen standardmäßig im normalen Modus daher, d.h. EEP F6-02-01. Um den Rolling Code Modus zu aktivieren sind beide Taster einer Seite (A oder B) zu drücken und danach der "Energy Bow" zu drücken, loszulassen und nochmal zu drücken. Dadurch werden zwei Dinge bewirkt, 1.) wechselt das PTM215 dadurch in den Rolling Code Modus und EEP D2-03-00, 2.) werden zwei Secure Teach in Telegramme versendet, dazu gleich mehr. Ein Wechsel zurück in den "normalen" Modus ist jederzeit möglich; einafch alle 4 Taster drücken und den "Energy bow" betätigen. Man zerschiesst sich also nichts dauerhaft. ;-)

Die zwei Einlerntelegramme übetragen die nötigen Infos für die Verschlüsselung, aus Längengründen aufgeteilt in zwei Telegramme(es werden also beide benötigt!). Hier gibt es einen kleinen Haken...
Es werden, neben einer kleinen Menge Protokollinfos, zum einen der aktuelle Wert des Rolling Code Zählers übertragen (16bit beim PTM215), als auch der zur Verschlüsselung verwendete "Private Key"(128bit) wie in EnOcean nennt. Das bedeutet konkret, lauscht jemand in diesem Moment mit, dann hat er alle nötigen Infos um die Telegramme zu fälschen! Es sind Gegenmassnahmen in der Spezifikation vorgesehen, dazu werden der Zählerwert und der Schlüssel zusätzlich mit einem Preshared Key(PSK) verschlüsselt, welcher dem Empfänger bekannt sein muss. Dies kann beim Teach-In angezeigt werden, wie das allerdings funktioniert, ist mir nicht klar. Die Spezifikation sagt dazu nur, dass ein 16Byte langer Code plus CRC8 Checksumme auf dem Sender vermerkt werden könnte. Ich habe eine Anfrage an EnOcean gestellt, was es damit auf sich hat. Der PTM215 auf jeden Fall signalisiert "kein PSK", es geht also alles im Klartext durch die Luft.

Diese beiden Werte (Zähler und Schlüssel) sind auch die wichtigsten zu speichernden Informationen pro SenderID. Es gibt noch ein paar weitere Parameter, aber die sind kaum der Rede Wert. Der Zählerwert wird bei späteren Schalttelegrammen nicht mehr übertragen, es muss als empfängerseitig mitgezählt werden (und gespeichert!). Die Spezifikation sieht ein Fenster von 128 Zählerwerten vor, um bei verlorenen Telegrammen wieder aufsynchronisieren zu können. Um das Telegram prüfen zu können, wird ein 3 byte langer CMAC Wert übertragen, welcher kryptographisch erzeugt wird, hierfür wird wieder der "Private Key" des Senders, der Zählerwert und ein bisschen AES128 und XOR Bitschubserei gebraucht.

Ist die Nachricht, durch Verifikation des MAC, als echt und korrekt eingestuft worden, kann man sich an die Verschlüsselung machen, hierfür wird de "Private Key" ein EnOcean weiter "Public Key" und der, evtl. erst gesuchte, Zählerwert benötigt. Veschlüsselt werden beim PTM215 gigantische 4Bit(übertragen in einem Byte), welche mit viel Padding in eine VAES getaufte Verschlüsselung gesteckt werden. Die Interpretation dieser 4Bit findet sich in  EEP D2-03-00, zusammen mit Übersetzungstabellen nach EEP EEP F6-02-01.

Und das wars als Überblick, ich hoffe das gibt schon mal einen Überblick darüber was zu erwarten ist. Meine Programmiererehre zwingt mich nur, das noch mal in Ruhe durchzuschauen, nicht das sich fiese Fehler in den kryptographischen Funtionen eingeschlichen haben; die haben mich ganzschön Nerven gekostet, das will ich anderen ersparen.

Ich denke morgen Abend werfe ich die ersten Schnipsel, wenn nicht sogar schon alles, hier ab. Laufen tut es "anscheinend" seit Sonntag Mittag, bin permanent am Testen. ;-) Wenns gut läuft sind nur durch Klaus noch ein paar Anpassungen an Datenformaten zu erledigen. :-)

Zephyr

Öhm... Dann besorge ich mal testweise einen PTM215. :D
FHEM 5.5 auf Fritz!Box 7390 und Beagle Bone black mit RFXtrx433

thghh

#7
Frage.

Was erhofft ihr euch durch die Verschlüsselung?

Das ist doch nur Marketing, weil der Wettbewerb bisher auf der fehlenden Verschlüsselung rumgeritten ist.

Ich wäre ja schon froh, wenn das Funksignal vom EG in den Keller gehen würde und selbst wenn jemand dieses auf der Strasse mitlesen sollte, um die ID zu missbrauchen was kann passieren? Licht ein- und ausschalten?

@ Zephyr

Wenn du deine Geräte bekommst achte auf die Produktionswoche. Nur darüber wird entschieden ob Verschlüsselung oder nicht besonders beim FAM14
Umfangreiche Haussteuerung auf Basis der Eltako Serie 14 inkl. DALI und GFVS Save II

JanS

ZitatWas erhofft ihr euch durch die Verschlüsselung?
Authorisierung und Authentifizierung, wie von jeder vernünftig umgesetzten Verschlüsselung.

ZitatDas ist doch nur Marketing, weil der Wettbewerb bisher auf der fehlten Verschlüsselung rumgeritten ist.
Die Umsetzung ist sehr ordentlich, deutlich besser als z.B. bei Homematic und deutlich über den Vorwurf eine Marketingnummer zu sein erhaben.

ZitatIch wäre ja schon froh, wenn das Funksignal vom EG in den Keller gehen würde...
Bei mir reicht das Funksignal eines PTM215 vom 3.OG bis auf die Straße und hinters Haus, mit -91dBm in diesem Fall.
Empfänger ist ein Busware EUL mit 3dbi Antennenstummel, also nix wildes. Für schiwerige Fälle gibt es Repeater die sogar hierrarchisch strukturierbar sind.

Zitat...und selbst wenn jemand dieses auf der Strasse mitlesen sollte, um die ID zu missbrauchen was kann passieren? Licht ein- und ausschalten?
Ja, Licht, Heizung Aktoren für größere Verbraucher, die Rolläden etc.
Kannst gerne auch deine Haustüre offen stehen lassen, zwingt dich ja keiner zum Abschließen. ;-)

ZitatWenn du deine Geräte bekommst achte auf die Produktionswoche. Nur darüber wird entschieden ob Verschlüsselung oder nicht besonders beim FAM14
Ja guter Hinweis, gilt aber nur für die Empfänger/Aktoren, das PTM215 kann es immer.

JanS

Ok, hier die gesäuberte teach-in Verarbeitung, mehr habe ich heute nicht geschafft...

Dieser Funktion muss die komplette Data Payload eines ESP3 RADIO Telegrams als HEX String übergeben werden.
Als Ergebnis wird ein Perl HASH mit Infos befüllt, welches dann von den eigentlichen Routinen zu Entschlüsselung verwendet wird.

@Klaus: Das kannst du schon komplett zum Testen von Teach-in Logik  und persistentem Store verwenden. Du solltest bei einem PTM215 danach einen 2Byte/4HEX-Chars langen Wert für den RLC bekommen und einen 16Byte/32 HEX-Chars langen Wert für den Key. RLC_ALGO muss als "2,++", MAC_ALGO als "3" und RLC_TX als "false" herauskommen.


Zephyr

Zitat von: thghh am 13 Mai 2014, 17:02:29
Frage.

Was erhofft ihr euch durch die Verschlüsselung?

Frage.

Du hast bestimmt auch nichts zu verbergen?

Ansonsten aber vielen Dank für den Hinweis. Ich mache mich die Tage mal auf die Suche nach entsprechenden Heizungsaktoren. Aber hat jemand von euch einen Hinweis? Ach, vergesst es. Falscher Thread dafür. :)

Viele Grüße
Zephyr
FHEM 5.5 auf Fritz!Box 7390 und Beagle Bone black mit RFXtrx433

JanS

Ok hier kommt der Rest (inkl. teach-in).

Das Gesamtkonstrukt unterstützt derzeit primär die PTM215 Module. Mehr ist machbar und an vielen Stellen im Code auch bereits vorgesehen, allerdings ist dafür entweder die Spezifikation noch etwas ungenau oder schlichtweg nichts zum Testen verfügbar. :-(
Ich schätze da wird es in Zukunft also noch mehr geben. :-)

So dann warte ich mal die Fragen ab, die sich bei der Implementierung evtl. ergeben. Sollte aber relativ straight-forward sein. Verbesserungsvorschläge, vor allem für die ganze Bitschubserei in generateMAC() & Co werden dankend angenommen. ;-)


Grüße,
Jan

klaus.schauer

#12
Das Teach-In habe ich eingebaut... Perfekt!

Internals:
   CFGFN
   DEF        FEFF91C3
   IODev      TCM_0
   NAME       EnO_STE_FEFF91C3
   NOTIFYDEV  global
   NR         508
   STATE      ???
   TYPE       EnOcean
Attributes:
   DATA_ENC   VAES
   IODev      TCM_0
   KEY        633EDF0A8E
   MAC_ALGO   3
   RLC        F426
   RLC_ALGO   3,++
   RLC_TX     false
   room       EnOcean
   subType    STE


2014.05.15 06:36:59 2: TCM set TCM_0 teach 600
2014.05.15 06:37:08 1: EnOcean Unknown device with ID FEFF91C3 and RORG switch, please define it.
2014.05.15 06:37:08 2: autocreate: define EnO_switch_FEFF91C3 EnOcean FEFF91C3 EnOcean:1:F6:70:FEFF91C3:20:03FFFFFFFF3C00
2014.05.15 06:37:08 2: autocreate: define FileLog_EnO_switch_FEFF91C3 FileLog ./log/EnO_switch_FEFF91C3-%Y.log EnO_switch_FEFF91C3
2014.05.15 06:39:31 1: EnOcean Unknown device with ID FEFF91C3 and RORG STE, please define it.
2014.05.15 06:39:31 2: autocreate: define EnO_STE_FEFF91C3 EnOcean FEFF91C3 EnOcean:1:35:244BF426BA3770929C:FEFF91C3:00:01FFFFFFFF3900
2014.05.15 06:39:31 2: EnOcean EnO_STE_FEFF91C3 Secure Teach-In OK: Part1-BA377092
2014.05.15 06:39:31 2: autocreate: define FileLog_EnO_STE_FEFF91C3 FileLog ./log/EnO_STE_FEFF91C3-%Y.log EnO_STE_FEFF91C3
2014.05.15 06:39:31 2: EnOcean EnO_STE_FEFF91C3 Secure Teach-In OK: Part2-876793E7

   1. Integration des Teach-In Moduls
Folgende Änderungen habe ich zur Integration vorgenommen, geändertes Modul siehe Anlage:

   - Umbenennung des Moduls
   - Übergabeparameter jetzt $hash und $DATA
   - Rückgabewerte $err und $msg
   - Speicherung der Kryptoparameter als Attribute

Das Modul wurde in der Parse-Routine  integriert und wird nach Anlegen des Devices (autocreate) aufgerufen. Hierbei wird RORG = 35 >> subType = STE ausgewertet. RORG wird deshalb nicht mehr übergeben. Die Kryptoparameter werden jetzt im Fhem-Konfigurationsfile gesichert.


if ($rorg eq "F6") {
... 
} elsif ($rorg eq "35" && $teach) {
     # Secure Teach-In
    ($err, $msg) = EnOcean_sec_parseTeachIn($hash, $data);
    if (defined $err) {
      Log3 $name, 2, "EnOcean $name Secure Teach-In ERROR: $err";
      return "";
    }
    Log3 $name, 2, "EnOcean $name Secure Teach-In OK: $msg";   
    CommandSave(undef, undef);
    return ""; 
}


Attribute werden i. d. R. nach der Art "subType" benannt. Es wäre schön, wenn die Namen der Kryptoparameter  gleich aufgebaut wären.

Zu Beginn des Teach-In wird dem Device per autocreate der subType = STE zugewiesen. Mit Abschluss des Teach-In Prozesses muss dann der "richtige" subType eingetragen sein. Hier müssen wir uns noch gemeinsam überlegen, wie wir es am besten machen. Ich habe mich noch nicht tief genug in das Krypto Teach-In eingearbeitet, um eine allgemeingültige Lösung - nicht nur für den subType = switch- parat zu haben. Z. B. könnte der EEP in der Form xx.yy.zz in einem zusätzlichen Rückgabewert $eep übergeben werden oder unmittelbar in der Teach-In Routine gesetzt werden, siehe  %EnO_subType.

In dem Internal $hash->{DEF} ist die SenderID des Devices  $hash->{NAME} gespeichert. In der  Teach-In Routine wird die SenderID auch extrahiert. Ich würde beide  Werte vergleichen und nur dann das Teach-In akzeptieren, falls beide Werte identisch sind. Ist sicher in kleines zusätzliches Sicherheitsmerkmal.

   2. Aufteilung in vier Routinen

Ich schlage vor, dass wir die gesamten Kryptoverfahren in vier Modulen kapseln. Das erleichtert die aufgabenteilige Betreuung. Ich gehe mal davon aus, dass Du die Kryptomodule dauerhaft betreuen und weiter ausbauen wirst!?

EnOcean_sec_convertToNonsecure
EnOcean_sec_convertToSecure
EnOcean_sec_createTeachIn
EnOcean_sec_parseTeachIn

Als nächstes stünde also EnOcean_sec_convertToNonsecure() an.

Ich würde für dieses Modul wieder die RORG = 30 und ggf. RORG = 31 auswerten. Übergeben wird

($err, $data, $rorg) = EnOcean_sec_convertToNonsecure($hash, $data, $rorg)

Rückgabewert $rorg = "32" ?

Siehe auch %EnO_rorgname:
...
"30" => "SEC",     # secure telegram
"31" => "ENC",     # secure telegram with encapsulation
"32" => "DEC",     # decrypted secure telegram
...

Bisher habe ich mich nur mit der Teach-In Routine befasst. Bitte gib mir eine Rückmeldung, wie wir weiter vorgehen. M. E. wäre es gut, wenn Du die Entschlüsselungsroutine entsprechend dem obigen Vorschlag anpassen würdest. Danach würde ich mich um die Integration kümmern.

JanS

Ok, hab ein paar Fehler wieder ausgebaut, die Abfrage auf rlc_algo == 2 war flöten gegangen und der Vergleich ob das zweite Telegram einem ersten gefolgt ist, verwendete einen anderen "KEY" ohne Punkt. ;-)
Generell funktioniert etwas in der Art "$attr{$name}{.RLC_ALGO} = '2,++';" nicht da kein Punkt im Key vorkommen darf. Da ich die genaue Nomenklatur für subTypes(?) in FHEM nicht kenne, schlag einfach etwas (funktionierendes) vor. Ich bin da leidenschaftslos.

Ich habe das R-ORG Feld wieder aufgenommen; Hintergund dazu ist, dass ich mir nicht sicher bin, ob wir es evtl. in Zukunft wieder brauchen werden. Daher wäre mein Vorschlag es einfach drinnen zu lassen.

Bezüglich der R-ORG Typen und EEPs.
Der R-ORG 0x30 ist nicht genau spezifiziert, soll bedeuten ein PTM215 schickt damit verschlüsselte Daten, welche nach EEP D2-03-00 zu interpretieren sind. Mir ist keine Möglichkeit bekannt wie man das näher unterscheiden können sollte, streng genommen müsste ich daraus einen R-ORG 0x32 machen, den Sinn dahinter sehe ich allerdings nicht. ;-) Es werden da auch nur 4bit daten übertragen beim PTM215 und keinerlei Identifizierungsmerkmale.
R-RORG 0x31 für Kapselung würde dechiffriert einen normalen R-ORG liefern, leider kann ich das aber wiederrum nicht testen.
Da wird sich in Zukunft evtl. etwas ändern, solange es aber keine Geräte die das unterstützen in freier Wildbahn gibt, macht es zu diesem Zeitpunkt keinen Sinn da viel zu implementieren.
Die Implementierung für den PTM215 seitens EnOcean wirkt ein wenig zurechtgeschustert, sobald mehr Geräte EnOcean Security unterstützen, wird bzw. muss sich da auch wieder was am Protokoll tun.

Ich hänge die reparierte Version des teach-ins an. Schau da bitte mal nach der Konvention für die Attributnamen im Hash, passe sie an und stell es wieder hier ein, dann baue ich die restlichen Routinen passend um.

Was die Pflege angeht, ich werde das pflegen, wenn es meine Zeit zulässt ;-)
Solange EnOcean nichts an der Spec ändert oder es mehr Geräte gibt, sehe ich das sehr entspannt.


klaus.schauer

Jetzt sollte es gehen. Die Teach-In Routine habe ich angepasst. Die Parameter $rorg $data werden getrennt übergeben. Dort wird jetzt auch für Switche ein EEP vergeben. Ergebnis des Teach-In:


Internals:
   CFGFN
   DEF        FEFF91C3
   IODev      TCM_0
   NAME       EnO_STE_FEFF91C3
   NOTIFYDEV  global
   NR         504
   STATE      ???
   TYPE       EnOcean
   Readings:
     2014-05-16 21:03:38   teach-in        EEP D2-03-00 Manufacturer: no ID
Attributes:
   IODev      TCM_0
   dataEnc    VAES
   key        633EDF0A8E
   macAlgo    3
   rlc        F42C
   rlcAlgo    2,++
   rlcTX      false
   room       EnOcean
   subType    switch.00



2014.05.16 21:00:28 2: TCM set TCM_0 teach 600
2014.05.16 21:00:39 1: EnOcean Unknown device with ID FEFF91C3 and RORG STE, please define it.
2014.05.16 21:00:39 2: autocreate: define EnO_STE_FEFF91C3 EnOcean FEFF91C3 EnOcean:1:35:244BF42ABA3770929C:FEFF91C3:00:01FFFFFFFF5000
2014.05.16 21:00:39 2: EnOcean EnO_STE_FEFF91C3 teach-in EEP D2-03-00 Rocker A Manufacturer: no ID
2014.05.16 21:00:39 2: EnOcean EnO_STE_FEFF91C3 secure teach-in part1: BA377092
2014.05.16 21:00:39 2: autocreate: define FileLog_EnO_STE_FEFF91C3 FileLog ./log/EnO_STE_FEFF91C3-%Y.log EnO_STE_FEFF91C3
2014.05.16 21:00:39 2: EnOcean EnO_STE_FEFF91C3 secure teach-in part2: 876793E7


Das EEP D2-03-00 (subType switch.00) muss ich noch bauen. Ist aber nur Fleißarbeit.

Falls wir derzeit davon ausgehen, dass ein RORG 32 nur von einem RORG D2 benutzt wird, ist die Rekonstruktion problemlos. Deshalb fürs Erste folgender Aufruf der Dekodierungsroutine:


...
  my $name = $hash->{NAME};
  my $teach = $defs{$name}{IODev}{Teach};
  my $teachOut;
 
  if ($rorg eq "30" || $rorg eq "31") {
    ($err, $rorg, $data) = EnOcean_sec_convertToNonsecure($hash, $rorg, $data);   
    if (defined $err) {
      Log3 $name, 2, "EnOcean $name security ERROR: $err";
      return "";
    }
    if ($rorg eq "32") {
    # reconstruct RORG
    $rorg = "D2";
    }
  }

  # extract data bytes $db[x] ... $db[0]
  my @db;
  my $dbCntr = 0;
  for (my $strCntr = length($data) / 2 - 1; $strCntr >= 0; $strCntr--) {
    $db[$dbCntr] = hex substr($data, $strCntr * 2, 2);
    $dbCntr++;
  } 
...

Bitte $rorg = "32" zurückgeben. Dann ist auch für später die Zuordnung eindeutig.

Ich hoffe, es gelingt mit diesmal die letzte Fassung der Routine beizupacken. Die wäre dann auch lauffähig gewesen.