Date: Mon, 6 Dec 1999 08:16:23 -0500 (EST)
From: support@redtenbacher.de
Subject: Automat. Ver-/Entschluesselung von E-Mail, Teil IIIc

Sehr geehrte "signatur"-Abonnenten,

im 3. Schritt des Implementierungsleitfadens für Programmierer
einer automatischen Ver-/Entschlüsselung/Signatur von E-Mail geht
es nun um die genauen Vorgänge, die im Fall einer
verschlüsselten/signierten Eingangsmail ablaufen sollten, um
maximale Interoperabilität mit den existierenden
OpenPGP-kompatiblen Programmen und -Plugins sicherzustellen.


Schritt 3: Abwicklung von Signatur/Entschlüsselung bei
           Eingangsmails: Formate, Algorithmen

Um maximale Interoperabilität sicherzustellen, sollte unser
Entschlüsselungs-Modul sowohl mit verschlüsselten (+ggf.
signierten) Mails als auch mit unverschlüsselten, aber signierten
Klartext-Mails, jeweils in ein- und mehrteiliger Form und in den
Formaten "OpenPGP" (RFC 2440) oder "PGP-MIME" (RFC 2015)
zurechtkommen, d.h. all diese Formate automatisch erkennen und
entschlüsseln (bzw. die Signatur verifizieren).

Dann wird alles, was von irgendeiner existierenden PGP-Version,
einem PGP-Plugin oder einem OpenPGP-kompatiblen Produkt erzeugt
wird, richtig erkannt und automatisch entschlüsselt.

Dieser hohe Anspruch ist gar nicht so schwierig umzusetzen, wenn
man richtig herangeht.

Die relevanten Datenformate sind in 3 Internet-Standards
beschrieben:

RFC 2440: "OpenPGP Message Format"
          (siehe unter "http://www.ietf.org/rfc/rfc2440.txt")

RFC 2045: "MIME Part 1: Format of Internet Message Bodies"
          (siehe unter "http://www.ietf.org/rfc/rfc2045.txt")

RFC 2015: "MIME Security with Pretty Good Privacy (PGP)"
          (siehe unter "http://www.ietf.org/rfc/rfc2015.txt")

Die von "KT-MAIL/Krypto" gewählte Vorgehensweise werde ich
wieder, wie in Teil IIIb, nachfolgend in Pseudo-Code näher
beschreiben.


Entschlüsselungroutine von KT-MAIL/Krypto:

Im Fall von KT-MAIL wird die Entschlüsselungsroutine unmittelbar
vor der internen Postverteilung aufgerufen, d.h. zu einem
Zeitpunkt, an dem die Internet-Transportkodierung einer
Eingangsmail (MIME, UUENCODE oder BinHex) bereits entfernt ist.

Falls dies bei Ihrem Mail-System anders ist, müssen Sie daher
ggf. zuerst eine Dekodierung aus dem Internet-Transportformat
vornehmen. Wer dafür noch kein geeignetes Programm hat, kann die
Algorithmen für einen Dekoder, der die Internet-Formate "MIME
Quoted Printable", "MIME Base64", "UUENCODE", "BinHex" und das
Microsoft-spezifische MS-TNEF-Format automatisch erkennt und
dekodiert, dem Programm MAILIN entnehmen, das Sie als Quellcode des
Hauptmoduls (MAILIN.MOD) sowie als kompilierte EXE-Datei (MAILIN.EXE)
unter "http://www.redtenbacher.de/signatur/mailutil.zip" in einem
ZIP-Archiv (MAILUTIL.ZIP) finden.

Anschließend können Sie die Vorgehensweise des Krypto-Moduls von
KT-MAIL verwenden:


"Subject:"-Header der Eingangsmail suchen und daraus die
  Zeichenfolgen "!V!", "!S!", "!VS!" und "!SV!" in jeder
  Schreibweise groß/klein löschen; anschließend alle
  Message-Zeilen löschen, die den Text
  "=====*DER*PGP-NACHRICHT=====" (mit "*" als Jokerzeichen)
  enthalten.

  [Hinweis: Dieser Schritt verhindert, daß jemand von außen eine
  Mail schickt, die die Verschlüsselungs-/Signaturmarkierungen
  von "KT-MAIL/Krypto" simuliert, um einem Nutzer des Programms
  eine scheinbar korrekt signierte Mail eines anderen
  unterzujubeln. Falls Sie für die internen Markierungen für
  Verschlüsselung/Signatur andere Markierungen als
  "KT-MAIL/Krypto" verwenden, sind die Löschbefehle natürlich
  entsprechend anzupassen.]

