Verschlüsselung aus Entschlüsselung...

lano

Mitglied
Moin.

Mir ist kein besserer Titel eingefallen.
Ich hab da folgendes Problem.
Ich hab 2 Funktionen zum entschlüsseln.
Nun such ich das Gegenstück.

C:
/* rotl16 */
u_int16_t rotl16(u_int16_t value, unsigned int count) {
  const unsigned int mask = (CHAR_BIT * sizeof(value) - 1);
  count &= mask;
  return (value << count) | (value >> ((-count) & mask));
}

u_int16_t decrypt(u_int16_t encrypted_location, u_int8_t key_xorval, u_int8_t key_xorstart, u_int8_t key_nrot) {

  return rotl16(encrypted_location ^ (key_xorval << key_xorstart), key_nrot);
}
 

german

Aktives Mitglied
devCommunity-Experte
Bitschubserei :LOL: Ohne viel getestet zu haben:
C:
u_int16_t rotr16(u_int16_t value, unsigned int count) {
  const unsigned int mask = (CHAR_BIT * sizeof(value) - 1);
  count &= mask;
  return (value >> count) | (value << ((-count) & mask));
}

u_int16_t encrypt(u_int16_t decrypted_location, u_int8_t key_xorval, u_int8_t key_xorstart, u_int8_t key_nrot) {
  return rotr16(decrypted_location, key_nrot) ^ (key_xorval << key_xorstart);
}
 

lano

Mitglied
Ich hab das jetzt mal so versucht.

C:
/* crack_tmc */
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/* rotl16 */
u_int16_t rotl16(u_int16_t value, unsigned int count) {
  const unsigned int mask = (CHAR_BIT * sizeof(value) - 1);
  count &= mask;
  return (value << count) | (value >> ((-count) & mask));
}

u_int16_t decrypt(u_int16_t encrypted_location, u_int8_t key_xorval, u_int8_t key_xorstart, u_int8_t key_nrot) {

  return rotl16(encrypted_location ^ (key_xorval << key_xorstart), key_nrot);
}

u_int16_t rotr16(u_int16_t value, unsigned int count) {
  const unsigned int mask = (CHAR_BIT * sizeof(value) - 1);
  count &= mask;
  return (value >> count) | (value << ((-count) & mask));
}

u_int16_t encrypt(u_int16_t decrypted_location, u_int8_t key_xorval, u_int8_t key_xorstart, u_int8_t key_nrot) {
  return rotr16(decrypted_location, key_nrot) ^ (key_xorval << key_xorstart);
}

int main(int argc, char *argv[], char *envp[]) {

  if (argc != 2) {
    printf("Usage: %s <encrypted location>\n", argv[0]);
    printf("\ntool to brutforce all keys for decoding tmc locations\n");
    return EXIT_FAILURE;
  }

  u_int16_t encrypted_location = atoi(argv[1]);
  u_int16_t decrypted_location = 0;

  u_int8_t key_xorval = 0;
  u_int8_t key_xorstart = 0;
  u_int8_t key_nrot = 0;

  for (key_xorval = 0; key_xorval < 255; key_xorval++) {
    for (key_xorstart = 0; key_xorstart < 255; key_xorstart++) {
      for (key_nrot = 0; key_nrot < 255; key_nrot++) {

        decrypted_location = decrypt(encrypted_location, key_xorval, key_xorstart, key_nrot);
        encrypted_location = encrypt(decrypted_location, key_xorval, key_xorstart, key_nrot);

        if (encrypted_location == decrypted_location) {
          printf("algo works\n");
          printf("enc: %d \t dec: %d \t \t xor: %d \t xors: %d \t rot: %d \n", encrypted_location, decrypted_location, key_xorval, key_xorstart, key_nrot);

        } else {
          printf("algo didnt work\n");
          printf("enc: %d \t dec: %d \t \t xor: %d \t xors: %d \t rot: %d \n", encrypted_location, decrypted_location, key_xorval, key_xorstart, key_nrot);
        }
      }
    }
  }

  return EXIT_SUCCESS;
}
Also um das mal zu erklären.
Es geht sich um die Location IDs von TMC.
Das kann zB so aussehen.
Code:
63863 - No through traffic.
56177 - Closed due to roadworks.
56177 - Closed due to roadworks.
56177 - Closed due to roadworks.
59333 - Roadworks. Carriageway reduced to one lane.
59333 - Roadworks. Carriageway reduced to one lane.
59333 - Roadworks. Carriageway reduced to one lane.
6868 - Closed due to roadworks.
6868 - Closed due to roadworks.
6868 - Closed due to roadworks.
33432 - Roadworks. Carriageway reduced to one lane. Temporary width limit.
21731 - Roadworks. Carriageway reduced to one lane.
10974 - Slip roads closed.
10974 - Slip roads closed.
10974 - Slip roads closed.
9918 - Broken down heavy lorr(y/ies). Danger. Dangerous situation on entry slip road.
61431 - Closed due to roadworks.
61431 - Closed due to roadworks.
61431 - Closed due to roadworks.
57757 - Closed due to roadworks.
57757 - Closed due to roadworks.
57757 - Closed due to roadworks.
Vorn weg die encrypted location IDs, gefolgt von dem Ereignis dort.

