Letzte Aktualisierung: 2023-09-18

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


Der beste AVR-Bootloader mit Verschlüsselung und minimalen Hardwareanforderungen geht in die nächste Dekade. Neues Softwaretool und weiter verbesserte Firmware für fast alle Mikrocontroller der Serie TinyAVR und MegaAVR. Anders als alle anderen verwendet der One-Way-Loader ein konsequent unidirektionales Protokoll. Daten empfängt er über eine existierende serielle Schnittstelle oder eine maßgeschneiderte Programmierschnittstelle, die tatsächlich nur einen einzigen Porteingang benötigt. Datenübertragungen sind technisch robust und kryptografisch abgesichert. So lassen sich komplette Firmware-Updates für EEPROM und Flash in einem verschlüsselten Container zusammenfassen und sind bei der Distribution über unsichere Kanäle gegen Übertragungsfehler, Manipulation und Ausspähung geschützt.



OWL web draft cc0
  • Universeller Krypto-Bootloader für viele ATtinys und ATmegas - Firmware nur 512 Bytes.

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

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

  • Neues Software-Tool generiert maßgeschneiderte Bootloader und erzeugt Krypto-Übertragungen. Intuitive Verwaltung eigener Bootloader und Schlüssel.

  • Senden von EEPROM- und Flash-Daten in einer Sitzung; verschlüsseltes Distributionsformat.

  • Open-Source-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 einfacher passwortgeschützter Bootloader kann den Programmierzugriff auf einen berechtigten Personenkreis beschränken. Innerhalb des Controllers sind die Daten und Programme auch ziemlich sicher, sofern der ISP-Zugriff per Lockbits und/oder physikalische Maßnahmen gesperrt wurde. Wenn Firmware-Updates jedoch außerhalb des Controllers in unverschlüsselter Form gehandhabt werden, dann sind sie weiterhin den Gefahren von Kompromittierung, Manipulation oder ganz profanen Zufallsfehlern ausgesetzt. Bei rein lokaler Nutzung des Bootloaders 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 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! Allerdings stellt schon die Realisierung eines kompakten Krypto-Bootloaders sportliche Herausforderungen an Codeeffizienz, Unabhängigkeit, Zuverlässigkeit und Transparenz. So etwas lässt sich nicht an einem Wochenende im Baukastensystem zusammenhämmern. Das ist ein klassischer Fall für die Programmierung in Assembler; dann klappt's auch mit dem transparenten Gesamtkonzept! Man hätte sich ein Beispiel an TinySafeBoot nehmen können... Der hat vor Jahren friedlich demonstriert, wie ein einsatzbereiter und ressourcensparender AVR-Bootloader samt plattformübergreifender Software-Unterstützung aussehen kann. Ein praktisches Feature besteht zum Beispiel darin, dass die Software maßgeschneiderte Bootloader generieren kann, ohne auf eine bestimmte Toolchain angewiesen zu sein.

Viele Entwickler wollen unabhängige und transparente Lösungen. Ein universeller Krypto-Bootloader stand auch auf meiner Wunschliste jahrelang ganz weit oben. Angesichts der vielen inspirierenden Bootloader-Machwerke, die sich meinem Bewusstsein aufgedrängt haben, wurde aus der Wunschliste 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, denn das Feature wird praktisch nie gebraucht. Nicht einmal im Entwicklerumfeld, denn dort steht meistens 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.
    Bei den üblichen Firmware-Updates fließen die Daten also immer nur in eine Richtung, nämlich vom Computer zum Controller. Dennoch benötigen die meisten Bootloader eine voll ausgebaute Datenschnittstelle mit Hin- und Rückkanal. Das ist den mehr oder weniger sinnigen 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 eines Bootloaders empfindlich ein. I/O-Ports sind ein knappes Gut, und nicht jede Anwendung sieht eine vollständige RS232-, RS485- oder gar USB-Anbindung vor.
    Nun, manch neuzeitlicher AVR-Bootloader kann immerhin "One-Wire", sodass sich der Bedarf an Datenübertragungsleitungen vordergründig minimieren ließe. Doch die eine Leitung muss logischerweise bidirektional funktionieren, wenn ein bidirektionales Protokoll bedient werden soll. Das erschwert eine etwaige Mehrfachnutzung der betreffenden Leitung. Zudem wird für die serielle Kommunikation über eine bidirektionale Leitung eine spezielle Adapterschaltung benötigt, also immerhin außerhalb der Mikrocontrollerplatine wieder ein gewisser technischer Mehraufwand.
    Da sollten wir uns doch fragen: Ist dieses Hin und Her auf zwei Leitungen, oder auf einer bidirektionalen Leitung, wirklich "alternativlos", wie uns die 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 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 der Einweg-Bootloader direkt kompatibel zu gewöhnlicher RS232- oder RS485-Hardware, wo er dann eben nur den Empfangszweig aktiv nutzt. Auf Computerseite vereinfacht sich die Handhabung der seriellen Schnittstelle noch ein ganzes Stück. Es muss nur gesendet werden. Hier sind ohne besondere Klimmzüge ausgesprochen robuste und plattformübergreifende Lösungen umsetzbar. Was zu beweisen war!

  2. Kryptografie sichert Datenschutz, Datenintegrität, Authentisierung und einzigartige Geräteadressen
    Manch einer dürfte spätestens an dieser Stelle in nervöse Zuckungen verfallen: "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. Wenn man weiß, was man tut. Aber der Reihe nach.
    Für Firmware-Datenübertragungen gilt bekanntlich "Null Fehlertoleranz". Also sollte die Einweg-Übertragung technisch so robust angelegt sein, wie nur möglich. Realistischerweise können aber selbst unter kontrollierten Bedingungen noch Übertragungsfehler vorkommen. Dagegen gibt's fehlererkennende und fehlerkorrigierende Codierungen, die aber das Datenvolumen enorm aufblähen, wenn sie einigermaßen sicher sein sollen. Wird aber ein Fehler erkannt, der nicht automatisch repariert werden kann, dann bräuchte man doch wieder einen Rückkanal, um das betreffende Paket neu anzufordern oder ein abschließendes Verifying durchzuführen. Ein Dilemma?
    Jetzt kommt Kryptografie ins Spiel. Wir nehmen eine geeignete Blockchiffre, wenden eine bestimmte Form der Schlüsselverkettung an und bauen damit ein Übertragungsformat, das die Schreibdaten nicht nur ordentlich verschlüsselt, sondern auch eine kryptografische Prüfsumme (vergleichbar einer MAC) liefert. Unser Bootloader kann damit zum Ende der Übertragung einseitig und mit allergrößter Zuverlässigkeit feststellen, ob die ganzen Daten vollständig und fehlerfrei durchgekommen sind. War die "Super-Prüfsumme" korrekt, dann kann der Bootloader bedenkenlos an die neu geschriebene Applikations-Firmware übergeben. Sollte es in der Übertragung 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...:-) und der Bootloader wird stillschweigend alle fehlerhaften Daten wieder löschen und dem Nutzer auf indirektem Weg mitteilen, dass das Update fehlgeschlagen ist. Der Nutzer kann jetzt eine neue Sitzung unter konsolidierten Bedingungen versuchen. Diese Vorgehensweise ist im Zusammenhang mit Firmware-Updates ohnehin die einzig gute Praxis!
    Die Verwendung von Kryptografie bringt neben dem Schutz der Daten vor neugierigen Blicken und der zuverlässigen Erkennung von Übertragungsfehlern noch mindestens einen weiteren Vorteil: Starke kryptografische Schlüssel werden bekanntlich nach dem Zufallsprinzip erzeugt. Auf diese Weise bekommt der Krypto-Bootloader eine einzigartige Geräteadresse (UUID) zugeteilt. Das bedeutet, wir müssen uns später nie wieder mit schwachen Passwörtern und möglichen Kollisionen herumschlagen.

  3. Kompakte Firmware für die meisten ATtinys und ATmegas
    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 auf einem kleinen Mikrocontroller nicht allzu weit. Erst die Programmierung in reinem Assembler macht's möglich, Signalverarbeitung, Ablaufsteuerung und Kryptosystem in hochkompaktem und lückenlos nachvollziehbarem Code unterzubringen. Ich spoiler' schon mal: Der One-Way-Loader braucht 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 als ausführbare Datei mindestens für Linux- und Windows-Systeme compiliert werden kann. (Update 2020: In der neueren Programmierung in "C99" ist auch eine Portierung auf "Mac" denkbar.) Ein Konsolenprogramm bedeutet minimale Abhängigkeiten und klar definierbare Eingabe-Ausgabe-Schnittstellen. Der Aufruf lässt sich in Entwicklungs- und Editorumgebungen sowie in Skript-Abläufe einbinden.
    Die PC-Software muss verschlüsselte Firmware-Updates an Zielgeräte senden können, für die der Nutzer selbst den kryptografischen Schlüssel besitzt. Das Ganze sollte aber nicht mehr Umstände machen, als der Zugriff auf irgendeinen unverschlüsselten Bootloader. Niemand merkt sich heutzutage Bootloader-Passwörter. Ein pragmatischer und benutzerfreundlicher Kompromiss besteht darin, für jedes Zielgerät einen starken Zufallsschlüssel zu generieren und diesen mit einem eindeutigen und memorierbaren Klarnamen zu verknüpfen. Später gibt der autorisierte User nur diesen Bootloader-Namen an, und die Software holt sich den dazugehörigen Krypto-Schlüssel und alle Meta-Daten aus einer geschützten lokalen Datenbank.
    Die PC-Software soll auch wieder maßgeschneiderte Bootloader "out of the box" erzeugen. Eine nützliche und rationale Option, kein Muss. Wer will, kann auch gern den mühsamen Weg gehen und den offengelegten Assemblerquelltext in der Arbeitsumgebung seiner Wahl von Hand anpassen. Transparenz!
    Ein weiteres Feature, das in den Beschäftigungstherapien für Nerds nicht einmal angedacht wird: Automatische Erzeugung einer Bootloader-Serie mit individuellen Schlüsseln und serieller Nummerierung. Und passend dazu die Generierung von verschlüsselten Firmware-Updates für so eine Bootloader-Serie in einem Rutsch. Falls mal jemand auf die total verrückte Idee kommt, mehrere baugleiche Geräte mit Krypto-Bootloadern ausstatten und später mit verschlüsselten Firmware-Updates versorgen zu wollen.

  5. Cooler Name, coole Lizenz
    Nach einigem Hin und Her habe ich mich entschlossen, den neuen Bootloader nach seinem Alleinstellungsmerkmal, der Einweg-Übertragung, zu benennen. Also heißt das Teil jetzt "One-Way-Loader", "OneWayLoader" oder kurz "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 bietet Rechtssicherheit für alle Beteiligten und ermöglicht eine freiwillige und faire Zusammenarbeit.

Direkt ausprobieren: Schnellstartanleitung

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


