C-Programm lucifer.c mit alter Syntax auf neue Syntax umarbeiten

rustyoldguy

Mitglied
Hallo Leute!

Vor einiger Zeit habe ich meine CD-Sammlung durchforstet und in einer ZIP-Datei ein Programm Namens Lucifer
gefunden. Zu meiner Schande muss ich gestehen das ich mich mit Piping noch nicht so auseinander gesetzt habe.
Das originale Erstellungsdatum der Datei lautet auf 05.08.85. Ist also ganze 35 Jahre alt.
Bei
C:\>dir > inhalt.txt
wird ja die Ausgabe von dir in eine Text-Datei umgeleitet.
Do weit bin ich auch gekommen, war ja in DOS-Zeiten schon so.

Lucifer aber arbeitet mit

C:\lucifer < arg1 arg2

So weit ich das verstanden habe.
Da setzt es leider bei mir aus. Erst recht, weil ich mit Linux arbeite
Zuerst zeige ich euch das Original , nur geringfügig bearbeitet, der Editoren und Zeichensätze wegen:
Code:
/***************************** lucifer *************************
 * LUCIFER: encrypt/decrypt bytes using IBM's LUCIFER algorithm.
 * Programmed by R.W.Outerbridge
 *
 * Usage: lucifer (+|-)([ecb]|<cbc|cks>) key1 <ivec>
 *          EN/DE      MODES       KEYS
 *
 *    + :    ENcrypt (default if MODE specified)
 *    - :    DEcrypt (presumes encrypted input)
 *
 *    Modes of Operation (choose ONE):
 *
 *    ecb : (default) Electronic Code Book.  Only uses one key.
 *        If simply "+" or "-" is specified, ecb is used.
 *    cbc : Cipher Block Chaining.  Uses two keys.
 *    cks : ChecKSum.  Generates a 128-bit checksum using two keys.
 *
 *    Both keys may be up to 16 characters long.  NON-ASCII MACHINES
 *    MAY GET DIFFERENT RESULTS.  Any character may be used in keys,
 *    but the one letter key "@", when used as "key1", will cause
 *    lucifer to use a preset default key for "key1".  This is used
 *    for verification and testing.  Failing to specify "ivec", if
 *    required, will result in "key1" being used for both keys.  It
 *    is an error to omit "key1".  There is no provision for specifying
 *    arbitrary, absolute, bit-valued keys.
 *
 *    As painful as they are to use, long keys are MUCH safer.
 *
 *                    ~~ Graven Cyphers, 8404.16
 *                       University of Toronto
 */

#include "a:stdio.h"
#define toascii(a)    ((a)&0177)
#define EN    0
#define DE    1
#define CKS    2
#define MODS    3
typedef char    BYTE;    /* BYTE = (VAX) ? int : char;    */
typedef int    void;    /* void = ("void") ? N/A : int; */

/* cryptographic declarations    */
void copy16(), xor16(), getkey(), loadkey(), lucifer();
BYTE Block[16], Link[16], Temp[16], IV[16];
BYTE DFLTKY[16] = { 1,35,69,103,137,171,205,239,254,220,186,152,118,84,50,16 };
    /* DO NOT ALTER! => 0x0123456789abcdeffedcba9876543210 <=    */

/* I/O declarations    */
void ruderr(), put16(), vraiput(), initio();
int IOedf, End, Once;
BYTE Last[16];

int Ecb(), Cbc(), Cks();
struct modes {
    char *name;
    int (*func)();
    };
struct modes ModsOp[MODS] = {    /* CAPS for CP/M - sorry!    */
    { "ECB", Ecb },
    { "CBC", Cbc },
    { "CKS", Cks }  };

main(argc, argv)
int argc;
char **argv;
    {
    int (*xeqtr)();
    int step, ende, edio, ok, i;
    BYTE kv[16];

    argv++; argc--;
    if(argc > 3 || argc < 2) ruderr();

    for(step=0; argc > 0; step++) {
        switch(step) {
        case 0: /* set en/de and/or default mode    */
            if(*argv[0] == '+' || *argv[0] == '-') {
                ende = (*argv[0] == '+') ? EN : DE;
                *argv[0]++ = NULL;
                if(*argv[0] == NULL) {
                    xeqtr = Ecb;    /* default mode */
                    edio = ende;
                    argv++; argc--;
                    break;
                    }
                }
            else ende = EN;

            for(i=ok=0; i < MODS && !ok; i++) {
                if(strcmp(argv[0], ModsOp[i].name) == 0) {
                    xeqtr = ModsOp[i].func;
                    ok = 1;
                    }
                }
            if(!ok) {
                fprintf(stderr, "Lucifer: unknown mode >%s<.\n", argv[0]);
                ruderr();
                }
            while(*argv[0]) *argv[0]++ = NULL;
            argv++; argc--;

            /* set appropriate IO modes    */
            if(xeqtr == Cks) edio = CKS;
            else edio = ende;

        /* falling through....    */
        case 1: /* get the key and IV, if needed and present    */
            if(strcmp(argv[0], "@") == 0) copy16(DFLTKY, kv);
            else getkey(argv[0], kv);
            argv++; argc--;

            /* if nothing left, but an IV needed, use the key    */
            if(argc == 0) {
                if(xeqtr != Ecb) copy16(kv, IV);
                break;
                }
            else if(xeqtr == Ecb) {
                fprintf(stderr, "Lucifer: ivec ignored.\n");
                while(*argv[0]) *argv[0]++ = NULL;
                argv++; argc--;
                break;
                }

            else getkey(argv[0], IV);
            argv++; argc--;
            break;

        default:
            fprintf(stderr, "Lucifer: Programming error!\n");
            exit(1);
            break;
            }    /* switch    */
        }    /* argument parsing    */

    initio(edio);
    loadkey(kv, ende);
    (*xeqtr)(ende);     /* ta-da!  Take it away xeqtr!    */
    exit(0);
    }    /* end of main    */

void ruderr() {
    fprintf(stderr, "Usage: lucifer (+|-)([ecb]|<cbc|cks>) key1 <ivec>\n");
    exit(1);
    }

Cbc(e_d)    /* Cipher Block Chaining        */
int e_d;    /* Ciphertext errors are self-healing.    */
    {
    copy16(IV, Link);
    while(get16(Block) != EOF) {
        if(e_d == DE) copy16(Block, Temp);
        else xor16(Block, Link);
        lucifer(Block);
        if(e_d == DE) {
            xor16(Block, Link);
            copy16(Temp, Link);
            }
        else copy16(Block, Link);
        put16(Block);
        }
    return;
    }

Cks(dummy)    /* CBC authentication checksum generator    */
int dummy;    /* The banks use this for verifications.    */
    {
    int i, j, k;
    long count = 0;
    copy16(IV, Link);
    while(get16(Block) != EOF) {
        xor16(Block, Link);
        lucifer(Block);
        copy16(Block, Link);
        count += 16L;
        }
    fprintf(stdout, ": %0ld bytes\t: ", count);
    for(i=j=0; i < 4; i++) {
        for(k=0; k < 4; k++, j++) fprintf(stdout, "%02x", Link[j]&0377);
        putc(' ', stdout);
        }
    fprintf(stdout, ":\n");
    return;
    }

Ecb(dummy)    /* Electronic Code Book : simple substitution    */
int dummy;    /* Yawn.  For static data and random access.    */
    {
    while(get16(Block) != EOF) {
        lucifer(Block);
        put16(Block);
        }
    return;
    }

void copy16(from, to)
register BYTE *from, *to;
    {
    register BYTE *ep;
    ep = &to[16];
    while(to < ep) *to++ = *from++;
    return;
    }

void xor16(to, with)
register BYTE *to, *with;
    {
    register BYTE *ep;
    ep = &to[16];
    while(to < ep) *to++ ^= *with++;
    return;
    }

void put16(block)
register BYTE *block;
    {
    if(IOedf == DE) copy16(block, Last);
    else vraiput(block, &block[16]);
    return;
    }

get16(input)
register char *input;
    {
    register int i, j;
    if(End == 1) return(EOF);    /* no more input    */

    for(i=0; i < 16 && ((j = getc(stdin)) != EOF); i++) *input++ = j;

    if(IOedf == DE) {    /* DECRYPTION    */
        if(i == 16 && (Once > 0)) vraiput(Last, &Last[16]);
        else if(j == EOF) {
            End = 1;
            if(Once > 0) {
                if(i != 0) i = 0;    /* no NULLs    */
                else {
                    i = Last[15]&037;
                    if(i > 16) i = 0;    /* huh? */
                    }
                vraiput(Last, &Last[16-i]);
                }
            return(EOF);
            }
        }
    else if(j == EOF) {    /* ENCRYPTION    */
        End = 1;
        if(i == 0 && (IOedf == EN || (Once > 0))) {
            if(IOedf == EN && (Once > 0)) putc('0', stdout);
            return(EOF);
            }
        for(j=i; j < 15; j++) *input++ = NULL;
        *input = 16-i;
        }
    Once = 1;
    return(0);
    }