Was weiß ich über die Keys? eigentlich nix. Es werden wohl 32 Stück verwendet. Sie sind immer 24h gültig.
0:04 Uhr wechselt der Key wohl.

Um den Möglichen Keys auf die Spur zu kommen hab ich den Bruteforce gedanken gehabt, wie immer...
Ich hab mir jetzt gedacht ich nehme eine Location ID von heute. Geh alle schlüssel Kombis durch.
Irgend wo im ergebnis muss die richtig entschlüsselte Location ID sein.
Jetzt werden die TMC Nachrichten regelmäßig gesendet. und die ein oder andere Straßensperrung geht auch länger als ein Tag. Manch ein Auto brennt auch gern auf der Fahrbahn ab über die Tagesschwelle hinweg.
Ich nehm mir nun also die selbe Nachricht "Auto fackelt ab" und beobachte wann sich der schlüssel ändert.
Jetzt müsste sich die location ID geändert haben. Solange jetzt nicht noch nen 2. auto abbrennt.
Nu nehm ich die Id und geh wieder mit brute force drüber. Auch da muss jetzt das richtige ergebnis irgendwo sein.
Jetzt wollte ich beide ergebnisse vergleichen und gucken welche davon übereinstimmen. Denn das auto brennt ja immer noch an der decrypted location.
Wenn es jetz wieder zu erwarten nur eine übereinstimmung gibt ist der key für gestern und heute gefunden.
Gibt es mehrere übereinstimmungen hab ich zumindest eine liste möglicher kandidaten.

Anregungen dazu ?
Bitschubserei :LOL: Ohne viel getestet zu haben:
:rolleyes: Ich hatt gehofft du bemerkst es nicht :LOL:

Ich mach doch da sicher blödsinn. Es gibt doch sicher maximalwerte die überhaupt sinn ergeben oder ?


Nur ma so aus Spass pack ich mal ne Grafik dran wo man schön sehen kann wie die Nachrichten dichte am Tag zunimmt.

Screenshot_20200730_174044.png
 

german

Aktives Mitglied
devCommunity-Experte
Ich verstehe nicht allzu viel von dem was du da tust. Falls da noch irgendwas nicht richtig funktioniert, dann vielleicht weil die Wertebereiche nicht mit den Typen übereinstimmen. Anhand der Typnamen lässt sich herauslesen:
u_int8_t - 0..255
u_int16_t - 0..65535

Um mein
Ohne viel getestet zu haben:
zu erklären - damit meinte ich mich. Mein kompletter Testcode sieht so aus:
C:
#include <limits.h>
#include <stdint.h>
#include <stdio.h>