EndZeile := (Zeilennr. der Leerzeile, die die Header-Zeilen der
  Eingangsmail vom eigentlichen Mailinhalt trennt);

Sprungmarke "NextInBlock":

AnfZeile := (niedrigste Zeilennummer größer als 'EndZeile',
  deren Text entweder mit "-----BEGIN PGP MESSAGE-----" oder mit
  "-----BEGIN PGP SIGNED MESSAGE-----" anfängt);
IF (keine [weitere] solche Zeile gefunden)
THEN
  GOTO DoneInMail
END;

Entschlüsseln := (Zeile Nr. 'AnfZeile' enthält kein "SIGNED");

  [Hinweis: Eine signierte Klartext-Mail beginnt mit "BEGIN PGP
  SIGNED MESSAGE", eine verschlüsselte (+ggf. signierte) Mail
  hingegen mit "BEGIN PGP MESSAGE".]

EndZeile := (Nr. der letzten Zeile der verschlüsselten oder
  signierten Mail [bei signierten Klartext-Mails ist das die
  Zeile "-----END PGP SIGNATURE-----", bei verschlüsselten Mails
  die Zeile "-----END PGP MESSAGE-----"]);
IF (keine solche Zeile gefunden)
THEN
  GOTO NextInBlock
END;

Textblock von 'AnfZeile' bis 'EndZeile' (inkl. dieser beiden
  Zeilen mit "BEGIN/END PGP ...") in ein eigenes Fenster kopieren
  und als Datei M.SRC speichern, dann evtl. vorhandene Dateien
  M.DST und M.CMT löschen;

  [Hinweis: Die Dateinamen "m.src" (Message Source), "m.dst"
  (Message Destination) und "m.cmt" (Message Comment) sind hier
  willkürlich gewählt. Man kann also für diese 3 Temporärdateien
  auch 3 andere, feste Dateinamen wählen, die immer wieder
  überschrieben werden.]

Mantra := "";
IF (Entschlüsseln="FALSE")
THEN
  GOTO DecryptVerify
END;

Programmaufruf: "pgpscan m.src/K";

  [Hinweis: Eine verschlüsselte OpenPGP-Datei enthält die KeyIDs
  der Empfängerschlüssel in den PGP-Daten der Mail versteckt.
  Da wir möglicherweise auf unserem System mehrere private
  Schlüssel haben, aber nur den Paßworttext für genau 1 dieser
  Schlüssel an PGP übergeben können, müssen wir vorab
  herausfinden, für welche(n) Empfänger die Eingangsmail
  verschlüsselt ist.

  Zum Auslesen dieser Empfängerschlüssel dient das Programm
  PGPSCAN, das mit dem Dateinamen der zu prüfenden Datei
  aufgerufen wird. (Der Aufruf ohne Option "/K" analysiert und
  listet alle PGP-Pakete der Datei, der Programmaufruf mit "/K"
  für "Nur Key-IDs extrahieren" liest lediglich die Key-IDs der
  Empfängerschlüssel aus und schreibt sie in die Datei
  PGPSCAN.KEY.)

  Das Programm PGPSCAN finden Sie als Quellcode des Hauptmoduls
  (PGPSCAN.MOD) sowie als kompilierte EXE-Datei (PGPSCAN.EXE) im
  ZIP-Archiv MAILUTIL.ZIP unter
  "http://www.redtenbacher.de/signatur/mailutil.zip".]

IF (Datei PGPSCAN.KEY existiert nicht oder hat 0 Bytes Größe)
THEN
  Entschlüsseln := FALSE;
  GOTO DecryptVerify