void vraiput(cp, ep)
register char *cp, *ep;
    {
    while(cp < ep) putc(*cp++, stdout);
    return;
    }

void initio(edf)
int edf;
    {
    IOedf = edf;
    End = Once = 0;
    return;
    }

/* LUCIFER is a cryptographic algorithm developed by IBM in the early
 *    seventies.  It was a predecessor of the DES, and is much simpler
 *    than that algorithm.  In particular, it has only two substitution
 *    boxes and just one permutation box.  The permutation box is only
 *    eight bits wide.  It does, however, use a 128 bit key and operates
 *    on sixteen byte data blocks...
 *
 *    This implementation of LUCIFER was crafted by Graven Cyphers at the
 *    University of Toronto, Canada, with programming assistance from
 *    Richard Outerbridge.  It is based on the FORTRAN routines which
 *    concluded Arthur Sorkin's article "LUCIFER: A Cryptographic Algorithm",
 *    CRYPTOLOGIA, Volume 8, Number 1, January 1984, pp22-42.  The interested
 *    reader should refer to that article rather than this program for more
 *    details on LUCIFER.
 *
 *    These routines bear little resemblance to the actual LUCIFER algorithm,
 *    which has been severely twisted in the interests of speed.  They do
 *    perform the same transformations, and are believed to be UNIX portable.
 *    The package was developed for use on UNIX-like systems lacking crypto
 *    facilities.  They are not very fast, but the cipher is very strong.
 *    The routines in this file are suitable for use as a subroutine library
 *    after the fashion of crypt(3).    When linked together with applications
 *    routines they can also provide a high-level cryptographic system.
 */

static BYTE Dps[64] = {     /* Diffusion Pattern schedule    */
    4,16,32,2,1,8,64,128,    128,4,16,32,2,1,8,64,
    64,128,4,16,32,2,1,8,    8,64,128,4,16,32,2,1,
    1,8,64,128,4,16,32,2,    2,1,8,64,128,4,16,32,
    32,2,1,8,64,128,4,16,    16,32,2,1,8,64,128,4    };

/* Precomputed S&P Boxes, Two Varieties */
static char TCB0[256] = {    /* NB: char to save space.    */
     87, 21,117, 54, 23, 55, 20, 84,116,118, 22, 53, 85,119, 52, 86,
    223,157,253,190,159,191,156,220,252,254,158,189,221,255,188,222,
    207,141,237,174,143,175,140,204,236,238,142,173,205,239,172,206,
    211,145,241,178,147,179,144,208,240,242,146,177,209,243,176,210,
    215,149,245,182,151,183,148,212,244,246,150,181,213,247,180,214,
     95, 29,125, 62, 31, 63, 28, 92,124,126, 30, 61, 93,127, 60, 94,
    219,153,249,186,155,187,152,216,248,250,154,185,217,251,184,218,
     67,  1, 97, 34,  3, 35,  0, 64, 96, 98,  2, 33, 65, 99, 32, 66,
    195,129,225,162,131,163,128,192,224,226,130,161,193,227,160,194,
    199,133,229,166,135,167,132,196,228,230,134,165,197,231,164,198,
    203,137,233,170,139,171,136,200,232,234,138,169,201,235,168,202,
     75,  9,105, 42, 11, 43,  8, 72,104,106, 10, 41, 73,107, 40, 74,
     91, 25,121, 58, 27, 59, 24, 88,120,122, 26, 57, 89,123, 56, 90,
     71,  5,101, 38,  7, 39,  4, 68,100,102,  6, 37, 69,103, 36, 70,
     79, 13,109, 46, 15, 47, 12, 76,108,110, 14, 45, 77,111, 44, 78,
     83, 17,113, 50, 19, 51, 16, 80,112,114, 18, 49, 81,115, 48, 82 };

static char TCB1[256] = {
     87,223,207,211,215, 95,219, 67,195,199,203, 75, 91, 71, 79, 83,
     21,157,141,145,149, 29,153,  1,129,133,137,  9, 25,  5, 13, 17,
    117,253,237,241,245,125,249, 97,225,229,233,105,121,101,109,113,
     54,190,174,178,182, 62,186, 34,162,166,170, 42, 58, 38, 46, 50,
     23,159,143,147,151, 31,155,  3,131,135,139, 11, 27,  7, 15, 19,
     55,191,175,179,183, 63,187, 35,163,167,171, 43, 59, 39, 47, 51,
     20,156,140,144,148, 28,152,  0,128,132,136,  8, 24,  4, 12, 16,
     84,220,204,208,212, 92,216, 64,192,196,200, 72, 88, 68, 76, 80,
    116,252,236,240,244,124,248, 96,224,228,232,104,120,100,108,112,
    118,254,238,242,246,126,250, 98,226,230,234,106,122,102,110,114,
     22,158,142,146,150, 30,154,  2,130,134,138, 10, 26,  6, 14, 18,
     53,189,173,177,181, 61,185, 33,161,165,169, 41, 57, 37, 45, 49,
     85,221,205,209,213, 93,217, 65,193,197,201, 73, 89, 69, 77, 81,
    119,255,239,243,247,127,251, 99,227,231,235,107,123,103,111,115,
     52,188,172,176,180, 60,184, 32,160,164,168, 40, 56, 36, 44, 48,
     86,222,206,210,214, 94,218, 66,194,198,202, 74, 90, 70, 78, 82 };

statiã BYTE Key[16]¬ Pkey[128];
static int P[8] = { 3,5,0,4,2,1,7,6 };
static int Smask[16] = { 128,64,32,16,8,4,2,1 };

void lucifer(bytes)
BYTE *bytes;    /* points to a 16-byte array    */
    {
    register BYTE *cp, *sp, *dp;
    register int *sbs, tcb, val, j, i;
    BYTE *h0, *h1, *kc, *ks;

    h0 = &bytes[0];     /* the "lower" half     */
    h1 = &bytes[8];     /* the "upper" half     */
    kc = Pkey;
    ks = Key;

    for(i=0; i<16; i++) {
        tcb = *ks++;
        sbs = Smask;
        dp = Dps;

        for(j=0; j<8; j++) {
            /* nibbles are selected by the bits of ks    */
            if(tcb&*sbs++) val = TCB1[h1[j]&0377];
            else val = TCB0[h1[j]&0377];
            val ^= *kc++;

            /* fiddle bits in the "lower" half      */
            for(cp=h0, sp = &h0[8]; cp<sp; cp++)
                *cp ^= (val&*dp++);
            }

        /* swap (virtual) halves    */
        cp = h0;
        h0 = h1;
        h1 = cp;
        }

    /* REALLY swap halves    */
    dp = &bytes[0];
    cp = &bytes[8];
    for(sp=cp; dp<sp; dp++, cp++) {
        val = *dp;
        *dp = *cp;
        *cp = val;
        }
    return;
    }

void loadkey(keystr, edf)    /* sets master key    */
BYTE *keystr;
register int edf;
    {
    register BYTE *ep, *cp, *pp;
    register int kc, i, j;
    BYTE kk[16], pk[16];
    cp = kk;
    pp = pk;
    ep = &kk[16];
    while(cp < ep) {
        *cp++ = *keystr;
        for(*pp=i=0; i<8; i++)
            if(*keystr&Smask[i]) *pp |= Smask[P[i]];
        keystr++;
        pp++;
        }
    cp = Key;
    pp = Pkey;
    kc = (edf == DE) ? 8 : 0;
    for(i=0; i<16; i++) {
        if(edf == DE) kc = (++kc)&017;
        *cp++ = kk[kc];
        for(j=0; j<8; j++) {
            *pp++ = pk[kc];
            if(j<7 || (edf == DE)) kc = (++kc)&017;
            }
        }
    return;
    }

/* getkey: using up to 16 bytes of aptr, makeup a 16 byte key in savp.
    aptr must be NULL terminated, savp 16 bytes long.  The key
    returned in savp is aptr encrypted with itself ONCE.    */
void getkey(aptr, savp)
register char *aptr;
register BYTE *savp;
    {
    register BYTE *store, *cp;
    register int i;
    store = savp;

    /* copy aptr into savp; NULL aptr    */
    for(i=0; i<16 && (*aptr != NULL); i++) {
        *savp++ = toascii(*aptr);
        *aptr++ = NULL;
        }
    while(*aptr) *aptr++ = NULL;
    if(i == 0) savp++;    /* aptr could have been NULL    */

    /* expand savp out to 16 bytes of "something" and encrypt it    */
    for(cp=store, savp--; i<16;) store[i++] = (*cp++ + *savp++)&0377;
    loadkey(store);
    lucifer(store);
    return;
    }

/*    lucifer cks @ < /dev/null
 *    : 16 bytes    : 32186510 6acf6094 87953eba 196f5a75 :
 *            (rwo/8406.23.16:37/V3.2)            */
/**************************** lucifer ***********************************/