// keine Ahnung wo diese Typen bei dir definiert sind ...
typedef uint8_t u_int8_t;
typedef uint16_t u_int16_t;

/* rotl16 */
u_int16_t rotl16(u_int16_t value, unsigned int count) {
  const unsigned int mask = (CHAR_BIT * sizeof(value) - 1);
  count &= mask;
  return (value << count) | (value >> ((-count) & mask));
}

u_int16_t decrypt(u_int16_t encrypted_location, u_int8_t key_xorval, u_int8_t key_xorstart, u_int8_t key_nrot) {
  return rotl16(encrypted_location ^ (key_xorval << key_xorstart), key_nrot);
}

/* rotr16 */
u_int16_t rotr16(u_int16_t value, unsigned int count) {
  const unsigned int mask = (CHAR_BIT * sizeof(value) - 1);
  count &= mask;
  return (value >> count) | (value << ((-count) & mask));
}

u_int16_t encrypt(u_int16_t decrypted_location, u_int8_t key_xorval, u_int8_t key_xorstart, u_int8_t key_nrot) {
  return rotr16(decrypted_location, key_nrot) ^ (key_xorval << key_xorstart);
}

int main(void) {
  unsigned cnt = 0U;
  for (unsigned i = 0U; i < UINT16_MAX + 1U; ++i) {
    u_int16_t val = (u_int16_t)i;
    val = encrypt(val, 5, 2, 8);
    val = decrypt(val, 5, 2, 8);
    cnt += (i == val);
  }

  // Sollte 65536 ausgeben, wenn aufeinanderfolgende Ver- und Entschlüsselung
  // in jeder Iteration wieder denselben Wert ergibt.
  printf("%u\n", cnt);
  return 0;
}
Ich habe zwar über den kompletten Wertebereich iteriert, die letzten 3 Argumente sind aber immer dieselben gewesen.
 

lano

Mitglied
Ich verstehe nicht allzu viel von dem was du da tust.
Keine Sorge, ich auch nicht.

Es geht um die TMC Nachrichten die per FM aufs Navi gesendet werden.

Da gibt es halt die Nachricht und die location ist halt verschlüsselt.
durch die bitschubserei bekommt man dann die richtige location id raus.
Dazu halt die drei Argumente.
Soweit ich das in irgend welchen dokus lesen konnte werden die location ids mit einem aus einem pool von 32 keys verschlüsselt übertragen.
Wenn man dann die richtige location id hat, kann man in einer Datenbank nachschauen welcher streckenabschnitt das ist.
Ähnlich der Mautstreckenliste
Screenshot_20200731_001631.png

Anhand der Typnamen lässt sich herauslesen:
Ja so hab ich das auch verstanden.

Mein kompletter Testcode sieht so aus:
Du nimmst ja immer nur den selben "key" zum testen. aber sollte ja klappen.

die letzten 3 Argumente sind aber immer dieselben gewesen.
Und ich geh die in ihrem Wertebereich durch. von 0 bin 254...

Aber, und das ist mir grad zu hoch. wenn ich nur ne gewisse breite habe und ich dann zu einer seite verschiebe, dann machen doch gewisse werte einfach keinen sinn. zb 0,0,0 oder 255,255,255 wäre doch beides blödsinn. Jetzt frag ich mich was für minimum maximum werte ich da sinniger weise eintragen müsste um alle möglichen schlüssel durch zu probieren.
Es durfte ja optimalerweise irgendwann die richtige location id bei raus kommen. die kann ich dann ggf sogar bei OSM finden.
 

german