END;

  [Hinweis: Signierte Klartext-Mails haben wir vorab
  ausgesondert. Diese können daher an dieser Code-Stelle nicht
  auftreten. Es könnte sich aber immer noch um eine signierte
  Binärdatei handeln, die äußerlich genau wie eine verschlüsselte
  Datei aussieht, aber in den PGP-Daten keinen Empfängerschlüssel
  enthält. Solche PGP-Mails ohne Empfängerschlüssel sind daran zu
  erkennen, daß das Programm PGPSCAN eine Datei PGPSCAN.KEY mit
  0 Bytes Größe erzeugt. (Ist die PGP-Datei fehlerhaft, so fehlt
  hingegen die Datei PGPSCAN.KEY gänzlich.)]

Lade die Datei PGPSCAN.KEY, gehe ihre Zeilen der Reihe nach durch
  und vergleiche diese KeyIDs mit den KeyIDs, die im Schritt 2
  (Initialisierung des Krypto-Moduls) in den Variablen
  'PGPKeyzzzzzzzz' gespeichert wurden:
IF (keine passende Variable gefunden)
THEN
  GOTO NextInBlock
END;
  [Wenn wir auf unserem Schlüsselbund keinen passenden
  Empfängerschlüssel haben, können wir diesen PGP-Block der
  Eingangsmail auch nicht automatisch entschlüsseln und
  lassen ihn daher unverändert - denn es könnte ja sein, daß der
  Endbenutzer noch einen lokalen PGP-Schlüsselring für
  supergeheime Nachrichten hat, die auch vor dem
  Mailserver-Administrator geheim gehalten werden sollen und
  daher manuell beim Endbenutzer entschlüsselt werden.]

Mantra := (Paßworttext des zum Empfängerschlüssels gehörenden
          Signaturschlüssels);

  [Hinweis: Dem Wert der passenden Variablen 'PGPKeyzzzzzzzz'
  kann die KeyID "xxxxxxxx" des zugehörigen Signaturschlüssels,
  und dann dem Wert der entsprechenden Variablen 'PGPPWxxxxxxxx'
  (vgl. Schritt 2, Initialisierung des Krypto-Moduls) wiederum
  der Paßworttext zum Empfängerschlüssel entnommen werden.

  Falls Ihre Entwicklungsumgebung keine dynamisch generierten
  Variablennamen unterstützt, läßt sich die benötigte
  Funktionalität alternativ auch über POINTER auf den jeweils
  zugehörigen Paßworttext realisieren.]

Sprungmarke "DecryptVerify":

  [Hinweis: Hier erfolgt die eigentliche Entschlüsselung
  (Mantra<>"") bzw. Signaturprüfung (Mantra="").]

IF (Mantra="")
THEN
  Programmaufruf der Art:
  'pgp -v m.src -o m.dst +batchmode >m.cmt'
ELSE
  Programmaufruf der Art:
  'pgp -v m.src -o m.dst +batchmode -z"Mantra" >m.cmt'
END;

  [Hinweis: Die Programmaufrufe sind für PGP 5.0 (DOS) angegeben
  und sind bei Verwendung anderer PGP-Versionen oder des "Gnu
  Privacy Guard" entsprechend anzupassen. Außerdem setzen die
  obigen Programmaufrufe voraus, daß in der Datei PGP.CFG die
  beiden Zeilen "OutputInformationFD=1" und "OutputWarningFD=1"
  stehen, damit Ausgabekommentare und Warnungen von PGP in die
  Datei "m.cmt" (Message Comment) geschrieben werden.]

IF (Datei M.DST existiert nicht oder hat 0 Bytes Größe)
THEN
  GOTO NextInBlock
END;
  [Hinweis: Wenn beim Entschlüsseln irgend etwas schiefgeht
  (keine Ergebnisdatei), lassen wir diesen PGP-Block
  unverändert. Normalerweise sollte dieser Fall allerdings
  nur auftreten, wenn der Mailserver-Administrator den
  Paßworttext für den Empfängerschlüssel falsch
  eingegeben hat.]

DatName := (Dateiname des PGP-Blocks, sofern in der Eingangsmail
            enthalten [z.B. über einen "Content-Type:"-Eintrag
            mit Parameter "name=..." oder einen
            "Content-Disposition:"-Eintrag mit Parameter
            "filename=...", der vom Programm MAILIN.EXE oberhalb
            des PGP-Blocks eingetragen wird], sonst leer);

IF ('DatName' endet auf ".asc")
THEN
  Endung ".asc" aus Variable 'DatName' entfernen