Natürlich schlucken das die modernen Compiler nicht. Deshalb habe ich den code mit codeblocks aufgeteilt in
main.c
lucifer.c und lucifer.h

Danach musste ich tricksen um das Ding überhaupt kompilieren zu können.
Zunächst
main.c:
Code:
/**--------------------main.c von lucifer.c ----------------------
 * LUCIFER: encrypt/decrypt bytes using IBM's LUCIFER algorithm.
 * Programmed by R.W.Outerbridge
 *
 * Usage: lucifer (+|-)([ecb]|<cbc|cks>) key1 <ivec>
 *          EN/DE      MODES       KEYS
 *
 *    + :    ENcrypt (default if MODE specified)
 *    - :    DEcrypt (presumes encrypted input)
 *
 *    Modes of Operation (choose ONE):
 *
 *    ecb : (default) Electronic Code Book.  Only uses one key.
 *        If simply "+" or "-" is specified, ecb is used.
 *    cbc : Cipher Block Chaining.  Uses two keys.
 *    cks : ChecKSum.  Generates a 128-bit checksum using two keys.
 *
 *    Both keys may be up to 16 characters long.  NON-ASCII MACHINES
 *    MAY GET DIFFERENT RESULTS.  Any character may be used in keys,
 *    but the one letter key "@", when used as "key1", will cause
 *    lucifer to use a preset default key for "key1".  This is used
 *    for verification and testing.  Failing to specify "ivec", if
 *    required, will result in "key1" being used for both keys.  It
 *    is an error to omit "key1".  There is no provision for specifying
 *    arbitrary, absolute, bit-valued keys.
 *
 *    As painful as they are to use, long keys are MUCH safer.
 *
 *                    ~~ Graven Cyphers, 8404.16
 *                       University of Toronto
 */
#include "lucifer.h"


struct modes {
    char *name;
    int (*func)();
    };
struct modes ModsOp[MODS] = {    /* CAPS for CP/M - sorry!    */
    { "ECB", Ecb },
    { "CBC", Cbc },
    { "CKS", Cks }  };

int main(int argc, char **argv)
{
 int (*xeqtr)();
 //int step, ende, edio, ok, i;
 char kv[16];

    argv++; argc--;
    if(argc > 3 || argc < 2) ruderr();

    for(step=0; argc > 0; step++) {
        switch(step) {
        case 0: /* set en/de and/or default mode    */
            if(*argv[0] == '+' || *argv[0] == '-') {
                ende = (*argv[0] == '+') ? EN : DE;
                *argv[0]++ = NULL;
                if(*argv[0] == NULL) {
                    xeqtr = Ecb;    /* default mode */
                    edio = ende;
                    argv++; argc--;
                    break;
                    }
                }
            else ende = EN;

            for(i=ok=0; i < MODS && !ok; i++) {
                if(strcmp(argv[0], ModsOp[i].name) == 0) {
                    xeqtr = ModsOp[i].func;
                    ok = 1;
                    }
                }
            if(!ok) {
                fprintf(stderr, "Lucifer: unknown mode >%s<.\n", argv[0]);
                ruderr();
                }
            while(*argv[0]) *argv[0]++ = NULL;
            argv++; argc--;

            /* set appropriate IO modes    */
            if(xeqtr == Cks) edio = CKS;
             else edio = ende;

        /* falling through....    */
        case 1: /* get the key and IV, if needed and present    */
            if(strcmp(argv[0], "@") == 0) copy16(DFLTKY, kv);
            else getkey(argv[0], kv);
            argv++; argc--;

            /* if nothing left, but an IV needed, use the key    */
            if(argc == 0) {
                if(xeqtr != Ecb) copy16(kv, IV);
                break;
                }
            else if(xeqtr == Ecb) {
                fprintf(stderr, "Lucifer: ivec ignored.\n");
                while(*argv[0]) *argv[0]++ = NULL;
                argv++; argc--;
                break;
                }

            else getkey(argv[0], IV);
            argv++; argc--;
            break;

        default:
            fprintf(stderr, "Lucifer: Programming error!\n");
            exit(1);
            break;
            }    /* switch    */
        }    /* argument parsing    */

    initio(edio);
    loadkey(kv, ende);
    (*xeqtr)(ende);     /* ta-da!  Take it away xeqtr!    */

    return EXIT_SUCCESS;
}    /** end of main    */


nun der Header lucifer.h:
Code:
/**    header lucifer.h  of Project    lucifer                   */

#ifndef LUCIFER_H_INCLUDED
#define LUCIFER_H_INCLUDED

#include <stdio.h>
#include <stdlib.h>

#define toascii(a)    ((a)&0177)
#define EN    0
#define DE    1
#define CKS    2
#define MODS    3

typedef char    BYTE;    /* BYTE = (VAX) ? int : char;    */
//typedef int    void;    /* void = ("void") ? N/A : int; */


static BYTE Dps[64] = {     /* Diffusion Pattern schedule    */
    4,16,32,2,1,8,64,128,    128,4,16,32,2,1,8,64,
    64,128,4,16,32,2,1,8,    8,64,128,4,16,32,2,1,
    1,8,64,128,4,16,32,2,    2,1,8,64,128,4,16,32,
    32,2,1,8,64,128,4,16,    16,32,2,1,8,64,128,4    };

/* Precomputed S&P Boxes, Two Varieties */
static char TCB0[256] = {    /* NB: char to save space.    */
     87, 21,117, 54, 23, 55, 20, 84,116,118, 22, 53, 85,119, 52, 86,
    223,157,253,190,159,191,156,220,252,254,158,189,221,255,188,222,
    207,141,237,174,143,175,140,204,236,238,142,173,205,239,172,206,
    211,145,241,178,147,179,144,208,240,242,146,177,209,243,176,210,
    215,149,245,182,151,183,148,212,244,246,150,181,213,247,180,214,
     95, 29,125, 62, 31, 63, 28, 92,124,126, 30, 61, 93,127, 60, 94,
    219,153,249,186,155,187,152,216,248,250,154,185,217,251,184,218,
     67,  1, 97, 34,  3, 35,  0, 64, 96, 98,  2, 33, 65, 99, 32, 66,
    195,129,225,162,131,163,128,192,224,226,130,161,193,227,160,194,
    199,133,229,166,135,167,132,196,228,230,134,165,197,231,164,198,
    203,137,233,170,139,171,136,200,232,234,138,169,201,235,168,202,
     75,  9,105, 42, 11, 43,  8, 72,104,106, 10, 41, 73,107, 40, 74,
     91, 25,121, 58, 27, 59, 24, 88,120,122, 26, 57, 89,123, 56, 90,
     71,  5,101, 38,  7, 39,  4, 68,100,102,  6, 37, 69,103, 36, 70,
     79, 13,109, 46, 15, 47, 12, 76,108,110, 14, 45, 77,111, 44, 78,
     83, 17,113, 50, 19, 51, 16, 80,112,114, 18, 49, 81,115, 48, 82 };

static char TCB1[256] = {
     87,223,207,211,215, 95,219, 67,195,199,203, 75, 91, 71, 79, 83,
     21,157,141,145,149, 29,153,  1,129,133,137,  9, 25,  5, 13, 17,
    117,253,237,241,245,125,249, 97,225,229,233,105,121,101,109,113,
     54,190,174,178,182, 62,186, 34,162,166,170, 42, 58, 38, 46, 50,
     23,159,143,147,151, 31,155,  3,131,135,139, 11, 27,  7, 15, 19,
     55,191,175,179,183, 63,187, 35,163,167,171, 43, 59, 39, 47, 51,
     20,156,140,144,148, 28,152,  0,128,132,136,  8, 24,  4, 12, 16,
     84,220,204,208,212, 92,216, 64,192,196,200, 72, 88, 68, 76, 80,
    116,252,236,240,244,124,248, 96,224,228,232,104,120,100,108,112,
    118,254,238,242,246,126,250, 98,226,230,234,106,122,102,110,114,
     22,158,142,146,150, 30,154,  2,130,134,138, 10, 26,  6, 14, 18,
     53,189,173,177,181, 61,185, 33,161,165,169, 41, 57, 37, 45, 49,
     85,221,205,209,213, 93,217, 65,193,197,201, 73, 89, 69, 77, 81,
    119,255,239,243,247,127,251, 99,227,231,235,107,123,103,111,115,
     52,188,172,176,180, 60,184, 32,160,164,168, 40, 56, 36, 44, 48,
     86,222,206,210,214, 94,218, 66,194,198,202, 74, 90, 70, 78, 82 };

static BYTE Key[16], Pkey[128];
static int P[8] = { 3,5,0,4,2,1,7,6 };
static int Smask[16] = { 128,64,32,16,8,4,2,1 };

/** cryptographic declarations    */
static BYTE Block[16], Link[16], Temp[16], IV[16];
static BYTE DFLTKY[16] = { 1,35,69,103,137,171,205,239,254,220,186,152,118,84,50,16 };
    /* DO NOT ALTER! => 0x0123456789abcdeffedcba9876543210 <=    */


