Programmer’s Toolbox - Dateien, Teil 13: Einfache Verschlüsselungsverfahren

In der heutigen Folge beginnt der dritte und letzte thematische Block der Programmer’s Toolbox. Hierbei geht es ausschließlich um das Verschlüsseln. Es werden Kommandos zum Verschlüsseln von ganzen Dateien implementiert. Darüber hinaus werden einige Kommandos eingeführt, mit deren Hilfe sich eine Benutzerverwaltung mit Paßwortschutz aufbauen läßt.

Vom Verschlüsseln

Der dritte thematische Block umfaßt insgesamt drei Serienteile. Im folgenden sehen Sie eine kurze Übersicht.

In der heutigen Folge (13. Teil) stelle ich Ihnen drei Kommandos zum Ver- und Entschlüsseln von ganzen Dateien vor. Hierbei handelt es sich um:

CAESAR - ein einfaches Verschlüsselungsverfahren

POLY - polyalphabetische Verschlüsselung

GEO - Verschlüsselung durch Permutation mit Hilfe einer Matrix

In der nächsten Folge (14. Teil) kommen wir zum Data Encryption Standard (DES), und es wird gezeigt, wie man mit dem DES eine Benutzerverwaltung mit Paßwortschutz aufbauen kann. Die letzte Folge dieser Serie (15. Teil) führt dann vier Kommandos ein, die auf der Benutzerverwaltung des vorhergehenden Teils aufbauen:

MKUSER - Anlegen eines Benutzerdatensatzes

RMUSER - Löschen eines Benutzerdatensatzes

PASSWD - Ändern von Paßwörtern

LOGIN - Einloggen in das System

Einige Verschlüsselungsverfahren

Soviel zur Einstimmung. Es folgen konkrete Verschlüsselungsverfahren, implementiert innerhalb der drei Kommandos CAESAR, POLY und GEO. Die Dokumentation erfolgt im Rahmen des Schemas, welches bereits bei den früheren Kommandos verwendet worden ist.

Name
CAESAR - ein einfaches Verschlüsselungsverfahren

Anwendung
CAESAR [ -C I -E ] Buchstabe

Beschreibung
Das Kommando CAESAR realisiert einen einfachen Algorithmus zum Ver- bzw. Entschlüsseln von Dateien, der angeblich bereits von Cäsar verwendet worden ist. Auf den Text einer Botschaft wird ein bestimmter Buchstabe „aufaddiert“, wodurch man die Botschaft unkenntlich macht.

Beim Kommando CAESAR wird der Schlüsselbuchstabe als Parameter übergeben. Die Botschaft wird aus dem Standardeingabekanal gelesen und in den Standardausgabekanal geschrieben.

Optionen
-C Verschlüsseln einer Botschaft. Die Option -C ist voreingestellt. Sie muß also nicht explizit notiert werden.

-E Entschlüsseln der Botschaft

Beispiel
Im folgenden Beispiel wird eine winzige Datei mit dem CAESAR-Verfahren zunächst ver- und dann wieder entschlüsselt, wobei die Zwischenergebnisse jeweils ausgegeben werden.

$ #
$ # Erzeugen und Anzeigen der Datei KLARTEXT
$ #
$ ECHO "Dies ist eine geheime Botschaft." > KLARTEXT 
$ CAT KLARTEXT

Dies ist eine geheime Botschaft.

$ #
$ # Verschlüsseln und Anzeigen von CRYPTEXT
$ #
$ CAESAR -C F < KLARTEXT > CRYPTEXT 
$ CAT CRYPTEXT

e»1/2"f»"'f1/2»œ1/2fi1/2«1/2»|1/2feOŒ'"-«®1/4'tfP

$ #
$ # Entschlüsseln von CRYPTEXT 
$ #
$ CAESAR -E F < CRYPTEXT

Implementierung

Die Implementierung des Kommandos CAESAR ist recht einfach (Listing 3.1). Im wesentlichen umfaßt sie die beiden Funktionen crypt und encrypt, die das Ver- bzw. Entschlüsseln realisieren. In crypt wird auf die Daten aus der Standardeingabe der Schlüsselbuchstabe aufaddiert. In encrypt wird dagegen umgekehrt verfahren.