Tipp: Für invertierte Bildschirmdarstellung steht (seit 'ner halben Ewigkeit) ein alternativer 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
  • Zugriff überhaupt nur mit Autorisierung (128-Bit-Schlüssel)
  • Für lokale Projekte vollkommen transparent nutzbar
  • Firmware-Updates "im Feld" über besonders simple und/oder robuste Schnittstellen
  • Gesicherter Update-Kanal für EEPROM/Flash-Daten
  • Nutzung existierender RS232/RS422/RS485-Schnittstellen
  • Nutzung minimalistischer und versteckter Programmierschnittstellen, z. B. LED + Fotodiode
  • Distribution kompletter Firmware-Updates über öffentliche Kanäle (Web, FTP, E-Mail)
  • Firmware-Schutz für Anwendungen, deren Updates einem ernsten Angriffsrisiko ausgesetzt sind



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 keinen ununterbrochenen Datenstrom verarbeiten. Das hat technische Gründe und trifft für AVR wie für die meisten Controller-Architekturen zu, die internen nichtflüchtigen Speicher überschreiben können (Self-programming). Eine übliche Bootloader-Firmware muss die empfangenen Daten auf Fehlerfreiheit prüfen, und wenn noch Entschlüsselung dazu kommt, kostet das richtig viel Rechenzeit. Der eigentliche Knackpunkt sind aber die physischen Schreibzugriffe in EEPROM oder Flash. Dafür wird der Prozessorkern tatsächlich angehalten, sodass auch eine ausgeklügelte Interruptsteuerung keinen kontinuierlichen Datenempfang sicherstellen kann. Durch die physischen Schreibzugriffe entsteht immer eine Zwangspause (wir nennen sie mal reißerisch "Totzeit"), in der unsere Bootloader-Firmware nichts mehr mitbekommt.
Der Datenfluss muss also zeitlich koordiniert werden. In einem typischen bidirektionalen Protokoll sendet der Computer die Daten in kleinen Blöcken, die der Controller problemlos empfangen und puffern kann. Dann wartet der Computer sehnsüchtig auf die Rückmeldung vom Controller, dass die Daten verarbeitet sind. Vorher darf der Computer keinesfalls weitere Daten oder Kommandos senden. Dieses Hin und Her auf zwei Leitungen (oder auf einer bidirektionalen Leitung) wollen wir abschaffen.

Lösung: Es ist natürlich möglich, die Totzeiten eines Controllers im Voraus zu berechnen, wenn einige Rahmenbedingungen bekannt sind. Dann weiß der Computer ganz genau, wie lange der Controller zur Verarbeitung jedes einzelnen Datenpakets unter den jeweiligen technischen Bedingungen brauchen wird. Im Grunde müsste der Computer einfach nur ein Datenpaket senden, die vorausberechnete Zeitspanne großzügig abwarten, und danach ungefragt weitere Daten senden. Gibt's aber schon das nächste Problem: Ein zeitgenauer Sendestart und definierte Sendepausen lassen sich auf einer aktuellen RS232-Implementierung (Multitasking-Betriebssystem, mehrere Abstraktionsebenen, virtuelle Gerätetreiber) überhaupt nicht mehr umsetzen. Was aber immer funktioniert, ist das Senden von seriellen Stopf- oder Füllzeichen. Diese enthalten keine Nutzdaten, aber sie erzeugen genau definierte zeitliche Mindestabstände zwischen den Datenblöcken. Wenn die Schutzintervalle aus Füllzeichen korrekt berechnet sind, kann der Computer alles in einem Rutsch senden, und selbst dann bekommt der Bootloader immer genügend Zeit, um den vorherigen Datenschwung zu verarbeiten. Kurz nachdem der Bootloader wieder auf Empfang gegangen ist, "sieht" er noch ein paar von den Füllzeichen und dann 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 auch nur halbwegs normgerechte RS232-Schnittstelle senden.
  • Es überträgt nur in eine Richtung, nämlich vom Computer ("Sender") zum Controller ("Empfänger"). Einfach!
  • Diese "Transmission" besteht aus verschlüsselten Blöcken, um Vertraulichkeit und Datenintegrität sicherzustellen.
  • Außerdem berücksichtigt das Signal die Totzeiten des Empfängers, indem zwischen den Blöcken eine vorausberechnete Anzahl von Füllzeichen eingefügt wird.
  • Diese "Präambeln" garantieren zeitliche Mindestabstände zwischen den Datenblöcken.
  • Die Präambel-Zeichen ermöglichen dem Empfänger außerdem eine schnelle Neusynchronisation auf das serielle Signal.
  • Die Einweg-Übertragung funktioniert ohne Flusssteuerung und benötigt keinen Rückkanal.
  • Die Einweg-Übertragung stellt minimale Anforderungen an RS232-Hardware und Software.
  • Das unterbrechungsfrei gesendete Signal ist binär ausgeglichen und damit technisch besonders 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 Verfahren abgeleitet. Es handelt sich um einen durchgehenden Sendedatenstrom, aber 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 müssten an diesen Stellen Protokollzeichen ausgetauscht und Sendepausen eingehalten werden, abgesehen davon würde sich aber bezüglich der Nutzdaten ein ähnliches Muster ergeben. Die individuell berechneten Präambeln einer OWL-Transmission berücksichtigen die Totzeiten (Datenverarbeitung plus Schreibzugriffe) im Ziel-Controller abhängig vom momentanen Betriebszustand und ersetzen das bidirektionale Protokoll.

Block-Sendedauer: Der einzelne Datenblock besteht immer aus einem Startzeichen und 16 verschlüsselten Bytes. Die Sendedauer eines Datenblocks ist somit bei gegebener Baudrate immer gleich. Bei 9600 Baud dauert jeder Block etwa 18 Millisekunden (tB).

Einleitende Präambel (INTRO PREAMBLE): Zum Beginn einer OWL-Sitzung muss sich der Empfänger erstmalig auf das ankommende Sendesignal einstellen oder in eine bereits laufende Präambel einsteigen. Die INTRO PREAMBLE ist in der Beispielgrafik recht kurz dargestellt. Sie kann beliebig verlängert werden. Das ist hilfreich, wenn Controller-Reset und Sendebeginn manuell koordiniert werden müssen.

Block-Entschlüsselungsdauer: Die Entschlüsselung eines Datenblocks kostet Rechenzeit. Bei Anwendung einer ernsthaften Chiffre und Taktfrequenzen im einstelligen MHz-Bereich sind das schon einige Millisekunden. Jeder Block muss entschlüsselt werden. Deshalb fließt die "decryption time" (tD) in alle Präambel-Berechnungen mit ein und gibt also die Mindestdauer der Präambeln vor. Sicherheitshalber legt man noch ein paar Zeichen "obendrauf", um Laufzeitabweichungen auszugleichen und um dem Empfänger eine sichere Nachsynchronisation zu ermöglichen. Im Vergleich zur Entschlüsselung brauchen die Schreibzugriffe in EEPROM und Flash aber zum Teil noch viel länger.

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 bedeutet kaum zusätzlichen Rechenaufwand. Daher reichen zwischen den Blöcken der Authentisierungs-Sequenz die Basis-Präambeln mit der Mindestlänge (tD) aus.

EEPROM-Sequenz (S2): EEPROM-Speicher kann direkt überschrieben werden, braucht aber pro Byte schon etliche Millisekunden, sodass sich die Schreibzeit für einen Block aus 16 EEPROM-Datenbytes 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 in der Grafik deutlich zu erkennen.

Flash-Sequenz (S3): Nach dem ersten Flash-Datenblock zeigt das Diagramm eine auffällig lange Pause von ca. 180 ms (tFE). In dieser Phase löscht der Bootloader den gesamten für Applikations-Firmware reservierten Flash, bevor neue Daten geschrieben werden können. Danach geht es zügig voran mit einzelnen Flash-Seitenzugriffen. Dem aufmerksamen Leser wird nicht entgangen sein, dass die Länge der Präambeln zwischen den Flash-Datenblöcken leicht variiert. 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 der Bootloader immer die Daten von 2 Blöcken zusammenfassen, bevor er eine ganze Flash-Page schreiben kann. Dementsprechend muss der Sender auch nur nach jedem zweiten Block die verlängerte Präambel für den Flash-Write-Zyklus (tFW) in den Datenstrom einfügen.
(Anmerkungen: 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 ein beachtlicher Optimierungseffekt. (Auf ATmegas kann das vorherige Löschen und auch eine etwaige Not-Löschung des AppFlash komplett entfallen, weil man sich hier nicht vom Bootloader "aussperren" würde, falls fehlerhafter Code stehen bleibt. Weiteres dazu in der Beschreibung der Firmware.)

Ausleitende Präambel (OUTRO PREAMBLE): In manchen Fällen ist es aus technischen Gründen notwendig, die Übertragung nach dem letzten Datenblock nicht abrupt enden zu lassen. Dann hängt man eben noch eine "ausleitende Präambel" hinten dran. Sie dient nur dazu, den Übertragungskanal noch für eine definierte Zeit offenzuhalten.

Zu den Berechnungen: Um das maßgeschneiderte Timing zu erzeugen, braucht der Sender ein Vorwissen über den Empfänger. Der Sender muss die Speicherorganisation, die durchschnittliche Anzahl von Prozessortakten bei der Block-Entschlüsselung und natürlich die 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
Hinweis: Das Hörbeispiel ist eine Vertonung des seriellen Datensignals, die den zeitlichen Charakter einer OWL-Transmission verdeutlichen soll. Es ist nicht dasselbe, war aber Ideengeber für das später entwickelte und weiter unten erwähnte Exportformat 'OWL-Audio'!

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 realisiert damit garantierte Schutzintervalle, die dem Empfänger 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 dem Empfänger 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.

Erste Synchronisation:

  • Zum Beginn einer OWL-Transmission kann der Empfänger entweder auf einen Leerlaufzustand oder asynchron in eine laufende Übertragung stoßen. Er reagiert nach folgenden Regeln:
    • 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 genau 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 beiden Low-Phasen innerhalb desselben Zeichens erfasst wurden. Am Ende der zweiten Messung ist der Empfänger mit dem Zeichenrahmen synchron und das Messergebnis ist der gesuchte Timing-Referenzwert.
    • Negatives Ergebnis ( 2 - 3 = -1 ) bedeutet, dass zwei Low-Phasen aus getrennten Zeichen erfasst wurden. Der Empfänger ist also noch nicht synchron. Er überspringt den nächsten High-Low-Wechsel und startet eine neue Doppelmessung am nächstfolgenden Präambel-Zeichen. Deren Ergebnis wird höchstwahrscheinlich positiv sein, und der Empfänger hat jetzt den richtigen Timing-Referenzwert und ist synchron.
  • 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;
    • liest 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 noch laufende Präambel vor und startet eine Neusynchronisation und erneutes Autobauding. Der Kreis schließt sich.

Anmerkungen:

  • Allgemein profitieren wir auf AVR-Seite von den Hauptvorteilen eines Software-UAR(T) mit Autobauding: Das Verfahren ist nicht auf eine controllerseitige UART-Komponente angewiesen. Es kann beliebige Portleitungen als Interface verwenden und verschiedene Baudraten für den Zeichenempfang nutzen. Insbesondere muss die Taktfrequenz nicht zwangsläufig über einen speziellen "Baudraten-Quarz" erzeugt werden und wegen der wiederholten Nachsynchronisierung in der OWL-Übertragung muss die Taktfrequenz noch nicht einmal besonders langzeitstabil sein. (D. h. die Verwendung des internen RC-Oszillators/PLL-Vervielfacher ist problemlos möglich!)
  • Das Verfahren ist flexibel. Es kann vor und während der Übertragung bis zum vorgegebenen Timeout auf ein Signal warten, aber es kann sich eben auch asynchron in eine laufende Präambel "einklinken" und dann in kürzester Zeit neu synchronisieren. Letzteres ist während der OWL-Übertragung sogar der Normalfall.
  • Das Verfahren wertet nur die aktiven Low-Zustände auf der Datenleitung aus. Eine "stotternde" Übertragung mit verlängerten Stoppbit/Leerlauf-Zuständen beeinflusst die Messgenauigkeit nicht.
  • Die Signalauswertung ist ausgesprochen robust. Die Differenzbildung kompensiert Asymmetrien in den Signalflanken, sodass sich selbst hochgradig verzerrte Signale noch auswerten lassen.
  • Präambeln, Blockstarter und die verschlüsselten Datenblöcke bilden einen digital ausgeglichenen Datenstrom. Bei kontinuierlicher Sendung liegt ein perfekt ausbalanciertes Signal vor, dessen Gleichspannungsmittelwert genau zwischen Low- und High-Pegel liegt. Das begünstigt gleichspannungsfreie und/oder differenzielle Übertragungsarten und verbessert die Störsicherheit auf realen Kanälen.
  • Neusynchronisation und Autobauding vor jedem einzelnen Datenblock. Das sichert einen stabilen Betrieb auch bei sehr langen Durchgängen unter schwankenden oder driftenden Taktfrequenzen.
  • Breiter Arbeitsbereich. Die gegenwärtige Programmierung für AVR-Mikrocontroller (natürlich in Assembler) nutzt den Wertebereich der verwendeten 16-Bit-Zähler optimal aus, sodass sich ein breites "Baudraten-Fenster" für jede realistische Taktfrequenz ergibt (Tabelle).
  • Synchronisation und Autobauding benötigen nur zwischen 1 und 2½ Präambel-Zeichen. Die Präambeln können durchaus knapp bemessen sein, mit wenigen Zeichen "Sicherheitsmarge", da das Timing recht genau vorherbestimmt ist. Damit ist die OWL-Transmission eine zeitoptimierte Übertragung, die bei gleicher Baudrate schneller durchkommt, als eine bidirektionale Bootloader-Sitzung mit einem Minimalprotokoll. Die unidirektionale OWL-Transmission vertrödelt keine Zeit mit dem Zurücksenden von Protokollzeichen, und auf PC-Seite entstehen keine weiteren Verzögerungen durch Richtungsumschaltung und die 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, siehe weiter unten. Dies bringt in einigen Fällen weitere Hardware-Vereinfachungen.

Performance

Nachstehende Tabelle gibt einen Überblick, was mit dem Synchro-Autobaud-Verfahren im OWL-Bootloader 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 zum Füllen des EEPROM sowie 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, um "falsch positive" Ergebnisse auszuschließen.

Auswertung: Wenn die LED unmittelbar nach Abschluss der Transmission fröhlich zu blinken anfing, dann muss logischerweise die gesamte Transmission bei der verwendeten Baudrate vollständig und fehlerfrei durchgelaufen sein. Es bestätigte sich, dass die Fehlererkennung durch die aktuelle Bootloader-Firmware extrem zuverlässig 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 ausgesprochen breiten Arbeitsbereich!
  2. Näherungsformel für das sichere Baudraten-Fenster:
    CLOCK/10 < BAUDRATE < CLOCK x 2
  3. Liefert das Interface unsaubere (weniger steile) Pegelwechsel, kann es mit der höchsten Baudrate Probleme geben. Die nächstniedrigere Norm-Baudrate sollte funktionieren.
  4. Die Untergrenze (Minimum-Baudrate) ergibt sich aus der Tatsache, dass der Wertebereich des Zählers zur Pulsbreitenmessung bei zu langsamem Signal überläuft.
  5. Die Obergrenze (Maximum-Baudrate) ergibt sich aus der zunehmenden Messungenauigkeit, 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 und der ATtiny2313-20PU auch "eigentlich" nur bis 20 MHz spezifiziert war. Uneigentlich lief dieses Exemplar bis über 32 MHz (!) scheinbar problemlos, was die Kernfunktionalität der MCU anging. (Overclocking-Experimente mit Mikrocontrollern - ein interessanter und nicht so kostspieliger Zeitvertreib...)
  7. Im Test wurden nur Norm-Baudraten verwendet. An einem USB-COM-Wandler (z.B. FT232) können ggf. auch andere, nicht-standardkonforme Baudraten, wie etwa 64.000 Baud, eingestellt werden. Das ist für dieses 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 spielen die technischen Signaleigenschaften keine Rolle. Auf der Kryptoschicht wird nur mit den Datenblöcken zu 16 Bytes gearbeitet.

Alle Blöcke sind mit RST verschlüsselt. Aufgrund des verwendeten Feedback-Modus' dieser Blockchiffre ist jeder einzelne Block von allen vorausgegangenen Blöcken kryptografisch abhängig. Diese Eigenschaft lässt sich zur sicheren Fehlererkennung nutzen. Der rechtmäßige Empfänger kann zweifelsfrei feststellen, ob alle Daten in einem logischen Abschnitt ("RST-Sequenz") komplett und korrekt übertragen wurden und bekommt zusätzlich das Signal, dass die nächste Sequenz beginnt, denn ...

Die OWL-Transmission besteht aus drei verketteten RST-Sequenzen, die immer in derselben Reihenfolge gesendet werden: Authentisierung, EEPROM-Daten, Flash-Daten. Beim Wechsel zur nächsten Sequenz wird der Schlüsselgenerator jedoch nicht wieder mit dem Initialschlüssel zurückgesetzt, sondern läuft weiter. Damit sind nicht nur die Blöcke innerhalb einer Sequenz, sondern alle 3 Sequenzen kryptografisch voneinander abhängig. Wird der abschließende VI-Block erkannt, weiß der Empfänger, dass die vorausgegangenen Daten fehlerfrei und vollständig übertragen wurden. Anschließend erwartet er die Daten der Folgesequenz. Im Fehlerfall verbleibt der Empfänger in der gegenwärtigen Sequenz und kann am Ende der Transmission Maßnahmen zur Schadensbegrenzung treffen. Eine weiter gehende Differenzierung ist für den Einweg-Bootloader auch gar nicht nötig.


Logischer Ablauf der OWL-Transmission:
  • 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 = Fertig! Gesamte Übertragung fehlerfrei, Applikation sofort starten!

Normalfall: Der Sender verwendet 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 der letzten Sequenz S3. Damit ist sicher, dass alle bereits geschriebenen Daten vollständig und fehlerfrei durchgekommen sind. Die Sitzung war 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); fehlgeschlagene Nachsynchronisation bei stark gestörtem Signal; versehentliche Anwendung eines falschen Schlüssels; absichtliche Anwendung eines falschen Schlüssels zur Adressierung eines anderen Empfängers auf derselben Leitung; plumpe Manipulationsversuche. Alle diese Situationen erkennt der Empfänger zuverlässig 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, abgesehen von Präambel und Blockstarter, ohne weitere Steuerzeichen und Kommandos aus. Innerhalb der verschlüsselten Blöcke werden keine sonstigen 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 um ein recht starres Schema handelt, sind die Schreibzugriffe in EEPROM oder Flash optional. Es ist selbstverständlich 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 Substitutions and Transpositions"). Dabei handelt es sich um ein ehemaliges Studienprojekt zum Thema Blockverschlüsselung. Mein inzwischen gut erprobtes Kryptosystem ist auf praktische Anwendbarkeit und Transparenz angelegt. Es definiert nicht nur eine kombinatorisch eher simple Blockchiffre, sondern auch einen dazu passenden Key-Feedback-Modus und ein bevorzugtes Dateiformat.
Doch warum in diesen Zeiten "das Rad neu erfinden"? Unbenommen, auf der PC-Plattform gibt es eine Menge an Krypto-Optionen, die brauchbar erscheinen und dem weit verbreiteten Glauben an "Zertifiziertes" huldigen. Zu einigen Algorithmen gibt es sehr schnelle Umsetzungen in Software und auch Hardware (z. B. AES), sodass diese in der Regel einen höheren Datendurchsatz erzielen, als meine inoffizielle und bisher nur teiloptimierte PC-Implementierung von RST.
Bei Mikrocontroller-Anwendungen sind die Prioritäten etwas anders gelagert. So zeigte sich im Vergleich mit prominenten Kandidaten, dass RST als Bootloader-Chiffre einen attraktiven Kompromiss aus Codeeffizienz und Sicherheit zu bieten hat.

Funktionsweise von RST

Das Verfahren nutzt für seine "randomisierten Substitutionen und Transpositionen" einfachste arithmetische Standardoperationen, wie Addition, Bitshifting, Invertierung und Vertauschung, auf denen auch etablierte Blockchiffren beruhen. Die Rechenschritte innerhalb einer Blockrunde werden bei RST jedoch nicht über magische Konstanten oder Tabellen gesteuert, sondern von einem fortlaufenden Pseudozufallsgenerator, der lediglich zum Beginn der Ver- oder Entschlüsselung mit dem geheimen Schlüssel als Startzahl (seed) geladen wird.
Der PRNG ist also wortwörtlich eine "Schlüsselkomponente" des Kryptosystems. Er kann nach unterschiedlichen Qualitätskriterien realisiert werden. So lässt sich je nach Anwendungsgebiet ein günstiger Kompromiss aus Rundenzahl, PRNG-Stärke und Codebedarf (Mikrocontroller-Anwendungen) finden.
Der Block-Algorithmus von RST erzielt schon bei Mindestrundenzahl eine ausgezeichnete Balancierung der Bit-Häufigkeiten und einen mittleren bis guten Avalanche-Effekt. Letzteres bedeutet, ein einziges "gekipptes" Bit im Chiffrat verändert nach der Entschlüsselung ca. 25 bis 50 Prozent der Bits im wiederhergestellten Klartextblock. Nach jeder vollständigen Blockrunde wird der innere Zustand des PRNG mit dem Klartext des vorherigen Blockes modifiziert. Daraus resultiert eine massive Fehlerfortpflanzung, die Grundlage für einen zuverlässigen Authentisierungs- und Fehlererkennungsmechanismus.


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

Dateiformat

Für PC-Anwendungen entstand ein einfaches Format zur authentisierbaren und kryptografisch abgesicherten Übertragung von Dateien. Das RST-Kryptogramm besteht ausschließlich aus verschlüsselten Blöcken (kein Header) und erfüllt auch sonst alle statistischen Anforderungen an ein gutes Chiffrat. Es ist von einer Reihe echter Zufallszahlen nicht unterscheidbar und selbstverständlich erzeugt derselbe Klartext aufgrund der randomisierenden Komponente jedes Mal ein komplett anderes Chiffrat. Nur die erfolgreich entschlüsselte RST-Sequenz gliedert sich in drei Abschnitte:
  • IV = Block mit verschlüsseltem (geheimem) Initialisierungsvektor
  • DATA = Block/Blöcke mit verschlüsselter Nachricht (Nutzdaten)
  • VI = Block mit Wiederholung des verschlüsselten IV (Nachricht-Ende-Signatur, Über-Alles-Prüfsumme)
Der erste Block ist der einzige Block, der mit dem Originalschlüssel verschlüsselt wird. Dieser erste Block ist mit Zufallszahlen gefüllt. Infolge der Klartext-Schlüssel-Rückkopplung verändert dieser Zufallsblock nach der ersten Runde den Zustand des PRNG. Somit hat der erste Block einer RST-Sequenz die klassische Funktion eines Initialisierungsvektors oder IV. Durch diese Randomisierung werden die nachfolgenden Blöcke mit einem komplett neuen Zufallsschlüssel verarbeitet. Damit sind triviale Angriffe auf das Kryptosystem (v. a. "known plaintext") ziemlich sicher ausgeschlossen, da es, vereinfacht gesagt, für verschlüsselte Zufallszahlen keine kryptoanalytische "Abkürzung" gibt.

Der IV-Block hat noch eine weitere Funktion. Sein Muster aus Zufallszahlen wird mit allergrößter Wahrscheinlichkeit in der gesamten Nachricht kein zweites Mal vorkommen. Das bedeutet, der IV kann als eindeutige Markierung für das Nachrichten-Ende benutzt werden. Zur funktionalen Unterscheidung nenne ich diese Wiederholung des IV-Musters "VI". Zum Beginn der Entschlüsselung einer RST-Sequenz speichert der Empfänger einfach den ersten entschlüsselten Block ab und vergleicht diesen VI mit jedem nachfolgend entschlüsselten Block. Dabei wendet er ein paar einfache Regeln an:
  • Wenn sich der entschlüsselte Block vom VI unterscheidet, geht der Empfänger davon aus, dass dies ein normaler Datenblock ist, der weiterverarbeitet (z. B. abgespeichert) werden kann.
  • Erkennt der Empfänger einen Block, der exakt mit dem VI übereinstimmt, dann weiß er mit allergrößter Sicherheit, dass die ganze vorherige Übertragung authentisch, vollständig und fehlerfrei war.
  • In allen anderen Fällen wird das Dateiende erreicht, ohne dass der Empfänger den VI jemals erkennt. FEHLER!
Anstelle von Fehler-Lokalisation und Fehler-Korrektur tritt eine zuverlässige Fehlererkennung. RST ist also kein Streaming-Format, wo eine Fehlerkorrektur innerhalb der laufenden Übertragung möglich sein muss, und es ist kein Format, das wahlfreien Zugriff auf einzelne Blöcke erlauben würde. Es ist ein "Alles-oder-Nichts-Verfahren". Fehlerhaft entschlüsselte Dateien sind in der Regel komplett unbrauchbar. Es wäre Zeitverschwendung, sich auf Datei-Ebene mit fehlerkorrigierenden Maßnahmen zu befassen, wenn die Alternative schlicht und ergreifend darin besteht, den Download zu wiederholen oder die E-Mail noch einmal zu senden. Der rechtmäßige Empfänger kann auf Grundlage des IV-VI-Mechanismus in einem Durchgang und mit vergleichsweise geringem Aufwand an Rechenleistung und Speicher die Authentizität, Vollständigkeit und Fehlerfreiheit einer Übertragung einwandfrei feststellen. Diese Funktionalität reicht in vielen Anwendungsbereichen aus. So auch beim Bootloader.

"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 äußerst wertvoll.

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 deutliche kryptografische Abhärtung der LFSR-Sequenz (Eliminierung von Autokorrelation) 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 recht codeeffizient, elegant und transparent in Assembler umsetzen lassen.

Da RST keine Feistel-Chiffre ist, müssen die Pseudozufallsvektoren für Verschlüsselung und Entschlüsselung jeweils in umgekehrter Reihenfolge zur Anwendung kommen. Daraus folgert, dass entweder beim Verschlüsseln oder beim Entschlüsseln die ganze Pseudozufallssequenz für eine komplette Blockrunde zwischengespeichert werden muss. Auf der Gegenseite können die Zahlen dann aber direkt aus dem PRNG gezogen werden. Es versteht sich von selbst, dass in der Bootloader-Anwendung die speicher- und codesparende Variante auf den Mikrocontroller verlagert wird.

Zur Diskussion

Folgende Vorteile sehe ich in der Verwendung 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 unglücklich gewählten Feedback-Modus vorkommt, ist 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 ermöglicht die Verwendung eines geheimen IV und garantiert massive Fehlerfortpflanzung, was wiederum die Grundlage für die sichere Über-Alles-Fehlererkennung ist.

Offensichtlicher Nachteil: Der PRNG läuft immer weiter... Ein kryptografisch starker PRNG (Cryptographically Strong PRNG, auch "CSPRNG") braucht Rechenzeit. Auf dem PC war RST128 in einer teiloptimierten Variante, die noch vergleichsweise holprig in FreeBASIC geschrieben war, um das 3- bis 5-fache langsamer, als eine vergleichbare Implementierung von AES. Mit TEA/XTEA lag sie fast gleichauf. (Die Benchmarks werde ich wohl mal mit einer in C neugeschriebenen Referenzimplementierung wiederholen müssen.)

Mein vorläufiges Fazit: In der Bootloader-Umgebung auf einem Mikrocontroller 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 Authentisierung bietet.
Kritik an dieser hausgemachten Lösung ist billig und legitim. In diesem Zusammenhang möchte ich darauf hinweisen, dass die wohl kritischste Komponente, der Pseudozufallsgenerator, 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. Diese Variante gilt als kryptografisch sicher.
Weiter 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 LFSR-Sequenz abzielen, noch erheblich erschweren. Hierzu höre ich gern qualifizierte Argumente und Vorschläge.

Nach oben | Index



Firmware

Die OWL-Firmware ist natürlich in AVR-Assembler geschrieben. Sie nutzt den Standard-Befehlssatz, welcher von nahezu allen 8-Bit-AVRs unterstützt wird. Die Firmware macht sich von keinen spezifischen Hardwarekomponenten abhängig und verwendet keine Interrupts. Der Quellcode ist dank bedingter Assemblierung auf mehr als 120 verschiedene ATtinys und ATmegas anwendbar. Mit den neuesten Anpassungen in der Syntax ist der Assemblercode vollständig kompatibel zu Atmel's proprietärem Assembler, aber auch zur freien und plattformübergreifend verfügbaren Alternative gavrasm! Wie bereits im Abschnitt 'Software' erwähnt, ist ein Assemblieren von Bootloader-Firmware normalerweise nicht nötig. Es steht Maschinencode für alle unterstützten AVR-Modelle zur Verfügung, der in einem automatisierten Verfahren nur noch an Benutzervorgaben angepasst werden muss. Die Programme für den PC sind alle in Standard-C geschrieben, restlos offengelegt, wohlstrukturiert und reichlich kommentiert.

Features:
  • Hochgradig portabler Code, läuft auf vielen AVRs
  • Fast alle Varianten der OWL-Firmware unter 512 Bytes (Ausnahme einige wenige ATmegas)
  • Nutzung beliebiger Ports für den Datenempfang
  • Schnelles und zuverlässiges Verfahren für wiederholte Neusynchronisation und Autobauding
  • Warten bis zum Timeout oder Einstieg in laufendes Signal
  • Datenempfang in nichtinvertierter oder invertierter Logik
  • Ausgabe eines Steuersignals in nichtinvertierter oder invertierter Logik (Idle-TXD, RS485-TE)
  • Individueller 128-Bit-Zufallsschlüssel bzw. individuelle Geräteadresse
  • Sichere Authentisierung, Entschlüsselung und Ablaufsteuerung
  • Lineare Schreibzugriffe in EEPROM und/oder Flash
  • Bereichsprüfung für Schreibzugriffe in Flash (insbes. ATtinys)
  • Klar definiertes Verhalten im Fehlerfall
  • Unterscheidung von Reset-Quellen und gezielte Weiterleitung

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-Updates 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.

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

Hinweis: Adressen in den Diagrammen sind Bytes.


Es folgt: High-Level-Beschreibung zu den wesentlichen Funktionen 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, durch Verbinden des Controllers mit der Stromversorgung, durch Abfall und Wiederanstieg der Versorgungsspannung oder durch den Watchdog-Timer 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.
Die neue Firmware von 2020 kann diese Reset-Quellen unterscheiden und entweder darauf reagieren, also den Bootloader-Betrieb starten, oder aber direkt zur Applikations-Firmware weiterleiten. (Siehe Erläuterungen zum Feature "Reset Sources"!)
Auch Grandioses lässt sich mitunter noch verbessern... Seit April 2023 verfügt die Firmware über ein weiteres nützliches Feature in Bezug auf das Reset-Verhalten des OWL. Eine Applikation, die ihrerseits den Bootloader aufrufen will, kann durch komplettes Löschen des Controller-Statusregisters und anschließenden unbedingten Sprung zur Bootloader-Startadresse die Reset-Quellenprüfung umgehen und den Bootloader auf elegante Weise aufrufen. (Details weiter unten: "Reset-Filter-Umgehung")

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 einem an die Firmware angehängten INFO TAG, und holt sich von dort das Timeout-Byte. Anschließend lädt er seinen individuellen Krypto-Schlüssel, der sich "hard-coded" am oberen Ende des Flash-Speichers befindet, in die PRNG-Arbeitsregister (r0-r15). Dann beginnt der Bootloader, auf der Empfangsleitung zu lauschen. Erscheint dort vor Ablauf des Timeout ein Signal, 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, kein INFO TAG, alles $FF-Bytes) verwendet der Bootloader immer den längstmöglichen Timeout und startet sich anschließend selbst wieder. Auf diese Weise bleibt der Bootloader permanent erreichbar, solange noch gar keine Applikations-Firmware geladen wurde.

  • ATmegas: Der Bootloader lädt seinen Krypto-Schlüssel, der sich "hard-coded" am obersten Flash-Ende befindet, in die PRNG-Arbeitsregister. Auch der Timeout ist bei den ATmegas fest in die Firmware eincodiert. Die Reset-Rücksprungadresse ist immer $0000. Für ATmegas ist daher kein INFO TAG vorgesehen. Nach dem Holen des Timeout-Bytes lauscht der Bootloader auf der Empfangsleitung. Kommt noch vor Ablauf der Zeit ein Signal an, dann wird der Bootloader versuchen, sich darauf zu synchronisieren. Passiert bis zum voreingestellten Timeout gar nichts, springt der Bootloader pauschal zur Adresse $0000, wo die Applikations-Firmware regulär gestartet wird. Bei leerem Flash landet der Prozessor wieder beim Bootloader, und dieser wird im Timeout-Intervall immer wieder neu gestartet, bleibt also durchgängig ansprechbar.