/* I/O declarations    */
static int IOedf, End, Once;
static BYTE Last[16];

static int step, ende, edio, ok, i;



void ruderr(void);
int Cbc(int e_d);    /** Cipher Block Chaining     Ciphertext errors are self-healing.    */
int Cks(int dummy);
int Ecb(int dummy);
void copy16(BYTE *from, BYTE *to);
void xor16(BYTE *to, register BYTE *with);
void put16(BYTE *block);
int get16(char *input);
void vraiput(char * cp, char * ep);
void initio(int edf);
void getkey(register char * aptr, register BYTE * savp);
void loadkey(BYTE *keystr, int edf);    /* sets master key    */
void lucifer( BYTE *bytes);/* points to a 16-byte array    */



#endif // LUCIFER_H_INCLUDED

Nun die dazugehörige Datei lucifer.c mit den Funktionen:
Code:
/** lucifer.c of Project lucifer */
#include "lucifer.h"

void ruderr(void)
{
 fprintf(stderr, "Usage: lucifer (+|-)([ecb]|<cbc|cks>) key1 <ivec>\n");
 exit(1);
}


int Cbc(int e_d)    /** Cipher Block Chaining     Ciphertext errors are self-healing.    */
{
    copy16(IV, Link);
    while(get16(Block) != EOF) {
        if(e_d == DE) copy16(Block, Temp);
        else xor16(Block, Link);
        lucifer(Block);
        if(e_d == DE) {
            xor16(Block, Link);
            copy16(Temp, Link);
            }
        else copy16(Block, Link);
        put16(Block);
        }
return 0;
}

int Cks(int dummy)    /** CBC authentication checksum generator The banks use this for verifications.    */
    {
    int i, j, k;
    long count = 0;
    copy16(IV, Link);
    while(get16(Block) != EOF) {
        xor16(Block, Link);
        lucifer(Block);
        copy16(Block, Link);
        count += 16L;
        }
    fprintf(stdout, ": %0ld bytes\t: ", count);
    for(i=j=0; i < 4; i++) {
        for(k=0; k < 4; k++, j++) fprintf(stdout, "%02x", Link[j]&0377);
        putc(' ', stdout);
        }
    fprintf(stdout, ":\n");
    return 0;
}

int Ecb(int dummy)    /** Electronic Code Book : simple substitution     Yawn.  For static data and random access.    */
{
    while(get16(Block) != EOF) {
        lucifer(Block);
        put16(Block);
        }
return 0;
}

void copy16(BYTE *from, BYTE *to)
{
    register BYTE *ep;
    ep = &to[16];
    while(to < ep) *to++ = *from++;
//    return;
}

void xor16(register BYTE *to, register BYTE *with)
{
    register BYTE *ep;
    ep = &to[16];
    while(to < ep) *to++ ^= *with++;
//    return;
}

void put16(BYTE * block)
{
 if(IOedf == DE) copy16(block, Last);
 else vraiput(block, &block[16]);
// return;
}

int get16(char *input)
{
    int i, j;
    if(End == 1) return(EOF);    /* no more input    */

    for(i=0; i < 16 && ((j = getc(stdin)) != EOF); i++) *input++ = j;

    if(IOedf == DE) {    /* DECRYPTION    */
        if(i == 16 && (Once > 0)) vraiput(Last, &Last[16]);
        else if(j == EOF) {
            End = 1;
            if(Once > 0) {
                if(i != 0) i = 0;    /* no NULLs    */
                else {
                    i = Last[15]&037;
                    if(i > 16) i = 0;    /* huh? */
                    }
                vraiput(Last, &Last[16-i]);
                }
            return(EOF);
            }
        }
    else if(j == EOF) {    /* ENCRYPTION    */
        End = 1;
        if(i == 0 && (IOedf == EN || (Once > 0))) {
            if(IOedf == EN && (Once > 0)) putc('0', stdout);
            return(EOF);
            }
        for(j=i; j < 15; j++) *input++ = NULL;
        *input = 16-i;
        }
    Once = 1;
    return(0);
}

void vraiput(char * cp, char * ep)
{
 while(cp < ep) putc(*cp++, stdout);
 //return;
}

void initio(int edf)
{
 IOedf = edf;
 End = Once = 0;
 // return;
}


/* getkey: using up to 16 bytes of aptr, makeup a 16 byte key in savp.
    aptr must be NULL terminated, savp 16 bytes long.  The key
    returned in savp is aptr encrypted with itself ONCE.    */
void getkey(char *aptr, BYTE *savp)
{
    BYTE *store, *cp;
    int i;
    store = savp;

    /* copy aptr into savp; NULL aptr    */
    for(i=0; i<16 && (*aptr != NULL); i++) {
        *savp++ = toascii(*aptr);
        *aptr++ = NULL;
        }
    while(*aptr) *aptr++ = NULL;
    if(i == 0) savp++;    /* aptr could have been NULL    */

    /* expand savp out to 16 bytes of "something" and encrypt it    */
    for(cp=store, savp--; i<16;) store[i++] = (*cp++ + *savp++)&0377;

    loadkey(store, edio);
    lucifer(store);

    return;
}

/**     lucifer cks @ < /dev/null
 *    : 16 bytes    : 32186510 6acf6094 87953eba 196f5a75 :
 *            (rwo/8406.23.16:37/V3.2)            */


void loadkey(BYTE *keystr, int edf)    /* sets master key    */
{
    BYTE *ep, *cp, *pp;
    int kc, i, j;
    BYTE kk[16], pk[16];

    cp = kk;
    pp = pk;
    ep = &kk[16];

    while(cp < ep)
     {
      *cp++ = *keystr;
      for(*pp=i=0; i<8; i++)
       if(*keystr&Smask[i]) *pp |= Smask[P[i]];
      keystr++;
      pp++;
     }

    cp = Key;
    pp = Pkey;
    kc = (edf == DE) ? 8 : 0;

    for(i=0; i<16; i++)
     {
        if(edf == DE) kc = (++kc)&017;
        *cp++ = kk[kc];
      for(j=0; j<8; j++)
       {
        *pp++ = pk[kc];
        if(j<7 || (edf == DE)) kc = (++kc)&017;
       }
     }
    //return;
}

/* LUCIFER is a cryptographic algorithm developed by IBM in the early
 *    seventies.  It was a predecessor of the DES, and is much simpler
 *    than that algorithm.  In particular, it has only two substitution
 *    boxes and just one permutation box.  The permutation box is only
 *    eight bits wide.  It does, however, use a 128 bit key and operates
 *    on sixteen byte data blocks...
 *
 *    This implementation of LUCIFER was crafted by Graven Cyphers at the
 *    University of Toronto, Canada, with programming assistance from
 *    Richard Outerbridge.  It is based on the FORTRAN routines which
 *    concluded Arthur Sorkin's article "LUCIFER: A Cryptographic Algorithm",
 *    CRYPTOLOGIA, Volume 8, Number 1, January 1984, pp22-42.  The interested
 *    reader should refer to that article rather than this program for more
 *    details on LUCIFER.
 *
 *    These routines bear little resemblance to the actual LUCIFER algorithm,
 *    which has been severely twisted in the interests of speed.  They do
 *    perform the same transformations, and are believed to be UNIX portable.
 *    The package was developed for use on UNIX-like systems lacking crypto
 *    facilities.  They are not very fast, but the cipher is very strong.
 *    The routines in this file are suitable for use as a subroutine library
 *    after the fashion of crypt(3).    When linked together with applications
 *    routines they can also provide a high-level cryptographic system.
 */

void lucifer(BYTE *bytes)    /** points to a 16-byte array    */
{
    BYTE *cp, *sp, *dp;
    int *sbs, tcb, val, j, i;
    BYTE *h0, *h1, *kc, *ks;

    h0 = &bytes[0];     /* the "lower" half     */
    h1 = &bytes[8];     /* the "upper" half     */
    kc = Pkey;
    ks = Key;

    for(i=0; i<16; i++) {
        tcb = *ks++;
        sbs = Smask;
        dp = Dps;

        for(j=0; j<8; j++) {
            /* nibbles are selected by the bits of ks    */
            if(tcb&*sbs++) val = TCB1[h1[j]&0377];
            else val = TCB0[h1[j]&0377];
            val ^= *kc++;

            /* fiddle bits in the "lower" half      */
            for(cp=h0, sp = &h0[8]; cp<sp; cp++)
                *cp ^= (val&*dp++);
            }

        /* swap (virtual) halves    */
        cp = h0;
        h0 = h1;
        h1 = cp;
        }

    /* REALLY swap halves    */
    dp = &bytes[0];
    cp = &bytes[8];
    for(sp=cp; dp<sp; dp++, cp++) {
        val = *dp;
        *dp = *cp;
        *cp = val;
        }
//    return;
}

/**************************** lucifer ***********************************/

