ASCII Char array in uint8 wandeln --> Hex to uint

Hallo Zusammen,

ich stehe gerade ein wenig auf dem Schlauch und wäre um einen Vorschlag froh.

Ausgangspunkt ist ein Char Array das mit Pärchen von Hex Werten befüllt ist, die aber nicht als Zahlen vorliegen sondern als ASCII. Herkunft des Char Arrays ist eine WebGUI bei dem der User das eingeben kann.

Also zum Beispiel:

char asciiKey[6] = “A0B3C4”

Als Ergebnis soll dann der uint mit den Zahlen befüllt sein.

uint8_t hexKey[3] = {0xA0, 0xB3, 0xC4};

Gibts da ne fertige Funktion oder wie kann ich das lösen?

Danke schon mal.

Als Anregung. Das Zerlegen und die Prüfung, ob nur gültige Zeichen eingegeben wurden, kannst Du selbst.

byte HDigit2Dez(const char c) {
  if (c >= 'A') return 10 + c - 'A';
  return c - '0';
}

byte H2Digit2Dez(const char *arr) {
  return HDigit2Dez(arr[0]) * 16 + HDigit2Dez(arr[1]);
}

void setup() {
  Serial.begin(115200);
  Serial.println(F("Start"));
  Serial.println(H2Digit2Dez("0F"));
  Serial.println(H2Digit2Dez("F0"));
  Serial.println(H2Digit2Dez("F1"));
}

void loop() {}

Gruß Tommy

1 Like

Das ist kein C++

Und das folgende ist ein bedenkliches Beispiel!

#include <Streaming.h> // die Lib findest du selber ;-)
Print &cout = Serial; // cout Emulation für "Arme"

char asciiKey[] = "A0B3C4"; // 7, nicht 6

union TypePun // nicht die feine Art
{
  using ByteArray = byte[4];
  ByteArray asByte;
  unsigned long asULong;
};

void setup()
{
  Serial.begin(9600);
  cout << F("Start: ") << F(__FILE__) << endl;

  TypePun pun;
  char *endptr = nullptr;
  pun.asULong = strtol (asciiKey, &endptr, 16);
  for(byte b : pun.asByte) cout << _HEX(b) << endl;

}

void loop()
{
}

Dies ist falsch, da die Zeichenfolge aus 6 Zeichen plus dem Zeichenfolgenabschlusszeichen besteht und daher anders definiert werden muss:
char asciiKey[7] = “A0B3C4”
Mithilfe der von @tommy56 erstellten Funktionen müssen Sie jeweils zwei Zeichen aus dem String-Array lesen und in ein Byte konvertieren.
Beispiel versuchen Sie Folgendes, wenn es bei Ihnen funktioniert:

// String to parse
char asciiKey[7] = "A0B3C4";
// Bytes converted
uint8_t hexKey[3];

byte HDigit2Dez(const char c) {
  if (c >= 'A') return 10 + c - 'A';
  return c - '0';
}

byte H2Digit2Dez(const char *arr, byte idx) {
  return HDigit2Dez(arr[idx]) * 16 + HDigit2Dez(arr[idx+1]);
}

void setup() {
  Serial.begin(115200);
  Serial.println(F("Start"));
  for(int i=0; i<strlen(asciiKey); i +=2) {
    hexKey[i/2] = H2Digit2Dez(asciiKey, i);
    Serial.print(hexKey[i/2], HEX);
    Serial.print(" ");
  }
  Serial.println();
}

void loop() {}

Wow, Danke.

Habs grad in Wokwi laufen lassen. klappt!

Kannst Du mir diesen Teil noch erklären. Ist immer besser man versteht auch was warum funktioniert.

Das ist klar, es kommt ja dann schon mit dem Terminator aus der GUI. Aber eine Frage dazu. Wenn ich aus dem Array eh nur einzelne Bytes auslese, und es nie über irgendeinen String oder Print usw. Befehl auslese, kann ich mir dann nicht den Terminator sparen?

Der Terminator ist bereits in der GUI enthalten, Sie haben jedoch nicht geplant, das entsprechende Byte im Array zuzuweisen. Wenn Sie 6 Zeichen haben (und es sich um einen String und nicht um ein einfaches Byte-Array handelt), müssen Sie die Größe auf 7 Bytes anpassen!

Ja, solange du niemals String-Funktionen auf dieses Array anwendest. Und da du "strlen()" verwenden musst, um die Anzahl der Zeichen zu ermitteln, würde ich nein sagen.
Aber deine Initialisierung ist auch hier nicht korrekt, da du versuchst, 7 Bytes in ein 6-Zeichen-Arrays zu packen.

Natürlich!

Aber dann darfst du nicht:

schreiben.
Denn das ist aus mehreren Gründen falsch.