Die Übersetzungsinformationen werden wie bisher mit Hilfe eines Make-Files notiert (Listing MAKE). Das entsprechende Listing enthält die Informationen für sämtliche Module und Kommandos des dritten Blocks der Programmer’s Toolbox.

Name
POLY - polyalalphabetische Verschlüsselung

Anwendung
POLY [ -C | -E ] Wort

Beschreibung
Das im Kommando CAESAR verwendete Verfahren ist offensichtlich nicht besonders sicher. Zu Zeiten Casars mag es wohl ausgereicht haben, aber geht man davon aus, daß nur 256 Schlüsselbuchstaben existieren (der Zeichensatz des ST umfaßt 256 Zeichen), ist das Knacken dieses Codes mit Leichtigkeit zu bewerkstelligen. Einen höheren Sicherheitsgrad erlangt man durch die Verwendung mehrerer Buchstaben, die abwechselnd auf den Klartext aufaddiert werden. Es ergibt sich die sogenannte polyalphabetische Verschlüsselung. Sie wird mit dem Kommando POLY realisiert. Als Schlüssel wird POLY ein Wort übergeben, dessen Komponenten (Buchstaben) abwechselnd auf die Buchstaben des Klartext „aufaddiert“ werden.

Optionen
Die Optionen des Kommandos POLY entsprechen den Optionen von CAESAR.

Beispiel
Auch für die Anwendung des Kommandos POLY soll mit dem folgenden ein Beispiel gegeben werden:

$ #
$ # Verschlüsseln und Anzeigen von CRYPTEXT
$ #
$ POLY -C ATARI < KLARTEXT > KRYPTEXT 
$ CAT KRYPTEXT

a©l_i_|OŒr«-xaraãa<!Átataij©œAÁ—|»Œea\

$ #
$ # Entschlüsseln von CRYPTEXT 
$ #
$ POLY -E ATARI < KRYPTEXT 

Dies ist eine geheime Botschaft.

Implementierung
Die Implementierung von POLY (Listing 3.2) entspricht weitgehend der von CAESAR (Listing 3.1). Innerhalb der Funktionen crypt und encrypt befinden sich nun lediglich zusätzliche Anweisungen, die eine Indizierung der Buchstaben des Schlüsselworts bewerkstelligen. Dadurch sind es immer andere Schlüsselbuchstaben, die auf die Botschaft „aufaddiert“ werden.

Name
GEO - Verschlüsselung durch Permutation mit Hilfe einer Matrix

Anwendung
GEO [ -C | -E ] Zahl Zahl Beschreibung

Mit POLY besitzt man nun bereits eine ganze Reihe von Variationsmöglichkeiten. Wortlänge und Wortinhalt des Schlüssels können variieren. Die Anzahl der möglichen Schlüssel steigt deutlich. POLY und CAESAR gehören dabei zu einer Klasse von Verschlüsselungsverfahren, die eine Verschlüsselung durch Verfremdung der Buchstaben einer Botschaft erreichen. Eine andere Möglichkeit besteht in der Permutation der Buchstaben einer Botschaft, d.h. die Positionen der Buchstaben werden nach bestimmten Regeln geändert. Von dieser Möglichkeit ist im folgenden Gebrauch gemacht.

Innerhalb des Kommandos GEO wird eine Verschlüsselung mit Hilfe einer Matrix vorgenommen. Die Botschaft wird in einer bestimmten Reihenfolge in die Matrix eingebracht und in einer anderen Reihenfolge wieder aus ihr ausgelesen. Dadurch ergibt sich eine Permutation der Botschaft.

Dieses Verschlüsselungsverfahren kann mit Hilfe der Matrixabmessungen parametrisiert werden. Entsprechend erwartet das Kommando GEO zwei positive ganze Zahlen als Schlüsselparameter.

Optionen
Die Optionen des Kommandos GEO entsprechen denen von CAESAR und POLY.

Beispiel
Das nachfolgende Beispiel für das Kommando GEO belegt, daß im Gegensatz zu den vorherigen Verschlüsselungen bei GEO eine Permutation der Botschaft stattfindet. - Die Buchstabenhäufigkeit der verschlüsselten Botschaft entspricht der der unverschlüsselten Botschaft.