Synchro-Autobauding:
Der Bootloader wartet bis zum Timeout darauf, dass ein Signal auf der für den Datenempfang konfigurierten Leitung eintrifft. Ein erster Pegelwechsel wird grundsätzlich verworfen, um ein "Einpendeln" des Signals zu ermöglichen. Nachfolgende Pegelwechsel werden mit dem oben beschriebenen Autobaud-Verfahren ausgewertet. Sofern das ankommende Signal eine OWL-Präambel ist und hinreichend sauber durchkommt, wird die Erstsynchronisation gelingen. Damit besitzt der Bootloader eine Timing-Referenz für den Empfang des ersten Datenblocks mittels Software-Decoder. Der Synchro-Autobaud-Zyklus wird mit jeder Präambel wiederholt. Dadurch ist dieser Bootloader völlig immun gegen mittel- bis langfristige Schwankungen der Taktfrequenzen auf Sender- und Empfängerseite. Auch sehr lange Durchgänge sind trotz driftender Taktfrequenzen kein Problem.


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


Block-Daten entschlüsseln: Der Bootloader klinkt sich aus der seriellen Übertragung aus und beginnt mit der 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. Die vom PRNG gelieferten Pseudozufallsvektoren hängen vom inneren Zustand des PRNG ab, welcher in den Registern r0-r15 gespeichert ist. Dieser ändert sich durch Anforderung weiterer Zufallsbits fortlaufend.
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. Dadurch fließt Entropie aus den Nutzdaten in die nachfolgende Ver-/Entschlüsselung ein. Vor allem wird eine massive Fehlerfortpflanzung erreicht, die Grundlage für den leistungsfähigen Authentisierungs- und Fehlererkennungsmechanismus.
Der erste Block einer neu begonnenen Sequenz, der IV-Block, besteht aus Zufallszahlen, die nach der Entschlüsselung auf den PRNG-Zustand rückgekoppelt werden. Faktisch läuft der PRNG also ab dem zweiten Block einer Sequenz mit einem völlig neuen Zufallsschlüssel weiter. Außerdem wird der IV-Block als "VI" in einen zweiten SRAM-Puffer kopiert.
Alle danach entschlüsselten Blöcke werden im Laufe der RST-Sequenz 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 wurde die RST-Sequenz erfolgreich abgeschlossen und der Bootloader weiß, dass alle vorherigen Blöcke in Ordnung waren. Gegebenenfalls schaltet er nun zur nächsten Sequenz weiter.
Im Fehlerfall wird der VI niemals erkannt und das Programm verbleibt in der aktuellen Sequenz, bis die Übertragung zuende geht und es zum Timeout kommt. Weiteres unter "Fehlerbehandlung".
Die gesamte Blockentschlüsselung benötigt in Assembler einschließlich PRNG gerade einmal 50 Maschinenbefehle! Blockvergleich und Key-Feedback konnten in einer gemeinsamen Schleife untergebracht werden, die gerade einmal 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.
Die Authentisierung gegenüber dem Bootloader ist natürlich keine simple Zugangssperre im Sinne einer Passwortabfrage. Die Authentisierung erfolgt über eine RST-Sequenz, die keine Nutzdaten enthält, sondern genau einen Block mit Dummy-Daten und einen abschließenden VI. Nur, wenn dieser VI als gültig erkannt wurde, war die Authentisierung erfolgreich. In diesem Fall geht der Bootloader vertrauensvoll in die nächste Runde, die 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 korrekt abgeschlossen. Der Bootloader verharrt in einer Endlos-Schleife ohne Timeout. Dieser Zustand kann nur noch über einen erneuten Hardware-Reset beendet werden. Der Blockade-Mechanismus erlaubt es, mehrere Bootloader mit verschiedenen Schlüsseln und sogar mit unterschiedlichen technischen Voraussetzungen, was die möglichen Baudraten angeht, auf einer gemeinsamen Programmierleitung anzusprechen. Pro Reset-Zyklus wird dann immer nur der tatsächlich angesprochene Bootloader die für ihn bestimmte Übertragung auswerten. Alle nicht angesprochenen Bootloader machen nach dem dritten Block "dicht", weil sie ihn nicht als VI erkennen, und verhalten sich bis zum nächsten Hardware-Reset passiv, d. h. eine bereits vorhandene Applikations-Firmware wird nicht angetastet und nicht unkontrolliert gestartet.
Wegen der Schlüsselverkettung ist die OWL-Transmission fälschungssicher in dem Sinne, dass ein Angreifer, der lediglich eine gültige Transmission aus S1 oder S1+S2 vor eine eigene Übertragung kopiert, auf diese Weise keine sinnvollen Änderungen in EEPROM oder Flash schreiben kann. Bei einer wie auch immer manipulierten Übertragung wird der abschließende VI von S3 niemals erkannt. Der Bootloader kann am Ende der Übertragung Gegenmaßnahmen treffen, mindestens aber in den Blockadezustand gehen.


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), 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 im oberen EEPROM-Adressbereich befinden, werden nicht angetastet, wenn ein neuer Schreibzugriff nur tiefer liegende Adressen berührt. Das kann für inkrementelle EEPROM-Updates ausgenutzt werden.
Ein separater EEPROM-Löschmodus erscheint verzichtbar. Zum Löschen des gesamten EEPROM wird eine Sequenz übertragen, die den ganzen Speicherbereich abdeckt und mit $00 oder $FF überschreibt.
In der EEPROM-Sequenz müssen keine Maßnahmen gegen Adressüberlauf getroffen werden. Sollte der Bootloader das Ende der EEPROM-Sequenz wegen Übertragungsfehlern nicht mitkriegen, so würden die weiteren Schreibzugriffe einfach nur immer wieder den EEPROM überschreiben. Dieses Risiko erscheint tragbar. Der EEPROM ist gewissermaßen die Knautschzone vor dem kritischen Flash-Zugriff.
Kommt es in der EEPROM-Sequenz zum Timeout, dann geht der Bootloader in den Blockadezustand, sodass auch hier eine indirekte Rückmeldung über den Misserfolg der Sitzung 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... (Das entspricht der Blockgröße bei heutigen SSD-Speichern. 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 einigermaßen stabile Betriebsbedingungen geherrscht haben. Beim OWL entschärft sich die Situation noch, da der gesamte Übertragungsweg 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 Applikation 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 übertragen wurden, sogar wenn gar keine Bootloader-Sitzung vorgesehen ist und eigentlich der normale Start der Applikations-Firmware erwartet wird. Denn jeder Kaltstart bringt es mit sich, dass Hardwarekomponenten und Portleitungen des Controllers für eine gewisse Zeit 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 Versorgungsspannung ausreichend stabilisiert hat; auf externe Hardwarekomponenten hat der BOD jedoch keinen Einfluss. So ist es durchaus möglich, dass gerade auf der für den seriellen Datenempfang vorgesehenen Leitung noch für längere Zeit ein unzulässiger oder undefinierter Pegel anliegt. Oder externe Hardware verursacht einen oder mehrere Pegelwechsel, weil sich die Versorgungsspannungen in externen Bausteinen noch nicht ausreichend stabilisiert haben. Wenn zu diesem Zeitpunkt das Bootloader-Programm bereits auf der Leitung lauscht, kann es also zu "Missverständnissen" kommen. Das ist mit dem TSB öfter passiert, besonders im Zusammenhang mit USB-Geräten, die nur durch Power-On initialisiert werden konnten. Hier gab es manchmal den unschönen Effekt, dass sich der Bootloader wegen eines ungültigen Anfangszustandes auf der Leitung "aufhängt". Auch hierfür gab es 'Workarounds', aber diese haben dann in anderen Hardwareumgebungen wieder Probleme bereitet. Man kann es eben nicht allen recht machen...
Der OWL zeigt ein verbessertes und noch robusteres Startverhalten. Hier hat der Start der Applikation Vorrang. Sollte die Empfangsleitung direkt nach einem Kaltstart noch sehr "wackelig" sein, dann kommt keine Bootloader-Sitzung zustande, weil auch die saubere Datenübertragung infrage gestellt wäre, aber der OWL geht nach dem Abklingen der Störung in den normalen Timeout und startet dann die Applikations-Firmware.
Wurde der erste Datenblock komplett entschlüsselt, und findet OWL dann wie erwartet die nächste Präambel vor, geht er davon aus, dass er sich in einer gültigen Transmission befindet und weitermachen kann. Sollte es in diesem fortgeschrittenen Stadium zu einem Timeout kommen, dann übergibt der Bootloader allerdings nicht an die Applikations-Firmware, sondern verbleibt im Blockade-Zustand.
Die Fehlerbehandlung bzw. -meldung ist beim OWL also recht einheitlich geregelt: Ein bisschen Gekruschel auf der Leitung blockiert nicht den Bootloader und verhindert vor allem nicht den Start der regulären Applikation. Wenn aber eine gültige Transmission empfangen wird, dann kommt ENTWEDER alles vollständig, fehlerfrei und zügig durch und die Applikation wird unmittelbar nach Beendigung der Transmission gestartet; ODER es kommt zu irgendeinem Fehler oder Timeout während der Übertragung und der Bootloader geht in den Blockadezustand.


Timeout-Timing: Der OWL-Timeout beginnt mit jedem Idle-Zustand auf der Leitung und funktioniert zu jedem Zeitpunkt, also auch innerhalb eines Zeichenrahmens, falls etwa die Übertragung abrupt unterbrochen wurde. Der Timeout soll in einem breiten Bereich von realistischen Taktraten (etwa 128 kHz bis 25 MHz) Verzögerungen von einigen hundertstel Sekunden bis hin zu mehreren Sekunden ermöglichen. Das ist nur möglich, indem die OWL-Software anhand der bekannten Taktfrequenz (aus der Target-Datei) einen entsprechenden Teilerfaktor berechnet, der dann direkt in der neu erzeugten Firmware eingebaut wird. Dieser Vorteiler ist auf eine Zeiteinheit von 1/100stel Sekunde normiert. Später kann der Timeout für jeden OWL-Bootloader über ein einziges Byte in der Maßeinheit 1/100 Sekunde (Centisekunden) angegeben werden. Ein Timeout-Byte mit dem Wert "1" entspricht also einer hundertstel Sekunde, der Wert "100" entspricht genau einer Sekunde, und der Wert "255" entspricht in etwa 2,5 Sekunden. Das spart beim nachträglichen Ändern des Timeouts (ATtinys) umständliche Rechnerei.


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, hocheffizient als Galois-XOR auf ein Register umgesetzt. 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 viel stärker drosseln. Die unregelmäßige Taktung könnte sogar noch Vorteile hinsichtlich möglicher Seitenkanalangriffe bedeuten.
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 Prozessortakte einspart. Meines Wissens ist das vorliegende SSG-LFSR eine der takt- und codeeffizientesten CSPRNG-Umsetzungen für 8-Bit-MCUs.


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 leider nur über SRAM-Befehle ansprechbar. Weil die entsprechenden Opcodes ein langsameres Timing haben und mehr Speicherplatz kosten, werden solche "memory mapped"-Zugriffe von der OWL-Firmware gegenwärtig nicht unterstützt.


Code-Flexibilität: Der Assembler-Quelltext der OWL-Firmware enthält auch wieder einige Präprozessor-Anweisungen zur bedingten Assemblierung, ein Konzept, das sich schon beim TSB bewährt hat. Mit einem Quelltext kann eine ganze Reihe von Devices abgedeckt werden. Die Anzahl solcher .if/.endif-Konstrukte ist beim OWL sogar geringer, als beim TSB. Denn das zugrundeliegende Übertragungsformat, die "OWL-Transmission" mit maßgeschneiderten Präambeln bleibt für alle Devices einheitlich und berücksichtigt schon auf der Senderseite etwaige Besonderheiten im Timing, die sich aus der geringfügig unterschiedlichen Architektur der Devices ergeben. Außerdem verschwendet der OWL keine zusätzliche Speicherseite für Benutzerdaten (wie TSB, FastBoot u.a.). Weniger Extrawürste und aufgeräumterer Code. Die OWL-Firmware ist sogar wartungsfreundlicher, als das Vorgängerprojekt.


Portierbarkeit: Der vorliegende Assemblercode ermöglicht ohne besondere Anpassungen die Erzeugung von OWL-Firmware für einen Kernbestand von ca. 120 ATtinys und ATmegas.
Zahlreiche ATtinys und ATmegas sind in der Vergangenheit auch erfolgreich mit TSB gelaufen. Für einige Chips waren Anpassungen am Code erforderlich; für den OWL musste das Rad glücklicherweise nicht neu erfunden werden.


Unterstützung für ATmega128x und ATmega256x: Der Zugriff auf Flash-Speicher über 64 KB ist bei den großen ATmegas durch eine Art Bankswitching (erweiterter Z-Pointer) geregelt. Entsprechende Modifikationen in der OWL-Firmware für diese ATmegas sind inzwischen ausgiebig getestet. Der lineare Adresszugriff wurde beibehalten. In einem Einweg-Szenario dürfte dies noch die sicherste und zuverlässigste Methode sein, um einen größeren Speicherbereich kontrolliert mit Daten zu befüllen.
Aber es geht komfortabler, als bisher. Auf einem ATmega kann fehlerhafter Code oder Reste einer alten Firmware die Integrität und Verfügbarkeit des Bootloaders nicht gefährden, insbesondere, wenn zusätzlich der Schreibschutz für die Bootloader-Sektion aktiviert ist. Beim nächsten Reset ist ein ATmega-Bootloader auf jeden Fall wieder verfügbar.
Daher wurde das vorausgehende Löschen des gesamten Applikations-Flash durch einen anderen Modus ersetzt: Seitenweises Überschreiben. Es werden nur diejenigen Flash-Pages gelöscht, die als Nächstes überschrieben werden sollen. Das bedeutet, wir müssen auch nicht immer die ganze Applikations-Firmware neu schreiben. Es besteht die Möglichkeit von abgestuften Updates. Wenn eine Applikation also tatsächlich die ganzen 128 oder 256 Kilobytes (abzüglich Bootloader-Sektion) in Anspruch nimmt, dann liegt es nahe, das Programm in Module aufzuteilen. Im höheren Adressbereich liegen dann diejenigen Programmteile, die nicht sehr häufig oder nie mehr geändert werden müssen (Libraries, Tabellen). Unten liegt die Haupt-Applikation mit Features, die im Rahmen von Firmware-Updates öfter mal aktualisiert werden sollen. Ein Update, das nur den unteren Flash abdeckt, lässt die weiter oben liegenden Speicherinhalte komplett unangetastet. Diese Methode bewahrt im Rahmen des Einweg-Zugriffs eine gewisse Flexibilität bei Firmware-Updates, ohne heilloses Chaos und Sicherheitsprobleme heraufzubeschwören.
Es kann schon ein paar Minuten dauern, bis 128 oder gar 256 Kilobytes an nicht komprimierbaren verschlüsselten Daten mit 9600 Baud auf den Controller rübergeschaufelt sind. Hier zeigt sich, dass das robuste OWL-Verfahren bestens für solche langen Durchgänge geeignet ist. Genießen wir doch den Nervenkitzel und die Spannung, bis sich das Gerät zurückmeldet!
Mit höheren Clockfrequenzen auf der Seite des Controllers erreicht OWL durchaus flotte Übertragungsgeschwindigkeiten, die so manchen ISP-Programmer übertrumpfen.


Watchdog-Unterstützung: Das Zusammenspiel einer Bootloader-Firmware mit einer Applikations-Firmware, die den Watchdog im Interrupt- oder Reset-Modus nutzt, ist nicht ganz unproblematisch. Es gab aber reichhaltiges Feedback zu diesem Thema von Leuten, die den OWL in genau so einem Umfeld produktiv einsetzen wollten. Grund genug, sich näher damit zu befassen... In der Regel bleibt der Watchdog über einen Warmstart-Reset hinaus aktiv, aber auf einigen AVRs wird der Prescaler, also der Timer, der die WD-Ansprechzeit steuert, durch ein Reset-Ereignis gelöscht, sodass der WD anschließend leider im kürzestmöglichen Abstand erneut getriggert wird. Ist außerdem die Fuse WDTON gesetzt, lässt sich dieses Verhalten auch nicht mehr per Software abschalten. Der WD wird ausgesprochen zuverlässig, man könnte auch sagen: penetrant. Eine Applikations-Firmware, die den WD nutzt, muss in ihrer Reset-Routine zum frühestmöglichen Zeitpunkt den WD (re-)initialisieren. Geschieht das nicht oder nicht in korrekter Weise, so kann es zu dem berühmt-berüchtigten Problem von endlosen WD-Resets kommen, wodurch sich die Applikation dann selbst blockiert. Wenn ein Bootloader dazwischengeschaltet ist, muss dieser den WD abschalten oder zumindest kontrollieren können. TinySafeBoot hat einfach an die Applikation weitergeleitet, wenn das WD-Flag gesetzt war. Dadurch wurde TSB in Setups mit dauerhaft eingeschaltetem WD praktisch wertlos. Der Bootloader von Welt stellt sich dem Problem! Die verbesserte OWL-Firmware (ab 02/2019) versucht zunächst einmal, den WD auszuschalten. Das funktioniert immer, solange die WDTON-Fuse nicht per Hardware gesetzt war. Sollte diese Fuse aber gesetzt sein, lässt sich der WD also per Software grundsätzlich nicht abschalten, dann greift Plan B und OWL stellt den WD-Prescaler auf seinen Maximalwert (je nach Chip 2 oder 8 Sekunden). Im weiteren Verlauf der Sitzung wird OWL dann regelmäßig Watchdog-Timer-Resets ausführen, wie dies auch in der eigentlichen Applikation an verschiedenen Punkten geschehen muss, damit kein WD-Interrupt oder WD-Reset ausgelöst wird.
Auf diese Weise kann der OWL sein gutes Werk ohne Störungen erledigen. Erst nachdem OWL die Kontrolle an die Applikations-Firmware zurückgegeben hat, wird diese im Rahmen ihrer Reset-Routine den Watchdog neu konfigurieren (müssen). Das wäre jedenfalls gute Programmierpraxis, davon muss ich an dieser Stelle einfach mal ausgehen. Generell gibt der OWL das Statusregister MCUSR unverändert weiter, sodass eine Applikation, genau wie in einer Installation ohne Bootloader, die verschiedenen Reset-Quellen unterscheiden und dementsprechend handeln kann.
Selbstverständlich ist auch der Fehlerstatus (Blockade) gegen WD-Resets abgesichert und wird bis zum nächsten Hardware-Reset aufrechterhalten. Anwendungen mit mehreren OWL-AVRs an einer gemeinsamen Programmierleitung werden vermutlich durch das neue WD-Feature nicht eingeschränkt.
Der Spaß kostete etwas Hirnschmalz, ein paar Diskussionen mit Anwendern, eine Reihe von zeitraubenden Versuchen am Steckbrett und ein Dutzend zusätzlicher Befehle im Code.


Reset-Filter-Funktion: Die neue OWL-Firmware (08/2020) kann zwischen Reset-Quellen (Reset Sources) unterscheiden. Abhängig davon, ob der Controller durch 'Watchdog', 'BrownOut', 'External' oder 'PowerOn' resettet wurde, wird er entweder normal gestartet, wartet also auf ein Signal bis zum Timeout, oder er leitet praktisch sofort (nur wenige Taktzyklen Verzögerung) zur Applikations-Firmware weiter. Damit kann sich der Bootloader vornehm im Hintergrund halten, wenn beispielsweise eine Anwendung ein besonders präzises Reset-Timing erwartet.
Technisch wird das neue Feature auf der Seite der Assemblerprogrammierung mit einer simplen Bitmaske realisiert, die das MCU Status Register nach Reset-Quellen auswertet. Konkret sind das ohnehin nur maximal 4 Flags im unteren Nibble (WDRF|BORF|EXTRF|PORF). Siehe AVR-Datenblätter!
Die Software muss bei der Anpassung eines Firmware-Template also gegebenenfalls die richtige Stelle im Maschinencode ausfindig machen und den Default-Wert 0b00001111 gegen die vom User gewünschte Reset-Maske austauschen. Dafür steht im Target Make Mode ein neues Argument '--resets=' bzw. '-rs=' zur Verfügung. Beispiel: 'rs=1110' bedeutet, dass die Reset-Quellen 'Watchdog', 'BrownOut' und 'Extern' zugelassen sind, also den Bootloader starten würden. Dagegen wird der Bootloader bei einem 'PowerOn'-Reset sofort an die Anwendung abgeben. Im Falle eines Kaltstarts wird der OWL dann in diesem Beispiel nicht aktiviert, wohl aber beim Auslösen eines Resets per Reset-Leitung, Watchdog-Timer oder Unterspannung. Default ist immer '-rs=1111' bzw. die normale Maske, die alle Reset-Quellen zulässt. Wird RS also nicht konfiguriert, verhält sich der neue OWL hinsichtlich Resets exakt wie der alte.


Reset-Filter-Umgehung: Darauf wäre ich ohne Benutzer-Feedback nie gekommen (04/2023). Es gibt einen Spezialfall, in dem sich die ansonsten bewährte Filtermethode etwas unvorteilhaft verhält: Sollten alle Bits im MCUSR beim Start von OWL den Wert "0" haben, wurde mit der bisherigen Firmware logischerweise immer an die Applikation weitergeleitet, denn das AND zur Prüfung des Bitmusters lieferte in diesem Fall immer 0. Der Fall kommt aber unter "natürlichen" Bedingungen NIE vor, da der Prozessorkern nach jedem hardwarebedingten Reset-Ereignis eines der Bits WDRF|BORF|EXTRF|PORF setzen wird.
Nun hat mich ein professioneller Anwender auf folgende Idee gebracht: Eine Applikations-Firmware möchte ihrerseits an den Bootloader weiterleiten können, am besten über ein standardisiertes Verfahren und nur durch Sprung an die reguläre Bootloader-Startadresse, welche versionsunabhängig als Konstante betrachtet werden kann. Der naheliegende Workaround war, dass die Applikation einfach eines oder alle Bits setzt, die beim Bootloader als Reset-Quelle durchgelassen werden. (Das Löschen oder Setzen von MCUSR-Bits ist laut Datenblatt möglich, da alle Bits im unteren Nibble "R/W" gekennzeichnet sind. Für die oberen Bits gilt das leider nicht, sie sind "reserved" und liefern immer nur eine Null zurück.) Allerdings könnte das betreffende Bit ebensogut durch ein tatsächliches Reset-Ereignis gesetzt worden sein. Daraus ergibt sich eine gewisse Unsicherheit. Eine Applikation, die nach einer Bootloadersitzung gestartet wird, kann nicht so ohne Weiteres feststellen, ob die Bootloadersitzung vielleicht durch sie selbst ausgelöst wurde.
Lösung: Der OWL umgeht bei MCUSR = 0 den RS-Check und startet direkt durch (d. h. Warten auf Signal bis Timeout). Diese Bedingung kann nur vorliegen, wenn vorher schon eine Applikations-Firmware gelaufen ist, das MCUSR gelöscht hat und zur Übergabe einen unbedingten Sprung nach BOOTSTART eingeleitet hat. Der OWL nimmt keine Veränderngen am MCUSR vor. Er wird nach dem Ende einer erfolgreichen Sitzung (nicht "Blockade") das "genullte" MCUSR wiederum an die alte oder neue Applikations-Firmware weitergeben. Die Applikation kann (und sollte) durch Auswertung des MCUSR wissen, was vor ihrem Start passiert ist. Das Beste, diese zusätzliche Möglichkeit für ein elegantes Hand-over beeinträchtigt nicht die sonstige RS-Prüfung.
Für eine Handvoll Devices sind die zusätzlichen 4 Bytes derzeit leider zuviel. Hier stand ich vor der Entscheidung, entweder schmerzhafte und eventuell noch nicht ausreichend geprüfte weitere Optimierungen zu wagen, oder das neue Feature bei einigen Devices wegzulassen. Ich habe mich für Letzteres entscheiden. Möglicherweise lassen sich bei genauerer Analyse des Codes doch noch ein paar Byte einsparen, aber das will man nicht überstürzen... Die Liste der wenigen Controller, für die das OWL-Feature "MCUSR-Null" also vorerst nicht zur Verfügung steht, befindet sich im Changelog. Wohlgemerkt, diese Devices haben ansonsten den vollen Funktionsumfang, den die aktuelle OWL Firmware bietet.


Fuses/Lockbits:

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

ATtinys:
  • SELFPRGEN aktivieren (sonst kann der 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:

  • Abhängigkeiten vermeiden. Bootloader-Firmware darf nicht von externen Firmware-Komponenten abhängig sein, sonst wäre der Bootloader ja auch nicht in der Lage, auf einem "leeren" Controller eine Applikations-Firmware zu installieren. Logisch!
    Aber auch der umgekehrte Fall ist eventuell problematisch. Der Aufruf eines vorhandenen Bootloaders durch eine Applikation wäre zwar durchaus möglich, aber meiner Meinung nach nur in Ausnahmefällen gerechtfertigt, wenn etwa bestimmte Reset-Ereignisse technisch ausgeschlossen sind oder/und der Bootloader nicht für jedermann erreichbar sein soll. Eine "Verzahnung" von Programmen führt jedoch 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 legitime Zusammenspiel zwischen einer Bootloader- und einer Applikations-Firmware sollte darin bestehen, dass der Bootloader nach getaner Arbeit (d. h. Timeout oder erfolgtes Firmware-Update) die Kontrolle an die Applikation abgibt. Eine zweite Möglichkeit, dass die Applikation den Bootloader bewusst aufruft, sollte nur über ein standardisiertes und versionsunabhängiges Verfahren möglich sein.

  • Applikations-Firmware und Bootloader-Firmware dürfen zusammen nicht mehr Speicherplatz belegen, als tatsächlich vorhanden ist... Auch klar. Aber keine Sorge, wenn's nicht passt, dann wird sich die Software schon melden und keinen Upload zulassen.
  • Vorsichtsmaßnahmen auf ATtinys: Da es auf ATtinys keine explizite Bootloader-Sektion gibt, die vor Schreibzugriffen geschützt werden kann, und da der Aufruf eines Bootloaders auf ATtinys durch einen modifizierten Reset-Vektor an Adresse $0000 realisiert wird, ist es am sichersten, wenn die Applikations-Firmware auf Flash-Schreibzugriffe verzichtet.
  • Vorsichtsmaßnahmen auf ATmegas: Die Bootloader-Sektion kann und sollte wenn möglich per Fusebits gegen Zugriffe aus der Programmsektion geschützt werden. Dadurch wird der Bootloader auf einem ATmega 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 C99-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
  • Abruf der Liste von unterstützten Controller-Modellen und deren Hardware-Optionen
  • Abruf der technischen Daten zu selbst erzeugten Krypto-Bootloadern
  • Verwaltung aller selbst generierten Bootloader über frei wählbare Dateinamen
  • Senden von Updates 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
  • Ausführliche Hilfetexte

Philosophie

So einfach wie möglich, aber nicht einfacher!
Meine Hardware-Software-Projekte setzen auf einfache Strukturen, 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 nicht umgekehrt. Wer Technik souverän einsetzt, wer den Unterschied zwischen gegenseitigem Nutzen und digitaler Versklavung kennt, und wer auf Nutzloses verzichten kann, wird frei sein, mehr Spaß mit Technik haben und seine privaten oder 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! DIESES Programm verfügt über einen menschenfreundlichen Kommandozeilen-Parser, der auch vergleichsweise informative Hilfe-Texte und Bildschirmmeldungen ausgeben kann. Das Teil ist auf Pragmatiker (wie mich) zugeschnitten. 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 in dem Zusammenhang benötigt werden. Vieles ergibt sich aus der Logik, und den Rest können wir über die integrierte Hilfe-Funktion nachschlagen. Durch das Feedback von Nutzern weiß ich inzwischen, dass das OWL-Tool tatsächlich recht intuitiv bedienbar ist. Im Gegensatz zu gewissen 'dudes' ist mein OWL-Kommandozeilentool auch ohne GUI-Frontend benutzbar!

Sämtliche Schlüsselwörter und Bildschirmmeldungen sind in englischer Sprache gehalten. Das ist wohl der linguistisch wie technisch günstigste Kompromiss. Lokalisierte Sprachversionen sind für diese Anwendung 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.
HINWEIS: Die neueren Versionen der OWL-Software (ab 2020) erlauben komplette Pfade als Dateireferenzen. Wir sind also keineswegs auf die vorgenannten Ordner festgelegt. Diese sind lediglich eine bequeme Default-Einstellung, die verwendet wird, wenn Dateinamen keine Pfadangabe beinhalten.

Ordnerstruktur

Es gibt drei Datentypen, die die OWL-Software verwalten muss:  Bootloader-Templates, Bootloader-Targets und Bootloader-Transmissionen. Diese liegen in separaten Dateien und Ordnern, normalerweise in den bereits genannten Standard-Ordnern. Wer es auch sonst gewohnt ist, seine Daten primär über das Dateisystem zu organisieren, wird hier problemlos den Überblick behalten.

Bootloader-Vorlagen:     ./templates
Für jedes unterstützte AVR-Modell existiert fertig assemblierter Maschinencode in Form einer Hex-Datei mit dem Namen des jeweiligen Ziel-Controllers. Dieser Code wurde für das jeweilige Device mit Default-Ports (B0/B1), Default-Timing und Default-Key assembliert. 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 diese Vorlage wunschgemäß anzupassen.

Bootloader-Firmware:     ./targets
Die Erzeugung eines neuen Bootloaders (Target) erfolgt nach bewährtem Prinzip auf Grundlage eines Code-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 auf PortB0/B1) und passt diese an die vom Benutzer gewünschten Ports an. Auch die Timeout-Zeitschleife wird mit dieser Methode direkt an die vorgesehene Taktfrequenz angepasst. Außerdem wird ein zufälliger Krypto-Schlüssel für den neuen Bootloader erzeugt.
Schließlich speichert das Programm die modifizierte Bootloader-Firmware in eine Hex-Datei unter einem frei wählbaren Pfad und/oder Dateinamen oder unter einem automatisch generierten Namen im Default-Ordner ./targets ab.
Die Datei im Format Intel-Hex kann von einem beliebigen "AVR-Brennprogramm" (z.B. avrdude) ü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!
Meta-Informationen zum jeweiligen Target sind als Kommentarzeilen hinter den letzten Hex-Record angehängt, also menschenlesbar und editierbar. Eine ISP-Software wird diese Zeilen komplett ignorieren. Die OWL-Software liest den Hex-Teil, aber auch die Kommentarzeilen, und hat dann auf einen Schlag den Schlüssel und alle erforderlichen Meta-Infos für den Zugriff auf den betreffenden Bootloader parat.
Nochmals: Alle Informationen zu einem individuellen Bootloader (Target) stehen in genau einer Datei, die den Namen des betreffenden Bootloaders trägt. Das Format ist vollkommen transparent. Ein Umbenennen, Kopieren, Verschieben und Modifizieren dieser Target-Dateien ist mit Bordmitteln jederzeit möglich. Kein aufgeblähter Datenbankschwachsinn, keine irren Abhängigkeiten!

Bootloader-Übertragungen:     ./transmissions
Die Software kann den Datenstrom für eine Bootloader-Übertragung an die angegebene serielle Schnittstelle senden. Sie speichert denselben Datenstrom standardmäßig in eine Datei, die bei Auto-Naming in den Ordner ./transmissions  geschrieben wird. (Auch hier kann ein abweichender Pfad und ein frei wählbares Namensschema verwendet werden.) Dabei handelt es sich um Binärdateien mit der Endung .owl.
Dies ist das für verschlüsselte Firmware-Distributionen ideale Exportformat. Es enthält eine exakte Kopie des seriellen Datenstroms einer OWL-Transmission. Das gesamte Timing bleibt in den Präambel-Durchläufen erhalten.
Die OWL-Software kann eine .owl-Datei übernehmen und an eine serielle Schnittstelle senden. Dabei wird der Datenstrom aus Präambeln und verschlüsselten Blöcken "blind" übernommen. Die Software verwendet automatisch die richtige Baudrate, da diese als ASCII-Tag an das Ende der Binärdatei angehängt ist. Weitere Meta-Infos enthält das Dateiformat für OWL-Transmissionen nicht.
Es ist ebenso möglich, eine OWL-Datei per Datenumleitung an eine serielle Schnittstelle zu senden. Auch damit erhalten wir in der Regel eine technisch einwandfreie OWL-Transmission.
Konsolenbeispiel DOS/Windows:
mode COM1 9600,n,8,1 | copy /b transmission0815.owl COM1
Gleiches unter Linux (Prinzip):
stty -F /dev/ttyS0 9600 cs8 -cstopb -parenb | cat transmission0815.owl > /dev/ttyS0

Bootloader-Erzeugung

Die Software erwartet einen gültigen Device-Namen und holt sich aus dem Ordner ./templates die zugehörige Datei mit dem standardisierten Maschinencode. Diesen passt sie individuell an und speichert die neu erzeugte Firmware als Target-Datei im Hex-Format zusammen mit ein paar Meta-Infos in den Ordner ./targets.
Beispiel:

owl --device=tn2313 --rxport=d0 --txport=d1 --clock=4000 --targetname=owl_tn2313

erzeugt im Ordner ./targets einen neuen Bootloader für ATtiny2313, RX-Portleitung D0, TX-Portleitung D1 und 4 MHz Taktfrequenz mit dem Namen "owl_tn2313.hex".

Bootloader-Serien-Erzeugung

Dazu geben wir das zusätzliche Argument "Number" (Anzahl) an. Die Software generiert dann fortlaufend durchnummerierte Targets für dieselbe Hardware-Konfiguration aber mit vollkommen unterschiedlichen Krypto-Schlüsseln.
Beispiel:

owl --device=tn2313 --rxport=d0 --txport=d1 --number=10 --targetname=testloader

erzeugt im Ordner ./targets 10 neue Bootloader mit den Dateinamen:

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


Diese Loader können nun auf 10 Zielgeräte installiert werden. Der Zugriff auf den Bootloader im jeweiligen Gerät ist nur für denjenigen möglich, der die dazu passende Target-Datei mit dem 128-Bit-Schlüssel besitzt.

Erzeugung von Transmissionen

Die Software braucht nur den Target-Namen eines Bootloaders, für den sie eine Transmission erzeugen soll. Sofern die dazugehörige Target-Datei gefunden wurde, kennt das Programm den Krypto-Schlüssel, die Taktrate, die bevorzugte Baudrate und die wichtigsten Device-Konstanten.
Wenn außerdem eine Hex-Datei mit Daten für EEPROM und/oder Flash (oder ein Löschbefehl für EEPROM und/oder Flash) angegeben wurde, dann steht der Erzeugung einer maßgeschneiderten Transmission nichts mehr im Wege.
Das Tool schreibt OWL-Transmission immer erst in eine Datei, und zwar in der Reihenfolge der RST-Sequenzen:
  1. Authentisierungssequenz (S1): Zuerst wird die längere Einleitende Präambel erzeugt. Der PRNG wird mit dem Bootloader-Schlüssel geladen. Die Authentisierungssequenz besteht nur aus dem IV, einem Dummy-Block (Zufallszahlen) und dem abschließenden VI. Die Blöcke werden mit RST verschlüsselt. Zwischen den Blöcken 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 RST-verschlüsselt. Zwischen den Blöcken fügt das Programm die für EEPROM-Schreibzugriffe und Krypto-Rechenzeit notwendigen Präambeln ein. Falls keine EEPROM-Daten vorliegen, besteht S2 nur aus verschlüsseltem IV und VI im Abstand einer Mindest-Präambel.
  3. Flash-Sequenz (S3): Das Programm liest Flash-Daten aus dem angegebenen Hexfile und füllt die letzte angebrochene Page mit Zufallsbytes auf. (Bei ATtiny wird gegebenenfalls auch der initiale Reset-Jump modifiziert und ein INFO TAG angefügt.) Flash-Daten werden auf Grundlage des zu diesem Zeitpunkt vorliegenden Schlüssels blockweise mit RST verschlüsselt. Es werden die verlängerten Präambeln für Flash-Erase und Flash-Writes zwischen den Flash-Krypto-Blöcken eingefügt. Falls keine Flash-Daten vorliegen, besteht S3 nur aus dem verschlüsselten IV- und VI-Block im Abstand einer Mindest-Präambel. Gegebenenfalls wird an das Ende der Transmission noch eine verlängerte Outro-Präambel angehängt. Zum Schluss wird die Baudrate, für die diese Transmission berechnet wurde, als ASCII-Zahl an das Binärfile angehängt. Damit ist die Transmissions-Datei komplett und liegt in der Regel unter einem automatisch generierten Namen im Ordner ./transmissions.

Einzel-Transmission

Wurde im Transmissions-Modus eine serielle Schnittstelle angegeben, leitet die Software die soeben erzeugte Transmissions-Datei an die serielle Schnittstelle weiter.

Beispiel:
owl --targetname=bootloader_m8 --flashfile=testprogram.hex --serialport=COM2

Wurde keine serielle Schnittstelle angegeben, kann die .owl-Datei im Ordner ./transmissions zu einem späteren Zeitpunkt an eine Schnittstelle weitergeleitet werden. (Das ist der "Transfer-Modus" mit der Option --transfile=Pfad/Dateiname)


Serien-Transmission

Es ist möglich, im Transmissions-Modus für mehrere Targets in einem Arbeitsgang individuell verschlüsselte Transmissionen zu erzeugen, die dann aber grundsätzlich als Dateien abgespeichert und nicht "live" an eine Schnittstelle weitergegeben werden.
Voraussetzung ist, dass die Targets systematische Dateinamen, zum Beispiel eine fortlaufende Nummerierung haben. Dann kann im Target-Namen mit Platzhaltersymbolen ("?" oder "*") gearbeitet werden. Das Programm sucht alle zu diesem Muster passenden Targets und erzeugt für jedes eine individiell verschlüsselte Transmission, jedoch alle mit dem angegebenen EEPROM- und/oder Flash-Update.

Beispiel:
owl --targetname=bootloader0? --flashfile=testprogram.hex
Dies 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 "testprogram.hex" enthält. Die .owl-Dateien landen per Default im Ordner ./transmissions mit einem analog durchnummerierten Dateinamen, der dem jeweiligen Target eindeutig zuzuordnen ist.

Audio-Export

Die neue OWL-Software stellt einen Schalter --audioexport bzw. -ax bereit. Im Transmissions- und Transfer-Modus werden Ausgabedaten dann nicht nur an eine serielle Schnittstelle oder in die reguläre Transmissionsdatei gespeichert, sondern auch in eine Audio-Datei umcodiert, die mit angehängter .wav Dateiendung abgespeichert wird. Es handelt sich um eine waschechte WAV/RIFF-Containerdatei in "CD-Qualität" (2 Kanäle 44,1 kHz, 16-Bit LPCM), die sich wohl auf jedem multimediafähigen Gerät abspielen lässt. Die Rückgewinnung des bitseriellen digitalen Datenstroms ist an einem Stereo-Ausgang für Kopfhörer mit sehr geringem Aufwand möglich. Eine krasse Programmierschnittstellen-Alternative für den One-Way-Loader!
Da das Feature "Soundkarte als seriellen Datenausgang missbrauchen" auch für andere Anwendungen interessant sein könnte und möglicherweise noch weiter verbessert wird, habe ich die Kommandozeilen-Option für den Transfer-Modus in der OWL-Software so ausgelegt, dass sie nicht nur OWL-Transmissionen annimmt, sondern beliebige Quelldateien in das Audioformat exportiert. Viel Spaß beim Experimentieren! Technische Details weiter unten.


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 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 von einer zentralen Stelle gespeichert und auf Kollisionen geprüft werden müssten. Solche Schlüssel sind von keiner Drittpartei kontrollier- oder manipulierbar. Das bedeutet Freiheit UND Sicherheit.
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. Jede neu erzeugte OWL-Firmware bekommt einen individuellen 128-Bit-Schlüssel, der mit allergrößter Wahrscheinlichkeit noch kein zweites Mal vergeben wurde. Egal, wieviele OWLs lokal erzeugt und in einem Gerät mit einer gemeinsamen Programmierleitung zusammenschaltet werden, die Target-Controller sind konfliktfrei adressierbar und durch die Verknüpfung mit einem "sprechenden" Target-Namen, der überdies später noch beliebig geändert werden kann, ist die Handhabung auch für den Menschen recht angenehm. Für den autorisierten Nutzer ergibt sich ein transparenter Zugriff auf alle selbst erzeugten Bootloader, als gäbe es gar keine mächtige 128-Bit-Verschlüsselung im Hintergrund. Für den Herausgeber einer Serie von Bootloadern bleibt ebenfalls alles übersichtlich. Target-Namen und Transmissionen können systematisch durchnummeriert sein, sodass sich immer eine klare Zuordnung zu den Zielgeräten beim Kunden ergibt.
Für den unberechtigten Angreifer ergibt sich nicht besonders viel. Der Einweg-Loader antwortet nicht und rückt praktisch keine für einen Angriff verwertbaren Timing-Informationen heraus. Es gibt auch nach Jahren keinen Hinweis darauf, dass die verwendete RST-Chiffre irgendwelche Schwächen aufweisen würde, die einen praktischen Angriff auf OWL-Transmissionen begünstigen.
Kleiner Wermutstropfen: Die Erzeugung guter Krypto-Schlüssel ist bekanntlich eine Kunst für sich. Wir brauchen einen guten Zufallsprozess. Hmm, das Thema hatten wir doch schon einmal ...

Random-Pooling

Computer können keine Zufallszahlen erzeugen, und den in modernen CPUs integrierten "Zufallsgeneratoren" sowie kommerziell angepriesenen Lösungen ist schon einmal gar nicht zu trauen. Für die Erzeugung einzelner kryptografischer Schlüssel sind aber bisweilen schon die üblichen "Hausmittel" hinreichend. Peripherie-Interrupts (Tastatur, Maus, Netzwerk), Systemzeit in Mikrosekunden, vielleicht noch eine Prise Entropie aus dem Dateisystem; alle diese Quellen liefern bei eher seltener Nutzung recht brauchbare Zufallszahlen.
Nun werden bei der Erzeugung einer Bootloader-Serie oder einer Serie von Transmissionen in kurzer Zeit eine ganze Menge kryptografisch robuster Zufallszahlen benötigt. Hier beginnen die vorgenannten Methoden zu schwächeln. Dann ist es in jedem Fall besser, wenn schon ein Vorrat an Entropie zur Verfügung steht, ein sogenannter "Random Pool", der sich nicht augenblicklich erschöpft und gegebenenfalls mit einem guten Pseudozufallsalgorithmus noch gestreckt werden kann.
Die OWL-Software legt in ihrem Stammverzeichnis einen eigenen Random Pool an, die Datei randpool.bin. Dieser enthält 512 Byte an Zufallszahlen, aus verschiedenen Quellen zusammengetragen. Der Random Pool wird mit jedem Programmaufruf mindestens einmal unter Einbeziehung von frischer Timer-Entropie aufgefrischt. Ideal ist es, wenn wir den Random Pool mithilfe eines echten physikalischen Zufallsgenerators (z. B. XR232USB [Auch zu diesem Dauerbrenner-Projekt plane ich eine verbesserte Software-Unterstützung.]) erzeugen und aktualisieren.
Mit etwas Geduld führen aber auch die erwähnten Hausmittel zum Ziel. Auf einem Desktop-Computer mit grafischer Benutzeroberfläche und allerlei Hintergrundprozessen entsteht schon im regulären Betrieb recht viel "Rauschen", also Zufall, der sich vor allem aus der Interaktion der Maschine mit Nutzer, Hardware-Subsystemen und Netzwerk ergibt.
Der Linux-Kernel bietet seit Jahren einen Gerätetreiber /dev/random bzw. /dev/urandom an, der Zufallszahlen von kryptografischer Qualität ausspuckt. Diese werden aus verschiedenen Quellen auf dem laufenden System gemixt. Eine robuste und einigermaßen vertrauenswürdige Lösung, von der ich viel gelernt habe.
Die OWL-Software verwendet unter Linux /dev/urandom als primäre Zufallsquelle. Unter Windows existiert meines Wissens keine vergleichbar vertrauenswürdige API, weshalb wohl jede ernsthafte Krypto-Software (insofern man auf Windows irgendwas "ernsthaft" machen kann) auf eigene Verfahren zur Zufallsgenerierung zurückgreift. Das ist auch völlig okay, solange die Methode und alle anderen sicherheitstechnischen Details offengelegt sind.
Für Windows-User stelle ich mit der neuen OWL Software 2020xxxx eine Extrawurst zur Verfügung. Es wird auf ähnliche Methoden zur Entropie-Gewinnung zurückgegriffen, wie im Linux-Kernel. Weiter steht die Option --randpool zur Verfügung, mit der die Software Entropie aus Timing-Fluktuationen auf dem laufenden System gewinnt und in den existierenden Random Pool einpflegt. Dies empfiehlt sich besonders dann, wenn größere Mengen an Schlüsseln in einem Durchlauf generiert werden sollen. Die Option einfach einige Minuten im Hintergrund laufen lassen. Im Vordergrund startet man ein paar ressourcenfressende Anwendungen, wie Multimedia oder Browsing, die ein eher unregelmäßiges Lastprofil erzeugen und damit einiges an "Rauschen" produzieren. Details bitte ich dem Quelltext zu entnehmen.


Datensicherung

Die Software erstellt keine automatischen 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 schon existieren. Sollte ein Target-Name bereits vergeben sein, erfolgt eine Warnmeldung und die Operation wird abgebrochen.
Um das versehentliche Überschreiben von Target-Dateien durch andere Anwendungen zu verhindern, können wichtige Dateien mit Schreibschutz versehen werden. Aber der beste Schutz vor dem Undenkbaren sind und bleiben Sicherungskopien.
Jede Person, die Zugriff auf den Computer mit OWL-Verzeichnissen 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 unter anderem OWL verwendet wird, sollte für Unbefugte nicht so ohne Weiteres zugänglich sein. Wer sich einem konkreten Spionage- oder Sabotagerisiko ausgesetzt sieht, wird sich früher oder später ohnehin mit dem Konzept einer gesicherten Umgebung auseinandersetzen. Hier ist eine allgemeine Sicherheitsphilosophie wichtiger, als Flickschusterei an einzelnen Programmen. Weitgehende Kontrolle über die verwendete Hardware und Software, Verzicht auf obskuren Müll, geschärftes Bewusstsein für Sicherheitslücken des Betriebssystems, Arbeitsumgebung auf einer vollverschlüsselten Festplatte usw.

Dateiformate

  • Daten-Export:
    • Die Software erzeugt Intel-Hex-Dateien von Targets als Standard-7-Bit-ASCII mit den Zeilenvorschüben in der jeweils systemüblichen Codierung. Hexdateien können in der Regel trotz abweichender CR/LF-Codierung systemübergreifend ausgetauscht werden (Windows, Linux, Max).
    • Das OWL-Format für Transmissionen ist ein Binärformat und kann alle möglichen Byte-Werte enthalten. Sie dürfen wie jede andere Binärdatei nicht umcodiert werden, dann steht einer plattformübergreifenden Nutzung nichts entgegen.
    • Das OWL-Format für Audio-Transmissionen ist ein RIFF-Container (Audio 44,1 kHz, Stereo, 16-Bit LPCM) mit der Dateiendung .wav, der auf praktisch jedem multimedia-fähigen Gerät direkt abspielbar ist. Wem das Dateiformat zu klobig erscheint, der kann diese Dateien auch in ein verlustfrei komprimiertes Audioformat (z. B. FLAC) umwandeln. Mit ZIP oder RAR lassen sich OWL-Audiodateien gut und gern auf 1/30 der ursprünglichen Länge (!) schrumpfen. Da sage noch mal einer, "Audio-Export" wäre nichts für den E-Mail-Versand.
    • Die für den Random Pool verwendete externe Datei randpool.bin ist eine Binärdatei mit 8-Bit-Zufallszahlen. Der Random Pool wird mit jedem Programmaufruf durch Live-Entropie aufgemischt bzw. neu erzeugt, falls nicht vorhanden. Ein Austausch zwischen verschiedenen Systemen wäre möglich, aber aus Sicherheitsgründen unsinnig.

  • Daten-Import: Hex-Dateien mit Datensätzen für EEPROM oder Flash kann das Programm mit Zeilenvorschüben im LF (Unix), CR (Mac) oder CRLF (DOS) Format einlesen. Die Software sollte daher alle normgerechten Intel-Hex-Files, wie sie von diversen Assemblern und Compilern unter verschiedenen Plattformen ausgegeben werden, problemlos einlesen können.

Krypto-Tests

Die Software bietet einige Test- und Demofunktionen zum Krypto-System:

Schlüsselgenerator:    owl --key=Hexstring
Die Angabe eines Hex-Schlüssels ohne weitere Optionen löst den Testmodus für den Schlüsselgenerator aus. Der PRNG wird 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 gut zum Vergleich mit einer Referenzimplementierung des 128-Bit-MLS-LFSR-SSG.
Die erste Zeile stellt den Startzustand (seed) des PRNG in Hex dar. Alle nachfolgenden Zeilen sind Rohwerte, welche vom PRNG-Modul ausgeworfen werden, also die Vektoren, mit denen die RST-Blockchiffre gesteuert wird.
Bei Angabe des Default-Schlüssels (--key="00112233445566778899aabbccddeeff" ) oder eines leeren Arguments (--key="") muss die Bildschirmausgabe der ersten 256 Vektoren wie folgt aussehen:

00112233445566778899AABBCCDDEEFF

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


Datei-Verschlüsselung:    owl --key=Hexstring --encrypt=Dateiname.xxx
Verschlüsselt die angegebene Datei mit dem angegebenen Schlüssel nach OWL-RST (eine RST128-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.xxx.raw
Entschlüsselt die angegebene Datei mit dem angegebenen Schlüssel nach OWL-RST. War die Entschlüsselung erfolgreich (IV=VI), dann wird die entschlüsselte Datei mit einem vorangestellten Zeitstempel unter dem ursprünglichen Namen mit der ursprünglichen Dateiendung abgespeichert, sodass die Originaldatei nicht versehentlich überschrieben werden kann. Originaldatei und wiederhergestellte Datei sind nach erfolgreicher Entschlüsselung binär identisch, da etwaige Padding-Bytes automatisch entfernt werden. Bei fehlgeschlagener Entschlüsselung speichert die Demofunktion für RST128 eine Datei ab, die für Analysezwecke ausgewertet werden kann.

Testfunktion echter Zufallsschlüssel:     owl --key=R
Mit dem Buchstaben 'r' oder 'R' wird ein echter 128-Bit-Zufallsschlüssel gezogen und in den PRNG geladen. Auf diese Weise lässt sich die Funktionalität der Gewinnung echter Zufallsschlüssel/IVs testen. Die folgenden Zeilen sind dann die von diesem zufälligen Schlüssel abgeleitete (deterministische) Sequenz.


Virtuelle Maschinen

Verschiedene Konstellationen mit VirtualBox 5.xx wurden erfolgreich und ausgiebig getestet. Der Gast-Maschine wurde jeweils eine serielle Schnittstelle des Host-Computers per Durchleitung zugeteilt. Diverse Kombinationen aus WinXP/Win7/Ubuntu14/Debian8 liefen problemlos hinsichtlich der OWL-Software. Von der Performance der Schnittstellenanbindung sind natürlich keine Wunder zu erwarten. In einigen Fällen machte sich die zusätzliche Abstraktionsschicht deutlich bemerkbar. Hier kam der serielle Datenstrom gelegentlich ins "Stottern", aber es gingen keine Zeichen verloren, sodass ALLE Datenübertragungen an das OWL-Zielgerät erfolgreich durchkamen. "Notfallbetrieb" der OWL-Software in einer VM - check!

Weitere Anmerkungen zu VMs: WENN DU VIRTUAL BOX 5 VERWENDEST - BLEIB DABEI ! NICHT AUF VERSION 6 UPGRADEN! Mit Version 6 auf Linux habe ich leider genau das durchmachen müssen, worüber schon so einige Leute in einschlägigen Foren berichtet haben, was ich aber natürlich erst las, nachdem das Kind schon in den Brunnen gefallen war: Windows-Gastsysteme stürzen wiederholt ab oder "frieren ein", wenn sie eine ansonsten vollkommen ordnungsgemäß zugewiesene serielle Schnittstelle nutzen wollen. Das ist natürlich hinsichtlich der OWL-Software eher suboptimal... Dieser Scheiß ist mir unter VirtualBox 5 noch NIE untergekommen!



Weiterentwicklung und Bugfixes

Schade, dass die Welt am Arsch ist. Aber abgesehen davon habe ich persönlich durch den Wechsel zu C99 einen gewissen Motivationsschub erfahren, der sicher noch eine Weile anhalten wird.
In der Datei changelog.txt finden sich Erklärungen zu bisherigen Versionen. 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 einen klaren Leerlaufzustand sieht. Ein solches 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 (nach Art des SN75176) benötigen zur Datenrichtungsumschaltung ein Hardware-Steuersignal (Transmit-Enable, TE), das normalerweise von der Applikations-Firmware ausgegeben wird. Der Bootloader sollte ebenfalls ein solches Signal liefern, damit sichergestellt ist, dass der externe Baustein während der Bootloader-Sitzung permanent in Empfangsrichtung geschaltet bleibt. Auch dafür kann der OWL den TX-Port einsetzen. 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 gleich noch interessanter. Standalone-Anwendungen, die normalerweise nichts mit RS232 am Hut haben, ließen sich bisher nur über ISP/JTAG oder über vergleichsweise aufwendige Two-Wire- oder One-Wire-Interfaces mit Firmware-Updates versorgen, vorausgesetzt, ein Bootloader ist dort überhaupt implementierbar und unterstützt solche Minimalschnittstellen. Der OWL braucht nur eine beliebige Portleitung, die für die Dauer der Bootloader-Sitzung durchgängig als Eingang funktioniert. Minimale Anforderungen und ganz 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 heraus. Zur Not könnte die Verbindung auch über zwei Klemmprüfspitzen hergestellt werden. Naheliegende Variante, wenn ohnehin ein sogenannter One-Wire-Adapter (CI-V-Interface) vorhanden ist.
      Mit einer klassischen RS232 geht es sogar noch einfacher. Wir können das TXD-Signal mit Vorwiderstand und Z-Diode (4V7) auf TTL-Pegel zwingen und direkt am Controller einspeisen. In diesem Fall wäre das Signal allerdings gegenüber der sonst üblichen Logik invertiert. Halb so schlimm. Dann konfigurieren wir uns eben einen OWL, der mit dem invertierten RXD-Signal klar kommt.

    • Optokoppler: Optokoppler sind für eine konsequente Einweg-Übertragung besonders empfehlenswert, zumal sich nebenbei eine etwaige Signalinvertierung realisieren lässt. Nebenbei 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 Empfangsleitung mit einem Pullup nach High gezogen. Ein Fototransistor zieht diese Leitung auf Low, wenn ausreichend rotes oder infrarotes Licht einstrahlt. Für solche offenen Opto-Ports gibt es interessante Varianten für "getarnte" und/oder kostenoptimierte Programmierschnittstellen. Für den Datenempfang lässt sich z. B. auch der Fototransistor in einer Gabellichtschranke zweckentfremden, da auch dieser relativ schnell schalten kann. Wenn das Zielgerät also einen oder mehrere Gabelkoppler eingebaut hat, wäre das schon ein potenzieller Programmiereingang für den One-Way-Loader! (Die Sende-LED des Gabelkopplers müsste für die Dauer der OWL-Sitzung ausgeschaltet oder abgedunkelt werden.)
      Zur Datenübertragung halten wir unser TX-Lichtschwert  nah genug dran, resetten den Controller und starten die OWL-Transmission.



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 mittleren Geschwindigkeiten am besten. (Wenn's vor allem auf die Potenzialtrennung ankommt, würde ich jedoch eine Opto-Lösung vorziehen!)


  • PC-Audio an OWL-Target: Eine OWL-Transmission kann mit der Option -ax in ein digitales Audiofile konvertiert werden, das sich auf jedem multimediafähigen Gerät abspielen lässt. Mein Verfahren nutzt die üblicherweise vorhandenen zwei Stereokanäle, um die binäre Information als Differenzsignal zwischen linkem und rechtem Kanal zu übertragen. Die binäre "0" entspricht einer Spannungsdifferenz zwischen linkem und rechtem Kanal, die binäre "1" entspricht keiner Differenzspannung. Durch gegenphasige Steuerung der Audio-Kanäle erzielt man ungefähr den doppelten Spannungshub im Vergleich zur Spitze-Spitze-Spannung, welche zwischen einem Kanal und Masse messbar wäre. Das bedeutet, wenn der Kopfhörerausgang maximal 0,75 V ausspuckt, erhalten wir mit beiden Stereokanälen im Gegentakt ca. 1,5 V Spitze-Spitze - das reicht locker aus, um eine IR-LED zu treiben.
    Zusätzlich erfolgt eine zum Zeichenrahmen synchrone Phasenumtastung. Akustisch ähnelt das Signal dem eines PSK-Modems, und die technischen Eigenschaften sind ganz ähnlich. Das Frequenzspektrum wird in einen mittleren Bereich transformiert, der Spannungsmittelwert ausgeglichener. Trennkondensatoren, welche sich üblicherweise im Pfad von Kopfhörer- oder Line-Ausgängen befinden, stören diese Übertragung nicht mehr. Es dürfte klar sein, dass sich mit der zweistufigen Modulation keine überragenden Geschwindigkeiten erzielen lassen. Aber wir bekommen wir für lau einen sehr robusten bitseriellen Ausgabekanal! Tatsächlich reicht zur Rückgewinnung von OWL-Audio auf der Empfängerseite schon diese verstörend simple Schaltung.
    Die funktioniert an fast jedem niederohmigen Kopfhörer- oder Line-Ausgang mit einigermaßen symmetrischen Eigenschaften, unabhängig von der Polung auf linkem und rechtem Kanal und weitgehend unabhängig von leichten Pegel- und Phasenunterschieden. Schon erstaunlich, wenn man bedenkt, dass ich zu 70 Prozent aus Wasser bestehe... Alternativer Programmierpfad per Soundkarte - check!
    OBLIGATORISCHE SICHERHEITSWARNUNG: Für OWL Audio muss die Ausgabelautstärke zuweilen bis Anschlag hochgedreht werden. Bitte dran denken, wenn wir später wieder einen Kopfhörer anschließen ... wollte es nur mal erwähnt haben ...


Einfachstmögliches unidirektionales RS232-Programmierinterface für OWL Unidirektionale RS232-Übertragung ohne Optokoppler
Einfaches unidirektionales RS232-Interface mit galvanischer Trennung:
TXD treibt Wald-und-Wiesen-Optokoppler.
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 mit LED und Fototransistor. (Der RS232-Adapter links hat zwei Sende-LEDs für invertiertes und nichtinvertiertes TXD)

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





Nach oben | Index


Anmerkungen

Kleiner Krypto-Kontest

Die Wahl eines geeigneten Kryptosystems war die mit Abstand schwierigste Entscheidung des ganzen Projektes. Es musste "gepaarter" Code einerseits für die Verschlüsselung in der PC-Anwendung, andererseits für die Entschlüsselung im AVR-Mikrocontroller vorliegen oder geschrieben werden. Ich habe mit kompakten Implementierungen von AES und XTEA, einer klassischen XOR-Stromchiffre und schließlich "RST" experimentiert. Der Entscheid für RST fiel aufgrund der folgenden pragmatischen Überlegungen:

Algorithmus
AVR-Implementierung
Vorteile
Nachteile
AES
(Rijndael)
  • Zertifizierbar, weit verbreitet
  • Gute statistische Eigenschaften (Diffusion und Konfusion)
  • Vergleichsweise schnell
  • Blockchiffre-typische Key-Feedback-Varianten
  • Enormer Speicherbedarf (Lookup-Tabellen)
  • Weiterer Code für CRC und Key-Feedback erforderlich
  • Nur für ATmegas
  • Entschlüsselung langsamer als Verschlüsselung
  • Für Bootloader-Anwendung überdimensioniert
  • Für kommerzielle Nutzung ggf. 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
  • Patentfrei und i.d.R. lizenzfrei
  • Gute statistische Eigenschaften
  • AVR-Assembler-optimierte Version elegant und kompakt
  • Erheblicher Zusatzaufwand für Key-Feedback und Fehlererkennung
  • Eher schwach bei minimaler Rundenzahl
  • Arbeitet auf 64-Bit-Blöcken; Anpassung für 128-Bit-Key-Chaining könnte Angriffspunkte liefern.
PRNG-XOR (Stromchiffre)
  • Code: ~60 Bytes
    optimiert für Kernfunktionalität
  • Blockweises XOR
  • Takte pro 128-Bit: <1000
  • Klassische Stromverschlüsselung
  • Mit starkem PRNG für einige Zwecke ausreichend
  • Kompakteste Lösung
  • Erheblicher Aufwand für Key-Feedback und Fehlererkennung.
  • Stromchiffre anfällig für Known-Plaintext-Angriff.
  • Selbst für Bootloader-Anwendungen zu simpel!
RST
("Randomized Substitution-Transposition")
  • Blockchiffre gesteuert durch Stromchiffre
  • 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ührlich erprobt
  • Extrem kompakt auf 8-Bit-CPUs umsetzbar
  • Verschiedene kyptografisch starke PRNGs verwendbar
  • Günstiger Kompromiss zwischen Verschlüsselungsstärke, Codeffizienz und Funktionalität
  • Einfacher und lückenlos nachvollziehbarer Algorithmus.
  • Nicht "zertifiziert"...
  • Starker PRNG kostet viel Rechenzeit.
  • Strenges Avalanche-Kriterium im einzelnen Block bei Mindestrundenzahl nicht garantiert.
  • 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 kB.
(Das entspricht 2500 Blöcken à 16 Bytes!)
Verschlüsselt im ungeeigneten ECB-Modus. Jeder Block wurde mit demselben Schlüsselsatz 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

OWL-Download für Dein Betriebssystem

Übliche Hardware-Software-Ausstattung für AVR-Projekte (Compiler, Assembler, ISP-Brenner, Experimentierboards)

AVR-Controller, der von OWL unterstützt wird
, auf 'ner Platine mit ISP-Anschluss (oder geeigneter Zwischenstecker)


Hello-World-Testprogramm für diesen Controller, z.B. einfachen LED-Blinker, im Format Intel-Hex (Standard)


Schonmal 'was an der Kommandozeile gemacht...

Respekt, aber keinen Schiss vor den Fusebits!

Reale RS232-Schnittstelle oder USB-COM-Wandler
( COMx, /dev/ttySx, /dev/ttyUSBx )

2. PC-Installation der OWL-Software

Das Download-Paket 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 optional. Eine Liste aller Kurz- und Langschreibweisen liefert die Option: --help.

3. Maßgeschneiderte OWL-Firmware erzeugen

Beispiel: ATmega8 in einem typischen RS232-Setup (MAX232, FT232) mit Quarz 8 MHz
Der Controller ist mit einem MAX232 (oder FT232) verbunden. Es werden die Portleitungen PD0/PD1 als RXD/TXD genutzt (Standard, wenn normalerweise der Hardware-UART benutzt wird). Die ordnungsgemäße Funktion der RS232-Anbindung sollte vorher schon getestet worden sein.
Für eine LED an PB2 steht ein primitives Blinkprogramm zur Verfügung. Auch dieses am besten vorher schon einmal ganz ohne Bootloader hochladen und testen. 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 also ebenfalls PD0 als RXD-Eingang. Die Kommandozeile zur Erzeugung des neuen OWL-Bootloaders lautet dann:

owl --device=m8 --rxport=d0 --clock=8000 --baud=9600 --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 wohl jedes Brennprogramm eine entsprechende Funktion anbietet. Schön auf die Zuordnung Low, High, Extended achten. Wichtigste Voraussetzung für einen Bootloader ist die Fähigkeit, Flash-Speicher per Software schreiben zu können (SPM). Auf ATtinys muss hierfür explizit Self-Programming (SELFPRGEN) aktiviert sein, auf ATmegas, wo Bootloader ja direkt unterstützt werden, muss dies nicht extra berücksichtigt werden. Vor allem sollte immer der Brown-Out-Detektor (BODEN) eingeschaltet sein. Damit ergibt sich ein sauberes Kaltstartverhalten, und die Gefahr von Flash-Korrumpierung wird minimiert. Für den Beispiel-ATmega8 mit externem 8-MHz-Quarz wären folgende Fuses eine gute Basis:


BOOTSZ=10; BODEN=0; BODLEVEL=0; BOOTRST=0; CKSEL=1100; SUT=00
Byte-Werte:     Ext: $FF    Low: $8D     High: $EC

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 neuer 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. Standardmäßig sind beim Bootloader eine Sekunde Timeout eingestellt, die Transmission bekommt etwa eine Sekunde Intro-Präambel. Am besten ERST die Kommandozeile "abfeuern", DANN den Controller resetten:

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

Die Übertragung geht mit Standardgeschwindigkeit von 9600 Baud über "COM2" (Windows) 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

Lange Beschreibung zu allen Befehlsoptionen:
owl --helpall

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

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

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

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


Der One-Way-Loader unterstützt aktuell die folgenden AVR-Controller:

m1280 m1281 m1284 m1284P m128A m128 m128RFA1 m128RFR2 m162 m164A m164PA m164P m165A m165PA m165P m168A m168 m168PA m168P m169A m169PA m169P m16A m16 m16HVA m16HVB m16M1 m16U2 m16U4 m2560 m2561 m256RFR2 m324A m324PA m324P m3250A m3250 m3250PA m3250P m325A m325 m325PA m325P m328 m328PB m328P m3290A m3290 m3290PA m3290P m329A m329 m329PA m329P m32A m32C1 m32 m32HVB m32M1 m32U2 m32U4 m406 m48A m48 m48PA m48P m640 m644A m644 m644PA m644P m6450A m6450 m6450P m645A m645 m645P m6490A m6490 m6490P m649A m649 m649P m64A m64C1 m64 m64M1 m64RFR2 m8515 m8535 m88A m88 m88PA m88P m8A m8 m8HVA m8U2 tn13A tn13 tn1634 tn167 tn2313A tn2313 tn24A tn24 tn25 tn261A tn261 tn4313 tn441 tn44A tn44 tn45 tn461A tn461 tn48 tn80 tn840 tn841 tn84A tn84 tn85 tn861A tn861 tn87 tn88


Nach oben | Index


Lizenz

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 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
Freuen Sie sich nicht zu früh. Ich mache auf jeden Fall weiter ...


Nach oben | Index


Download

Nach oben | Index

Links


Nach oben | Index
Erstveröffentlichung: 06/2018