Mehr oder weniger sind die nötigen Umbauarbeiten etwas umfangreich.
Ich geb es ja zu, es ist so, wie wenn man einen Oldtimer restauriert, dabei das Fahrwerk, das Chassis
das Getriebe, den Innenraum erneuert nur einige Teile des Motors bleiben original.
Mich hat aber die Aufgabe gereizt. Kann mir jemand bezüglich des Piping Tipps geben?
Wie könnte ich jetzt weiter bei der Programm-Restaurierung vorgehen?

Gruß
rustyoldguy
 
Hmm, also so richtig habe ich nicht verstanden was deine Frage ist :confused: Sieht mir eher nach einer Frage in Richtung Shell-Syntax aus.

prog > file Das stdout des Programms prog wird in Datei file umgeleitet. Heißt, das Programm schreibt zum stdout (statt die Datei selbst zu öffnen), Rest erledigt die Shell.
prog < file Das stdin des Programms ist auf die Datei umgeleitet. Heißt, das Programm liest den Dateiinhalt vom stdin (statt die Datei selbst zu öffnen).
prog1 | prog2 Das stdout von prog1 wird zu einer Pipe umgeleitet an die das stdin von prog2 angebunden ist.

Die File-Descriptors 0 (für stdin) und 1 (für stdout) werden automatisch angenommen. Die 2 (für stderr) müsstest du allerdings spezifizieren, à la
prog 2> file um das stderr in die Datei umzuleiten.

Das ist übrigens unter DOS, Linux und Windows bis auf wenige Details gleich.
 
Das Proggi läss sich problemlos kompilieren, die Testeingabe liefert auch Ergebnisse. Aber bevor ich keine genaueren Kenntnisse über den lucifer-Algorithmus habe, lasse ich lieber von weiteren Modifikationen die Finger. Ging aber überaschend einfach, die source-Dateien anzupassen. Vielleicht später greife ich das Projekt wieder auf. Mit der Befehlszeilensyntax lässt sich so eine Datei nicht chiffrieren. Die herkömmliche Weise wäre mir lieber.
 
Ehrlich gesagt habe ich innerhalb kürzester Zeit aufgegeben beim Sourcecode durchzublicken, wegen unverständlich zusammengekürzten Variablen-, Macro- und Funktionsnamen. Ich habe dann darauf geantwortet, was ich als dein derzeitiges Problem verstanden hatte:
Lucifer aber arbeitet mit

C:\lucifer < arg1 arg2

So weit ich das verstanden habe.
Da setzt es leider bei mir aus.
 
Moin,

Ich möchte hinzufügen : wenn clang -Weverything auf 430 Zeilen 300 Warnings wirft würde ich vielleicht nicht von "problemlos kompilieren" sprechen, sondern von "ich ignoriere Probleme die hoffentlich nicht sofort explodieren" ;)

Merke : immer mit so vielen Warnungen wie irgend möglich kompilieren.

wenn du es durchblicken willst würde ich vielleicht damit beginnen, mal nen Formatter drüber zu jagen, mit ein bisschen refactoring die ganzen Namen mal sinnvoll umbenennen und dann die Warnings fixen, ich glaub dann ist schon viel gewonnen.

Und, nur der generische Disclaimer : es taugt natürlich nicht als Produktivwerkzeug, Jahrzehnte alte Kryptoalgorithmen in einer ebenso alten Implementierung heute zu verwenden, Kryptosoftware sollte man auch nie selbst schreiben oder auch nur kompilieren, wenn man nicht genau weiß was man tut, um keine riesigen Seitenkanäle zu öffnen oder so.

Insgesamt antik und zumindest für das Heute ein furchtbarer Stil^^

mfg,

Lowl3v3l
 
Hallo!

Bei mir sieht die Test-Ausgabe so aus:
lucifer_test.jpg



Natürlich ist der Stil antik und furchtbar. Klar. Aber mich hat die Aufgabe gereizt, mal so ein altes Ding
überhaupt mal zum laufen zu bringen. Um aber das Proggi besser zu verarbeiten müsste ich mich mehr
mit dem lucifer-Algorithmis beschäftigen. Dazu habe ich momentan überhaupt keinen Bock drauf.
Wie man damit überhaupt chiffrieren und dann dechiffrieren kan, ist mir genau so ein Rätzel wie euch.
In der Hoffnung jemand hätte damit schon mal experimentiert, habe ich das hier rein gestellt.
Ich selbst habe nur mit monoalphabetischer Verschlüsselung, Vigenere-Tafel und anderen
Arten der Substitution experimentiert. Dann noch mit Transposition auf Bit-Ebene.

Hier meine Arbeiten die ich auf anderen Foren veröffentlicht habe:

Ein anderes Beispiel eine etwas gelungere Portierung in die moderne c und c++ Zeit:
Riemenrad-Berechnung mit evalx.jpg


Das hier noch jede Menge Arbeit drin steckt ist mir klar.
 
Zuletzt bearbeitet:
Hallo German und die anderen!

Falls ich mit der Wahl meiner Worte anderen zu nahe gekommen bin, möchte ich mit dafür entschuldigen. Momentan ist es mir nicht möglich, mit der nötigen Kraft das Projekt Lucifer zu verfolgen. Es fliegt mir wegen meiner Arbeitslosigkeit mein ganzes Leben
um die Ohren. Den code und die momentanen Ergebnisse habe ich rein gestellt, da bei mir Polyarthritis in den Fingergelenken
festgestellt wurde und ich nicht weis, wie lange ich noch am PC arbeiten kann. Bevor es zu spät ist, also meine Arbeiten ins Web.
Wenn schon ich nichts mehr damit anfangen kann, dann vielleicht andere.
Die anderen Beispiele sollen zeigen, das alte Source generell nicht verurteilt werden sollte. Oftmals finden sich darin ganz brauchbare
Tipps die man modifizert für eigene Zwecke gut verwenden kann, oder simpel als Ideen-Lieferanten.

Zum Thema Lucifer:
Der eigentliche Haken am diesen Projekt war zuerst das Commandline-Parsing, wurde von mir aber bei einer späteren Version wesentlich
verbessert. Zudem wurde codeblocks nun entgültig in "Rente" geschickt. Eine Arbeit damit wird immer schwieriger. Zudem fehlen
diesem Code die Pipedeskriptoren zum Lesen und Schreiben. Wie sinnvoll Piping wie

lucifer cks @ < /dev/null

ist, bleibt dahin gestellt.


Das Problem liegt in diesen Zeilen der main.cpp bzw main.c:


initio(edio);
loadkey(kv, ende);
(*xeqtr)(ende); /* ta-da! Take it away xeqtr! */

Zuerst denke ich mal, das 'getkey' angepasst werden muss.
In wie weit da Zeiger auf Funktionen wie in dieser Source hinderlich sind, werde ich noch sehen. Das Ganze wie in der Ur-Source zwecks
"Vereinfachung" in eine Struktur zu geben und mit einem Zeiger auf eine Funktion zu verarbeiten, halte ich für den falschen Weg.
Mangelhaft ist leider die geringe Beschreibung und ein fehlendes Beispiel für den Einsatz um die Richtigkeit der Modifikationen zu testen.
Zudem sind andere Arbeiten mit dem lucifer-Algorithmus im Web so gut wie nicht zu finden, außer in kurzen Beschreibungen.
Vielleicht ist dieser Algorithmus den meisten c und c++ Programmierern nicht attraktiv genug.
Ziel bleibt jedoch, weg vom Piping zu kommen, um so den Code später nach c++ zu portieren und dann erst zur Verwendung in einer GUI.
Wie auch immer, das selbst viele Sourcen aus den Siebzigern noch modifiziert werden können, zeigt meiner Meinung nach das
Potential von c und cpp.
 
Ich schau gleich mal drüber, behebe ein paar Fehler und kommentiere wie der Algo funktioniert.

Generell kannst du Feistel-Systeme testen wie alle anderen symmetrischen Kryptoverfahren auch, indem du prüfst ob bei bekanntem Klartext und bekanntem Schlüssel der richtige Cipher raus kommt, wenn er das tut sind Fehler sehr unwahrscheinlich.

Zum Verständnis hilft vielleicht, dir mal DES anzuschauen, dazu gibts viel, es ist zwar nicht ganz Lucifer, aber auch ein Feistel-System.

mfg
 
So, ich hab mir den Code angeschaut und, was soll ich sagen, zur Erklärung des Algorithmus ist er völlig ungeeignet, da er viel viel zu kleinteilig optimiert ist( einschließlich Optimierungen, die heute Nutzlos oder sogar schädlich wären).

Generell bin ich zum entwirren den Ansatz gegangen erstmal den CBC-Modus rauszuwerfen( das ist Code der den weg verstellt,also weg damit), ähnlich wie die Fehlerausgabe, die vrainput-Funktion hab ich überall wo sie noch auftrat inlined. Statt einigen der Macros etc. hab ich die Standard-Integer verwendet(int8_t statt BYTE) und alles in einer Datei gehalten, um die Prototypen erst einmal los zu werden.