$ #
$ # Verschlüsseln und Anzeigen von CRYPTEXT
$ #
$ GEO -C 6 7 < KLARTEXT > KRYPTEXT 
$ CAT KRYPTEXT

.c hnD hBesi 
aoetefi stmge tseeii

$ #
$ # Entschlüsseln von CRYPTEXT 
$ #
$ GEO -E 6 7 < KRYPTEXT

Dies ist eine geheime Botschaft.

Vorausschau

Die drei in der heutigen Folge betrachteten Verschlüsselungsverfahren besitzen einen entscheidenden Nachteil: Sie sind sehr einfach. Die ersten beiden Verfahren verschlüsseln lediglich die Buchstaben der Botschaft. Die Positionen bleiben dabei erhalten. Das dritte Verfahren behält die Buchstaben bei und modifiziert lediglich die Positionen derselben. Alle drei Verfahren sind entsprechend relativ leicht zu „knacken“.

In der nächsten Folge wird ein Verschlüsselungsverfahren abgelistet, das sich nicht so leicht knacken läßt.

##################################################
# Listing MAKE Datei : MAKE3                     #
# Modifikationsdatum : 8-Jan-91                  #
# Abhängigkeiten     : -                         #
##################################################

COMPILER  = \megamax\ccom.ttp -I\megamax\headers 
LINKER    = \megamax\ld.ttp \megamax\init.o 
PROGRAMM3 = caesar.ttp poly.ttp geo.ttp mkuser.ttp \
            rmuser.ttp passwd.ttp login.ttp 
MODUL3    = crypt.o usermain.o

make_3 : $(PROGRAMM3) $(MODUL3)

##################################################
# Teil 3 - Vom Verschlüsseln                     #
##################################################

caesar.ttp : caesar.c 
$(COMPILER) caesar.c
$(LINKER) caesar.o -lc -o caesar.ttp

poly.ttp : poly.c
$(COMPILER) poly.c
$(LINKER) poly.o -lc -o poly.ttp

geo.ttp : geo.c
$(COMPILER) geo.c
$(LINKER) geo.o -lc -o geo.ttp

mkuser.ttp : mkuser.c usermain.h usermain.o
$(COMPILER) mkuser.c
$(LINKER) mkuser.o usermain.o -lc -o mkuser.ttp

rmuser.ttp : rmuser.c usermain.h usermain.o 
$(COMPILER) rmuser.c
$(LINKER) rmuser.o usermain.o -lc -o rmuser.ttp

passwd.ttp : passwd.c usermain.h usermain.o crypt.h crypt.o 
$(COMPILER) passwd.c
$(LINKER) passwd.o usermain.o crypt.o -lc -o passwd.ttp

login.ttp : login.c usermain.b usermain.o crypt.h crypt.o 
$(COMPILER) login.c
$(LINKER) login.o usermain.o crypt.o -lc -o login.ttp

crypt.o : crypt.c 
$(COMPILER) crypt.c

usermain.o : usermain.c 
$(COMPILER) usermain.c

/*
 * Listing 3.1, Datei : caesar.c
 * Programm           : CAESAR - Ein einfaches
 *                      Verschlüsselungsverfahren
 * Modifikationsdatum : 14-Juli-1990
 * Abhängigkeiten     : stdio.h, local.h
 */

#include <stdio.h>
#include "local.h"

/*
 * Funktionen   : crypt, encrypt
 *
 * Parameter    : crypt(key);
 *                encrypt(key);
 *                unsigned char key;
 *
 * Aufgabe      :
 *
 * Ver- und Entschlüsselung mit dem CAESAR-Verfahren.
 * Der Schlüssel <key> wird als Parameter übergeben.
 * Als Ein- und Ausgabe dienen die beiden
 * Standardkanäle.
 */

void crypt(key) 
unsigned char key;
{   short help;

    while (!feof(stdin)) {
        help = getchar() + key; 
        if (help > 255) 
            help -= 256; 
        if (!feof(stdin))
            putchar((unsigned char)help);
    }
}

void encrypt(key) 
unsigned char key;
{   short help;

    while (!feof(stdin)) {
        help = getchar() - key; 
        if (help < 0)
            help += 256; 
        if (!feof(stdin))
            putchar((unsigned char)help);
    }
}

