One-Way-Loader - kompakter Krypto-Bootloader für AVR-Mikrocontroller


Dieser Bootloader läuft auf den meisten Mikrocontrollern der Serie TinyAVR und MegaAVR. Anders als alle anderen verwendet er ein konsequentes Einweg-Protokoll. Seine Daten empfängt er über eine existierende RS232-, RS485- oder USB-RS232-Anbindung oder über eine minimalistische und/oder maßgeschneiderte Programmierschnittstelle, die tatsächlich nur einen einzigen Porteingang belegt. Die Datenübertragung ist technisch robust und kryptografisch abgesichert. Komplette Firmware-Updates für EEPROM und Flash lassen sich in einem verschlüsselten Containerformat zusammenfassen und sind bei der Distribution über unsichere Kanäle gegen Übertragungsfehler, Manipulation und Ausspähung geschützt.


Einleitung | Idee und Konzept | Technische Details | Schnellstart | Anmerkungen | Lizenz | Download | Links | Zurück

OWL web draft cc0
  • Universeller Bootloader für viele ATtinys und ATmegas; Firmware unter 512 Bytes.

  • Robuste Einweg-Übertragung; viele Interface-Möglichkeiten; RS232, RS485, One-Wire, Lichtstrahl, Audio... oder was ganz Anderes.

  • Kryptografie besorgt Datenschutz, Datenintegrität, Authentisierung und einzigartige Geräteadressen.

  • Software-Tool generiert maßgeschneiderte Bootloader einzeln oder in Serie, verwaltet Bootloader und Schlüssel.

  • Senden von EEPROM- und Flash-Daten in einem Durchgang; verschlüsseltes Distributionsformat.

  • Komplettlösung für Firmware-Sicherheit und gute Laune!


Einleitung

In der Welt der Mikrocontroller stellen sogenannte Bootloader mit RS232-Schnittstelle eine unkomplizierte und preiswerte Alternative zur Programmierung über ISP dar.

Das Thema Sicherheit wird in diesen Tagen immer wichtiger... Schon ein passwortgeschützter Bootloader kann den Zugriff auf einen berechtigten Personenkreis beschränken. Innerhalb des Controllers sind Daten und Programme auch sehr sicher, sobald der ISP-Zugriff per Lockbits gesperrt wurde. Außerhalb des Controllers liegen Firmware-Updates oft in unverschlüsselter Form vor und sind weiterhin den Gefahren von Kompromittierung, Manipulation oder ganz profanen Zufallsfehlern ausgesetzt. Bei rein lokaler Nutzung ist das noch kein Problem. Interessant wird es im Zusammenhang mit Applikationen, die erhöhte Sicherheitsanforderungen stellen und von realen Anwendern im Feld aktualisiert werden sollen. Hier braucht es nicht nur eine idiotensichere Schnittstelle, sondern gegebenenfalls auch echte Verschlüsselung.

Ein Krypto-Bootloader schützt Datenübertragungen auf dem gesamten Transportweg von der Quelle bis zum Zielgerät gegen Ausspähung, Manipulation und Übertragungsfehler. Der Krypto-Bootloader akzeptiert nur verschlüsselte Übertragungen und entschlüsselt die Daten erst unmittelbar vor den Schreibzugriffen im Inneren des Controllers. Firmware-Updates liegen idealerweise nur noch an den "Endpunkten" in unverschlüsselter Form vor; einmal in der geschützten Entwicklungsumgebung des Erstellers und natürlich in einem oder mehreren Ziel-Geräten. Für Krypto-Bootloader kommt meist symmetrische Verschlüsselung zum Einsatz, da diese ressourcensparend umsetzbar ist und klare Zugriffsrechte sicherstellt. Nur, wer den Bootloader-Schlüssel für ein Zielgerät besitzt, kann dort ein Firmware-Update einspielen. Keine Hintertürchen, keine Drittparteien, kein Verfallsdatum. Wenn man es richtig macht, garantiert der Krypto-Bootloader einen umfassenden Firmware-Schutz.

So einfach kann, soll und muss es sein! Nun stellt so eine Bootloader-Firmware bekanntlich spezielle Anforderungen: Codeeffizienz, Unabhängigkeit, Zuverlässigkeit und Transparenz. So etwas lässt sich leider nicht an einem Wochenende im Baukastensystem zusammenhämmern. Das ist ein klassischer Fall für die richtige Programmierung in Assembler, dann klappt's auch mit dem transparenten Gesamtkonzept! Man hätte sich ein Beispiel an TinySafeBoot nehmen können... Der hat schon vor Jahren friedlich demonstriert, wie ein einsatzbereiter und ressourcensparender AVR-Bootloader samt plattformübergreifender Software-Unterstützung aussehen kann. Ein praxisbezogenes Feature besteht zum Beispiel darin, dass die Software maßgeschneiderte Bootloader generieren kann, ohne auf eine bestimmte Toolchain angewiesen zu sein.

Das anhaltende Feedback zu TSB scheint zu bestätigen: Viele AVR-Nutzer, die noch selbst denken und entwickeln, wollen unabhängige und transparente Lösungen. Ein vergleichbarer Krypto-Bootloader stand auch auf meiner Wunschliste ganz weit oben... Angesichts der vielen inspirierenden Bootloader-Machwerke, die sich meinem Bewusstsein in letzter Zeit aufgedrängt haben, wurde aus der Wunschliste nun doch wieder eine To-Do-Liste - und schließlich dieses kleine Projekt hier...

Nach oben | Index


Idee und Konzept

Der "One-Way-Loader" verwirklicht und vereint folgende Ideen und Konzepte:
  1. Einweg mit Mehrwert
    In der Regel empfängt so ein Bootloader Daten von einem Computer, um sie in verschiedene Speicherbereiche seines "Wirts-Controllers" zu schreiben. Die umgekehrte Übertragungsrichtung, also Daten lesen, um sie an einen Computer zurückzusenden, beherrscht kaum ein Bootloader, und das Feature wird auch praktisch nie gebraucht. Nicht einmal im Entwicklerumfeld, denn dort steht üblicherweise ISP/JTAG zur Verfügung. Im Übrigen heißt es ja auch Bootloader, und nicht Bootsaver... Wir stellen nüchtern fest: Ein Bootloader für Pragmatiker und Endanwender muss nur Schreibzugriffe beherrschen.
    Die Daten fließen nur in eine Richtung, nämlich vom Computer zum Controller. Dennoch benötigen die meisten Bootloader eine voll ausgebaute serielle Schnittstelle mit Hin- und Rückkanal. Das ist natürlich den mehr oder weniger angestaubten Protokollen geschuldet, die ständig irgendwelche Bestätigungszeichen oder Prüfsummen zurücksenden wollen.
    Die Abhängigkeit von einer bidirektionalen Schnittstelle schränkt die Einsatzgebiete des Bootloaders empfindlich ein, vor allem dort, wo Portleitungen knapp sind oder wo eigentlich gar keine RS232/RS485-Anbindung vorgesehen war. Manch neuzeitlicher Bootloader kann immerhin "One-Wire". Damit halbiert sich der Bedarf an Portleitungen, aber die eine Leitung muss nun bidirektional funktionieren und wir brauchen auf der PC-Seite eine spezielle Adapterschaltung (CI-V-Interface).
    Da sollten wir uns doch fragen: Ist dieses Hin und Her auf zwei Leitungen, oder auf einer bidirektionalen Leitung, wirklich "alternativlos", wie uns die Tellerrandhocker und Protokollfetischisten weismachen wollen?
    Spoiler-Alarm: Die Datenflusssteuerung wird überflüssig, wenn der Sender ein auf den Empfänger zugeschnittenes Timing vorausberechnen und einhalten kann. Der Fehlerschutz lässt sich mit einer kryptografischen Über-Alles-Prüfsumme erschlagen!
    So kommen wir zu einem Einweg-Bootloader, der dann auch wirklich keinen Rückkanal mehr braucht. Ihm reicht eine einzelne unidirektionale Portleitung, auf der wir bedarfsweise ein serielles Datensignal einspeisen. Mit derart minimalen Anforderungen ergeben sich eine Menge interessanter Optionen für ultrasimple, maßgeschneiderte oder alternative Programmierschnittstellen. Bei alledem bleibt dieser Einweg-Bootloader jedoch direkt kompatibel zu gewöhnlicher RS232- oder RS485-Hardware, wo er dann nur den Empfangszweig aktiv nutzt. Auf der Softwareseite beim Computer vereinfacht sich die Handhabung der seriellen Schnittstelle noch ein ganzes Stück, sodass hier ohne besondere Klimmzüge ausgesprochen robuste und plattformübergreifende Lösungen umsetzbar sind. Was zu beweisen war!

  2. Kryptografie sichert Datenschutz, Datenintegrität, Authentisierung und einzigartige Geräteadressen
    Manch einer wird wohl spätestens an dieser Stelle in nervöse Zuckungen verfallen und einwerfen wollen: "Erst diese krasse Einweg-Idee, und jetzt will er auch noch mit KRYPTO rummachen? Das kann doch NIEMALS hinhauen..."
    Und ob das hinhaut! Es funktioniert sogar bedeutend besser, als ohne Krypto. Aber immer der Reihe nach.
    Für Firmware-Datenübertragungen gilt bekanntlich "Null Fehlertoleranz". Die Einweg-Übertragung sollte und kann durchaus robust angelegt sein. Realistischerweise können Fehler aber selbst unter kontrollierten technischen Bedingungen gelegentlich mal vorkommen. Fehlerkorrigierende Codes gibt es, aber die würden das Datenvolumen enorm aufblähen und wären dennoch kein Garant für absolute Fehlerfreiheit. Ohne Rückkanal kann unser Einweg-Bootloader jedoch kein fehlerhaftes Paket neu anfordern und er kann kein externes Verifying durchführen. Konzepte aus der Mottenkiste der Modem-Übertragungen sind hier fehl am Platze.
    Jetzt kommt Kryptografie ins Spiel. Wir nehmen eine beliebige Blockchiffre, wenden eine bestimmte Methode der Schlüsselverkettung an und bauen damit ein Übertragungsformat, das die Schreibdaten nicht nur richtig verschlüsselt, sondern auch eine kryptografische Gesamt-Prüfsumme liefert (vergleichbar einer MAC). Damit kann unser Bootloader zum Ende der Übertragung einseitig und mit allergrößter Sicherheit feststellen, ob alle Daten vollständig und fehlerfrei durchgekommen sind. War die Super-Prüfsumme okay, dann übergibt der Bootloader direkt an die neu geschriebene Applikations-Firmware. Sollte es jedoch zu einem oder mehreren Fehlern gekommen sein, dann müssen wir halt "in den sauren Apfel beißen" (der aber bekanntlich auch der Gesündeste ist...:) Der Bootloader wird dann fehlerhafte Daten komplett wieder löschen, und der Nutzer muss eine neue Übertragung versuchen. Das ist im Zusammenhang mit Firmware-Updates ohnehin die einzig gute Praxis!
    Die Verwendung von Krypto bringt neben der Absicherung der Daten vor neugierigen Blicken und der zuverlässigen Erkennung von Übertragungsfehlern noch weitere Vorteile: Starke kryptografische Schlüssel werden nach dem Zufallsprinzip erzeugt. Auf diese Weise bekommt jeder Krypto-Bootloader eine einzigartige Geräteadresse im Sinne einer UUID zugeteilt. So müssen wir uns in einem Multi-Bootloader-Setup nie wieder mit Passwort-Phantasie-Problemen und möglichen Kollisionen herumschlagen.

  3. Kompakte Firmware für die meisten ATtinys und ATmegas (und, wer weiß...)
    Auch dieser Bootloader soll, wie das Vorläuferprojekt, auf möglichst vielen AVR-Chips laufen. Insbesondere war es mir wichtig, weiterhin die "kleinen" Chips zu unterstützen, schon um ein weiteres Zeichen gegen Ressourcenverschwendung zu setzen.
    Mit paralympischen Übungen in "C" kommt man hier nicht weit! Erst die Programmierung in Assembler ermöglicht es, Signalverarbeitung, Ablaufsteuerung und Kryptosystem in hochkompaktem und transparentem Code unterzubringen. Und so braucht dieser One-Way-Loader für seine erstaunliche Funktionalität keine zwei Kilobytes... er braucht nichtmal ein Kilobyte... er kommt mit einem halben Kilobyte aus!

  4. Software-Tool für Bootloader-Generierung, Bootloader-Datenübertragung und Schlüsselverwaltung
    Die PC-Software zum Krypto-Bootloader ist als Kommandozeilentool konzipiert. Das bedeutet minimale Abhängigkeiten und standardisierte Eingabe-Ausgabe-Schnittstellen. Der Aufruf lässt sich plattformunabhängig in diverse Entwicklungs- und Editorumgebungen sowie in Skript-Abläufe einbinden. Selbstverständlich wird die Software als ausführbare Datei für Linux- und Windows-Konsole zur Verfügung stehen.
    Die Software muss verschlüsselte Firmware-Updates an "autorisierte Zielgeräte" (also solche, für die wir selbst den Schlüssel besitzen) senden können. Das Ganze soll nicht mehr Umstände machen, als der Zugriff auf einen unverschlüsselten Bootloader. Niemand merkt sich Bootloader-Passwörter. Der benutzerfreundliche Kompromiss besteht darin, jedem Zielgerät einen eindeutigen und memorierbaren Klarnamen zuzuordnen. Die Software holt sich den dazu passenden Krypto-Schlüssel und alle weiteren Infos aus einer lokalen Datenbank.
    Die Software soll auch wieder maßgeschneiderte Bootloader "out of the box" erzeugen. Eine nützliche und rationale Option, kein Muss. Wer will, kann auch aus dem offengelegten Assemblerquelltext in der Arbeitsumgebung seiner Wahl einen Bootloader zaubern; und sei es nur zur Vergewisserung, dass der selbst assemblierte Code mit dem von der Software erzeugten Code identisch ist.
    Ein weiteres Feature, das in den Beschäftigungstherapien für Nerds nicht einmal angedacht wird, gehört beim One-Way-Loader zum Standardumfang: Die halbautomatische Erzeugung einer ganzen Bootloader-Serie mit individuellen Schlüsseln und Seriennummern, und dazu passend die Generierung von Firmware-Updates für eine solche Bootloader-Serie. Könnte ja sein, dass mal jemand auf die total verrückte Idee kommt, und mehr als nur nur zwei oder drei Geräte mit Krypto-Bootloadern versorgen will...

  5. Cooler Name, coole Lizenz
    Nach einigem Hin und Her habe ich mich entschlossen, den Einweg-Bootloader nach seinem Alleinstellungsmerkmal, der Einweg-Übertragung, zu benennen. Also heißt das Teil jetzt "One-Way-Loader", "OneWayLoader" oder "OWL".
    Der One-Way-Loader ist quelloffen. Das ist alternativlos, da sich hier alles um Sicherheit und Krypto dreht.
    Der One-Way-Loader steht unter MIT-Lizenz.
    Das hat vor allem pragmatische Gründe. Meine Zeit ist kostbar und ich habe Wichtigeres zu tun, als über seitenlange Lizenzbedingungen zu diskutieren. Die freizügige und unkomplizierte MIT-Lizenz ist eine Sicherheitsgarantie für alle Beteiligten und ermöglicht eine freiwillige und faire Zusammenarbeit.

Wer's ganz genau wissen will, sollte sich die Technischen Details reinziehen. Nur für Hardcore-Fans!


Direkt ausprobieren: Schnellstartanleitung