Aktives Mitglied
devCommunity-Experte
key_xorval und key_xorstart sind beide 8 Bit breit. Das key_xorval << key_xorstart bedeutet dann, dass key_xorval 0..255 sein kann, aber key_xorstart nur von 0..7 zu liegen hat, denn bei 8 hättest du alle Bits rausgeschiftet. // EDIT: Wobei ja dann 8 immer noch Sinn machen könnte, da dann das Resultat 0 wäre. Größere Werte aber definitiv nicht.
Die rot... Funktionen shiften die 16 Bits rotierend. Heißt, die bits die auf einer Seite rausgeschiftet werden, gehen auf der anderen Seite wieder rein. Bedeutet, wenn count 0 ist, bekommst du als Ergebnis denselben Wert, wenn count 15 ist, bekommst du den letztmöglichen veränderten Wert, denn bei count 16 hast du eine komplette Runde gedreht. An den count Parameter geht das was ursprünglich an key_nrot übergeben wurde. Hier ist also 0..15 sinnig.
 
Zuletzt bearbeitet:

lano

Mitglied
key_xorval und key_xorstart sind beide 8 Bit breit.
Jo

Das key_xorval << key_xorstart bedeutet dann, dass key_xorval 0..255 sein kann
Kann dir folgen.

key_xorstart nur von 0..7 zu liegen hat, denn bei 8 hättest du alle Bits rausgeschiftet.
Ja macht sinn.

Die rot... Funktionen shiften die 16 Bits rotierend.
Ah ok.

Hier ist also 0..15 sinnig.
Jo, klingt logisch. Erklärt auch so einiges. in meinen versuchen.
 

german

Aktives Mitglied
devCommunity-Experte
Schau noch mal auf mein EDIT oben. Zieh das mal in Erwägung falls das sonst noch nicht zuverlässig funktioniert.
 

lano

Mitglied
ohha, darfste ja schon wieder keinem zeigen den code... naja fehler gefunden.
 

lano

Mitglied
Zieh das mal in Erwägung falls das sonst noch nicht zuverlässig funktioniert.
Ja zu doof. Was soll ich sagen. Keine Ahnung was ich da vergleichen wollte.
Auf jedenfall machen die Werte nu sinn.

Noch ne Idee wie ich den key raus bekommen kann ?
Es macht den Anschein das die Meldung immer mit dem selben Key verschlüsselt ist und nach 24 stunden nur bei neuen nachrichten geändert wird. sehnsüchtig hab ich gewartet bis die tiere vonn bahn geschafft sind. die meldungen hab ich auch nach 12 noch bekommen. Aber die meldung das die tiermeldung aufgehoben wurde, die war schon neu verschlüsselt und ist so auch schwer die passende raus zu finden.
 

german

Aktives Mitglied
devCommunity-Experte
Hmm, nee. Liegt aber eher daran dass ich mich mit dem Thema nicht auseinander gesetzt habe. Ist aber ziemlich wahrscheinlich dass es eine andere Möglichkeit gibt. Dein Autoradio wird da wohl kaum mit Brute Force arbeiten. Also entweder wird der Key irgendwie mit gesendet oder es gibt einen Algorithmus mit dem er berechnet wird (vielleicht aus Datum und Zeit, keine Ahnung).
 

lano

Mitglied
Also entweder wird der Key irgendwie mit gesendet oder es gibt einen Algorithmus mit dem er berechnet wird (vielleicht aus Datum und Zeit, keine Ahnung).
Ja hab ich auch gedacht. Wenigstens ne Test Nachricht. Aber egal.