ACHTUNG : DER CODE IST NOCH VOLLER WARNINGS UND ICH HABE IHN NICHT AUSGIEBIG GETESTET!
C:
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#define EN 0
#define DE 1
#define MODS 1

int8_t Dps[64] = {/* Diffusion Pattern schedule    */
                  4,   16,  32, 2,  1,   8,   64, 128, 128, 4,   16,  32, 2,
                  1,   8,   64, 64, 128, 4,   16, 32,  2,   1,   8,   8,  64,
                  128, 4,   16, 32, 2,   1,   1,  8,   64,  128, 4,   16, 32,
                  2,   2,   1,  8,  64,  128, 4,  16,  32,  32,  2,   1,  8,
                  64,  128, 4,  16, 16,  32,  2,  1,   8,   64,  128, 4};

/* Precomputed S&P Boxes, Two Varieties */
char TCB0[256] = {/* NB: char to save space.    */
                  87,  21,  117, 54,  23,  55,  20,  84,  116, 118, 22,  53,
                  85,  119, 52,  86,  223, 157, 253, 190, 159, 191, 156, 220,
                  252, 254, 158, 189, 221, 255, 188, 222, 207, 141, 237, 174,
                  143, 175, 140, 204, 236, 238, 142, 173, 205, 239, 172, 206,
                  211, 145, 241, 178, 147, 179, 144, 208, 240, 242, 146, 177,
                  209, 243, 176, 210, 215, 149, 245, 182, 151, 183, 148, 212,
                  244, 246, 150, 181, 213, 247, 180, 214, 95,  29,  125, 62,
                  31,  63,  28,  92,  124, 126, 30,  61,  93,  127, 60,  94,
                  219, 153, 249, 186, 155, 187, 152, 216, 248, 250, 154, 185,
                  217, 251, 184, 218, 67,  1,   97,  34,  3,   35,  0,   64,
                  96,  98,  2,   33,  65,  99,  32,  66,  195, 129, 225, 162,
                  131, 163, 128, 192, 224, 226, 130, 161, 193, 227, 160, 194,
                  199, 133, 229, 166, 135, 167, 132, 196, 228, 230, 134, 165,
                  197, 231, 164, 198, 203, 137, 233, 170, 139, 171, 136, 200,
                  232, 234, 138, 169, 201, 235, 168, 202, 75,  9,   105, 42,
                  11,  43,  8,   72,  104, 106, 10,  41,  73,  107, 40,  74,
                  91,  25,  121, 58,  27,  59,  24,  88,  120, 122, 26,  57,
                  89,  123, 56,  90,  71,  5,   101, 38,  7,   39,  4,   68,
                  100, 102, 6,   37,  69,  103, 36,  70,  79,  13,  109, 46,
                  15,  47,  12,  76,  108, 110, 14,  45,  77,  111, 44,  78,
                  83,  17,  113, 50,  19,  51,  16,  80,  112, 114, 18,  49,
                  81,  115, 48,  82};

char TCB1[256] = {
    87,  223, 207, 211, 215, 95,  219, 67,  195, 199, 203, 75,  91,  71,  79,
    83,  21,  157, 141, 145, 149, 29,  153, 1,   129, 133, 137, 9,   25,  5,
    13,  17,  117, 253, 237, 241, 245, 125, 249, 97,  225, 229, 233, 105, 121,
    101, 109, 113, 54,  190, 174, 178, 182, 62,  186, 34,  162, 166, 170, 42,
    58,  38,  46,  50,  23,  159, 143, 147, 151, 31,  155, 3,   131, 135, 139,
    11,  27,  7,   15,  19,  55,  191, 175, 179, 183, 63,  187, 35,  163, 167,
    171, 43,  59,  39,  47,  51,  20,  156, 140, 144, 148, 28,  152, 0,   128,
    132, 136, 8,   24,  4,   12,  16,  84,  220, 204, 208, 212, 92,  216, 64,
    192, 196, 200, 72,  88,  68,  76,  80,  116, 252, 236, 240, 244, 124, 248,
    96,  224, 228, 232, 104, 120, 100, 108, 112, 118, 254, 238, 242, 246, 126,
    250, 98,  226, 230, 234, 106, 122, 102, 110, 114, 22,  158, 142, 146, 150,
    30,  154, 2,   130, 134, 138, 10,  26,  6,   14,  18,  53,  189, 173, 177,
    181, 61,  185, 33,  161, 165, 169, 41,  57,  37,  45,  49,  85,  221, 205,
    209, 213, 93,  217, 65,  193, 197, 201, 73,  89,  69,  77,  81,  119, 255,
    239, 243, 247, 127, 251, 99,  227, 231, 235, 107, 123, 103, 111, 115, 52,
    188, 172, 176, 180, 60,  184, 32,  160, 164, 168, 40,  56,  36,  44,  48,
    86,  222, 206, 210, 214, 94,  218, 66,  194, 198, 202, 74,  90,  70,  78,
    82};

int8_t Key[16], Pkey[128];
int P[8] = {3, 5, 0, 4, 2, 1, 7, 6};
int Smask[16] = {128, 64, 32, 16, 8, 4, 2, 1};

int8_t Block[16], Link[16], Temp[16], IV[16];
int8_t DFLTKY[16] = {1,   35,  69,  103, 137, 171, 205, 239,
                     254, 220, 186, 152, 118, 84,  50,  16};
/* DO NOT ALTER! => 0x0123456789abcdeffedcba9876543210 <=    */

/* I/O declarations    */
int IOedf, End, Once;
int8_t Last[16];

int step, ende, edio, ok, i;

void copy16(int8_t *from, int8_t *to) {
  int8_t *ep;
  ep = &to[16];
  while (to < ep)
    *to++ = *from++;
}

void put16(int8_t *block) {
  if (IOedf == DE)
    copy16(block, Last);
  else
    while (block < &block[16])
      putc(*block++, stdout);
}

void lucifer(int8_t *bytes) {
  int8_t *cp, *sp, *dp;
  int *sbs, tcb, val, j, i;
  int8_t *h0, *h1, *kc, *ks;

  h0 = &bytes[0]; /* the "lower" half     */
  h1 = &bytes[8]; /* the "upper" half     */
  kc = Pkey;
  ks = Key;

  for (i = 0; i < 16; i++) {
    tcb = *ks++;
    sbs = Smask;
    dp = Dps;

    for (j = 0; j < 8; j++) {
      /* nibbles are selected by the bits of ks    */
      if (tcb & *sbs++)
        val = TCB1[h1[j] & 0377];
      else
        val = TCB0[h1[j] & 0377];
      val ^= *kc++;

      /* fiddle bits in the "lower" half      */
      for (cp = h0, sp = &h0[8]; cp < sp; cp++)
        *cp ^= (val & *dp++);
    }

    /* swap (virtual) halves    */
    cp = h0;
    h0 = h1;
    h1 = cp;
  }

  /* REALLY swap halves    */
  dp = &bytes[0];
  cp = &bytes[8];
  for (sp = cp; dp < sp; dp++, cp++) {
    val = *dp;
    *dp = *cp;
    *cp = val;
  }
}

int Ecb(int dummy) {
  while (get16(Block) != EOF) {
    lucifer(Block);
    put16(Block);
  }
  return 0;
}

void xor16(int8_t *to, int8_t *with) {
  int8_t *ep;
  ep = &to[16];
  while (to < ep)
    *to++ ^= *with++;
}

int get16(char *input) {
  int i, j;
  if (End == 1)
    return (EOF); /* no more input    */

  for (i = 0; i < 16 && ((j = getc(stdin)) != EOF); i++)
    *input++ = j;

  if (IOedf == DE) { /* DECRYPTION    */
    if (i == 16 && (Once > 0))
      while (Last < &Last[16])
        putc(*Last++, stdout);
    else if (j == EOF) {
      End = 1;
      if (Once > 0) {
        if (i != 0)
          i = 0; /* no NULLs    */
        else {
          i = Last[15] & 037;
          if (i > 16)
            i = 0; /* huh? */
        }
        while (Last < &Last[16 - i])
          putc(*Last++, stdout);
      }
      return (EOF);
    }
  } else if (j == EOF) { /* ENCRYPTION    */
    End = 1;
    if (i == 0 && (IOedf == EN || (Once > 0))) {
      if (IOedf == EN && (Once > 0))
        putc('0', stdout);
      return (EOF);
    }
    for (j = i; j < 15; j++)
      *input++ = NULL;
    *input = 16 - i;
  }
  Once = 1;
  return (0);
}

void initio(int edf) {
  IOedf = edf;
  End = Once = 0;
}

void loadkey(int8_t *keystr, int edf) /* sets master key    */
{
  int8_t *ep, *cp, *pp;
  int kc, i, j;
  int8_t kk[16], pk[16];

  cp = kk;
  pp = pk;
  ep = &kk[16];

  while (cp < ep) {
    *cp++ = *keystr;
    for (*pp = i = 0; i < 8; i++)
      if (*keystr & Smask[i])
        *pp |= Smask[P[i]];
    keystr++;
    pp++;
  }

  cp = Key;
  pp = Pkey;
  kc = (edf == DE) ? 8 : 0;

  for (i = 0; i < 16; i++) {
    if (edf == DE)
      kc = (++kc) & 017;
    *cp++ = kk[kc];
    for (j = 0; j < 8; j++) {
      *pp++ = pk[kc];
      if (j < 7 || (edf == DE))
        kc = (++kc) & 017;
    }
  }
}