/*
 * Funktion     : caesar
 *
 * Parameter    : ok = caesar(argc, argv);
 *                BOOLEAN ok;
 *                short argc;
 *                char *argv[];
 *
 * Aufgabe      :
 *
 * Interpretation der durch <argc> und <argv>
 * spezifizierten Parameterliste gemäß den Fest-
 * legungen des Kommandos CAESAR.
 */

BOOLEAN caesar(argc, argv) 
short argc; 
char *argv[];
{   unsigned char key;

    if (argc == 3) {
        if (strlen(argv[2]) == 1) 
            key = argv[2][0]; 
        else {
            fprintf(stderr,"caesar; command expects a letter for key\n");
            return(FALSE);
        }
        if (strcmp(argv[1], "-e") == 0 || strcmp(argv[1], "-E") == 0) {
            encrypt(key); 
            return(TRUE);
        }
        else if (strcmp(argv[1], "-c") == 0 || strcmp(argv[1], "-C") == 0) {
            crypt(key); 
            return(TRUE);
        }
        else {
            fprintf(stderr,"caesar: option -c or -e expected\n"); 
            return(FALSE);
        }
    }
    else {
        fprintf(stderr, "%s\n%s\n",
                "SYNOPSIS: caesar -c key",
                "          caesar -e key");
        return(FALSE);
    }
}

void main(argc, argv) 
short argc; 
char  *argv[];
{   if (!caesar(argc, argv)) 
        exit(1); 
    exit(0);
}

/*
 * Listing 3.2, Datei : poly.c
 * Programm           : POLY - Polyalphabetische
 *                      Verschlüsselung
 * Modifikationsdatum : 14-Juli-1990
 * Abhängigkeiten     : stdio.h, local.h
 */

#include <stdio.h>
#include "local.h"

/*
 * Funktionen   : crypt, encrypt
 *
 * Parameter    : crypt(key);
 *                encrypt(key);
 *                unsigned char *key;
 *
 * Aufgabe      :
 *
 * Ver- und Entschlüsselung mit einem
 * polyalphabetischen Verfahren. <key> ist ein
 * Zeiger auf eine nullterminierte Zeichenkette. 
 */

void crypt(key) 
unsigned char *key;
{   short help,
          i = 0,
          l = strlen(key);

    while (!feof(stdin)) (
        help = getchar() + key[i]; 
        if (help > 255) 
            help -= 256; 
        if (!feof(stdin))
            putchar((unsigned char)help);
        i++;
        if (i == 1)
            i = 0;
    }
}

void encrypt(key) 
unsigned char *key;
{   short help, 
          i = 0,
          l = strlen(key);

    while (!feof(stdin)) {
        help = getchar() - key[i]; 
        if (help < 0)
            help += 256; 
        if (!feof(stdin))
            putchar((unsigned char)help);
        i++;
        if (i == 1) 
            i = 0;
    }
}

/*
 * Funktion     : poly
 *
 * Parameter    : ok = poly(argc, argv);
 *                BOOLEAN ok;
 *                short   argc;
 *                char    *argv[];
 *
 * Aufgabe      :
 *
 * Interpretation der durch <argc> und <argv>
 * spezifizierten Parameterliste gemäß den Fest-
 * legungen des Kommandos POLY.
 */

BOOLEAN poly(argc, argv) 
short argc; 
char  *argv[];
{   if (argc == 3) (
        if (strcmp(argv[1], "-e") == 0 ||
            strcmp(argv[1], "-E") == 0) {
            encrypt(argv[2]); 
            return(TRUE);
        }
        else if (strcmp(argv[1], "-c") == 0 ||
                 strcmp(argv[1], "-C") == 0) {
            crypt(argv[2]); 
            return(TRUE);
        }
        else {
            fprintf(stderr,
                "poly: option -c or -e expected\n"); 
            return(FALSE);
        }
    }
    else {
        fprintf(stderr,  "%s\n%s\n",
                "SYNOPSIS: poly -c key",
                "          poly -e key");
        return(FALSE);
    }
}

void main(argc, argv) 
short argc; 
char  *argv[];
{   if (!poly(argc, argv)) 
        exit(1); 
    exit(0);
}