END;

DatTyp := (Typ der Datei M.DST [Text/Binär]);

  [Hinweis: Die Typbestimmung kann z.B. mit dem Programm FILETYPE
  erfolgen, das Sie als Quellcode des Hauptmoduls (FILETYPE.MOD)
  sowie als kompilierte EXE-Datei (FILETYPE.EXE) unter
  "http://www.redtenbacher.de/signatur/mailutil.zip" finden.

  Dieses Programm prüft die angegebene Datei und klassifiziert
  5 Typen:
    A = Textdatei mit 7-Bit-ASCII-Zeichen
    L = Textdatei mit 8-Bit-Zeichen innerhalb von Latin1
    T = Textdatei mit 8-Bit-Zeichen außerhalb von Latin1
    M = Komforttext-Makro o.ä. (enthält CHR$(0)-Zeichen)
    B = Binärdatei
  Der gefundene Typ wird als Datei FILETYPE.LST (mit 1 Byte
  Größe) geschrieben. In unserem Fall brauchen wir keine so
  detaillierte Klassifizierung, daher würde der Ablauf der
  Typbestimmung etwa so aussehen:

  Programmaufruf der Art: "filetype m.dst";
  Datei FILETYPE.LST laden;
  IF (1. Zeichen ist "M" oder "B")
  THEN DatTyp := "Binär"
  ELSE DatTyp := "Text"
  END; ]

IF (DatTyp="Text")
THEN
  1. Zeile der Datei M.DST laden;
  IF (dort steht "MIME-Version: ...")
  THEN
    DatTyp := "PGP-MIME"
  END;
END;

  [Hinweis: Wir hatten uns vorgenommen, auch die PGP-MIME-
  Erweiterungen gemäß RFC 2015 in Eingangsmails zu unterstützen.
  Dazu brauchen wir bei unserer Vorgehensweise lediglich nach dem
  Entschlüsseln zu prüfen, ob das Ergebnis wiederum eine
  MIME-Datei ist, und wenn ja, diese noch einmal über das
  Programm MAILIN dekodieren.]

IF (DatTyp="PGP-MIME")
THEN
  Programmaufruf der folgenden Art: "mailin m.dst"
ELSIF (DatTyp="Binär")
THEN
  IF (DatName="")
  THEN
    DatName := "binmail.000"
    [Hinweis: Dadurch wird sichergestellt, daß wir einen
    gültigen Dateinamen für die Binäranlage haben]
  END;
  Programmaufruf der Art "mailout m.dst/B<DatName>";
  Programmaufruf der Art "mailin m.dst" (mit anschließendem
    Umbenennen der Ergebnisdatei MAIL.MSG in M.DST);

    [Hinweis: KT-MAIL leitet Binärdateien aus Sicherheitsgründen
    _nicht_ direkt zum Endbenutzer weiter (mit Ausnahme von
    DOC-Dateien, die aber vorher zu RTF konvertiert werden);
    statt dessen landen Binärdateien in einem
    "Quarantäne"-Verzeichnis, und der Endbenutzer bekommt nur
    einen entsprechenden Hinweis auf die Binärdatei in seiner
    Mail. Dieser Hinweis wird vom Programm MAILIN erzeugt, das
    auch die Verwaltung der Dateinamen der Binäranlagen erledigt.
    Daher ruft der Krypto-Modul im Fall von entschlüsselten
    Binärdateien einfach den Kodierer MAILOUT (mit der Option zum
    Erzeugen einer "MIME Base64"-Kodierung) und gleich danach den
    Dekodierer MAILIN auf. Anschließend ist die Datei M.DST nur
    noch eine Textdatei, die einen Verweis auf die
    Original-Binäranlage im Quarantäne-Verzeichnis enthält.

    Das Programm MAILOUT finden Sie als Quellcode des Hauptmoduls
    (MAILOUT.MOD) sowie als kompilierte EXE-Datei (MAILOUT.EXE)
    unter "http://www.redtenbacher.de/signatur/mailutil.zip".

    Sollen bei Ihrem Mail-System die Binärdateien direkt zum
    Endbenutzer durchgeleitet werden, sind die Konverteraufrufe
    entsprechend zu modifizieren: Virenscanner aufrufen; falls
    Datei okay ist, dann den Konverter MAILOUT aufrufen; den
    Aufruf von MAILIN weglassen und statt dessen bei der
    Sprungmarke "DoneInMail" (siehe unten) im Fall von
    mehrteiligen MIME-Mails die MIME-Header-Zeilen passend
    modifizieren - denn das Programm MAILOUT produziert
    einteilige MIME-Dateien.]