Du hast ja bei den Hexziffern 2 Bereiche
'0' ... '9': '0' = 0x30 --> '0' - '0' = 0 Dez, '9' - '0' = 9
'A' ... 'F': 'A' = 0x41 --> 'A' - 'A' = 0, 'F' - 'A' = 5, also +10, damit man auf 10 ... 15 kommt

Schau Dir mal eine ASCII-Tabelle an.

Gruß Tommy

Ja, ich weis, das war ein Fehler in meinem Beispiel. Im Moment entsteht der Code erst in meinem Kopf. Daß ich aber grundsätzlich ein Zeichen mehr Platz vorhalten muss ist mir absolut geläufig. Es geht darum einen 16 Byte Crypto Key zum dechiffrieren in einer Gui einzugeben und der soll am Schluss in einem uint8 Array landen. Entweder ich mach es jetzt so wie vorgeschlagen, oder ich sehe 16 einzelne Eingabefelder im HTML vor. Muss mal schauen ob HTML auch direkt Hex akzeptiert.

Danke

Super, Danke!

Ich hatte mir bereits bei der Eingabe gedacht das es falsch ist. Ich wollte aber klar stellen, das ich aus 6 Chars 3 Zahlen machen will.

Ich gelobe Besserung :slight_smile:

Dein Beispiel verstehe ich noch nicht ganz. Lohnt es sich mich da einzuarbeiten oder bist du auch mit Tommys Beispiel zufrieden?

Hallo,

habe ich ein Verständnisproblem?
Die ASCII Tabelle bis kleines 'z' geht in ASCII Hex bis "7A".
Das heißt, Eingaben von A0 oder B3 oder C4 sind nicht möglich.
Ist das Beispiel falsch oder wurden Begriffe vertauscht?
Sind die Eingaben vielleicht doch keine ASCII Codes?
Nur Zahlen im Hex Format?

Weil eine Wandlung von ASCII-Hex zu Zahl-Hex kann in der HEX Schreibweise, nur durch Komma getrennt, nicht gleich bleiben. Da stimmt etwas nicht.

char asciiKey[6] = “A0B3C4”
uint8_t hexKey[3] = {0xA0, 0xB3, 0xC4};

Ich?
Es ist dein Problem.

Aber:
Du solltest schon verstehen, was da passiert.

In den Chars stecken ganz normale ASCIIs als Buchstaben oder Zahlen. Immer 2 Chars repräsentieren ein Byte als Zahl. Du lässt dich vom Hex Code des ASCII verwirren. Den meine ich nicht.

Ja, die Eingabe eines 16-Byte-Kryptografieschlüssels (also 32 Hexadezimalzeichen?) über eine grafische Oberfläche ist möglich. Sie müssen mein Beispiel lediglich um einen 32-stelligen String (plus Terminator, sodass das Array 33 Elemente enthält) erweitern und in ein Byte-Array konvertieren (uint8 ist dasselbe). Es müssen keine 16 separaten Felder erstellt werden.

Für HTML ist es nur ein String; Sie müssen nichts weiter tun, als zu überprüfen, ob alle eingegebenen Zeichen gültig sind, d. h. nur Zeichen zwischen „0“ und „9“ sowie Zeichen zwischen „A“ und „F“. Sie können dies über Steuerelemente auf der Webseite oder über Arduino tun.

Schau Dir mal das Pattern-Attribut vom HTML-Input-Tag an. (ungetestet)

pattern="[0-9A-F]{32}"

--> Zeichen 0 bis 9 und A bis F und das Ganze 32 Mal

Wobei ich die Fehlerquote bei der manuellen Eingabe von 32 Hex-Ziffern für gegen 100% gehend halte.

Gruß Tommy

Danke, mach ich.

Den Key bekommt der User von seinem Versorger als HEX Spagetti mitgeteilt und muss ihn nur reinkopieren. Mal sehen, gibt noch genug andere Baustellen :slight_smile:

Es geht um das auslesen von Stromzählern.

Ist der Versorger schon so "modern" dass er den Key elektronisch übermittelt und nicht auf Papier? :wink:
Ist der dann auf dem Übertragungsweg auch gesichert? Also nicht als einfache Email?
Und Du sicherst die Eingabe per HTTPS ab?

Gruß Tommy

Das kann ich dir gar nicht mit Sicherheit sagen, habe weder so einen Zähler, noch wohne ich in einem Versorgungsgebiet, die das so handhaben. (Österreich)

Aber, ich habe ein ähnliches Projekt, und habe Spaß daran es für österreichische Zähler zu erweitern. Die, warum auch immer, verschlüsselt übertragen. Es ist ja eine Kabelverbindung, wenn ich Zugriff habe, kann ich auch am Display lesen.