void getkey(char *aptr, int8_t *savp) {
  int8_t *store, *cp;
  int i;
  store = savp;

  /* copy aptr into savp; NULL aptr    */
  for (i = 0; i < 16 && (*aptr != NULL); i++) {
    *savp++ = toascii(*aptr);
    *aptr++ = NULL;
  }
  while (*aptr)
    *aptr++ = NULL;
  if (i == 0)
    savp++; /* aptr could have been NULL    */

  /* expand savp out to 16 bytes of "something" and encrypt it    */
  for (cp = store, savp--; i < 16;)
    store[i++] = (*cp++ + *savp++) & 0377;

  loadkey(store, edio);
  lucifer(store);

  return;
}

struct modes {
  char *name;
  int (*func)();
};
struct modes ModsOp[MODS] = {{"ECB", Ecb}};

int main(int argc, char **argv) {
  int (*xeqtr)();
  // int step, ende, edio, ok, i;
  char kv[16];

  argv++;
  argc--;
  for (step = 0; argc > 0; step++) {
    switch (step) {
    case 0: /* set en/de and/or default mode    */
      if (*argv[0] == '+' || *argv[0] == '-') {
        ende = (*argv[0] == '+') ? EN : DE;
        *argv[0]++ = NULL;
        if (*argv[0] == NULL) {
          xeqtr = Ecb; /* default mode */
          edio = ende;
          argv++;
          argc--;
          break;
        }
      } else
        ende = EN;

      for (i = ok = 0; i < MODS && !ok; i++) {
        if (strcmp(argv[0], ModsOp[i].name) == 0) {
          xeqtr = ModsOp[i].func;
          ok = 1;
        }
      }
      while (*argv[0])
        *argv[0]++ = NULL;
      argv++;
      argc--;

    /* falling through....    */
    case 1: /* get the key and IV, if needed and present    */
      if (strcmp(argv[0], "@") == 0)
        copy16(DFLTKY, kv);
      else
        getkey(argv[0], kv);
      argv++;
      argc--;

      /* if nothing left, but an IV needed, use the key    */
      if (argc == 0) {
        if (xeqtr != Ecb)
          copy16(kv, IV);
        break;
      } else if (xeqtr == Ecb) {
        fprintf(stderr, "Lucifer: ivec ignored.\n");
        while (*argv[0])
          *argv[0]++ = NULL;
        argv++;
        argc--;
        break;
      }

      else
        getkey(argv[0], IV);
      argv++;
      argc--;
      break;

    default:
      fprintf(stderr, "Lucifer: Programming error!\n");
      exit(1);
      break;
    } /* switch    */
  }   /* argument parsing    */

  initio(edio);
  loadkey(kv, ende);
  (*xeqtr)(ende); /* ta-da!  Take it away xeqtr!    */

  return EXIT_SUCCESS;
} /** end of main    */

Eigentlich wollte ich gern am Code Lucifer erklären, aber wie gesagt, der ist dafür ungeeignet, weil viel viel zu optimiert auf irgendwelche obskuren Maschinen und Compiler, daher hier mal kurz in Worten.

Generell ist Lucifer eine Familie von Blockchiffren, die auch die Vorgänger des DES stellt, das heißt, die Nachrichten werden in Blöcke( bei Lucifer 48, 32 oder 128 Bit) zerlegt, die dann einzeln mit einem Schlüssel der entsprechenden Längen 48, 64 oder 128Bit in 16 Runden verschlüsselt wird. Im Falle des ECB(Electronic Code Book) Modus findet keine zusätzliche Verknüpfung der Blöcke untereinander statt, das heißt die Blöcke A und B zu verschlüsseln und dann zu Tauschen hat das gleiche Ergebnis wie die Blöcke B und A zu verschlüsseln, während beim CBC(Cipher-Block-Chaining) eine XOR-Verknüpfung des Plaintextblocks mit dem vorherigen Ciphertextblock gemacht wird, um Bruteforce zu erschweren, da man sequentiell alles verschlüsseln muss, und nicht blockweise arbeiten kann.

Die Variante die in dem Code vorliegt ist die so genannte Sorkin-Variante. Sie benutzt wie der DES 16 Runden, hat anders als der aber keine initiale oder finale Permutationsphase, Block und Schlüssellänge sind bede 128 Bit groß.
Die Feistel-Funktion selber arbeitet in diesem Fall auf 64-Bit Halbblöcken mit 64-Bit Teilschlüsseln und einem Byte, das eine Swapoperation regelt : der Halbblock wird in 8 Bytes zerlegt, und jedes davon durchläuft einen "Swap"-Schritt : wenn das ICB(das "Swapbit") zu einem dieser 8 Bytes 0 ist, werden seine beiden Nibbles getauscht. Wenn es 1 ist nicht.
Im folgenden Schritt wird jedes Byte durch die beiden S-Boxen(Substitions-Boxen) gejagt wie folgt : es wird in beide Nibbles unterteilt, jedes Nibble kommt in eine der S-Boxen(die auch auf Nibbles arbeiten) die eine Lookup-Tabelle darstellen. Im vorliegenden Fall zum Beispiel ist TCB0 für das linke, TCB1 für das rechte Nibble zuständig. Die beiden Outputs werden zusammen gehängt und mit dem Rundenschlüssel mit XOR verknüpft. Anschließend wird in 2 Stufen die Bitreihenfolge permutiert : mit einer festen Maske (Dps heißt sie im Code) findet eine fixe Permutation innerhalb des Bytes statt, die zweite Stage mischt Bits zwischen den Bytes.

Die Rundenschlüsselgeneration ist der letzte Teil den man betrachten muss : Die 128 Bit des Hauptschlüssels werden in ein Shift-Register geladen. In jeder Runde werden die linken 64 Bits zum Rundenschlüssel, und die 8 ganz rechts zum ICB-Byte. Danach wird das Register 56 Bit nach links rotiert.

Die Entschlüsselung erfolgt mit dem Ciphertext als Input genauso.

Dass du nichts gefunden hast überrascht kaum : zum einen ist Lucifer kein Algorithmus genau genommen, sondern eine ganze Gruppe, deren bekanntestes Mitglied DES du bestimmt gefunden hättest. Zweitens sind Feistelchiffren alt, langsam und unsicher und bestenfalls noch aus historischem Interesse. Und Drittens gab es als sie modern waren das Internet noch nicht, weshalb es kaum Online-Publikationen darüber gibt.

Ich hoffe das hilft dir etwas weiter beim Verständnis,

mfg
 
Danke dir!

Hätte suchen bis ich schwarz werde, bis ich eine so gute Erklärung gefunden hätte wie Du sie mir gegeben hast.
Alle Achtung. Du hast mir sehr geholfen.
Ich konnte nur raus kriegen, das dieses Verfahren mit daran schuld war, das damals die Schlüssellänge auf 40 Bit
begrenzt wurde, Verschlüsselungstechniken unters amerikanische Waffengesetz gestellt wurden(hä???)
und das Gesetz 1991 wieder liberalisiert wurde.
Zum Thema Verschlüsselung von Nachrichten bin ich gekommen, da ich mich früher für Kurzwellenfunk interessiert
habe. Ab und zu, sehr selten, stößt man da auf Sender, welche Zahlenkolonnen von sich geben. Etwa "Neugen acht
acht vier drei...." und so weiter. Ein einziges mal, vor Jahrzehnten, sah ich übrigens auf einem Flohmarkt für
Funktechnik und Elektronik eine Enigma. Original Morsetasten der Wehrmacht auch. Mal sehen, was die vom Arbeitsamt
noch mit mir machen. Wenn Zeit übrig bleibt, werde ich mich da mal wieder reinschmeißen.

Daaaanke!!
 
Naja das Waffengesetz war e nicht genau, aber es gab Ausfuhrlimitierungen für starke Kryptographie, zeitweise gabs 3 Versionen : eine sichere für die Amis, eine unsichere für den Rest der Welt und eine noch unsicherere für die Franzosen( wo noch "Hinweise" eingebaut sein mussten für den Geheimdienst). Aus Gründen die ich bis heute nicht verstehe hat nie ein anderes Land der ersten Welt versucht, daraus Kapital zu ziehen indem sie selbst im großen Stil Krypto verkaufen.

Die erste Version von PGP kam übrigens als Buch nach Europa und wurde auf nem Feld in den Niederlanden abgetippt^^
 
Auch das war nie "im großen Stil" und vor allem auf entsprechendem Level(besonders von entsprechender Qualität), und für relativ beschränkte Einsatzbereiche(bei Kudelski zum Beispiel weiß ich aus dem Kopf nur von Systemen für Bezahlfernsehen, und die haben auch erst in den 90ern angefangen als das alles vorbei war mit den Cryptowars).
 