Ich hab jetzt
JSON:
{
  group => "8A",
  pi => "0xD388",
  prog_type => "Pop music",
  tmc => {
    message => {
      coordinates        => [
                              { lat => 50.1223, lon => 7.55575 },
                              { lat => 50.1218, lon => 7.54375 },
                            ],
      description        => "Closed.",
      direction          => "single",
      encrypted_location => 55242,
      event_codes        => [401],
      extent             => "+1",
      location           => 55022,
      road_number        => "L215",
      span_from          => "M\xFChlpfad",
      span_to            => "Hunsr\xFCckh\xF6henstra\xDFe",
      update_class       => 5,
      urgency            => "U",
    },
  },
  tp => 1,
}
55242 - Closed.
oder auch
JSON:
{
  group => "8A",
  pi => "0xD388",
  prog_type => "Pop music",
  tmc => {
    message => {
      coordinates        => [{ lat => 49.8358, lon => 7.8773 }],
      description        => "Closed due to roadworks.",
      direction          => "single",
      encrypted_location => 56683,
      event_codes        => [735],
      extent             => "+0",
      location           => 56399,
      road_name          => "Alzeyer Stra\xDFe",
      road_number        => "L412",
      update_class       => 5,
      urgency            => "U",
    },
  },
  tp => 1,
}
56683 - Closed due to roadworks.
Mit anderen Worten der Key ist für heute gefunden.
31,73,2,0

Ich hatte noch das gefunden:
TMCpro Im Empfanger sind Schlussel fur bestimmte CC/SID/LTN Kombinationen hinterlegt;
in Deutschland z.B. CC=D, SID=50, LTN=1, ENCID=31


Als gegen halb 5 dann nen LKW verreckt ist und nur noch eine Spur offen war hatte ich die Katze im Sack.
Ich bau das mal nen bisschen weiter aus...
 

lano

Mitglied
Also entweder wird der Key irgendwie mit gesendet oder es gibt einen Algorithmus mit dem er berechnet wird (vielleicht aus Datum und Zeit, keine Ahnung).
ISO 14819-6 ... Encryption and conditional access for the Radio Data System — Traffic Message Channel ALERT C coding

Da steht drin das der Encryption Identifier ENCID...
value indicating which line in the Service Key table of parameters the service provider is using in the encryption process that day

Ich brauch in meiner CSV Datei also nur die richtigen Schlüssel der ENCID zuordnen dann passt das.
 

german

Aktives Mitglied
devCommunity-Experte
Klingt gut. Das ist auf jeden Fall wesentlich einfacher, schneller und zuverlässiger als irgend ein Brute Force Algorithmus.
 

lano

Mitglied
schneller und zuverlässiger als irgend ein Brute Force Algorithmus.
Ja, was soll ich machen? Ich hab mir jetzt nen Keyfinder gebastelt. verschlüsselte location id und entschlüsselte angeben.
Die unverschlüsselte hole ich mir aus der Liste, hab doch tatsächlich ne mail bekommen...
Ich muss halt nur nen paar meldungen vergleichen. Ich hatte gestern alle Hoffnung auf nen paar Tiere auf der Fahrbahn gesetzt, aber die wurden zuschnell eingesammelt und eins wohl nen paar abschnitte weiter überfahren, jedenfalls noch vorm key wechsel. Aber nen LKW der in Berlin verreckt ist hat mir dann geholfen.

Meine Theorie um das zu automatisieren.
ich logg die messages mit, also auch die verschlüsselte location id. bei einem schlüssel tausch müsste mindestens ein großteil wegfallen.
der wird dann mit neuer verschlüsselter id gesendet.
jetzt hab ich ne liste mit den alten verschlüsselten locations und mit den neu verschlüsselten locations.
beide müssen das selbe ergebnis bringen. Kreuz-Wunstdorf oder so.
ich entschlüssel also eine alte nachricht mittels brute force und alle neuen nachrichten nach einander auch mittels bf und gucke wo die location übereinstimmt. meine hoffnung das es da nicht viel abweichung geben wird.
wenn das mit allen nachrichten und den selben zwei schlüsseln klappt dann ist ende.
Ich könnte natürlich auch die Nachrichten anzahl einschränken in dem ich zb nur gesperrte straßen meldungen nehme. Die sind ja meist doch länger gesperrt.

So wie ich das bis her verstanden habe gibt es wohl 8 listen mit je 31 keys. also für weltweit. wären 248 keys..

und die entschlüsselte location id geht von 1 bis 63487
 
Oben Unten