END;

Lade die Datei M.CMT (mit den PGP-Kommentaren zur Dekodierung
  bzw. Prüfung der Signatur);
IF (Entschlüsseln="TRUE")
THEN
  Füge davor eine Zeile folgender Art ein:
  "=====STATUS DER PGP-NACHRICHT====="
ELSE
  Füge davor eine Zeile folgender Art ein:
  "=====STATUS DER SIGNIERTEN PGP-NACHRICHT====="
END;
Schreibe die ergänzte Datei M.CMT zurück;

Lade die Datei M.DST (mit dem entschlüsselten Textinhalt des
  PGP-Blocks);
IF (Entschlüsseln="TRUE")
THEN
  Füge davor eine Zeile folgender Art ein:
  "=====ANFANG DER PGP-NACHRICHT====="
  und ans Ende eine Zeile wie:
  "=====ENDE DER PGP-NACHRICHT====="
ELSE
  Füge davor eine Zeile folgender Art ein:
  "=====ANFANG DER SIGNIERTEN PGP-NACHRICHT====="
  und ans Ende eine Zeile wie:
  "=====ENDE DER SIGNIERTEN PGP-NACHRICHT====="
END;
Schreibe die ergänzte Datei M.DST zurück;

Kehre zum Fenster mit der Original-Eingangsmail zurück;
Lösche daraus die Zeilen von "AnfZeile" bis "EndZeile" sowie
  alles davor bis zum letzten Blocktrenner;
  [Hinweis: Die Details der Zeilen vor dem PGP-Block hängen hier
  von Ihrem Dekodierer ab. Bei MAILIN steht unmittelbar vor
  "AnfZeile" der zu löschende Trenner, und im Fall einer
  PGP-MIME-Datei kann davor noch ein leerer Blockteil stehen, der
  ebenfalls gelöscht werden sollte.]
Füge statt des gelöschten PGP-Blocks in die Eingangsmail den
  Inhalt der Datei M.CMT und dahinter den Inhalt der Datei M.DST
  ein;
EndZeile := (Zeilennr., auf der anschließend die letzte Zeile der
  eingefügten Datei M.DST steht);
GOTO NextInBlock;

Sprungmarke "DoneInMail":

Alle Fenster bis auf dasjenige mit der Eingangsmail schließen;
IF (Eingangsmail enthält jetzt eine Zeile mit
    "=====ANFANG DER PGP-NACHRICHT=====")
THEN
  Füge ans Ende des "Subject:"-Headers den Hinweis "!V!" an
  [Hinweis: Der Zusatz "!V!" garantiert, daß eine Antwortmail auf
  diese verschlüsselte Eingangsmail standardmäßig ebenfalls
  verschlüsselt wird - siehe Teil I, "Die Sicht des
  Endanwenders".]
END;

Schleuse die Ergebnisdatei ins normale Mail-System zur Zustellung
  an den Empfänger im Haus ein [siehe Teil IIIa, "Einfügen einer
  Dateischnittstelle in ein bestehendes Mail-System"].

ENDE der Entschlüsselungroutine von KT-MAIL/Krypto.

  [Hinweis: Im Fall von KT-MAIL wird die Entschlüsselungsroutine
  automatisch für jede Eingangsmail einzeln aufgerufen. Bei
  anderen Mail-Systemen ist daher der obige Ablauf ggf. um eine
  Schleife über alle wartenden Eingangsmails zu ergänzen.]


Damit ist der Schritt 3 des Leitfadens für Programmierer
abgeschlossen. Im 4. (und letzten) Abschnitt behandeln wir dann
den Ablauf bei der Abwicklung von Signatur/Verschlüsselung von
Ausgangsmails.

- Wolfgang Redtenbacher
  "signatur"-Moderator

[Zurück zur Hauptseite des Verschlüsselungsprojekts]