/*
 * Listing 3.3, Datei : geo.c
 * Programm           : GEO - Verschlüsselung durch
 *                      Permutation mit Hilfe einer
 *                      Matrix
 * Modifikationsdatum : 15-Juli-1990
 * Abhängigkeiten     : stdio.h, local.h
 */

#include <stdio.h>
#include "local.h"

/*
 * Funktionen   : crypt, encrypt
 *
 * Parameter    : crypt(x, y);
 *                encrypt(x, y);
 *                short x, y;
 *
 * Aufgabe      :
 *
 * Ver- und Entschlüsselung mit einem
 * geometrischen Verfahren. Die Eingabedaten werden
 * in eine Matrix eingetragen, deren Größe durch <x>
 * und <y> parametrisiert ist.
 */

void crypt(x, y) 
short x, y;
{   short max_char, 
          akt_char, 
          xi,
          yi,
          px,
          py;
    char  *infield, 
          help;

    max_char = x * y;
    infield = malloc(max_char);
    do {
        akt_char = 0; 
        do {
            help = getchar(); 
            if (!feof(stdin)) {
                infield[akt_char] = help; 
                akt_char++;
            }
        } while(!feof(stdin) && akt_char < max_char); 
        for (xi = 0; xi < x; xi++)
            for (yi = 0; yi < y; yi++) {
                px = (xi + yi) % x; 
                py = y - yi - 1; 
                if (py * x + px < akt_char) 
                    putchar(infield[py * x + px]);
            }
    } while (!feof(stdin)); 
    free(infield);
}

void encrypt(x, y) 
short x, y;
{   short max_char, 
          akt_char, 
          xi,
          yi,
          px,
          py,
          i;
    char  *infield,
          *outfield,
          help;

    max_char = x * y; 
    infield = malloc(max_char); 
    outfield = malloc(max_char); 
    do {
        akt_char = 0; 
        do {
            help = getchar(); 
            if (!feof(stdin)) {
                infield[akt_char] = help; 
                akt_char++;
            }
        } while(!feof(stdin) && akt_char < max_char);
        i = 0;
        for (xi = 0; xi < x; xi++)
            for (yi = 0; yi < y; yi++) {
                px = (xi + yi) % x;
                py = y - yi - 1;
                if (py * x + px < akt_char) 
                    outfield[py * x + px] = infield[i++];
            }
        for (i = 0; i < akt_char; i++) 
            putchar(outfield[i]);
    } while (!feof(stdin)); 
    free(infield); 
    free(outfield);
}

/*
 * Funktion     : geo
 *
 * Parameter    : ok = geo(argc, argv);
 *                BOOLEAN ok;
 *                short argc;
 *                char *argv[];
 *
 * Aufgabe      :
 *
 * Interpretation der durch <argc> und <argv>
 * spezifizierten Parameterliste gemäß den Fest-
 * legungen des Kommandos GEO.
 */

BOOLEAN geo(argc, argv) 
short argc; 
char  *argv[];
{   short x, y;

    if (argc == 4) {
        x = atoi(argv[2]); 
        y = atoi(argv[3]);
        if (x <= 0 || y <= 0) {
            fprintf(stderr,"geo: the keys have to be positive integers\n");
            return(FALSE);
        }
        if (strcmp(argv[1], "-e") == 0 ||
            strcmp(argv[1], "-E") == 0) {
            encrypt(x, y); 
            return(TRUE);
        }
        else if (strcmp(argv[1], "-c") == 0 ||
                 strcmp(argv[1], "-C") -- 0) {
            crypt(x, y); 
            return(TRUE);
        }
        else {
            fprintf(stderr,"geo: option -c or -e expected\n"); 
            return(FALSE);
        }
    }
    else {
        fprintf(stderr, "%s\n%s\n",
                "SYNOPSIS: geo -c key1 key2",
                "          geo -e key1 key2");
        return(FALSE);
    }
}

void main(argc, argv) 
short argc; 
char  *argv[];
{   if (!geo(argc, argv))
        exit(1);
    exit(0);
}


Aus: ST-Computer 07 / 1991, Seite 114

Links

Copyright-Bestimmungen: siehe Über diese Seite