So weit ich weis, steht das bei einigen Ländern heute noch unter Strafe, wenn man "bessere Verschlüsselungssoftware" benutzt.
Bei PGP waren damals die letzten sicheren Versionen 2.6.3.i und 5.5.3.i das i bedeutete, das diese Versionen in Europa kompiliert
wurden und deshalb nicht unter dem amerikanischen Waffengesetz standen.
PGP verwendete bis zur Version 5.5.3i noch das sogenannte RSA und den neuen HDSS-Algorithmus. PGP wurde von Network Associates aufgekauft. Diese Firma ist Mitglied bei der Key-Recovery-Alliance. Diese verpflichten sich dazu, Ihre Programme so zu gestalten,
Das die Geheimdienstler mitlesen können. Wer Mitglied in diesen Verein ist, konnte man damals einigen Jahren unter www.kra.org lesen.
Mit der Freiheit ist es übrigens auch in der Schweiz nicht grenzenlos. Solche Bücher mit dem Titel "Die verbotene Wahrheit" sind dort
auf dem Index.
Zudem läuft das so weit ich weis so, das Satelliten, welche etwa alle 90 Minuten die Erde umkreisen, von Agenten angefunkt werden,
wenn sich dieser gerade über dem Einsatzgebiet befindet. Die dort abgespeicherte Nachricht wird dann abgesendet, wenn sich der
Satellit dann über dem Staat befindet, zu dem die Nachricht gesendet werden soll. Als ehemaliger Funkamateur weis ich, das schon
Verbindungen über den englischen Kanal(!!!) mit Laserstrahlen dazu benutzt wurden, um Daten auszutauschen.

Andere Arten der Nachrichtenübermittlung gibt es ja auch schon länger:
QUEST.JPG

Oben:
Eine im Kriegsjahr 1941 im NEW YORKER erschienene Anzeige. Nach dem Überraschungsangriff(???) der Japaner auf Pearl Harbor
geriet die Firma in Verdacht mittels dieser vorher erschienenen Anzeigen, in denen ein Würfelspiel angepriesen wurde, auf dieses
Datum hingewiesen zu haben. Sollten so Agenten das Datum erfahren?.

Quelle:
Rudolf Kippenhahn
„Verschlüsselte Botschaften“
Rowohlt Verlag GmbH
ISBN 3-498-03495-2

Um die Dechiffrierung etwas schwerer zu machen, kann man ja auch zum Beispiel Briefe an "Kumpels" in Mundart abfassen, oder
in Sütterlin schreiben:
IMAGE23.GIF


Oben: Aus einen Buch von Wilhelm Busch um 1898 gedruckt(mein Privatbesitz). Gerade ältere Bücher sind oft schwer zu bekommen.
Natürlich müsste man quasi zwei Exemplare besitzen um Nachrichten damit zu übermitteln. Im einfachsten Falle würde das so gehen:

Sehen wir uns einmal folgende Worte eines Mannes in einem Brief zu seinem „alten Freund“ an:

Hallo Anton!

Nach so vielen schönen Jahren in Berlin an der guten alten Spree sahen wir uns heute
Nach
mittag wieder.

Lesen wir nun die in Rot hervorgehobenen Buchstaben an, dann können Wir lesen:
Anschlag heute Nacht!

Die Möglichkeiten sind geradezu riesig, da ganz unauffällige gewöhnliche Alltagsgegenstände als
Datenträger herangezogen werden können. Es reicht schon eine Tageszeitung, eine als Zufall getarnte
Unterhaltung zweier CB-Funker, also der Wortlaut der Unterhaltung, oder man „leiht sich ganz Zufällig
eine Musikkassette“, eine Musik-CD, deren Inhalt digitalisiert in Form einer Abbilddatei als Datenträger
in Frage kommt. Oder nehmt irgendwelche Gebrauchsanweisungen von Medikamenten, Notenfolgen von
Musikstücken berühmter Komponisten deren Inhalt dann digitalisiert als Datenquelle zur Verschlüsselung
verwendet werden kann.
Ebenso eignen sich auch Lieder die auf dem Index stehen, das heißt, mit einem Jugendverbot belegt sind.
Jene sind weitestgehend aus den Regalen der Geschäfte Verschwunden. Besonders sind hier auch sogenannte
„Live-Mitschnitte“ von kleinen Bands und Kabarett-Künstlern geeignet, die oft in kleineren Ortschaften
ihre Show abliefern.

Kleine Ankdote:
Ich war in den Achzigern als Bundeswehrersatz beim Katastrophenschutz. Als wir einen Gastbesuch auf
dem Übungsplatz Grafenwöhr hatten, erzählte man uns das (zu derer Zeit) auffällig viel Tschechische
Bands in der dortigen Gegend gastierten.

Heute würde man das etwas anders machen denke ich. Mit einem Diktiergerät oder anderem technischen
Equipment unauffällig als Zuschauer aufgenommen, digitalisiert sind die Aufnahmen zum codieren geeignet.
Solche WAV-, oder MP3-Dateien kann man wegen darin enthaltener Aufnahmefehler zur Datenverschlüsselung
verwenden. Oder versucht einmal im Iran eine katholische Version der Bibel (neues Testament), oder
Zeitschriften mit erotischem Inhalt, bzw. Informationszeitschriften über sogenannte Clubs für Swinger zu
bekommen. Bezüglich des ersten Beispiels mit dem Brief eines Mannes an seinem „alten Freund“ aus Berlin
ist zu sagen, das über das Internet so ganz unauffällige Daten und Dateien ausgetauscht werden können,
ohne das jemand darin irgend eine Nachricht finden könnte. Logisch, die Nachricht ist ja im Datenträger
nicht vorhanden, die wird nur daraus geformt. Aber man braucht dafür einen besonderen Schlüssel. So
könnt selbst Reden von Politikern für fast jede Art der Nachrichtenübermittlung genutzt werden. Dann
lautet die Frage nicht, eine Stecknadel im Heuhaufen zu finden, sondern eine Stecknadel unter Milliarden
von Heuhaufen die einander identisch sind, zu finden.

Die Möglichkeiten sind geradezu riesig, da ganz unauffällige gewöhnliche Alltagsgegenstände als
Datenträger herangezogen werden können. Es reicht schon eine Tageszeitung, eine als Zufall getarnte
Unterhaltung zweier CB-Funker, also der Wortlaut der Unterhaltung, oder man „leiht sich ganz zufällig
eine Musik-CD, deren Inhalt digitalisiert in Form einer Abbilddatei als Datenträger in Frage kommt.
Oder nehmt irgendwelche Gebrauchsanweisungen von Medikamenten, Notenfolgen von
Musikstücken berühmter Komponisten deren Inhalt dann digitalisiert als Datenquelle zur Verschlüsselung
verwendet werden kann.
Ebenso eignen sich auch Lieder die auf dem Index stehen, das heißt, mit einem Jugendverbot belegt sind.
Jene sind weitestgehend aus den Regalen der Geschäfte Verschwunden. Besonders sind hier auch sogenannte
„Live-Mitschnitte“ von kleinen Bands und Kabarett-Künstlern geeignet, die oft in kleineren Ortschaften
ihre Show abliefern. Mit einem Diktiergerät oder anderem technischen Equipment unauffällig als Zuschauer
aufgenommen, digitalisiert sind die Aufnahmen zum codieren geeignet.
Solche WAV-, oder MP3-Dateien kann man wegen darin enthaltener Aufnahmefehler zur Datenverschlüsselung
verwenden. Oder versucht einmal im Iran eine katholische Version der Bibel (neues Testament), oder
Zeitschriften mit erotischem Inhalt, bzw. Informationszeitschriften über sogenannte Clubs für Swinger zu
bekommen. Bezüglich des ersten Beispiels mit dem Brief eines Mannes an seinem „alten Freund“ aus Berlin
ist zu sagen, das über das Internet so ganz unauffällige Daten und Dateien ausgetauscht werden können,
ohne das jemand darin irgend eine Nachricht finden könnte.

Logisch, die Nachricht ist ja im Datenträger nicht vorhanden, die wird nur daraus geformt. So wäre selbst bei
einer Durchsuchung nichts zu finden.!
Aber man braucht dafür einen besonderen Schlüssel. Im Prinzip reicht da schon ein Hex-Editor und eine ganz
gewöhnliche Datei. Ein Bild zum Beispiel.

So könnt selbst Reden von Politikern für fast jede Art der Nachrichtenübermittlung genutzt werden. Dann
lautet die Frage nicht, eine Stecknadel im Heuhaufen zu finden, sondern eine Stecknadel unter Milliarden
von Stecknadelhaufen die einander identisch sind, zu finden.

Digitale Verschlüsselung ist da wirklich nur ein Tropfen auf dem heißen Stein denke ich.

Nix fur ungut!
 
Zurück
Oben Unten