_C PROGRAMMING COLUMN_ by Al Stevens [LISTING ONE] /* -------------- des.h ---------------- */ /* Header file for Data Encryption Standard algorithms */ /* -------------- prototypes ------------------- */ void initkey(char *key); void encrypt(char *blk); void decrypt(char *blk); /* ----------- tables ------------ */ extern unsigned char Pmask[]; extern unsigned char IPtbl[]; extern unsigned char Etbl[]; extern unsigned char Ptbl[]; extern unsigned char stbl[8][4][16]; extern unsigned char PC1tbl[]; extern unsigned char PC2tbl[]; extern unsigned char ex6[8][2][4]; [LISTING TWO] /* Data Encryption Standard front end * Usage: des [-e -d] keyvalue infile outfile */ #include #include #include "des.h" static void setparity(char *key); void main(int argc, char *argv[]) { FILE *fi, *fo; char key[9]; char blk[8]; if (argc > 4) { strncpy(key, argv[2], 8); key[8] = '\0'; setparity(key); initkey(key); if ((fi = fopen(argv[3], "rb")) != NULL) { if ((fo = fopen(argv[4], "wb")) != NULL) { while (!feof(fi)) { memset(blk, 0, 8); if (fread(blk, 1, 8, fi) != 0) { if (stricmp(argv[1], "-e") == 0) encrypt(blk); else decrypt(blk); fwrite(blk, 1, 8, fo); } } fclose(fo); } fclose(fi); } } else printf("\nUsage: des [-e -d] keyvalue infile outfile"); } /* -------- make a character odd parity ---------- */ static unsigned char oddparity(unsigned char s) { unsigned char c = s | 0x80; while (s) { if (s & 1) c ^= 0x80; s = (s >> 1) & 0x7f; } return c; } /* ------ make a key odd parity ------- */ void setparity(char *key) { int i; for (i = 0; i < 8; i++) *(key+i) = oddparity(*(key+i)); } [LISTING THREE] /* ---------------------- des.c --------------------------- */ /* Functions and tables for DES encryption and decryption */ #include #include #include "des.h" /* -------- 48-bit key permutation ------- */ struct ks { char ki[6]; }; /* ------- two halves of a 64-bit data block ------- */ struct LR { long L; long R; }; static struct ks keys[16]; static void rotate(unsigned char *c, int n); static int fourbits(struct ks, int s); static int sixbits(struct ks, int s); static void inverse_permute(long *op,long *ip,long *tbl,int n); static void permute(long *op, long *ip, long *tbl, int n); static long f(long blk, struct ks ky); static struct ks KS(int n, char *key); static void swapbyte(long *l); /* ----------- initialize the key -------------- */ void initkey(char *key) { int i; for (i = 0; i < 16; i++) keys[i] = KS(i, key); } /* ----------- encrypt an 8-byte block ------------ */ void encrypt(char *blk) { struct LR ip, op; long temp; int n; memcpy(&ip, blk, sizeof(struct LR)); /* -------- initial permuation -------- */ permute(&op.L, &ip.L, (long *)IPtbl, 64); swapbyte(&op.L); swapbyte(&op.R); /* ------ swap and key iterations ----- */ for (n = 0; n < 16; n++) { temp = op.R; op.R = op.L ^ f(op.R, keys[n]); op.L = temp; } ip.R = op.L; ip.L = op.R; swapbyte(&ip.L); swapbyte(&ip.R); /* ----- inverse initial permutation ---- */ inverse_permute(&op.L, &ip.L, (long *)IPtbl, 64); memcpy(blk, &op, sizeof(struct LR)); } /* ----------- decrypt an 8-byte block ------------ */ void decrypt(char *blk) { struct LR ip, op; long temp; int n; memcpy(&ip, blk, sizeof(struct LR)); /* -------- initial permuation -------- */ permute(&op.L, &ip.L, (long *)IPtbl, 64); swapbyte(&op.L); swapbyte(&op.R); ip.R = op.L; ip.L = op.R; /* ------ swap and key iterations ----- */ for (n = 15; n >= 0; --n) { temp = ip.L; ip.L = ip.R ^ f(ip.L, keys[n]); ip.R = temp; } swapbyte(&ip.L); swapbyte(&ip.R); /* ----- inverse initial permuation ---- */ inverse_permute(&op.L, &ip.L, (long *)IPtbl, 64); memcpy(blk, &op, sizeof(struct LR)); } /* ------- inverse permute a 64-bit string ------- */ static void inverse_permute(long *op,long *ip,long *tbl,int n) { int i; long *pt = (long *)Pmask; *op = *(op+1) = 0; for (i = 0; i < n; i++) { if ((*ip & *pt) || (*(ip+1) & *(pt+1))) { *op |= *tbl; *(op+1) |= *(tbl+1); } tbl += 2; pt += 2; } } /* ------- permute a 64-bit string ------- */ static void permute(long *op, long *ip, long *tbl, int n) { int i; long *pt = (long *)Pmask; *op = *(op+1) = 0; for (i = 0; i < n; i++) { if ((*ip & *tbl) || (*(ip+1) & *(tbl+1))) { *op |= *pt; *(op+1) |= *(pt+1); } tbl += 2; pt += 2; } } /* ----- Key dependent computation function f(R,K) ----- */ static long f(long blk, struct ks key) { struct LR ir; struct LR or; int i; union { struct LR f; struct ks kn; } tr = {0,0}, kr = {0,0}; ir.L = blk; ir.R = 0; kr.kn = key; swapbyte(&ir.L); swapbyte(&ir.R); permute(&tr.f.L, &ir.L, (long *)Etbl, 48); tr.f.L ^= kr.f.L; tr.f.R ^= kr.f.R; /* the DES S function: ir.L = S(tr.kn); */ ir.L = 0; for (i = 0; i < 8; i++) { long four = fourbits(tr.kn, i); ir.L |= four << ((7-i) * 4); } swapbyte(&ir.L); ir.R = or.R = 0; permute(&or.L, &ir.L, (long *)Ptbl, 32); swapbyte(&or.L); swapbyte(&or.R); return or.L; } /* ------- extract a 4-bit stream from the block/key ------- */ static int fourbits(struct ks k, int s) { int i = sixbits(k, s); int row, col; row = ((i >> 4) & 2) | (i & 1); col = (i >> 1) & 0xf; return stbl[s][row][col]; } /* ---- extract 6-bit stream fr pos s of the block/key ---- */ static int sixbits(struct ks k, int s) { int op = 0; int n = (s); int i; for (i = 0; i < 2; i++) { int off = ex6[n][i][0]; unsigned char c = k.ki[off]; c >>= ex6[n][i][1]; c <<= ex6[n][i][2]; c &= ex6[n][i][3]; op |= c; } return op; } /* ---------- DES Key Schedule (KS) function ----------- */ static struct ks KS(int n, char *key) { static unsigned char cd[8]; static int its[] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1}; union { struct ks kn; struct LR filler; } result; if (n == 0) permute((long *)cd, (long *) key, (long *)PC1tbl, 64); rotate(cd, its[n]); rotate(cd+4, its[n]); permute(&result.filler.L, (long *)cd, (long *)PC2tbl, 48); return result.kn; } /* rotate a 4-byte string n (1 or 2) positions to the left */ static void rotate(unsigned char *c, int n) { int i; unsigned j, k; k = ((*c) & 255) >> (8 - n); for (i = 3; i >= 0; --i) { j = ((*(c+i) << n) + k); k = (j >> 8) & 255; *(c+i) = j & 255; } if (n == 2) *(c+3) = (*(c+3) & 0xc0) | ((*(c+3) << 4) & 0x30); else *(c+3) = (*(c+3) & 0xe0) | ((*(c+3) << 4) & 0x10); } /* -------- swap bytes in a long integer ---------- */ static void swapbyte(long *l) { char *cp = (char *) l; char t = *(cp+3); *(cp+3) = *cp; *cp = t; t = *(cp+2); *(cp+2) = *(cp+1); *(cp+1) = t; } [LISTING FOUR] /* --------------- tables.c --------------- */ /* tables for the DES algorithm */ /* --------- macros to define a permutation table ---------- */ #define ps(n) ((unsigned char)(0x80 >> (n-1))) #define b(n,r) ((n>r||n>, <<, & */ /* ---- s = 8 ---- */ 0,2,0,0x3f, 0,2,0,0x3f, /* ---- s = 7 ---- */ 0,0,4,0x30, 1,4,0,0x0f, /* ---- s = 6 ---- */ 1,0,2,0x3c, 2,6,0,0x03, /* ---- s = 5 ---- */ 2,0,0,0x3f, 2,0,0,0x3f, /* ---- s = 4 ---- */ 3,2,0,0x3f, 3,2,0,0x3f, /* ---- s = 3 ---- */ 3,0,4,0x30, 4,4,0,0x0f, /* ---- s = 2 ---- */ 4,0,2,0x3c, 5,6,0,0x03, /* ---- s = 1 ---- */ 5,0,0,0x3f, 5,0,0,0x3f }; [LISTING FIVE] /* ---------------------- encrypto.c ----------------------- */ /* Single key text file encryption * Usage: encrypto keyvalue infile outfile */ #include #include #include #define FALSE 0 #define TRUE !FALSE static void charout(FILE *fo, char prev, int runct, int last); static void encrypt(FILE *fo, char ch, int last); static char *key = NULL; static int keylen; static char *cipher = NULL; static int clen = 0; void main(int argc, char *argv[]) { FILE *fi, *fo; char ch, prev = 0; int runct = 0; if (argc > 3) { /* --- alloc memory for the key and cipher blocks --- */ keylen = strlen(argv[1]); cipher = malloc(keylen+1); key = malloc(keylen+1); strcpy(key, argv[1]); if (cipher != NULL && key != NULL && (fi = fopen(argv[2], "rb")) != NULL) { if ((fo = fopen(argv[3], "wb")) != NULL) { while ((ch = fgetc(fi)) != EOF) { /* ---- validate ASCII input ---- */ if (ch & 128) { fprintf(stderr, "%s is not ASCII", argv[2]); fclose(fi); fclose(fo); remove(argv[3]); free(cipher); free(key); exit(1); } /* --- test for duplicate bytes --- */ if (ch == prev && runct < 127) runct++; else { charout(fo, prev, runct, FALSE); prev = ch; runct = 0; } } charout(fo, prev, runct, TRUE); fclose(fo); } fclose(fi); } if (cipher) free(cipher); if (key) free(key); } } /* ------- send an encrypted byte to the output file ------ */ static void charout(FILE *fo, char prev, int runct, int last) { if (runct) encrypt(fo, (runct+1) | 0x80, last); if (prev) encrypt(fo, prev, last); } /* ---------- encrypt a byte and write it ---------- */ static void encrypt(FILE *fo, char ch, int last) { *(cipher+clen) = ch ^ *(key+clen); clen++; if (last || clen == keylen) { /* ----- cipher buffer full or last buffer ----- */ int i; for (i = 0; i < clen; i++) fputc(*(cipher+i), fo); clen = 0; } } [LISTING SIX] /* ---------------------- decrypto.c ----------------------- */ /* Single key text file decryption * Usage: decrypto keyvalue infile outfile */ #include #include #include #include static char decrypt(FILE *); static char *key = NULL; static int keylen; static char *cipher = NULL; static int clen = 0, coff = 0; void main(int argc, char *argv[]) { FILE *fi, *fo; char ch; int runct = 0; if (argc > 3) { /* --- alloc memory for the key and cipher blocks --- */ keylen = strlen(argv[1]); cipher = malloc(keylen+1); key = malloc(keylen+1); strcpy(key, argv[1]); if (cipher != NULL && key != NULL && (fi = fopen(argv[2], "rb")) != NULL) { if ((fo = fopen(argv[3], "wb")) != NULL) { while ((ch = decrypt(fi)) != EOF) { /* --- test for run length counter --- */ if (ch & 0x80) runct = ch & 0x7f; else { if (runct) /* --- run count: dup the byte -- */ while (--runct) fputc(ch, fo); fputc(ch, fo); } } fclose(fo); } fclose(fi); } if (cipher) free(cipher); if (key) free(key); } } /* ------ decryption function: returns decrypted byte ----- */ static char decrypt(FILE *fi) { char ch = EOF; if (clen == 0) { /* ---- read a block of encrypted bytes ----- */ clen = fread(cipher, 1, keylen, fi); coff = 0; } if (clen > 0) { /* --- decrypt the next byte in the input block --- */ ch = *(cipher+coff) ^ *(key+coff); coff++; --clen; } return ch; }