Tipp: Für invertierte Bildschirmdarstellung steht (seit 'ner halben Ewigkeit) ein alternativer CSS-Style zur Verfügung. Unter Firefox mal Ansicht - Webseitenstil - Schwarz auf Weiß ausprobieren!


Serviervorschläge:
  • Ultimativer Ersatz für TSB, da dieselbe Hardwarebasis unterstützt wird
  • Transparenter Krypto-Schutz für lokale Projekte
  • Firmware-Updates "im Feld" über besonders simple und/oder robuste Schnittstellen
  • Gesicherter Update-Kanal für Nur-EEPROM- oder Nur-Flash-Daten
  • Nutzung existierender RS232/RS422/RS485-Schnittstellen
  • Nutzung minimalistischer und versteckter Programmierschnittstellen, z.B. LED + Photodiode
  • Distribution kompletter Firmware-Updates über öffentliche Kanäle (Web, FTP, E-Mail)
  • Firmware-Schutz für besondere Anwendungen



Nach oben | Index


Technische Details

Eule auf Buch.
  1. Timing-Trick

  2. Autobauding

  3. Logisches Format

  4. Kryptografie

  5. Firmware

  6. Software

  7. Hardware-Optionen




OWL-Transmission (1) - Timing-Trick

Problem: Der Bootloader auf einem Mikrocontroller kann normalerweise keinen ununterbrochenen Datenstrom verarbeiten. Er muss seine Schreibdaten in kleinen mundgerechten Häppchen serviert bekommen, die er problemlos zwischenspeichern, bündeln und dann in die verschiedenen Speicherbereiche schreiben kann. Wenn die Daten noch anspruchsvoll entschlüsselt werden müssen, dann braucht dieser Verarbeitungsschritt schon eine nennenswerte Rechenzeit. Der eigentliche Knackpunkt sind aber die physischen Schreibzugriffe in EEPROM oder Flash. In dieser kritischen Phase muss eine Bootloader-Firmware normalerweise den laufenden Schreibzugriff abwarten, oder der Prozessorkern wird sogar komplett angehalten. Das bedeutet, ein interrupt-optimierter Datenempfang würde in der Bootloader-Anwendung nicht viel bringen, außer zusätzlichem Aufwand und Stabilitätsrisiken. Zwischen den Datenblöcken entsteht immer eine Zwangspause (wir nennen sie mal reißerisch "Totzeit"), in der unser Controller gar nichts mehr mitbekommt.
Der Datenfluss muss also zeitlich koordiniert werden. In einem einfachstmöglichen bidirektionalen Protokoll sendet der Computer einen Datenblock festgelegter Größe und wartet dann, bis der Controller irgendwann zurückmeldet, dass er wieder empfangsbereit sei. Vorher darf der Computer keine neuen Daten oder Kommandos senden. Dieses Hin und Her auf zwei Leitungen (oder auf einer bidirektionalen Leitung) wollen wir abschaffen. Und so geht's:

Lösung: Es ist möglich, die Totzeiten des Controllers im Voraus zu berechnen, wenn einige Rahmenbedingungen bekannt sind. Dann weiß der Computer ganz genau, wie lange der Controller zur Verarbeitung der aktuellen Daten brauchen wird. Der Computer muss also "nur noch" die zeitlich exakte Übertragung hinbekommen. Gibt's aber schon das nächste Problem: In einer modernen RS232-Implementierung lassen sich definierte Sendepausen praktisch nicht mehr umsetzen. Was aber immer funktioniert, ist das Senden von seriellen Stopf- oder Füllzeichen. Diese garantieren zeitliche Mindestabstände zwischen den Nutzdatenblöcken. Sind diese Schutzintervalle großzügig berechnet, dann bekommt der Bootloader immer genügend Zeit, um die aktuellen Daten zu verarbeiten. Kurz nachdem der Bootloader wieder auf Empfang geht, kommt auch schon das nächste Datenpaket.
Das OWL-Signal ist eine einseitige RS232-Übertragung im Modus 8-N-1 in der gegebenen Baudrate.
Das OWL-Signal lässt sich über jede normgerechte RS232-Schnittstelle senden.
  • Es überträgt nur in eine Richtung, nämlich vom Computer ("Sender") zum Controller ("Empfänger").
  • Es sendet verschlüsselte Datenblöcke, um Vertraulichkeit und Datenintegrität sicherzustellen.
  • Es berücksichtigt die Totzeiten des Empfängers, indem es zwischen den Blöcken eine vorausberechnete Anzahl von Füllzeichen einfügt.
  • Diese Füllzeichen ("Präambel") garantieren zeitliche Mindestabstände zwischen den Datenblöcken.
  • Die Präambeln ermöglichen dem Empfänger schnelle Neusynchronisation und präzises Autobauding.
  • Die Einweg-Übertragung ("Transmission") funktioniert ohne Flusssteuerung und benötigt keinen Rückkanal.
  • Die Einweg-Übertragung stellt minimale Anforderungen an RS232-Hardware und Software.
  • Das unterbrechungsfrei gesendete Signal wird technisch ausgesprochen robust.
Zeitlicher Verlauf einer typischen kurzen OWL-Übertragung
Zeitverlauf einer OWL-Transmission für ATtiny25 mit 10 MHz (4 Blöcke EEPROM, 8 Blöcke Flash bei 9600 Baud)
Allgemeines: Das obenstehende Diagramm wurde vom Mitschnitt einer realen "OWL-Transmission" nach dem ausgearbeiteten Standard abgeleitet. Es handelt sich um einen durchgehenden Sendedatentrom. Die verschiedenen Datentypen sind grafisch hervorgehoben. Wir sehen auf einen Blick, dass die Strecken mit Füllzeichen (PREAMBLE) ziemlich unterschiedliche Längen haben. In einer bidirektionalen Übertragung wären das die Sendepausen, und es würde sich ein ganz ähnliches Bild ergeben. Die Präambeln berücksichtigen die Verarbeitungs- und Totzeiten des Ziel-Controllers je nach momentanem Betriebszustand und sind individuell zu berechnen.

Block-Sendedauer: Der einzelne Datenblock besteht immer aus 16 Bytes plus Startzeichen. Die Sendedauer eines Datenblocks ist bei gegebener Baudrate immer gleich. Bei 9600 Baud dauert jeder Block knapp 18 Millisekunden (tB).

Einleitende Präambel (INTRO PREAMBLE): Zum Beginn der Bootloader-Sitzung muss sich der Empfänger erstmalig auf das ankommende (oder bereits laufende) Sendesignal einstellen. Die INTRO PREAMBLE ist in dieser Darstellung recht kurz geraten, kann aber beliebig verlängert werden. Das ist zum Beispiel hilfreich, wenn Controller-Reset und Sendebeginn manuell koordiniert werden müssen.

Block-Entschlüsselungsdauer:
Die Entschlüsselung eines Datenblocks kostet Rechenzeit. Bei Taktfrequenzen im MHz-Bereich liegt die "decryption time" (tD) bei wenigen Millisekunden. Jeder Block muss entschlüsselt werden. Deshalb fließt die Block-Entschlüsselungsdauer in alle Präambel-Berechnungen mit ein und gibt somit die Mindestdauer der Präambeln vor. Sicherheitshalber legt man aber noch ein paar Zeichen "obendrauf", um Laufzeitabweichungen auszugleichen und um dem Empfänger eine sichere Nachsynchronisation zu ermöglichen. Die physischen Schreibzugriffe in EEPROM und Flash brauchen zum Teil noch viel länger, wie wir sehen.

Authentisierungs-Sequenz (S1): Die ersten drei aufeinanderfolgenden Blöcke dienen der Authentisierung des Senders gegenüber dem Empfänger, also der "Anmeldung" beim Bootloader. Dieser Schritt spielt sich ausschließlich im Arbeitsspeicher des Controllers ab und ist nicht sehr rechenintensiv, daher reichen die Basis-Präambeln mit der Mindestlänge (tD) aus.

EEPROM-Sequenz (S2): EEPROM-Speicher kann direkt überschrieben werden, braucht aber pro Byte schon mehrere Millisekunden, sodass sich die Schreibzeit für einen Block aus 16 EEPROM-Adressen auf satte 60 Millisekunden (tEW) summiert. Da müssen wir durch, aber nur, wenn tatsächlich EEPROM-Daten geschrieben werden. Die längeren Präambeln nach jedem EEPROM-Datenblock sind deutlich zu erkennen.

Flash-Sequenz (S3): Nach dem ersten Flash-Datenblock sehen wir im Diagramm eine auffällig lange Pause von ca. 180 ms (tFE). In dieser Zeit löscht der Bootloader den Applikations-Flash, bevor neue Daten geschrieben werden können. Danach geht es aber zügig voran. Dem aufmerksamen Auge wird nicht entgangen sein, dass die Länge der Präambeln zwischen den Flash-Datenblöcken leicht unterschiedlich ist. Das hängt mit der Speicherorganisation im Flash zusammen. Im Ziel-Chip (hier ATtiny25), ist der Flash-Memory in Pages (Speicherseiten) von je 32 Bytes unterteilt. Der Datenblock hat aber immer genau 16 Bytes. Also muss das Bootloader-Programm die Daten von zwei Blöcken zusammenfassen, bevor es eine Flash-Page schreiben kann. Dementsprechend muss der Sender auch nur nach jedem zweiten Block die verlängerte Präambel (tFW) in den Datenstrom einfügen.
(Anmerkung: Auf Controllern mit größerem Flash ist gewöhnlich auch die Pagesize größer. Dann findet der Flash-Write nur noch alle 4, 8 oder 16 Blöcke statt, und es ergibt sich beim Flash-Erase und Flash-Write ein messbarer Optimierungseffekt.)

Zu den Berechnungen: Um das maßgeschneiderte Timing zu erzeugen, braucht der Sender ein Vorwissen über den Empfänger. Neben dem passenden Krypto-Schlüssel muss der Sender vor allem den Controller-Typ, die Anzahl Prozessortakte zur Block-Entschlüsselung und die absolute Taktfrequenz des Ziel-Controllers kennen. Wie diese Informationen verwaltet und verarbeitet werden, steht unter Software.
Hörbeispiel:  OWL-Transmission mit 1 kB Nutzdaten bei 9600 Baud als Audiodatei

Nach oben | Index




OWL-Transmission (2) - Synchronisation und Autobauding

Der Sender fügt zwischen den Datenblöcken eine genau berechnete Anzahl von Präambel-Zeichen ein und erzeugt damit garantierte Schutzintervalle, die dem Empfänger stets genügend Zeit zur Verarbeitung der bisherigen Daten verschaffen.

In dem Moment, wo sich der Empfänger wieder auf die Leitung schaltet, trifft er auf die letzten Zeichen der auslaufenden Präambel. Diese ermöglichen ihm eine schnelle Neusynchronisation auf den seriellen Zeichenrahmen und einen präzisen Abgleich auf die serielle Geschwindigkeit (Autobauding).

Auswertung der OWL-Präambel vor dem Wiedereinstieg in die Datenübertragung
Festlegungen:
  • Das Präambel-Zeichen ($CC, &b11001100) ermöglicht Synchronisation und Autobauding.
  • Das Blockstart-Zeichen ($55, &b01010101) markiert Ende der Präambel und Beginn des Datenblocks.

Vor-Synchronisation:

  • Der Empfänger kann auf einen Leerlaufzustand treffen oder asynchron in eine laufende Übertragung stoßen. Er kann folgende Signalzustände vorfinden:
    • Ein Low-Pegel, also Startbit oder 0-Bitzelle, wird immer abgewartet, bis wieder High anliegt.
    • Ein High-Pegel, also Leerlauf, Stoppbit oder 1-Bitzelle, wird abgewartet, bis die Leitung auf Low geht.
    • Der Beginn dieser Low-Phase ist der exakte Startzeitpunkt für die erste Messung.

Synchro-Autobaud-Messung:

  • Das Präambel-Zeichen enthält zwei durchgängige Low-Phasen von 3 und 2 Bitzellen Dauer.
  • Der Empfänger misst die Dauer von zwei aufeinander folgenden Low-Phasen.
  • Das Ergebnis der zweiten Messung wird vom Ergebnis der ersten Messung abgezogen:
    • Positives Ergebnis ( 3 - 2 = 1 ) bedeutet, dass die Low-Phasen innerhalb des Zeichenrahmens erfasst wurden. Der Empfänger ist mit dem Zeichenrahmen synchron und das Messergebnis ist auch schon der gesuchte Timing-Referenzwert.
    • Negatives Ergebnis ( 2 - 3 = -1 ) bedeutet, dass zwei Low-Phasen aus getrennten Zeichen erfasst wurden. Der Empfänger ist noch nicht vollständig synchron. Er überspringt den nächsten High-Low-Wechsel und startet eine neue Doppelmessung, die dann im synchronen Zustand das richtige positive Ergebnis liefern wird.
  • Die Differenzbildung liefert einen fehlerkompensierten Messwert über das Timing einer Bitzelle.

Datenempfang:
  • Nach der Synchro-Autobaud-Prozedur erfolgt der weitere Zeichenempfang per Software-Decoder.
  • Der Empfänger ...
    • verwirft weitere Präambel-Zeichen, bis das Blockstart-Zeichen eintrifft;
    • decodiert und puffert die nach dem Blockstarter folgenden 16 Datenbytes;
    • entschlüsselt und verarbeitet die Daten im Puffer.
  • Währenddessen beginnt der Sender schon einmal mit der Übertragung der nächsten Präambel.
  • Sobald der Empfänger wieder empfangsbereit ist, findet er die laufende Präambel vor und startet eine Neusynchronisation und erneutes Autobauding. Der Kreis schließt sich.

Anmerkungen:

  • Allgemein profitieren wir von den Hauptvorteilen eines Software-UAR(T) mit Autobauding: Es können beliebige Portleitungen und verschiedene Baudraten für den Zeichenempfang benutzt werden.
  • Das ausgearbeitete Verfahren ist vergleichsweise flexibel . Es kann vor und während der Übertragung bis zum Timeout auf ein Signal warten oder sich in eine bereits laufende Präambel "einklinken". Letzeres ist während der OWL-Übertragung sogar der Normalfall. Fehlsynchronisation oder Mehrdeutigkeiten sind sehr unwahrscheinlich.
  • Das Verfahren wertet nur die aktiven Low-Zustände auf der Datenleitung aus. Eine "stotternde" Übertragung (Leerlauf des Sendepuffers) beeinflusst die Messgenauigkeit überhaupt nicht.
  • Das Verfahren ist ausgeprochen robust. Die differenzielle Messung gleicht Asymmetrien in den Signalflanken aus. Damit lassen sich auch verzerrte Signale bis zu einem gewissen Grad noch auswerten.
  • Präambeln, Blockstarter und Datenblöcke sind als Datenstrom digital ausgeglichen. Bei kontinuierlicher Sendung entsteht ein perfekt ausbalanciertes serielles Signal. Diese bewusst "angezüchtete" Eigenschaft begünstigt gleichspannungsfreie und/oder differenzielle Übertragungsarten und verbessert ganz allgemein die Störsicherheit auf realen Kanälen.
  • Neusynchronisation und Autobauding vor jedem einzelnen Datenblock. Damit ist auch bei sehr langen Durchgängen unter schwankenden oder driftenden Taktfrequenzen ein stabiler Betrieb möglich.
  • Breites Baudraten-Fenster. Die gegenwärtige Assembler-Programmierung nutzt den Wertebereich der verwendeten 16-Bit-Zähler gut aus, sodass sich ein breiter Arbeitsbereich ergibt. (Tabelle)
  • Synchronisation und Autobauding benötigen nur zwischen 1 und 2,5  Präambel-Zeichen. Die Präambeln können bei eng tolerierten Taktfrequenzen durchaus knapp bemessen werden. Wir bekommen eine zeitoptimierte Übertragung, die bei gleicher Baudrate schneller durchläuft, als eine bidirektionale Bootloader-Sitzung mit einem optimiertem Minimalprotokoll. Grund: Bei der unidirektionalen OWL-Transmission entstehen auf Host-Seite keine weiteren Verzögerungen durch die Richtungsumschaltung und Handhabung von Empfangspuffern.
Hinweis: RS232-Signalverläufe sind hier als Logiksignale mit unipolaren Pegeln in Normallage dargestellt, wie sie von der U(S)ART-Komponente des Mikrocontrollers erwartet werden und üblicherweise an TTL-kompatiblen Ausgängen eines MAX232 oder FT232 vorliegen. Hier ist die logische "1" (Stoppbit oder Leerlauf) durch einen High-Pegel (meist 3,3 oder 5 Volt) definiert, eine logische "0" entspricht dem Low-Pegel (0 Volt). Darüber hinaus kann die OWL-Firmware auch für Empfangssignale in Inverslage mit umgedrehten Logikpegeln konfiguriert werden, dies bringt in einigen Fällen weitere Hardware-Vereinfachungen.

Performance

Nachstehende Tabelle gibt einen Überblick, was mit dem beschriebenen Synchro-Autobaud-Verfahren machbar ist. In einem realen Testaufbau mit ATtiny2313-20PU an 5V mit dem klassischen MAX232-Pegelwandler habe ich Reihenversuche bei verschiedenen Controller-Taktraten durchgeführt. Die Test-Transmission enthielt jeweils ein Datenmuster von 2 x 64 Bytes für den vollen EEPROM und ein einfaches LED-Blinkprogramm für den Flash, das mit ca. 1 kB an Zufallsdaten aufgefüllt war.
Der Chip wurde vor jedem neuen Versuch über ISP komplett gelöscht. Damit waren "falsch positive" Ergebnisse ausgeschlossen.

Auswertung: Wenn die LED unmittelbar nach Abschluss der Transmission fröhlich zu blinken anfing, dann muss logischerweise die gesamte Transmission vollständig und fehlerfrei durchgelaufen sein. In allen anderen Fällen wurde der Versuch als gescheitert abgehakt. In einigen Zweifelsfällen wurden Speicherinhalte nochmals per ISP ausgelesen und geprüft. Dabei bestätigte sich, dass die Fehlerbehandlung durch die aktuelle Bootloader-Firmware sehr verlässlich funktioniert. (Siehe OWL-Signal - Logisches Format.)

Baudraten-Fenster bei verschiedenen Prozessor-Taktraten

MCU-Takt (kHz)
Baud Min. Baud Max.
16
< 30
100
128
30
450
500
50
900
1000
100
1800
2000
200
3600
3000
300
4800
3560
450
7200
4000
450
7200
4433
450
9600
6000
450
14400
8000
600
14400
10000
600
19200
12000
1200
28800
14745
1800
38400
16000
2400
38400
17734
2400
57600
24000
3600
76800
27256
4800
115200
30000
9600
115200

Anmerkungen:
  1. Die Tabelle ist nicht auf TSB oder ähnliche Bootloader übertragbar. Dieses Verfahren hat einen sehr breiten Arbeitsbereich!
  2. Faustformel für das Baudraten-Fenster in der Benutzersoftware: CLOCK/10 < BAUDRATE < CLOCK x 2
  3. Liefert das Interface unsaubere (weniger steile) Pegel, kann es mit der höchsten Baudrate Probleme geben. Die nächstniedrigere Norm-Baudrate sollte dann funktionieren.
  4. Die Untergrenze (Minimum-Baudrate) ergibt sich aus der Tatsache, dass der AVR zur Pulsbreitenmessung einen 16-Bit-Zähler benutzt; dessen Wertebereich wird bei zu langsamem Signal überschritten.
  5. Die Obergrenze (Maximum-Baudrate) ergibt sich aus der zunehmenden Mess-Ungenauigkeit, wenn das serielle Signal im Verhältnis zum Prozessortakt schon relativ schnell ist.
  6. Taktfrequenzen über 24 MHz wurden von einem externen Quarzgenerator eingespeist, da keine spezielle Beschaltung für Obertonquarze vorgesehen war und der ATTiny2313-20PU "eigentlich" nur bis 20 MHz spezifiziert war. Uneigentlich lief dieses Exemplar noch bis über 32 MHz (!) scheinbar problemlos, was die Kernfunktionalität der MCU anging. (Overclocking-Experimente mit Mikrocontrollern - ein interessanter und gar nicht so kostspieliger Zeitvertreib...)
  7. Im Test wurden nur Norm-Baudraten verwendet. An einem USB-COM-Wandler (z.B. FT232) sind auch nicht-standardkonforme Baudraten, wie etwa 64.000 Baud, einstellbar. Für's Autobauding kein Problem!

Nach oben | Index



OWL-Transmission (3) - Logisches Format

Die Präambeln realisieren auf der Transportschicht ein maßgeschneidertes Timing, das den Rückkanal zur Datenflusssteuerung überflüssig macht und dem Empfänger immer wieder ein Referenzsignal für Synchronisation und Autobauding liefert.

Für das logische Format einer OWL-Transmission spielt diese Technik keine Rolle. Auf der höherliegenden Kryptoschicht wird nur mit den Datenblöcken zu 16 Bytes gearbeitet.

Alle Blöcke sind mit RST verschlüsselt . Eine sogenannte RST-Sequenz besteht immer aus einem Initialisierungsvektor (IV), dem eigentlichen Nachrichteninhalt (in einem oder mehreren Blöcken), sowie einem abschließenden Block (VI), der mit dem IV identisch ist. Die Blöcke sind aufgrund des Key-Feedbacks kryptografisch voneinander abhängig und der rechtmäßige Empfänger kann durch IV-VI-Vergleich zweifelsfrei feststellen, ob die bisherigen Daten komplett und korrekt übertragen wurden. Der OWL-Bootloader nutzt diese Eigenschaft schamlos aus...

Die OWL-Transmission macht es gleich dreimal hintereinander. Die drei RST-Sequenzen enthalten, immer in derselben Reihenfolge, Daten zur Authentisierung, für den EEPROM und für den Flash. Im Rahmen einer OWL-Transmission wird der Schlüsselgenerator gar nicht wieder zurückgesetzt. Somit sind nicht nur die Blöcke untereinander, sondern auch die Sequenzen kryptografisch aneinander gekoppelt. Im Normalfall erkennt der Empfänger den Abschluss einer fehlerfreien Sequenz und schaltet dann zur nächsten Sequenz weiter. Im Fehlerfall verbleibt der Empfänger in der gegenwärtigen Sequenz und kann (muss) am Ende der Transmission Maßnahmen zur Schadensbegrenzung treffen. Eine weitergehende Differenzierung ist für den Einweg-Bootloader nicht nötig!

Ablauf der OWL-Transmission (siehe auch Übersichtsdiagramm):
  • S1: Authentisierung
    • IV = Zufallsdaten, modifizieren Originalschlüssel für alle nachfolgenden Runden
    • Kein Datenblock = Blockade
    • Genau ein Datenblock = Wird verworfen, nur Key-Feedback
    • VI nicht erkannt = Blockade ohne Timeout!
    • VI erkannt = Weiter mit S2
  • S2: EEPROM-Daten
    • IV = Zufallsdaten; modifiziert PRNG-State nach S1
    • Kein Block, direkt VI = weiter mit S3
    • Datenblöcke = in EEPROM schreiben
    • VI nicht erkannt / Timeout = Fehler, bleibe in S2, Blockade
    • VI erkannt = weiter mit S3

  • S3: Flash-Daten
    • IV = Zufallsdaten; modifiziert PRNG-State nach S2
    • Kein Block, direkt VI = Fertig!
    • Mindestens ein Datenblock = Flash-Erase, Zusammenfassung mit weiteren Blöcken, dann Page-Write
    • VI nicht erkannt / Timeout = Fehler, Flash-Erase!
    • VI erkannt = Erfolg, gesamte Übertragung fehlerfrei, Applikation starten!

Normalfall: Der Sender verwendet exakt denselben Schlüssel, wie der Empfänger. Die Übertragung kommt von Anfang bis Ende störungsfrei durch. Der Empfänger kann jeden einzelnen Block korrekt entschlüsseln, erkennt die VIs der jeweiligen Sequenzen und erkennt auch den abschließenden VI von S3. In diesem Moment ist klar, dass alle bereits geschriebenen Daten vollständig und fehlerfrei gewesen sind. Die Sitzung war im Ganzen erfolgreich und die Bootloader-Firmware übergibt die Kontrolle an eine bestehende oder neu geschriebene Applikations-Firmware. Indirekte Rückmeldung: Sofortiger Start der Applikation.

Ausnahmefälle: Übertragungsfehler; Unterbrechungen, zu lange Sendepausen (Timeout); Synchronverlust; versehentliche Anwendung eines falschen Schlüssels; absichtliche Anwendung eines falschen Schlüssels (zur Adressierung mehrerer Empfänger auf derselben Leitung); plumpe Manipulationsversuche. Alle diese Situationen erkennt der Empfänger als FEHLER. Je nachdem, in welcher Sequenz er sich gerade befindet, trifft der Empfänger Gegenmaßnahmen. Indirekte Rückmeldung: Blockade bis zum Hardware-Reset.

Weitere Überlegungen: Die OWL-Transmission kommt ohne Steuerzeichen und Kommandos aus. Es werden keine Header-Blöcke oder sonstige Metadaten übertragen, die einen Known-Plaintext-Angriff begünstigen würden. Im Gegenteil, das Chiffrat bekommt mit jedem neuen IV zusätzliche Entropie verpasst.
Obwohl es sich hier um einen festgelegten Ablauf handelt, sind Schreibzugriffe in EEPROM oder Flash optional. Es ist möglich, nur in den EEPROM oder nur in den Flash zu schreiben, ohne jeweils den anderen Speicherbereich zu berühren. Es ist ebenso möglich, ein komplettes Firmware-Update, bestehend aus Daten für EEPROM und Flash, in einer und derselben Transmission bzw. in einer Transmissions-Datei unterzubringen.

Nach oben | Index


Kryptografie

Der OWL nutzt eine Blockchiffre mit der Bezeichnung "RST" (Randomized Substitution-Transposition). Dabei handelte es sich um ein Studienprojekt zum Thema Blockverschlüsselung. Das Kryptosystem definiert eine kombinatorisch eher simple Blockchiffre, einen bestimmten Key-Feedback-Modus und ein bevorzugtes Dateiformat. Es ist auf praktische Anwendungen ausgelegt, nicht auf akademische Anerkennung und mathematische Eleganz.
Auf der PC-Plattform gibt es genügend Krypto-Alternativen, die dem weit verbreiteten Glauben an "Zertifiziertes" huldigen und ganz objektiv einen höheren Datendurchsatz erreichen, als mein kleines modular aufgebautes System hier.
In der Bootloader-Anwendung sind die Prioritäten jedoch anders gelagert, und im Vergleich mit anderen Kandidaten für eine Bootloader-Chiffre stellte sich heraus, dass RST den vielleicht besten Kompromiss aus Codeeffizienz und Sicherheit zu bieten hat.

Funktionsweise von RST

Das Verfahren nutzt für seine "randomisierten Substitutionen und Transpositionen" einfache Standardoperationen, wie Addition, Bitshifting, Invertierung und Vertauschung, auf denen auch etablierte Blockchiffren beruhen. Die Rechenschritte innerhalb einer Blockrunde werden hier nicht über feststehende Schlüssel oder Tabellen gesteuert, sondern durch einen fortlaufenden Pseudozufallsgenerator, der zu Beginn der Ver- oder Entschlüsselung mit dem geheimen Schlüssel als Startzahl (seed) geladen wird.
Der PRNG ist wortwörtlich "Schlüsselkomponente" des Kryptosystems. Er ist im Prinzip austauschbar und kann nach unterschiedlichen Qualitätskriterien realisiert werden, sodass sich je nach Anwendung ein günstiger Kompromiss aus Rundenzahl, PRNG-Stärke und Codebedarf (Mikrocontroller-Anwendungen) finden lässt.
Der Block-Algorithmus von RST erzielt schon bei Mindestrundenzahl einen mittleren bis guten Avalanche-Effekt. Das bedeutet, ein einziges "gekipptes" Bit im Chiffrat wirkt sich nach der Entschlüsselung auf 10 bis 50 Prozent im wiederhergestellten Klartextblock aus. Nach jeder vollständigen Blockrunde wird jedoch der innere Zustand des PRNG mit dem Klartext des vorherigen Blockes modifiziert. Daraus resultiert eine massive Fehlerfortpflanzung, welche die Grundlage für den Authentisierungs- und Fehlererkennungsmechanismus bildet.


RST-Kryptosystem. Verschlüsselung, Entschlüsselung, Schlüsselfortschaltung, Klartext-Schlüssel-Rückkopplung, Fehlerfortpflanzung, Integritätsprüfung.
Klartext-Schlüssel-Rückkopplung in RST

RST-Dateiformat

Für PC-Anwendungen entstand ein logisches Format zur authentisierbaren und kryptografisch abgesicherten Übertragung von Dateien. Hier besteht das Kryptogramm ausschließlich aus verschlüsselten Blöcken und kommt ohne irgendwelche Header-Blöcke aus. Eine RST-Sequenz gliedert sich in drei Abschnitte:
  • IV = Block mit verschlüsseltem (geheimem) Initialisierungsvektor
  • DATA = Block oder Blöcke mit verschlüsselter Nachricht (Nutzdaten)
  • VI = Block mit Wiederholung des verschlüsselten IV (Nachricht-Ende-Signatur, MAC-Prüfsumme)
Der erste Block ist der einzige Block, der mit dem Originalschlüssel verschlüsselt wird. Dieser erste Block ist mit Zufallszahlen aufgefüllt. Infolge der Rückkopplung auf den PRNG wird der erste darauf folgende Nachrichtenblock bereits mit einem komplett neuen und einmaligen Schlüsselsatz bearbeitet. Der erste Block hat also die Funktion eines Initialisierungsvektors oder IV. Damit sind triviale Angriffe auf das Kryptosystem (insbesondere "known plaintext") bereits ziemlich sicher ausgeschlossen, da es, vereinfacht gesagt, für verschlüsselte Zufallszahlen keine kryptoanalytische "Abkürzung" gibt.
Der IV-Block hat aber noch eine weitere Funktion. Sein Muster aus Zufallszahlen wird mit allergrößter Wahrscheinlichkeit im nachfolgenden Nachrichtenblock nicht noch einmal vorkommen. Das bedeutet, der IV kann als eindeutige Markierung für das Nachrichten-Ende benutzt werden. Zur funktionalen Unterscheidung wird diese abschließende Wiederholung des IV-Blockes "VI" genannt. Der rechtmäßige Empfänger muss zu Beginn der Entschlüsselung nur den Inhalt des ersten entschlüsselten Blocks als VI zwischenspeichern. Im weiteren Verlauf vergleicht er jeden danach entschlüsselten Block mit diesem VI-Muster:
  • Wenn sich ein entschlüsselter Block vom VI unterscheidet, geht der Empfänger davon aus, dass dies ein gewöhnlicher Datenblock ist, der weiterverarbeitet (z.B. abgespeichert) werden kann. Ob diese Daten auch fehlerfrei sind, kann der Empfänger zu diesem Zeitpunkt allerdings noch nicht wissen.
  • Erkennt der Empfänger einen Block, der exakt mit dem VI übereinstimmt, dann weiß er mit größter Sicherheit, dass die vorherige Übertragung authentisch, vollständig und fehlerfrei war.
  • In allen anderen Fällen wird das Ende der Datei erreicht, ohne dass der Empfänger den VI erkennt. (Fehler!)
Anstelle von Fehler-Lokalisation und Fehler-Korrektur tritt eine zuverlässige Fehlererkennung. (Fehlerhaft entschlüsselte Krypto-Dateien sind normalerweise vollkommen unbrauchbar, und es ist Zeitverschwendung, sich mit fehlerkorrigierenden Maßnahmen auf Dateiebene zu befassen, wenn die Alternative einfach darin besteht, den Download noch einmal zu wiederholen oder die E-Mail noch einmal zu senden.) Der berechtigte Empfänger kann auf Grundlage des IV-VI-Mechanismus in einem Durchgang und mit geringem Aufwand die Authentizität, Vollständigkeit und Fehlerfreiheit einer Nachricht sicherstellen. Diese Funktionalität reicht in vielen Anwendungsbereichen bereits vollkommen aus.

"OWL-RST"

Für den One-Way-Loader kommt eine modifizierte 128-Bit-Variante von RST zum Einsatz. Block- und Schlüsselweite sind beim One-Way-Loader auf 128 Bits (16 Bytes) festgelegt.

Das OWL-Kryptogramm besteht immer aus drei aneinandergereihten kompletten RST-Sequenzen. Diese Sequenzen sind zwar in sich abgeschlossen, aber wie die einzelnen Blöcke kryptografisch voneinander abhängig, denn der PRNG wird im Laufe der Bootloader-Sitzung nicht mehr zurückgesetzt. Somit liefert der letzte VI eine Über-Alles-Prüfsumme zur Gesamtübertragung. Die Fähigkeit, einen Fehler in der Gesamtübertragung sicher zu erkennen, ist für einen Einweg-Bootloader ein äußerst wichtiges Feature.

Als PRNG kommt die Software-Umsetzung eines klassischen Galois-LFSR zum Einsatz, welches um die mächtige Self-Shrinking-Generatorfunktion erweitert wurde. Diese sorgt für eine bedeutende kryptografische Abhärtung der LFSR-Sequenz und bringt im Zusammenhang mit dem Key-Feedback ein hohes Maß an Nichtlinearität in das Kryptosystem ein. Für die Implementierung auf dem Mikrocontroller ist entscheidend, dass sich LFSR-basierte PRNGs sehr codeeffizient, elegant und transparent in Assembler umsetzen lassen.

Da RST keine Feistel-Chiffre ist, müssen Pseudozufallsvektoren für Verschlüsselung und Entschlüsselung jeweils in umgekehrter Reihenfolge angewandt werden. Daraus folgert, dass auf einer Seite die Pseudozufallssequenz aus dem PRNG für eine komplette Blockrunde zwischengespeichert werden muss. Auf der Gegenseite können die Zahlen dann direkt aus dem PRNG gezogen werden. Es versteht sich von selbst, dass die speicher- und codesparende Variante auf den Mikrocoontroller verlagert wird.


Blockverschlüsselung (Pseudocode):

load PRNG with initial key

# PRNG()             pseudo random number generator, consecutively clocked, similar to RND()
# RANDSET[0...63]    an array to keep 64
preloaded PRNG vectors to be read in reverse order
# BUFFER[0...15]     contains working data, initially loaded with plaintext block

for i = 63 to 0 
    RANDSET[i] = PRNG (state)
    state = state + 1
next i


for r = 3 to 0           # outer rounds counting down 3,2,1,0
    for x = 15 to 0      # inner block cycle counting down 15 to 0
       
        y = RANDSET(r*16 + x)   # read vectors from RANDSET in reverse order 63 to 0
        ax = BUFFER[x]         
        ay = BUFFER[y]         
               
invert ay
                ax = ax - ay    # substitution
                right-shift ax, rotate bit 0 to bit 7
   # bitshift permutation
               
BUFFER[y] = ax 
                BUFFER[x] = ay  # byte-swap elements
    next x
next r

BUFFER[0...15] = encrypted block
Blockentschlüsselung (Pseudocode):

load PRNG with initial key

# BUFFER[0...15]         encrypted block
# PRNG()                 deliver 4-bit pseudorandom vectors, according to state

state = 0
for r = 0 to 3           # outer rounds
    for x = 0 to 15      # inner block cycle
        y = PRNG(state)
        state = state + 1
        ax = BUFFER(y)   # byte-swap elements
        ay = BUFFER(x)      
                arithmetic left-shift ax, shift zero to bit 0, bit 7 into Carry
                ax = ax + ay + Carry
                invert ay       
                BUFFER(x) = ax   
                BUFFER(y) = ay
   
    next x
next r

BUFFER[0...15] = decrypted block

Zur Diskussion

Folgende Vorteile sehe ich in der gegenwärtigen Umsetzung von "OWL-RST": Der PRNG läuft immer weiter. Jeder Krypto-Block wird mit einem komplett neuen Schlüsselsatz beackert. Eine auffällige Musterbildung, wie sie bei klassischen Blockchiffren in einem ungünstig gewählten Feedback-Modus vorkommt, ist hier prinzipbedingt ausgeschlossen. Hier profitiert die Blockchiffre von den Eigenschaften einer Stromchiffre.
Der Verzicht auf Lookup-Tabellen und komplizierte Schlüssel-Transformationen spart bei der Implementierung auf Mikrocontrollern eine Menge Speicherplatz (siehe Firmware).
Schon bei Mindestrundenzahl erreicht RST recht ordentliche Balancierungs-, Konfusions- und Diffusions-Eigenschaften. Zusätzliche Maßnahmen zum "Whitening" des Chiffrats sind überflüssig. Die Klartext-Schlüssel-Rückkopplung von RST verfolgt allein den Zweck, einen geheimen IV verwenden zu können und massive Fehlerfortpflanzung zu garantieren.

Die Nachteile sind offensichtlich: Der PRNG läuft immer weiter. Ein kryptografisch starker PRNG braucht Rechenzeit. Auf dem PC war "RST-128" selbst in einer teiloptimierten Variante noch um das 3- bis 5-fache langsamer, als eine vergleichbare Implementierung von AES. (Mit TEA/XTEA lag es fast gleichauf!)

Mein vorläufiges Fazit: In der Bootloader-Umgebung spielt die Performance der Krypto-Schicht eine untergeordnete Rolle. Der Flaschenhals sind hier immer die physischen Schreibzugriffe und die serielle Übertragung. Mit OWL-RST steht eine echte Blockchiffre zur Verfügung, die mit sehr kompaktem Code solide Verschlüsselungssicherheit einschließlich Fehlererkennung und Authentifizierungsfunktion bietet.
Kritik an dieser hausgemachten Lösung ist billig und legitim. In diesem Zusammenhang möchte ich darauf hinweisen, dass die wohl kritischste Komponente des Systems, der Pseudozufallsgenerator, keine Eigenentwicklung ist, sondern eher konservativ ausgewählt wurde. Es handelt sich um ein 128-Bit-LFSR mit einfachem Generatorpolynom (Galois-Feedback auf den Bits 128, 127, 126 und 121), welches durch die Self-Shrinking-Filterfunktion bedeutend abgehärtet wurde. Das SSG-LFSR gilt als kryptografisch sicherer PRNG.
Des Weiteren gehe ich davon aus, dass die nachgeschaltete Blockchiffre und der IV-VI-Mechanismus keine neuen Schwachstellen aufreißen, sondern im Gegenteil sämtliche Angriffe, die auf Extraktion und Analyse der zugrundeliegenden LFSR-Sequenz abzielen, noch erheblich erschweren. Hierzu höre ich gern qualifizierte Argumente und Vorschläge!

Nach oben | Index



Firmware

Die OWL-Firmware ist in Assembler geschrieben und nutzt den Standard-Befehlssatz, welcher von nahezu allen 8-Bit-AVRs unterstützt wird. Die Firmware ist von keinen besonderen Hardwarekomponenten abhängig und verwendet keine Interrupts. Somit steht dieser Bootloader schon jetzt wieder für mehr als 100 verschiedene ATtinys und ATmegas zur Verfügung. Alle Varianten brauchen unter 512 Bytes. Der Quellcode ist offengelegt und reichlich kommentiert.

Features:
  • Portabler Code, läuft auf vielen 8-Bit-AVRs
  • Nutzung beliebiger Ports für den Datenempfang
  • Schnelles "patentiertes" Verfahren für wiederholtes Neusynchronisieren und Autobauding
  • Warten bis zum Timeout oder Einstieg in laufendes Signal
  • Datenempfang in nichtinvertierter oder invertierter Logik
  • Optionales Steuersignal in nichtinvertierter oder invertierter Logik (Dummy-TXD, RS485-TE)
  • Individueller 128-Bit-Zufallsschlüssel bzw. individuelle Geräteadresse "serienmäßig"
  • Sichere Authentisierung, Entschlüsselung und Ablaufsteuerung nach "OWL-RST"
  • Lineare Schreibzugriffe in EEPROM und/oder Flash (zurzeit bis 64-K-Devices)
  • Klar definiertes Verhalten im Fehlerfall

Speicherbelegung:
Speicherbelegung der OWL-Bootloader-Firmware auf einem AVR-ATtiny-Mikrocontroller.
Speicherbelegung der OWL-Bootloader-Firmware auf einem AVR-ATmega-Mikrocontroller.
Fußabdruck auf ATtinys:
Fußabdruck auf ATmegas:
  • Bootloader belegt 512 Bytes am oberen Flash-Ende.

  • Aufruf: Modifizierter rjmp/jmp an Adresse $0000 springt zur Startadresse des Bootloaders (BOOTSTART).

  • Bootloader springt nach beendigtem Job oder nach Timeout zur Reset-Routine der Applikation (RESET).

  • INFO TAG mit Meta-Daten wird jeweils an das Ende eines Flash-Uploads angehängt und liefert dem Bootloader Timeout (Byte) und Sprungadresse zur Reset-Routine der Applikation (Word).

  • Krypto-Schlüssel in Bootloader eincodiert (letzte 16 Bytes der Firmware).
  • Bootloader belegt BOOT FLASH SECTION
    von 512 Bytes am oberen Flash-Ende.

  • Aufruf: Standardmäßig über BOOT RESET VECTOR (BOOTRST), welcher beim Hardware-Reset zur Startadresse der Bootloader-Sektion springt (BOOTSTART).

  • Bootloader springt nach beendigtem Job oder nach Timeout zur Adresse $0000 und startet damit die Applikation.

  • Krypto-Schlüssel und Timeout-Byte sind fest eincodiert (letzte 17 Bytes der Firmware).

  • Bootloader-Sektion kann per Lockbits umfassend geschützt werden (direkte Bootloader-Unterstützung auf ATmegas).

Hinweis: Adressen in den Diagrammen sind Bytes.

An dieser Stelle eine "High-Level-Beschreibung" zu wesentlichen Funktionsblöcken der  OWL-Firmware:


Aufruf:
Gewöhnlich erfolgt der Aufruf eines Bootloaders über einen Hardware-RESET. Dieser wird durch eine steigende Flanke auf dem Controller-Eingang "RESET" oder durch Verbinden des Controllers mit der Stromversorgung (Power-On-Reset bzw. Brown-Out-Reset) ausgelöst. Der Aufruf des Bootloaders per Hardware-Reset ist die technisch sauberste und rechtlich einwandfreie Methode, um eine klare Trennung zwischen Bootloader- und Applikations-Firmware zu gewährleisten.


Initialisierung: Der Bootloader wird nach dem Hardware-Reset als erstes Programm gestartet. Er initialisiert den Stackpointer und alle von ihm selbst genutzten Register, Ports und Speicherzellen. Es findet keine Initialisierung des übrigen SRAM oder der sonstigen I/O-Ports statt.
  • ATtinys: Der Bootloader durchsucht absteigend den Applikations-Flash nach dem sogenannten INFO TAG und holt sich von dort das Timeout-Byte. Anschließend lädt er den individuellen Krypto-Schlüssel, der sich "hard-coded" am obersten Flash-Ende befindet, in die PRNG-Arbeitsregister (r0-r15). Dann beginnt der Bootloader auf der Empfangsleitung zu lauschen. Erscheint dort vor Ablauf des Timeout ein Signal, dann versucht der Bootloader, sich darauf zu synchronisieren. Passiert bis zum Timeout nichts, holt sich der Bootloader aus dem INFO TAG die Adresse der Reset-Routine der Applikations-Firmware und startet diese. Bei "leerem" Flash (keine Applikation, alles $FF-Bytes) verwendet der Bootloader immer den längstmöglichen Timeout und startet sich selbst wieder. In dieser Ausgangslage bleibt der Bootloader also permanent erreichbar und muss nicht immer wieder resettet werden.

  • ATmegas: Der Bootloader lädt den individuellen Krypto-Schlüssel in die Arbeitsregister r0-r15 und beginnt auf der Empfangsleitung zu lauschen. Der Timeout ist auf ATmegas fest in die Firmware eincodiert, hier wird auf den INFO TAG vollständig verzichtet. Trifft vor Ablauf des Timeout ein Signal ein, so wird der Bootloader versuchen, sich darauf zu synchronisieren. Passiert bis zum voreingestellten Timeout nichts, springt der Bootloader pauschal zur Adresse $0000, wo die Applikation auch ohne Reset-Vektor gestartet worden wäre. Bei ansonsten leerem Flash wird der Bootloader also auch hier immer wieder neu gestartet.

Synchro-Autobauding:
Der Bootloader wartet an der für den Datenempfang konfigurierten Leitung bis zum Timeout auf einen ersten Pegelwechsel. Dieser wird verworfen, um ein "Einpendeln" des Signals zu ermöglichen. Anschließende Pegelwechsel wertet die Firmware mit dem weiter oben beschriebenen Synchro-Autobaud-Verfahren aus. Hier sind eine Menge Erfahrungswerte von "TSB" eingearbeitet worden. Sofern das ankommende Signal tatsächlich eine OWL-Präambel ist, und sofern das Signal ausreichend flankensteil durchkommt, wird die Erstsynchronisation gelingen. Danach besitzt der Bootloader eine präzise Zeitbasis für den Empfang des ersten Datenblocks per Software-Decoder. Der Synchro-Autobaud-Zyklus wird vor jedem einzelnen Datenblock wiederholt, sodass die Transmission gegenüber Schwankungen der Taktfrequenzen auf beiden Seiten nahezu immun wird.


Blockdatenempfang: Nach erfolgreichem Synchro-Autobauding werden die nachfolgenden Zeichen über die reguläre Empfangsroutine decodiert. Zunächst wartet eine Schleife die restlichen Präambel-Zeichen ab, bis das Blockstart-Zeichen erscheint. Die darauf folgenden 16 Bytes sind der verschlüsselte Datenblock und werden zur weiteren Verarbeitung in einen SRAM-Puffer übernommen.


Block-Daten entschlüsseln: Der Bootloader klinkt sich aus der seriellen Übertragung aus und beginnt die Entschlüsselung des im SRAM-Puffer vorliegenden Datenblocks. Für 4 Runden auf 16 Bytes werden insgesamt 64 Pseudozufallsvektoren à 4 Bit aus dem PRNG gezogen (Mindestrundenzahl). Die vom PRNG gelieferten Pseudozufallsvektoren hängen vom inneren Zustand (state) des PRNG ab, welcher in den Registern r0-r15 gespeichert ist. Mit jedem gezogenen Bit verändert sich der innere Zustand des PRNG.
Nach dem Entschlüsseln liegen die 16 (mutmaßlich) fehlerfreien Bytes im selben Puffer vor.
Der frisch entschlüsselte Block wird per XOR auf die PRNG-Register r0-r15 rückgekoppelt (Key Feedback). Dadurch fließt Entropie aus den Nutzdaten in die nachfolgende Ver/Entschlüsselung ein und die massive Fehlerfortpflanzung wird garantiert.
Der erste Block einer neu begonnenen Sequenz, der IV-Block, besteht aus Zufallszahlen. Faktisch läuft der PRNG ab dem zweiten Block einer Sequenz mit einem völlig neuen Zufallsschlüssel weiter, der auch nur einmal verwendet wird. Außerdem wird der IV-Block als VI in einen zweiten SRAM-Puffer kopiert.
Alle danach entschlüsselten Blöcke werden mit dem VI verglichen. Solange der aktuelle Block nicht mit dem VI identisch ist, geht das Programm davon aus, dass es sich um reguläre Schreibdaten handelt, die entsprechend weiterverarbeitet werden.
Erkennt das Programm, dass der aktuelle Block mit dem VI identisch ist, dann ist die Sequenz erfolgreich abgeschlossen und der Bootloader weiß jetzt, dass alle vorherigen Blöcke in Ordnung waren. Dann schaltet er zur nächsten Sequenz weiter.
Im Fehlerfall wird überhaupt kein VI mehr erkannt. Das Programm verharrt in der aktuellen Sequenz, bis die Übertragung zuende ist und es zum Timeout kommt. Weiteres dann unter "Fehlerbehandlung".
Die gesamte Blockentschlüsselung benötigt in Assembler einschließlich PRNG gerade einmal 50 Maschinenbefehle! Der Blockvergleich und das XOR-Feedback auf den Schlüsselgenerator konnten in einer gemeinsamen Schleife untergebracht werden, die auch nur 12 Maschinenbefehle braucht.


Authentisierungs-Sequenz (S1): Bevor der Bootloader irgendwelche Schreibzugriffe zulässt, muss er sichergehen, dass der Sender das Schlüsselgeheimnis kennt. Ein "Türsteher" muss halt sein, damit nicht sonstwer reinkommt, einem die Bude vollkotzt und den Hund vergewaltigt.
Anders, als eine simple Passwort-Abfrage, ist die Authentisierung gegenüber dem Bootloader "nicht übertragbar". Hier wird eine komplette RST-Sequenz gesendet, die aufgrund des Key-Feedbacks untrennbar mit der nachfolgenden EEPROM- und Flash-Sequenz verbunden ist.
Wenn der Bootloader den dritten Block der Authentisierungs-Sequenz S1 als VI erkannt hat, dann weiß er mit allergrößter Sicherheit, dass der Sender den korrekten Schlüssel benutzt. Dann geht der Bootloader vertrauensvoll in die nachfolgende EEPROM-Sequenz S2.
In allen anderen Fällen, also bei Verwendung eines falschen Schlüssels oder bei gestörter Übertragung, wird die Authentisierungs-Sequenz S1 nicht als gültig erkannt. Der Bootloader geht in eine Endlos-Schleife ohne Timeout. Dieser Zustand kann nur über einen erneuten Hardware-Reset beendet werden.
Der Blockade-Mechanismus erlaubt es, mehrere Bootloader mit verschiedenen Schlüsseln und unterschiedlichen technischen Voraussetzungen auf einer gemeinsamen Programmierleitung zu betreiben. Pro Reset-Zyklus wird immer nur der tatsächlich angesprochene Bootloader die für ihn bestimmte Übertragung auswerten. Alle nicht angesprochenen Bootloader werden ab dem dritten Block in den Blockadezustand übergehen und sich bis zum nächsten Hardware-Reset vollkommen passiv verhalten. Eine dort vorhandene Applikations-Firmware wird nicht angetastet und nicht unkontrolliert gestartet. (Solche Multi-AVR-Szenarien sind im Zusammenhang mit TSB von einigen Leuten getestet worden, aber hier gab es wegen des eher primitiven Passwort-Verfahrens immer wieder Probleme.)


EEPROM-Sequenz (S2): Der Bootloader entschlüsselt und kopiert den IV der EEPROM-Sequenz. Die nachfolgenden Datenblöcke werden in Schüben von 16-Bytes im Atomic-Write-Modus in den EEPROM geschrieben. Enthielt die EEPROM-Sequenz keinen einzigen Datenblock (nur IV- und VI-Block), dann wird im EEPROM auch nichts verändert und der Bootloader geht über zur Flash-Sequenz S3.
Für den EEPROM erfolgt kein separater Löschzyklus. Das bedeutet, Speicherinhalte, die sich weiter "hinten" im EEPROM-Adressbereich befinden, werden nicht angetastet, wenn ein neuer Schreibzugriff nur tiefer liegende Adressen berührt. Das kann gegebenenfalls für eine Art "inkrementelle" EEPROM-Updates ausgenutzt werden.
Zum Löschen des gesamten EEPROM muss eine Sequenz übertragen werden, die den ganzen Speicherbereich abdeckt und mit $00 oder $FF überschreibt.
Im EEPROM-Modus müssen keine besonderen Vorkehrungen gegen Adressüberlauf getroffen werden, da im EEPROM kein ausführbarer Code stehen kann. Sollte in der EEPROM-Sequenz etwas gründlich schiefgehen, dann würden die Schreibzugriffe einfach nur immer wieder den EEPROM überschreiben. Dieses Risiko erscheint tragbar. Der EEPROM ist gewissermaßen die "Knautschzone" vor dem wirklich kritischen Flash-Zugriff.
Kommt es in der EEPROM-Sequenz zum Timeout, dann geht der Bootloader in den Blockadezustand, sodass auch hier die indirekte Standard-Rückmeldung "Hey, das war wohl nichts!", erfolgt.
Wurde die EEPROM-Sequenz korrekt mit dem VI abgeschlossen, dann erwartet der Bootloader als Nächstes die Flash-Sequenz S3.


Flash-Sequenz (S3): Der Bootloader entschlüsselt und kopiert den IV der Flash-Sequenz. Wenn der darauf folgende Block bereits der VI ist, dann ist der Bootloader schon fertig und wird den Flash unangetastet lassen.
Kommen nach dem IV jedoch Flash-Schreibdaten, dann löscht der Bootloader zunächst den gesamten Applikations-Flash unterhalb der Bootloader-Firmware. Der Löschzyklus erfolgt auf ATtinys mit Rücksicht auf die besonderen Risiken Top-to-Bottom. Generell muss der Bootloader Flash-Daten, die ja immer in Blöcken von 16 Bytes eintreffen, bis zur tatsächlichen Seitengröße (PAGESIZE) zusammenfassen, bevor er sie in einem Rutsch in die aktuelle Page schreiben kann.
Durch die Teilung in 16-Byte-Einheiten ist die Flash-Schreibroutine recht zukunftssicher. Sie würde im Prinzip noch bis zu einer Pagesize von 4096 Bytes funktionieren... (Die größte auf ATmegas eingesetzte Pagesize beträgt 256 Bytes.)
Auf ein explizites Verifying der geschriebenen Daten wird jetzt komplett verzichtet. Die langjährigen Erfahrungen mit TSB haben gezeigt, dass es NIE zu fehlerhaften Flash-Schreibzugriffen kommt, sobald die Daten erst einmal fehlerfrei im Schreibpuffer gelandet sind und für die Dauer des Flash-Write stabile Betriebsbedingungen bestehen. Beim OWL entschärft sich die Situation noch, da der gesamte Übertragungsweg ja durch das Kryptosystem abgesichert ist.
Wurde der letzte VI aus S3 erkannt, dann war die Transmission im Ganzen erfolgreich. Bereits geschriebene Daten sind mit allergrößter Wahrscheinlichkeit fehlerfrei und dürfen in den jeweiligen Speicherbereichen stehen bleiben. In diesem Fall ist der Bootloader auch schon fast am Ende.
Wurde kein VI erkannt, dann hat der Bootloader mit dem Ablauf des Timeout die schreckliche Gewissheit, dass in der Flash-Sequenz etwas schief gelaufen ist. Jetzt wird der Bootloader konsequenterweise den Applikations-Flash wieder löschen, damit hier kein fehlerhafter Code stehen bleibt.


Erfolgreiche Transmission und Übergabe an Applikations-Firmware: Nach erfolgreichem Abschluss der Flash-Sequenz S3 übergibt der Bootloader praktisch verzögerungsfrei an die neu geschriebene oder an eine unverändert gelassene Applikations-Firmware.
Auf einem ATtiny muss der Bootloader noch einmal nach dem INFO TAG suchen, welcher mit einer neuen Firmware ebenfalls neu geschrieben wurde. Dort steht dann der aktuelle Reset-Vektor der Applikations-Firmware als absolute Adresse. Diese springt der Bootloader per indirektem Jumpbefehl an und startet somit die Applikations-Firmware.
Auf einem ATmega muss der Bootloader nur den Zugriff auf den RWW-Speicherbereich (= Applikations-Flash) freigeben. Dann springt er pauschal nach $0000, wo sich üblicherweise die Interrupt-Tabelle mit dem unveränderten Original-Reset-Vektor der Applikation befindet, und die Applikation startet.
Günstig ist es also, wenn sich die Applilkation irgendwie bemerkbar machen kann, also zum Beispiel mit ihrem Programmstart eine LED zum Leuchten bringt, eine Display-Meldung ausgibt oder einen Piepser aktiviert. Damit erhalten wir eine indirekte aber klare Rückmeldung über den Erfolg der Transmission.


Allgemeine Fehlerbehandlung: Fehler können bereits auftreten, noch bevor irgendwelche Daten geflossen sind, sogar wenn gar keine Bootloader-Sitzung vorgesehen ist. Ein Kaltstart bringt es mit sich, dass Hardwarekomponenten und die Portleitungen des Controllers auch mal undefinierte Zustände einnehmen können. Der "Brownout-Detektor" des Mikrocontrollers stellt sicher, dass der Prozessor erst dann mit der Programmverarbeitung beginnt, wenn sich die Betriebsspannung stabilisiert hat; auf externe Hardwarekomponenten hat der BOD jedoch keinen Einfluss. So ist es möglich, dass auf der Empfangsleitung noch für längere Zeit ein unzulässiger oder undefinierter Pegel anliegt, oder externe Hardware verursacht einen oder mehrere Pegelwechsel, bis sich die Versorgungsspannungen stabilisiert haben. Wenn zu diesem Zeitpunkt das Bootloader-Programm bereits auf der Leitung lauscht, kann es zu "Missverständnissen" kommen. So gab es mit dem TSB im Zusammenhang mit USB-Geräten, die nur durch Power-On resettet werden konnten, manchmal den unschönen Effekt, dass sich der Bootloader wegen eines ungültigen Anfangszustandes auf der Leitung "aufhängt". Auch hierfür waren Workarounds in der Bootloader-Firmware möglich, aber diese haben dann in anderen Hardwareumgebungen wieder Probleme bereitet. Man kann es eben nicht allen recht machen...
Der OWL zeigt allerdings ein wesentlich verbessertes Startverhalten. Der Start der Applikation hat Priorität. Sollte die Empfangsleitung direkt nach einem Kaltstart noch etwas unentschlossen sein, dann kommt zwar keine Bootloader-Sitzung zustande, aber die Firmware geht nach dem Abklingen der Störung in den normalen Timeout und startet die Applikations-Firmware.
Wurde ein ganzer Datenblock komplett entschlüsselt, geht die Bootloader-Firmware davon aus, dass dies nun kein Zufall war und eine reguläre OWL-Transmission vorliegt. Sollte es in diesem fortgeschrittenen Stadium zu einem Timeout kommen, dann übergibt der Bootloader nicht mehr an die Applikations-Firmware. Stattdessen verbleibt er im Blockade-Zustand.
Auf diese Weise ergibt sich ein einheitliches Fehler-Verhalten: Ein bisschen "Gekruschel" auf der Leitung verhindert den Start der regulären Applikation nicht. Wenn eine echte Transmission empfangen wird, gilt: ENTWEDER es kommt alles vollständig, fehlerfrei und zügig durch, dann wird die Applikation unmittelbar nach Beendigung der Transmission gestartet, ODER es gab irgendeinen Fehler oder einen Timeout während der Übertragung, dann geht der Bootloader in den Blockadezustand.

Timeout-Timing: Der Timeout des Bootloaders soll in einem breiten Fenster von realistischen Taktraten (etwa 128 kHz bis 25 MHz) Verzögerungen von einer zehntel Sekunde bis hin zu mehreren Sekunden ermöglichen. Der OWL verwendet ebenfalls ein "Timeout-Byte", welches aber gewissermaßen normiert ist. Dafür wird die Timeout-Zeitschleife auf die vorgesehene Clock-Frequenz kalibriert. Wenn wir diese beim Erzeugen der Target-Firmware mit angeben, ist die Maßeinheit des Timeout-Bytes genau 1/100stel Sekunde. Das bedeutet, der Wert "100" für das Timeout-Byte entspricht immer einer Sekunde, der Wert "1" einer Hundertstel Sekunde, und der Wert "255" entspricht 2,5 Sekunden.
Die Anpassung der Zeitbasis-Schleife funktioniert ähnlich, die wie Anpassung der Portzugriffe, direkt im Maschinencode.


PRNG (Schlüsselgenerator): Der PRNG wird bei Aufruf des Bootloaders mit dem geheimen Schlüssel geladen. Dieser innere Zustand des PRNG verändert sich bei fortlaufender Taktung und er wird außerdem über den Klartext jedes entschlüsselten Blockes modifiziert (siehe Diagramm zum Key-Feedback).
Der PRNG ist die Software-Implementierung eines klassischen 128-Bit LFSR mit Rückführungen von den Bits 128, 127, 126 und 121 (als Galois-XOR mit einem Byte realisierbar). Der Output geht durch ein sogenanntes Self-Shrinking-Filter. Diese Funktion macht aus dem einfachen LFSR mit eher mäßigen Autokorrelationseigenschaften einen kryptografisch starken Pseudozufallsgenerator. Allerdings braucht das SSG-LFSR im Durchschnitt 3 mal mehr Taktzyklen, als ein ordinäres LFSR. Dieser Nachteil erscheint in der Bootloader-Anwendung tolerierbar, da Sicherheit an erster Stelle steht und andere Faktoren den Datendurchsatz stärker drosseln.
Nichtzuletzt ließ sich der Assemblercode für das SSG-LFSR deutlich optimieren. Man lernt ja dazu... Hier erfolgen die Bitshifts auf je zwei Arbeitsregistern (statt über alle 16), und nur mit jedem 8.Takt werden die übrigen 14 Register dann direkt als Bytes geshiftet ( mov), was eine ganze Menge Proztessortakte einspart.
Meiner Ansicht nach ist das vorliegende SSG-LFSR eine der takt- und codeeffizientesten PRNG-Optionen auf 8-Bit-MCUs, und es ist eine Schande, dass ich mal wieder selbst drauf kommen musste, weil sich nichts Vergleichbares im Netz fand! Die unregelmäßige Taktung könnte weitere Vorteile hinsichtlich möglicher Seitenkanalangriffe bedeuten (z.B. "Power analysis", dies müsste jedoch ausführlicher untersucht werden).


Port-Limits: Die Firmware kann nur auf I/O-Ports zugreifen, die über die Maschinenbefehle cbi, sbi, sbic, sbis direkt erreichbar sind. Einige exotische Devices kennen mittlerweile auch einen "PORTG" oder "PORTH" mit I/O-Adressen oberhalb von $3F. Diese Ports sind infolge der AVR-Prozessorarchitektur nur über SRAM-Befehle adressierbar. Weil die entsprechenden Opcodes ein langsameres Timing haben und mehr Speicherplatz kosten, werden solche "memory mapped"-Zugriffe von der OWL-Firmware bis auf Weiteres nicht unterstützt.


Code-Flexibilität im Vergleich zu TSB: Der Assembler-Quelltext der OWL-Firmware enthält auch wieder einige Präprozessor-Anweisungen, die den Code flexibel machen. Dennoch ist der Anteil solcher .if/.endif-Konstrukte zur bedingten Assemblierung deutlich geringer, als dies noch beim TSB der Fall war. Schließlich ist das zugrundeliegende Übertragungsformat ("OWL-Transmission") für alle Devices einheitlich, während Besonderheiten im Timing bereits auf Senderseite in Form der maßgeschneiderten Präambeln berücksichtigt werden. Auch benötigt der OWL keine zusätzliche Speicherseite ("LASTPAGE"), sodass sich im Vergleich zu TSB eine ganze Page einsparen lässt. Weniger Extrawürste und  aufgeräumterer Code - Ich bin guter Hoffnung, dass der OWL-Code noch wartungsfreundlicher sein wird, als sein Vorgängerprojekt.


Portierbarkeit: Der vorliegende Assemblercode ermöglicht ohne besondere Anpassungen die Erzeugung von OWL-Firmware für einen Kernbestand von ca. 100 ATtinys und ATmegas mit bis zu 64 Kilobytes an Flash.
Zahlreiche ATtinys und ATmegas sind in der Vergangenheit erfolgreich mit TSB gelaufen. Für einige Chips waren kleinere Anpassungen am Code erforderlich, die glücklicherweise nicht neu erarbeitet werden mussten. Es besteht also eine große Wahrscheinlichkeit, dass der OWL auf denselben Devices von Anfang an problemlos arbeiten wird.
AVR-Devices über 64 KiB (z.B. Mega128x und Mega256x) verlangen nach einer etwas dickeren Extrawurst. Diese Chips haben 128 bzw. 256 Kilobyte an Flash-Speicher, welcher sich bei Flash-Writes nicht mehr allein mit dem 16-Bit-Z-Register erfassen lässt. Für den erweiterten Zugriff kommt eine Art "Bankswitching" zur Anwendung (I/O-Register RAMPZ). Ein One-Way-Loader für diese Devices erscheint möglich, aber unter Beibehaltung des linearen Adresszugriffs wäre das vielleicht nichts für Ungeduldige. Im Extremfall dauert das Firmware-Update für den vollen Applikations-Flash von 128 oder gar 256 Kilobytes nicht mehr Sekunden, sondern Minuten. Andererseits ist die OWL-Transmission dank wiederholter Nachsynchronisation auch in langen Durchgängen sehr robust. Ein erweitertes Protokoll für den "modularen" Schreibzugriff (einzelne Bänke oder Pages) könnte die Situation entschärfen, wäre aber meiner Meinung nach keine gute Idee. Denn wenn der Bootloader hier und dort ein paar Kilobytes modifiziert, während an anderen Stellen älterer Code stehenbleibt, dann ist das Chaos eigentlich schon vorprogrammiert. Es gibt ja in einem abgesicherten Chip keine Möglichkeit, irgendwelche Daten zurückzulesen, und dies würde auch dem Sicherheitsgedanken komplett widersprechen. Genug spekuliert. Hier bin ich explizit auf Anregungen und Tipps von Leuten angewiesen, die solche dicken Dinger in verschiedenen praktischen Anwendungen tatsächlich einsetzen. Ich selbst habe eine kleine Testumgebung mit Mega1284 und schaue mir das demnächst mal an!
Mein Motivationsspielraum endet definitiv bei den "XMegas"! Ich nutze keine XMegas, und mit kleineren Code-Anpassungen ist es da nicht mehr getan; die ganze Architektur weicht deutlich von den "klassischen" AVRs ab. Die Unterschiede zwischen "ATmegas" und "XMegas" hinsichtlich I/O-Konzept und Interrupts erscheinen mir größer, als etwa zwischen ATmegas und PICs. Eine Portierung für XMegas oder PICs steht nicht auf meiner Agenda.

Fuses/Lockbits:

Für den Betrieb eines Bootloaders muss der Controller gewisse Voraussetzungen erfüllen.

ATtinys:
  • SELFPRGEN aktivieren (na klar, sonst kann OWL später nichts in den Flash schreiben!)
  • BODLEVEL aktivieren verhindert Flash-Korrumpierung bei unstabiler Betriebsspannung (Ein- und Ausschalten).
  • Lockbits Modus 3 verhindert das Ausspionieren oder Verändern von Speicherinhalten über die ISP/JTAG.
ATmegas:
  • BOOTRST aktivieren aktiviert den direkten Bootloader-Aufruf per Hardware-Reset.
  • BODEN + BODLEVEL aktivieren verhindert Flash-Korrumpierung bei unstabiler Betriebsspannung.
  • BOOTSZ=10 oder BOOTSZ=11 zur Verwendung einer Bootloader-Sektion von nur 512 Bytes (256 Words).
  • BLB in Modus 2 oder 3 schützt die Bootloader-Sektion vor unkontrollierten Schreibzugriffen.
  • Lockbits in Modus 3 verhindert das Ausspionieren oder Verändern von Speicherinhalten über ISP/JTAG.

Kompatibilitäts-Voraussetzungen und Vorsichtsmaßnahmen:

  • Keine Abhängigkeiten. Die Bootloader-Firmware darf nicht von weiteren Firmware-Komponenten abhängig sein, da sie sonst nicht in der Lage wäre, auf einem "leeren" Controller eine erste Applikations-Firmware zu laden.
    Umgekehrt wäre der Aufruf von vorhandenem Bootloader-Code durch eine Applikation zwar durchaus möglich, aber meiner Meinung nach nicht empfehlenswert. Eine solche "Verzahnung" von Programmen führt fast zwangsläufig zu technischen Problemen und bei eher restriktiven Lizenzmodellen auch zu großen rechtlichen Problemen, wenn nicht alles aus einer Hand stammt.
    Generell vertrete ich die Auffassung, dass Applikations-Firmware und Bootloader-Firmware auf einem Mikrocontroller in keiner Weise voneinander abhängig sein dürfen und sauber getrennt werden sollten.
    Das einzig legitime Zusammenspiel zwischen einer Bootloader- und einer Applikations-Firmware soll darin bestehen, dass der Bootloader nach getaner Arbeit (d.h. Timeout oder erfolgtes Firmware-Update) die Kontrolle an die Applikation abgibt.

  • Applikations-Firmware und Bootloader-Firmware dürfen zusammen nicht mehr Speicherplatz belegen, als tatsächlich vorhanden ist... Aber keine Sorge, wenn's nicht passt, wird sich die Software schon melden.
  • Vorsichtsmaßnahmen ATtinys: Die Applikation sollte am besten auf Flash-Schreibzugriffe verzichten, da es auf ATtinys möglich ist, den Bootloader durch fehlgeleitete Schreibzugriffe zu beschädigen oder durch Auslesen des Bootloader-Adressbereichs Schlüsselmaterial zu "leaken".

  • Vorsichtsmaßnahmen ATmegas: Die Bootloader-Sektion kann per Fusebits gegen Zugriffe aus der Programmsektion geschützt werden. Hier wird der Bootloader nahezu unsterblich und es sind keine besonderen Vorsichtsmaßnahmen erforderlich.

Nach oben | Index




Software

Allgemeines

Die OWL-Software ist ein Kommandozeilentool für die PC-Plattform. Das Programm steht im Quellcode sowie als ausführbare Datei für Windows (32 Bit) und Linux (32/64-Bit) zur Verfügung. Das Programm kann Folgendes:
  • Erzeugung von Einzel-Bootloadern mit angepassten Ports und Zufallsschlüsseln
  • Erzeugung von Serien-Bootloadern mit angepassten Ports und Zufallsschlüsseln
  • Infos zu unterstützten Controller-Modellen und Hardware-Optionen
  • Infos zu selbst erzeugten Krypto-Bootloadern
  • Verwaltung aller selbst generierten Bootloader, Schlüssel und Meta-Daten über frei wählbare Dateinamen
  • Senden von Daten für Flash und/oder EEPROM in einer Sitzung ("Transmission")
  • Export von Transmissionen in eine Binär- oder Audio-Datei für Distributionszwecke
  • Import verschlüsselter Transmissionen und Weiterleitung auf lokale Zielgeräte
  • Test der Krypto-Module
  • Hilfesystem

Philosophie

So einfach wie möglich, aber nicht einfacher! Meine Hardware-Software-Projekte setzen auf einfache Verwaltungsstrukturen, größtmögliche Transparenz und minimale Abhängigkeiten. Haltet mich für verrückt, aber ich gehe weiterhin davon aus, dass die Technik dem Menschen dienen soll und dass digitale Versklavung kein unentrinnbares Schicksal ist. Wer Technik souverän einsetzt, wer den Unterschied zwischen gegenseitigem Nutzen und einseitigem Benutztwerden kennt, und wer auf Nutzloses verzichten kann, der wird in Zukunft umso mehr Nutzen haben und seine privaten wie geschäftlichen Geheimnisse effektiv schützen können.

Nun hat die OWL-Software schon einen vergleichsweise großen Funktionsumfang. Und das bedeutet an der Kommandozeile ja bekanntlich immer: Kryptische Zeichenketten, Kraut-und-Rüben-Syntax, abartige Unterscheidung zwischen Groß- und Kleinschreibung, verschachtelte Abhängigkeiten, ätzende Semantik...

Aber nicht doch. Nicht hier! Das Programm verfügt über einen menschenfreundlichen Kommandozeilen-Parser und vergleichsweise informative Hilfe-Texte und Bildschirmmeldungen. Für jede Kommandozeilenoption gibts eine "sprechende" Langschreibweise und eine einprägsame Kurzschreibweise. Meinem Parser ist die Reihenfolge der Optionen und Argumente völlig egal (lateinische Semantik). Alles, was sich der Nutzer merken muss, um eine bestimmte Funktion auszulösen, ist der Name der dafür benötigten Option und eventuelle weitere Parameter, die zusätzlich angegeben werden müssen oder können. Vieles ergibt sich bereits durch Nachdenken, den Rest können wir nachschlagen. Wer jemals etwas an der Kommandozeile gemacht hat, für den dürfte dieses OWL-Tool ungewöhnlich "intuitiv" bedienbar sein. Ich behaupte sogar: Im Gegensatz zu gewissen 'dudes' ist mein OWL-Kommandozeilentool auch ohne GUI-Frontend benutzbar!

Sämtliche Interaktionen, Schlüsselwörter und Bildschirmmeldungen sind in der englischer Sprache gehalten. Das ist der wohl linguistisch wie technisch günstigste Kompromiss. (Lokalisierte Sprachversionen sind für diese Anwendung vorerst nicht geplant.)

Installation

Die Software ist portabel, d.h. sie läuft in jedem Verzeichnis, in dem wir Schreib- und Dateiausführungsrechte haben. Natürlich läuft das Programm auch von einem externen Medium, wie etwa einem USB-Stick. Zur "Installation" einfach das Download-Paket an den gewünschten Zielort entpacken. Dabei werden folgende Verzeichnisse angelegt:
  • owl
    • templates
    • targets
    • transmissions  
Der spätere "Umzug" mit einer kompletten OWL-Umgebung (Hauptordner samt Unterordnern) ist kein Problem. Die Anwendung selbst speichert keine absoluten Pfade.


Ordnerstruktur

Es gibt drei "Datentypen", die die OWL-Software verwalten muss:  Bootloader-Vorlagen, Bootloader-Firmware, und Bootloader-Transmissionen . Diese liegen in separaten Dateien und Ordnern vor. Wer es gewohnt ist, seine Daten über das Dateisystem zu organisieren, wird problemlos den Überblick behalten und für den ist diese Software auch keine Black Box.
Bootloader-Vorlagen:     /templates
Für jedes direkt unterstützte AVR-Modell gibt's fertig assemblierten Maschinencode. Dieser enthält für das jeweilige Device eine OWL-Firmware mit Default-Ports (B0/B1) und Default-Key ($0011...EEFF). Wenn die OWL-Software einen maßgeschneiderten Bootloader erzeugen soll, dann sucht sie standardmäßig im Ordner templates nach einer Hex-Datei mit dem passenden Namen, um ihn nach Kundenwunsch anzupassen. Wer über eine AVR-Assembler-Infrastruktur verfügt und weiß, was er (oder sie) tut, kann auch eigene Templates in diesen Ordner legen.

Bootloader-Firmware:     /targets
Die Erzeugung eines neuen Bootloaders (Target) erfolgt nach bewährtem Prinzip auf Grundlage eines Templates für den entsprechenden Controller-Typ (Device). Das Programm durchforstet den Maschinencode nach I/O-Befehlen, die sich auf die Standard-Ports für Templates beziehen (cbi,sbi, sbic, sbis an Port B0/B1) und passt diese an die vom Benutzer gewünschten Ports an. Außerdem wird ein zufälliger Krypto-Schlüssel für den neuen Bootloader erzeugt und in den Code eingefügt.
Schließlich speichert das Programm die modifizierte Bootloader-Firmware in eine Hex-Datei unter dem gewünschten Target-Namen (oder automatisch generiertem Namen) im Ordner targets ab. Die Datei im Format Intel-Hex soll von einem "AVR-Brenner" übernommen und per ISP in den Ziel-Controller geschrieben werden. Nach dem Ändern der Fusebits ist der neue OWL einsatzbereit.
Die Target-Datei ist der einzige Speicherort für Krypto-Schlüssel und Meta-Daten eines Bootloaders!
Also besser nicht löschen, wenn wir den betreffenden OWL tatsächlich benutzen wollen.
Die Meta-Informationen zum jeweiligen Target sind als Kommentarzeilen hinter den letzten Hex-Record angehängt, menschenlesbar und editierbar. Eine ISP-Software wird diese Zeilen einfach ignorieren. Die OWL-Software wertet diese Zeilen aus und hat sofort alle benötigten Meta-Infos zum angegebenen Target parat. Alle wichtigen Informationen zu einem individuellen Bootloader sind somit in einer Datei zusammengefasst. Das Umbenennen, Kopieren, Verschieben und Modifizieren von Target-Dateien ist mit Bordmitteln jederzeit möglich.

Bootloader-Übertragungen:     /transmissions
Die Software kann den Datenstrom für eine Bootloader-Übertragung an die angegebene serielle Schnittstelle senden, oder in eine Datei umleiten, welche standardmäßig in den Ordner transmissions  geschrieben wird. Dabei handelt es sich um Binärdateien mit der Endung .owl. Durch die Speicherung geht keine Timing-Information der ursprünglichen seriellen Übertragung verloren. Die Transmissions-Datei enthält ein vollständiges Firmware-Update mit Authentisierung und Daten für EEPROM und/oder Flash.
Die OWL-Software kann eine .owl-Datei übernehmen und an eine serielle Schnittstelle senden. Dabei wird automatisch die richtige Baudrate verwendet, da diese in ASCII-Codierung an das Ende der Binärdatei angehängt ist. Weitere Meta-Infos enthält das Dateiformat für OWL-Transmissionen nicht.
Es ist daher auch möglich, eine OWL-Datei per Datenumleitung an eine serielle Schnittstelle umzuleiten. Auch damit erhalten wir eine technisch einwandfreie OWL-Transmission.
Konsolenbeispiel DOS/Windows:
mode COM1 9600,n,8,1 | copy /b transmission0815.owl COM1
Gleiches unter Linux:
stty -F /dev/ttyS0 9600 cs8 -cstopb -parenb | cat transmission0815.owl > /dev/ttyS0


Kompilation der Transmission

Die Software braucht einen gültigen Target-Namen als Referenz zu dem Bootloader, für den sie eine Transmission erzeugen soll. Sofern die Target-Datei gefunden wurde, kennt das Programm mit einem Schlag den Krypto-Schlüssel und alle Meta-Infos, um für dieses bestimmte Gerät eine verschlüsselte Übertragung mit korrektem Timing zu berechnen.
Außerdem sollte natürlich eine Quelldatei mit Daten für den Flash- und/oder EEPROM angegeben werden. Oder mindestens ein Flash- oder EEPROM-Löschbefehl.
Ein serieller Port muss nur angegeben werden, wenn die Transmission "live" über eine lokale serielle Schnittstelle gesendet werden soll. Wird kein serieller Port angegeben, dann geht der Datenstrom in eine sogenannte Transmissions-Datei (Endung .owl) im Ordner transmissions (siehe weiter unten). Weitere optionale Angaben und Modifikatoren sind möglich (bitte Hilfe-Texte konsultieren).
Das Tool erzeugt die OWL-Transmission zweckmäßigerweise zunächst im Arbeitsspeicher, und zwar in Reihenfolge der RST-Sequenzen:
  1. Authentisierungssequenz (S1): Die erste Sequenz besteht nur aus IV, einem Dummy-Block (Zufallszahlen) und VI. Der PRNG wird mit dem Bootloader-Schlüssel geladen. Der verschlüsselte String für die Authentisierungs-Sequenz S1 hat zusammen mit IV und VI immer eine Länge von 3 Blöcken, entsprechend 48 Krypto-Bytes. Der String für S1 wird mit der längeren Einleitenden Präambel versehen. Im Abstand der Krypto-Blöcke werden Mindest-Präambeln und Blockstarter eingefügt.
  2. EEPROM-Sequenz (S2): Das Programm liest EEPROM-Daten aus dem angegebenen Hexfile und füllt diese gegebenenfalls bis zur nächsten Blocklänge auf (Padding mit Nullbytes). Der EEPROM-Datensatz wird mit IV und VI "umrahmt" und auf Grundlage des momentanen Schlüssels per RST verschlüsselt. In einem zweiten Durchlauf fügt das Programm zwischen den Krypto-Datenblöcken die notwendigen Präambeln ein. Diese berücksichtigen die Mindestdauer zur Entschlüsselung der Blöcke und die EEPROM-Schreibzeit für je 16 Bytes am Stück. Falls keine EEPROM-Daten vorliegen, besteht S2 überhaupt nur aus dem verschlüsselten IV- und VI-Block im Abstand einer Mindest-Präambel. Der fertiggestellte String für S2 wird an den String S1 angehängt.
  3. Flash-Sequenz (S3): Das Programm liest die Flash-Daten aus dem angegebenen Hexfile und füllt die letzte bereits angebrochene Page mit Zufallsbytes (und gegebenenfalls einem INFO TAG für ATtiny) auf. Der Flash-Datensatz wird auf Grundlage des momentanen Schlüssels zusammen mit IV und VI verschlüsselt und es werden die verlängerten Präambeln für Flash-Erase und Flash-Writes zwischen die Flash-Krypto-Blöcke eingefügt. Gegebenenfalls wird noch eine optionale abschließende "Präambel" hinzugefügt. Dieser letzte Teilstring wird dem bereits kombinierten String von S1 und S2 angehängt.

Einzel-Transmission

Wenn im Transmissions-Modus eine konkrete serielle Schnittstelle angegeben ist, etwa --serialport=COM2, sendet die Software den soeben erzeugten OWL-Datenstrom direkt über diese Schnittstelle aus. Es wird die Default-Baudrate aus der Target-Datei verwendet. Wurde an der Kommandozeile mit  --baudrate=xxxx eine abweichende Baudrate angegeben, wird diese verwendet. Die Software wird versuchen, die angegebene Baudrate zu verwenden, aber nur wenn diese noch innerhalb des rechnerisch möglichen Baudratenfensters liegt.
Wurde keine serielle Schnittstelle angegeben, geht der Datenstrom in eine Datei im Ordner transmissions, versehen mit einem einzigartigen Dateinamen, der sich aus einem Zeitstempel und dem ursprünglichen Target-Namen zusammensetzt. Mit der Option --transfile=Pfad/Dateiname können wir den Pfad und den vorderen Namensteil (Präfix) der abzuspeichernden Transmissions-Datei vorgeben. Dateiendung der OWL-Transmissionen ist immer .owl.


Serien-Transmission

Es ist möglich, im Transmissions-Modus mehrere Targets in einem Arbeitsgang anzusprechen. Die Transmissionen werden automatisch als Dateien abgespeichert.
Voraussetzung ist, dass die Targets systematisch durchnummeriert sind. Dann geben wir im Transmissions-Modus einfach einen Target-Namen mit Platzhaltersymbolen, also "?" oder "*", an, und das Programm sucht alle zu diesem Muster passenden Targets und erzeugt für jedes eine individuelle Transmission.
Auf diese Weise erzeugte Serien-Transmissionen werden per Default im Ordner transmissions mit einem analog durchnummerierten Dateinamen abgelegt. Beispiel:
owl --targetname=bootloader0? --flashfile=testprogram.hex
würde alle Bootloader erfassen, die in der Art "bootloader01" bis "bootloader09" durchnummeriert sind und für jedes einzelne Target eine maßgeschneiderte Transmission erzeugen, die die Firmware "testprogramm.hex" enthält. Die dazugehörigen Transmissions-Dateien mit der Endung .owl landen per Default im Ordner transmissions.


Bootloader-Erzeugung

Die Software erwartet einen gültigen Device-Namen und holt sich aus dem Ordner Templates die zugehörige Datei mit den Default-Einstellungen. Dann erzeugt sie aus auf Grundlage dieses Maschinencodes den individuellen Bootloader und speichert diese Datei zusammen mit Meta-Infos in der sogenannten Target-Datei im Ordner targets ab.

Serien-Bootloader-Erzeugung

Analog zum Feature "Serien-Transmission" gibt es natürlich die Möglichkeit, Bootloader in Serie zu erzeugen. Dazu geben wir einfach ein zusätzliches Argument, nämlich "Number" (Anzahl) an. Die Software generiert dann fortlaufend durchnummerierte Target-Dateien für die gleiche Hardware-Konfiguration aber mit unterschiedlichen Krypto-Schlüsseln.
Beispiel:
owl --device=tn2313 --rxport=d0 --txport=d1 --number=10 --targetname=testloader

erzeugt 10 neue Bootloader mit den Dateinamen

testloader00.hex
testloader01.hex
...
testloader09.hex

im Ordner targets. Diese Loader können an 10 individuelle Zielgeräte ausgegeben werden. Der Zugriff auf das einzelne Gerät ist aber nur für denjenigen möglich, der die dazu passende Target-Datei mit dem 128-Bit-Schlüssel besitzt.
Wegen des Entropie-Problems sollten in einem Rutsch nicht mehr als ca. 100 Bootloader erzeugt werden. Die Software gibt eine entsprechende Warnung heraus. Es ist aber durchaus möglich, in Etappen wesentlich mehr Bootloader zu erzeugen.

Audio-Export

Der kontinuierliche OWL-Datenstrom ist per Design binär ausgeglichen und hat überdies ein bandbegrenztes Frequenzspektrum. Es ist also nicht so weit her geholt, diesen Bitstrom in kompatible Samples umzurechnen und dann über die PC-Soundkarte rauszuhauen. Gibt's auch schon in mehr oder weniger anspruchsvollen Varianten. Ich mach's kurz: Die guten Eigenschaften des rohen OWL-Signals ermöglichen hier eine Minimallösung, die erstaunlich gut funktioniert und möglicherweise sogar "endkundentauglich" wäre.
Die OWL-Software stellt dafür eine Option --audiofile=Dateiname.wav bereit, mit der sich die Transmission in eine zu jedem Mediaplayer kompatible WAV-Datei umleiten lässt. (Geht auch "in Serie".) Eine weitere Programmierschnittstellen-Alternative für den One-Way-Loader! Technische Details siehe Hardwareoptionen.

Zufallsschlüssel

Die OWL-Software setzt bei der Erzeugung von Bootloader-Schlüsseln auf das Zufallsprinzip. Bei einer Schlüsselweite von 128 Bits ist praktisch ausgeschlossen, dass jemals im selben Universum zwei zufällig identische Schlüssel miteinander in Konflikt geraten. Dieser Unwahrscheinlichkeitsdrive macht es möglich, einzigartige Geräteschlüssel lokal zu erzeugen und weltweit zu nutzen, ohne dass diese Schlüssel von irgendeiner zentralen Stelle gespeichert und auf Kollisionen geprüft werden müssten. Das bedeutet Freiheit und Selbstbestimmung für die Nutzer.
Nebenbei lösen Zufallsschlüssel einige Probleme, die es mit dem passwortbasierten Zugriffsschema á la TSB immer wieder gegeben hat; insbesondere in Hardware-Setups mit mehreren Bootloadern an einer gemeinsamen Programmierleitung. Die OWLs haben von Anfang an individuelle 128-Bit-Schlüssel und sind konfliktfrei adressierbar, egal wie viele es sind. Die Verknüpfung mit einem memorierbaren "Target-Namen" erfolgt über den Dateinamen und kann auch später noch geändert werden. Für den berechtigten (autorisierten) Nutzer ergibt sich ein transparenter Zugriff auf alle selbst erzeugten Bootloader. Für den Herausgeber einer Serie von Bootloadern bleibt ebenfalls alles übersichtlich, da die Target-Namen ja durchaus systematisch (mit Seriennummerierung) erzeugt werden können.
Für den unberechtigten Angreifer ergibt sich höchstwahrscheinlich rein gar nichts! Das vorliegende Einweg-Konzept antwortet nicht direkt und plaudert somit keine für einen möglichen Angriff verwertbaren Timing-Informationen aus. (Spannender könnte es hinsichtlich möglicher "Seitenkanal-Angriffe" über Power-Analyse und EM-Abstrahlungen werden...)
Kleiner Wermutstropfen: Die Erzeugung guter Krypto-Schlüssel ist bekanntlich eine Kunst für sich. Wir brauchen vor allem einen brauchbaren Zufallsprozess. Hmm, das Thema hatten wir doch schon einmal...

Random-Pooling

Computer können keine Zufallszahlen erzeugen, und den in modernen CPUs integrierten "Zufallsgeneratoren" ist grundsätzlich nicht zu trauen. Für die Erzeugung einzelner kryptografischer Schlüssel sind die üblichen "Hausmittel" (Timerwerte, Mausbewegungen und vielleicht noch eine Prise Entropie aus dem Dateisystem) in der Regel vollkommen ausreichend.
Sollen aber in kurzer Zeit viele Schlüssel für Bootloader oder IVs für Transmissionen erzeugt werden, dann ziehen diese Methoden nicht mehr. Hier ist es besser, sich einen Vorrat an Entropie anzulegen, einen sogenannten "Random Pool". Dieser wird bei verschiedenen Gelegenheiten mit echter Entropie aufgefrischt, wobei durchaus die oben genannten improvisierten Quellen verwendet werden können, aber es können auch weitere Quellen, wie etwa die Entropie aus hochkomprimierten AV-Dateien oder aus einem physikalischen Zufallsgenerator hinzugezogen werden. Wenn die Software dann wieder echte Zufallszahlen benötigt, so kann sie auf den Random Pool zurückgreifen, der sich nicht so schnell erschöpft.
Die OWL-Software legt einen eigenen Random Pool an. Dazu erzeugt sie im Stammverzeichnis eine Datei randpool.bin. Diese enthält immer mindestens 512 Zufallsbytes, die gewissermaßen "akkumulierte Entropie" beinhalten. Der Zugriff erfolgt nach Art eines Ringpuffers, d.h. die Software liest vom Dateianfang 512 Bytes und kopiert diesen in ihren internen Random Pool in den Arbeitsspeicher. Diesen Block nutzt und modifiziert sie im weiteren Verlauf über aktuelle Timerwerte. Erst beim Verlassen des Programms werden die führenden 512 Bytes vom Dateianfang gelöscht und der modifizierte interne Random Pool wird an das Dateiende angehängt. Somit bleiben immer mindestens 512 Bytes in randpool.bin, die wegen der gelegentlichen Auffrischung mit neuen Zufallsereignissen ein Mindestmaß an Entropie garantieren.
Dieser Zugriff mag umständlich erscheinen, hat aber einen Grund. Wir halten uns die Möglichkeit offen, einen noch wesentlich größeren Random Pool anzulegen. Die Datei randpool.bin darf nämlich bis zu 65536 Bytes (64 KiB) groß sein. Wir können sie zum Beispiel mithilfe eines externen Programms und eines physikalischen Zufallsgenerators (z.B. XR232USB) mit echter Entropie auffüllen.
Wenn nun die OWL-Software auf randpool.bin zugreift, dann rückt der Inhalt der Zufallsdatei in 512-Byte-Schritten immer weiter nach vorne, während am hinteren Ende die modifizierten Zufallsdaten wieder angehängt werden. Der Pool wird auf diese Weise nie wirklich "aufgebraucht", und bevor eine 64k-Zufallsdatei komplett durchgenudelt wurde, kann viel Zeit vergehen. Somit verwischt sich auch der zeitliche Zusammenhang (Korrelation) zwischen Erzeugung und Nutzung der Zufallsdaten. Wenn gewährleistet ist, dass die Pool-Datei vor Fremdzugriffen geschützt ist, spricht nichts gegen diese Art der Vorratshaltung.
Steht dauerhaft ein TRNG zur Verfügung, ist es aber wohl sinnvoller, randpool.bin bei jeder Gelegenheit kurz vor der tatsächlichen Nutzung aufzufrischen.
Als Notbehelf bietet die Software außerdem die Kommandozeilenoption --randpool, mit der wir in bewährter Manie durch hektische Mausbewegungen auf dem Bildschirm einen Grundstock an Entropie erzeugen können.


Datensicherung

Die Software erstellt keine automatischen Backup-Kopien. Backups einer kompletten OWL-Installation lassen sich jederzeit mit Bordmitteln anfertigen. Insbesondere der Ordner targets sollte regelmäßig gesichert werden!

Datensicherheit

Die Software überschreibt keine Target-Dateien, die bereits existieren. Sollte der Target-Name schon vergeben sein, erfolgt eine Warnmeldung und die Operation wird abgebrochen.
Um das versehentliche Überschreiben von Target-Dateien durch andere Anwendungen zu verhindern, sollten wichtige Dateien zusätzlich mit einem Schreibschutz-Flag versehen werden. Sicherungskopien sind natürlich auch keine schlechte Idee. Ohne Target-Datei ist kein Zugriff auf den betreffenden Bootloader mehr möglich!
Jede Person, die Zugriff auf den Rechner mit dem OWL-Verzeichnis erhält, ist automatisch "autorisiert" für alles Mögliche. Eine zusätzliche Umschlüsselung, etwa durch ein Master-Passwort, ist nicht vorgesehen. Dieser Ansatz wurde getestet und für umständlich befunden.
Die Arbeitsumgebung, in der auch OWL verwendet wird, sollte für Unbefugte nicht so ohne Weiteres zugänglich sein. Wer sich einem realen Spionage- oder Sabotagerisiko ausgesetzt sieht, wird sich früher oder später ohnehin mit dem Konzept einer gesicherten Umgebung auseinandersetzen. Besser, als Flickschusterei an einzelnen Programmen zu betreiben, ist in jedem Fall: Weitgehende Kontrolle über die verwendete Hardware und Software, Verzicht auf obskuren Müll, geschärftes Bewusstsein für Sicherheitslücken des Betriebssystems, gesamte Arbeitsumgebung auf einer vollverschlüsselten Festplatte usw. Misstraue Regierungen und automatischen Updates! Es muss ja nicht gleich der vom Internet abgeschottete Einzelplatzrechner in einem mit Kupferfolie ausgekleideten Bunker sein...

Dateiformate

  • Export: Zur plattformübergreifenden Nutzung sind die von der Software neu generierten "Intel-Hex"-Dateien ( Targets) auf 7-Bit-ASCII mit CR-LF-Zeilenvorschüben vereinheitlicht.
    Das OWL-Format für Transmissionen ist ein reines Binärformat. Hier erwarten wir zu Recht, dass diese Dateien problemlos plattformübergreifend genutzt werden können, zumal keine mir bekannte Anwendung bisher mit der Dateiendung ".owl" assoziiert ist.
    Die für den Random Pool verwendete externe Datei randpool.bin ist eine Binärdatei mit 8-Bit-Zufallszahlen, die zwischen 512 und 65536 Bytes lang sein darf.
  • Import: Hex-Dateien mit Datensätzen für EEPROM oder Flash kann das Programm sowohl in LF (Unix), CR (Mac) oder CR-LF (DOS) Formatierung einlesen. Das ist nicht mein Verdienst, sondern der weitsichtigen Umsetzung der entsprechenden I/O-Routinen unter FreeBASIC zu verdanken. Die Software sollte also alle Formate lesen können, die diverse Assembler und Compiler unter dem Oberbegriff "Intel-Hex" auswerfen. (toi-toi-toi...)

Krypto-Tests

Die Software bietet drei einfache Test- und Demofunktionen zur Krypto-Schicht.
Schlüsselgenerator:    owl --key=Hexstring
Die Angabe eines Hex-Schlüssels ohne weitere Optionen löst den Testmodus für die Schlüsselsequenz aus. Der PRNG wird dann mit dem angegebenen Schlüssel geladen und fortlaufend weitergetaktet. 
Diese Funktion demonstriert, wie stark sich bereits minimal unterschiedliche Ausgangsschlüssel auf die generierte PRNG-Sequenz auswirken. Sie eignet sich auch gut zum Vergleich mit einer Referenzimplementierung des 128-Bit-SSG-LFSR.
Die erste Zeile stellt den Startzustand (seed) des PRNG in Hex dar. Die nachfolgenden Zeilen stellen die vom PRNG-Modul ausgegebene Rohsequenz in 4-Bit-Vektoren dar.
Bei Angabe des Default-Schlüssels (--key="00112233445566778899aabbccddeeff" ) oder eines leeren Arguments (--key="") muss die Bildschirmausgabe der ersten 256 Vektoren wie folgt aussehen (SW:201806xx):

00112233445566778899AABBCCDDEEFF

0035F2BFEBBC79D7B6FB6E536D14DCA2
8A41FABFDFA8A7CB278D9B93ED144009
4116BBDB07E70257590C1602B2F35DF4
4C932A9D825C6A464896D1173D8F910C
1A121048A968625C3513DA716419F961
9083A7F4853B5D7F2D08C286E12A8008
08620ECC967578F6AEA63B5FB2B2234F
0F5CBDE922983F8961C6BF9B65D75082


Datei-Verschlüsselung:    owl --key=Hexstring --encrypt=Dateiname
Verschlüsselt die angegebene Datei mit dem angegebenen Schlüssel nach Standardmethode (eine RST-Sequenz mit IV, Daten, VI). Der Ziel-Dateiname wird durch Anhängen von " .raw" an den ursprünglichen Dateinamen gebildet. Diese Dateiendung erleichtert den Import von gecrypteten Daten in diverse Grafik-, Audio- und Analyse-Tools zwecks weiterer Untersuchungen.

Datei-Entschlüsselung:     owl --key=Hexstring --decrypt=Dateiname.raw
Entschlüsselt die angegebene Datei mit dem angegebenen Schlüssel. War die Entschlüsselung erfolgreich (IV=VI), dann wird diese Datei mit einem vorangestellten Zeitstempel unter dem ursprünglichen Namen und wieder mit der ursprünglichen Dateiendung abgespeichert. Die Originaldatei kann also nicht versehentlich überschrieben werden. Originaldatei und wiederhergestellte Originaldatei müssten binär komplett identisch sein. Da die RST-Implementierung für den OWL-Bootloader kein Padding vorsieht, kann es vorkommen, dass die wiederhergestellte Datei bis zu 15 Bytes (Zufallsbytes) länger ist, als das Original. Dieser Effekt tritt in der PC-Variante von RST selbstverständlich nicht auf.
Wenn die Entschlüsselung fehlgeschlagen ist, speichert die Demofunktion dennoch eine Datei ab, die für Analysezwecke ausgewertet werden kann.

Virtuelle Maschinen

Verschiedene Konstellationen mit VirtualBox 5.xx wurden spaßeshalber getestet, wobei der Gast-Maschine jeweils eine serielle Schnittstelle des Host-Computers per Durchleitung zugeteilt wurde. Alle Kombinationen aus WinXP/Win7/Ubuntu14/Debian8 liefen problemlos. Von der Performance der Schnittstellenanbindung sind keine Wunder zu erwarten. In einigen Fällen machte sich die zusätzliche Abstraktionsschicht deutlich bemerkbar, hier kam der serielle Datenstrom regelmäßig ins "Stottern", aber es gingen keine Zeichen verloren, und ALLE Datenübertragungen an das OWL-Zielgerät waren erfolgreich. Ein "Notfallbetrieb" der OWL-Software in einer VW unter einem anderen Betriebssystem geht also, wenn die Ausgabe eines kontinuierlichem Sendedatenstroms nicht zwingend erforderlich ist.

To-Do-Liste

Hardware-Software-Projekte sind bekanntlich eine hochdynamische Kampfsituation. Was hier so schön organisiert rüberkommt, hat sich eher "organisch" entwickelt. Sicher wird auch dieses Projekt wieder die eine oder andere Überarbeitung erfahren und dadurch noch besser werden. Folgende Punkte sind bereits vorgemerkt:
  • Bildschirmausgaben aufräumen / besser formatieren
  • Namen einiger Kommandozeilenoptionen ggf. anpassen
  • Zufallsgeneratorprozess und Random-Pool-Verwaltung weiter verbessern
  • Fehlerbehandlung differenzieren
  • Erweiterungen für > 64K-Devices ausarbeiten und testen
  • Tests mit alternativen Schnittstellen
  • Code aufräumen
  • Bereichsprüfung für zulässige Baudrate
  • Bauerdaustelle Debb-Wokumentation...

Euer Feedback zählt!


Nach oben | Index



Hardware-Optionen

Viele Wege führen nach Flash und EEPROM...!

  • Zielplattform mit RS232-Hardware (RS422/RS485, USB-RS232): Das Zielgerät kommuniziert normalerweise über RS232 mit einem anderen Gerät, etwa einem PC oder einem Terminal. Die Schnittstelle kann als klassische RS232, in einer differenziellen Variante wie RS422/RS485 oder über einen USB-COM-Wandler realisiert sein.

    • Der One-Way-Loader kann selbstverständlich das vorhandene RS232-Interface nutzen und lauscht auf derselben Portleitung, die auch die reguläre Applikations-Firmware als "RXD" nutzen würde. In dieser Variante sind Firmware-Updates ohne Eingriffe in das Gerät und ohne speziellen Programmieradapter möglich. Das wird allgemein als sehr angenehm empfunden.

    • Der OWL braucht nur die Empfangsleitung RXD. Es ist aber sinnvoll, auch die nicht genutzte TXD-Leitung aktiv zu berücksichtigen, d. h. einen statischen High-Pegel auszugeben, damit die Gegenstelle auf einen klaren Leerlaufzustand "sieht". Dieses Signal "Dummy-TXD" erzeugt der OWL für die Dauer der Bootloader-Sitzung, wenn die entsprechende Portleitung als "TX-Port" definiert wurde.

    • RS422/RS485-Leitungstreiber (z. B. SN75176) benötigen zur Datenrichtungsumschaltung ein Hardware-Steuersignal (Transmit-Enable, TE), das softwaremäßig durch die Applikations-Firmware erzeugt werden muss. Der Bootloader sollte dieses Signal ebenfalls erzeugen, damit sichergestellt ist, dass der Leitungstreiber während der Bootloader-Sitzung permanent in Empfangsrichtung geschaltet ist. Auch hierfür kann der OWL seinen TXD-Kanal nutzen. Der wird dann mit einem statischen High oder Low-Pegel belegt, je nachdem, was die Elektronik drumherum so erwartet.

  • Zielplattform OHNE dedizierte RS232-Hardware: Da wird's noch interessanter. Standalone-Anwendungen, die normalerweise nichts mit RS232 am Hut haben, ließen sich bisher nur über vergleichsweise aufwendige Two-Wire- oder One-Wire-Interfaces mit Firmware-Updates versorgen. Der OWL braucht nur noch eine beliebige Portleitung, die durchgängig als Eingang arbeitet. Daraus ergeben sich neue Möglichkeiten:

    • Elektrisch: Wir reservieren auf der Seite des Mikrocontrollers eine beliebige Portleitung und führen diese zusammen mit Masse auf einen zweipoligen Steckverbinder raus. Zur Not kann die Verbindung auch über zwei Klemmprüfspitzen hergestellt werden. Naheliegende Variante, wenn ohnehin ein sogenannter One-Wire-Adapter (CI-V-Interface) vorhanden ist.
      Aber es geht noch einfacher. Wir können das TXD-Signal mit einem Vorwiderstand und einer Z-Diode 4V7 auf TTL-Pegel zwingen und ebenfalls direkt am Controller einspeisen. In diesem Fall wäre das Signal gegenüber der sonst üblichen Logik invertiert. Macht aber nichts. Dann konfigurieren wir eben den Bootloader für invertiertes RXD-Signal, schon stimmt's wieder!

    • Optokoppler: Optokoppler sind für die Einweg-Übertragung besonders empfehlenswert, zumal sich nebenbei eine etwaige Signalinvertierung realisieren lässt. Außerdem haben wir den Sicherheitsvorteil einer galvanischen Trennung zwischen Host-Computer und Ziel-Controller.
      Ein Standard-Optokoppler, wie etwa der PC817, befindet sich auf der Platine des Mikrocontrollers oder auf der Seite der RS232-Schnittstelle bzw. hinter einem FT232. Siehe nachstehende Schaltbeispiele.

    • Freiluft-Opto: Dabei handelt es sich um einen räumlich aufgespaltenen Optokoppler. Auf der Seite des Mikrocontrollers wird die von OWL genutzte Portleitung mit einem Pullup nach High gezogen und der Fototransistor zieht diese Leitung auf Low, wenn ausreichend rotes oder infrarotes Licht einstrahlt. Für offene Opto-Interfaces gibt es naturgemäß einige interessante Varianten. Auch "getarnte" und kostenoptimierte Programmierschnittstellen sind möglich. Der Datenempfang funktioniert z.B. ganz vorzüglich über den Fototransistor einer gewöhnlichen Gabellichtschranke, da auch dieser relativ schnell schalten kann. Wenn das Zielgerät also Gabelkoppler verwendet, ist das bereits ein potenzieller Programmiereingang für den One-Way-Loader! Die gegenüberliegende Sende-LED müsste natürlich abgeschaltet oder optisch verdunkelt werden. Zur Datenübertragung halten wir unser TX-Lichtschwert  nah genug dran, resetten den Controller und starten die OWL-Transmission. (Ich hielt das zunächst für eine wackelige Angelegenheit, war dann aber positiv überrascht, wie gut es in den meisten Fällen funktioniert!)



Programmierung eines ATmega per Lichtstrahl.


    • Kapazitive/magnetische Koppler: Der kontinuierliche OWL-Datenstrom lässt sich wegen der ausgeglichenen 0/1-Bilanz gleichstromfrei bzw. "floatend" übertragen, ohne dass eine zusätzliche Modulation erforderlich wäre. Die Übertragung über kapazitive oder induktive Eingangsbeschaltungen wurde ansatzweise getestet und funktionierte mit moderaten Geschwindigkeiten durchaus. (Wenn es vor allem auf die Potenzialtrennung ankommt, würde ich eine Lösung mit Optokopplern oder Freiluft-Opto vorziehen!)

    • PC-Audio auf OWL-RXD: Alternative Programmierschnittstelle zu RS232 gefällig? Bittesehr! Die OWL-Transmission kann jetzt auch in ein digitales Audio-File exportiert werden. Was wir bekommen, ist eine standardkompatible WAV-Datei, die sich über jeden Multimedia-Player abspielen lässt. Das verblüffend simple Audio-Interface (siehe Schaltbeispiele) macht aus den differenziell codierten Stereokanälen an einem Hochpegelausgang ('Headphones' oder 'Line-out') ganz schnell wieder ein passables Digitalsignal für den Mikrocontroller. Der Witz dabei ist, dass nur auf der Senderseite ein zusätzlicher Aufwand für eine differenzielle Codierung entsteht. Der Controller bekommt hinter dem Optokoppler automatisch sein phasenrichtiges "RS232"-Signal serviert. Weder muss die Bootloader-Firmware angepasst werden, noch spielen Polung und eine etwaige Vertauschung von linkem und rechtem Kanal bei "OWL-Audio" eine Rolle! Knackiger Pegel und einigermaßen lineare Übertragung sind natürlich Voraussetzung, dann funktioniert es sogar mit höheren Baudraten. Eigentlich erstaunlich, wenn man bedenkt, dass diese Variante ganz ohne FSK oder DPSK auskommt und ich zu 70 Prozent aus Wasser bestehe... Alternativer Programmierpfad per Soundkarte - check!


Einfaches RS232-Interface mit galvanischer Trennung:
TXD treibt Wald-und-Wiesen-Optokoppler
Preiswerte Lösung, wenn ansonsten kein RS232 vorgesehen ist.
Unidirektionale RS232-Übertragung per Optokoppler an den OWL
Universeller RS232-Opto-Adapter für die Freiluft-Datenübertragung zum Beispiel an den OWL-Bootloader. Sende-LEDs für invertiertes und nichtinvertiertes Signal.
Ansteuerung einer Sende-LED durch RS232 für unidirektionale Freiluft-Datenübertragung zum Controller

Freiluft-TXD per LED und Fototransistor.

Freiluft-TXD-Variante mit FT232.
Ansteuerung einer Sende-LED vom FT232 für unidirektionale Freiluft-Datenübertragung zum Controller
Ultrasimples differenzielles Audio-Interface für OWL-Transmissionen.
Einfache  Datenübertragung von der Soundkarte zum Controller


OWL rune draft jt (CC0)
Logo-Entwurf für den OWL-Kult

Nach oben | Index


Anmerkungen

Kleiner Krypto-Kontest

Die Wahl eines geeigneten Kryptosystems war die mit Abstand schwierigste Entscheidung des ganzen Projektes. Für AES, XTEA, eine klassische XOR-Stromchiffre und "RST" standen Assembler- UND FreeBasic-Quelltext zur Verfügung oder konnten mit vertretbarem Aufwand erstellt werden. Der Entscheid für RST fiel aufgrund folgender pragmatischer Abwägungen:

Algorithmus
AVR-Implementierung
Vorteile
Nachteile
AES
(Rijndael)
  • Zertifizierbar, weit verbreitet
  • Gute statistische Eigenschaften (Diffusion und Konfusion) 
  • Auf AVR-Mikrocontrollern vergleichsweise schnell
  • Alle Blockchiffre-typischen Key-Feedback-Varianten anwendbar
  • Weiterer Code für CRC und Key-Feedback erforderlich.
  • Enormer Speicherbedarf (Lookup-Tabellen in Flash).
  • Entschlüsselung langsamer als Verschlüsselung.
  • Für Bootloader-Anwendung überdimensioniert.
  • Für kommerzielle Implementierungen tw. Lizenzerwerb erforderlich!
XTEA
("eXtended Tiny Encryption Algorithm")
  • Standard 64-Bit-Blöcke,
    128-Bit-Schlüssel
  • Code: 206 Bytes (Kernfunktion)
  • Takte pro Block: ~ 12.600
    (aufgeteilt auf 2 x 8 Byte)
  • Referenz: www.efton.sk (Link veraltet)
  • Patentfrei und i.d.R. lizenzfrei
  • Nachgewiesen gute statistische Eigenschaften
  • AVR-Assembler-optimierte Version aufgeräumt und kompakt
  • Erheblicher Zusatzaufwand für Key-Feedback und Fehlererkennung.
  • Eher schwach bei minimaler Rundenzahl.
  • Arbeitet auf 64-Bit-Blöcken; Anpassungen für 128-Bit-Key-Chaining erforderlich, könnte Schwachstelle bedeuten.
PRNG-XOR (Stromchiffre)
  • Code: ~60 Bytes
    optimiert für Kernfunktionalität
  • Block-XOR
  • Takte pro Block: < 1000
  • Klassische Stromverschlüsselung
  • Mit kryptografisch abgehärtetem PRNG für viele Zwecke ausreichend
  • Sehr kompakte Lösung
  • Erheblicher Aufwand für Key-Feedback und Fehlererkennung.
  • Anfällig für Known-Plaintext-Angriffe.
  • Selbst für Bootloader-Anwendungen zu simpel!
RST
("Randomized Substitution-Transposition")
  • Blockchiffre gesteuert durch eine Stromchiffre , hier:
  • Pseudozufallsgenerator mit 128-Bit-Seed
  • Fortlaufender Schlüsselgenerator
  • Initialisierungsvektoren, Über-Alles-Fehlererkennung
  • Modularer Aufbau: Blockchiffre, PRNG, Key-Feedback
  • Code: ~ 160 Bytes
  • Takte pro Block: < 10.000
    bei Mindestrundenzahl
  • Gute statistische Eigenschaften schon bei Mindestrundenzahl
  • IV und Fehlererkennung
    "all inclusive"
  • Inoffiziell ausführlicher erprobt
  • Extrem kompakt auf 8-Bit-CPUs umsetzbar
  • Kyptografisch starker PRNG verwendbar
  • Günstiger Kompromiss zwischen Verschlüsselungsstärke, Codeffizienz und Funktionalität
  • Lückenlos nachvollziehbares Konzept
  • Nicht "zertifiziert"...
  • Starker PRNG kostet viel Rechenzeit.
  • Strenges Avalanche-Kriterium im einzelnen Block nicht immer erfüllt.
  • IV-VI-Mechanismus verlängert Chiffrat um 2 Blöcke.
  • Keine Feistel-Chiffre, auf einer Seite müssen Runden-Vektoren zwischengespeichert werden.


Blockverschlüsselung mit und ohne Fehlerfortpflanzung

(1)
(2)
(3)
(4)




Klartext unverschlüsselt:
Bitmap-Grafik 200x200 Pixel, 8-Bit Graustufen,
40 kByte.
(Das entspricht 2500 Blöcken à 16 Bytes!)
Verschlüsselt im bescheuerten ECB-Modus. Jeder Block wurde mit demselben Satz an RST-Vektoren verschlüsselt.
Musterbildung im Chiffrat erkennbar. (Schlecht!)

Verschlüsselt
mit fortlaufendem Schlüsselgenerator.
Keine Musterbildung, starkes Chiffrat.
Entschlüsselt mit Klartext-Schlüssel-Rückkopplung und einem Übertragungsfehler:
Nachfolgende Daten komplett unbrauchbar.
Fehler oder Manipulation sicher erkannt!

Nach oben | Index


Schnellstartanleitung

1. Voraussetzungen

  • Hardware-Software-Ausstattung für AVR-Projekte (IDE, Compiler/Assembler, ISP-Brenner, Board) AVR-Controller, der von OWL unterstützt wird, auf Platine mit ISP-Anschluss (oder Zwischenstecker)
  • OWL-Download für Dein Betriebssystem
  • Schonmal 'was an der Kommandozeile gemacht...
  • Respekt, aber kein Schiss vor den Fusebits!
  • Mindestens eine reale RS232-Schnittstelle oder USB-COM-Wandler ("COMx", "/dev/ttySx")
  • Hello-World-Testprogramm für diesen Controller, z.B. einfachen LED-Blinker, im Format Intel-Hex (Standard)

2. PC-Installation der OWL-Software

Das Download-Paket "owl_xxxxxxxx.zip" einfach an den gewünschten Ort entpacken. Ins Verzeichnis 'owl' gehen und dort ein Konsolenfenster öffnen. Nach Eingabe von owl ohne irgendwelche Optionen müsste die allgemeine Hilfeseite durchscrollen. Wenn das funktioniert, dann geht vermutlich auch der Rest. (Unter Unixen " ./" voranstellen, kennste!)

Der Anschaulichkeit halber verwende ich in diesen Beispielen mal die Langschreibweisen der Optionen.
Führende "-" bzw.
" -- "sind aber nicht zwingend. Eine Liste aller Kurz- und Langschreibweisen liefert die Option: --help.
3. Maßgeschneiderte OWL-Firmware erzeugen

Beispiel: ATmega8 in einem klassischen RS232-Setup (MAX232, FT232) mit Quarz 8 MHz

Der Mega8 ist mit einem MAX232 (oder FT232) verbunden. Hier werden die Portleitungen PD0/PD1 als RXD/TXD genutzt
(vom Hardware-UART vorgegeben) . Die ordnungsgemäße Funktion der RS232-Hardware sollte vorher gestet worden sein. Für eine LED an PB2 steht ein passendes Blinkprogramm zur Verfügung. Am besten, wir testen das Blinkprogramm schon einmal im Vorfeld ohne Bootloader. Testplattform mit funktionierender RS232-Anbindung - check! LED-Blinker - check!

Jetzt erzeugen wir für diese Hardware unseren ersten OWL-Bootloader. In diesem Beispiel verwendet der OWL ebenfalls PD0 als RXD-Eingang. Die Kommandozeile zur Erzeugung des neuen OWL-Bootloaders lautet dann:

owl --device=m8 --rxport=d0 --clock=8000 --targetname=testowl_m8

Das war's auch schon! Die neue OWL-Firmware steht unter  /targets/testowl_m8.hex

4. Installation OWL-Firmware (Bootloader)

Wir starten ein ISP-Brennprogramm (z.B. "avrdudess", "extreme burner", "TwinAVR") und übertragen die neue Bootloader-Firmware "testowl_m8.hex" per ISP in den Flash-Speicher des Ziel-Controllers! Vorher bitte den GESAMTEN Flash löschen.

Anschließend setzen wir die Fusebits, wofür eigentlich jedes Brennprogramm eine entsprechende Funktion anbietet. Schön auf die Zuordnung Extended, Low und High achten, das kann sonst ins Auge gehen. Die wichtigste Einstellung für einen Bootloader ist "Self-Programming" (SPIEN). Das muss aktiviert sein, sonst kann er keine Schreibzugriffe machen. Außerdem sollte immer der Brown-Out-Detektor (BODEN) eingeschaltet sein, damit sich ein sauberes Kaltstartverhalten ergibt (Vermeidung von Flash-Korrumpierung).


Fuses: SPIEN=0; BOOTSZ=10; BODEN=0; BODLEVEL=0; CKSEL=1111; SUT=11
Byte-Werte:    Ext: $FF         High: $DD         Low: $7F
Konkret-kryptisch mit "avrdude" an der Kommandozeile:
avrdude -U efuse:w:0xff:m -U fuse:w:0x7f:m -U hfuse:w:0xdd:m


Tipp: Im Web gibts praktische Fusebit-Kalkulatoren, die wesentlich informativer und benutzerfreundlicher ausgeführt sind, als so manche integrierte "Hilfefunktion" von prominenten ISP-Programmiertools.

Damit wäre unser Bootloader auf dem Chip installiert.

5. Test-Firmware übertragen

Für diesen Test sollte sich das Blinkprogramm ledblink_m8.hex im Hauptverzeichnis der OWL-Software befinden. Die Controller-Hardware sei in diesem Beispiel an COM2 angeschlossen. Also, Controller resetten, Kommandozeile "abfeuern":

owl --targetname=testowl_m8 --flashfile=ledblink_m8.hex --serialport=COM2

Die Übertragung geht mit Standardgeschwindigkeit von 9600 Baud über "COM2" an den Controller. Nach wenigen Sekunden sollte die LED fröhlich zu blinken anfangen. Na, hat's geklappt? War doch voll easy, oder etwa nicht?!

Hinweis: Für andere AVRs und LED-Ports muss das Testprogramm angepasst werden.

Info-Kommandos

Kurzübersicht zu allen Befehlsoptionen:
owl --help

Hilfetext zu einer oder mehreren Optionen (hier: 'flasherase', 'timeout' und 'serialport'):
owl --help --flasherase --timeout= --serialport=


Liste aller direkt unterstützte AVR-Modelle:
owl --supported

Technische Daten zu einem bestimmtem AVR-Modell einsehen:
owl --device=Modellname

Stammdaten zu einem selbst erzeugten Bootloader abrufen
(Beispiel):
owl --targetname=testowl_m8



Nach oben | Index


Lizenz

In das Projekt One-Way-Loader sind eine Menge Erfahrung, Tränen, Schweiß und Bier geflossen. Nach langem Vorlauf stelle ich der Weltgemeinschaft dieses Gesamtkunstwerk unter nachstehenden Bedingungen zur Verfügung:

Programme (Firmware, Software) zum One-Way-Loader unterliegen der MIT-Lizenz
. Ein entsprechender Vermerk ist in allen Quellcodes enthalten. Alle von mir herausgegebenen Programme zum One-Way-Loader sind außerdem quelloffen. Für Spezialversionen können individuelle Vereinbarungen gelten.

Dokumentation und Bilder zum One-Way-Loader stehen unter Creative Commons - Universell. Darunter fallen Schaltbeispiele, Grafiken, Diagramme und alle Begleitdokumente, die keinen expliziten Copyright-Hinweis enthalten und nicht automatisch einer anderen Lizenz unterliegen. Sämtliche Logos und Icons zum OWL-Projekt sind Eigenkreationen oder Abwandelungen allgemeinfreier Vorlagen.

Sie wollen meine Arbeit unterstützen? Verbesserungsvorschläge, Lob, Kritik, Spenden


Nach oben | Index


Download

Nach oben | Index


Links


Nach oben | Index


Erstveröffentlichung: 06/2018 ~ Letzte Änderung: 07/2018