home *** CD-ROM | disk | FTP | other *** search
-
- /* --- C ---
- ************************************************************************
- *
- * Filename : des.c
- * Description : Crypting routines
- * Part of : SECMPEG
- *
- * Version : 1.0
- * Language : C
- * For machine : SunOS 4.1.x, INTERACTIVE Unix 2.2.1, Linux, MS-DOS
- * Compile as : see Makefile
- *
- * Authors : Juergen Meyer, Frank Gadegast
- * Contact : jm@cs.tu-berlin.de, phade@cs.tu-berlin.de
- *
- ************************************************************************
- */
-
- #include <stdio.h>
- #include <fcntl.h>
- #include <string.h>
- #include "defs.h"
- #include "des.h"
-
- /* ------ DEFINES ------ */
-
- /*
- #define LITTLE_ENDIAN
- */
- #ifdef DOS
- #define bcopy(src,dest,size) memcpy(dest,src,size)
- #define bzero(dest,size) memset(dest,0,size)
- #endif
-
- /* ------ PUBLIC ------ */
-
- int desinit();
- void desdone();
- int Encrypt(char *,unsigned long);
- int Decrypt(char *,unsigned long);
- char *string_to_key(char *);
- void setdeskey(char *);
-
- /* ------ PRIVAT ------ */
-
- static void permute(char *,char [16][16][8],char *);
- static void round(int,unsigned long *);
- static long f(unsigned long,unsigned char [8]);
- static void perminit(char [16][16][8],char [64]);
- static int spinit();
- static void endes(char *);
- static void dedes(char *);
- static void endes_cbc(char *);
- static void endes_ecb(char *);
- static void dedes_cbc(char *);
- static void dedes_ecb(char *);
-
- #ifdef LITTLE_ENDIAN
- static unsigned long byteswap(unsigned long);
- #endif
-
-
-
-
- int Encrypt(char *buffer,unsigned long len)
- {
- unsigned long nblocks;
- char *block;
-
- block = buffer;
-
- nblocks = len / 8;
-
- while(nblocks--)
- {
- endes_ecb(block);
- block += 8;
- }
- return(1);
- }
-
- int Decrypt(char *buffer,unsigned long len)
- {
- unsigned long nblocks;
- char *block;
-
- block = buffer;
-
- nblocks = len / 8;
- while(nblocks--)
- {
- dedes_ecb(block);
- block += 8;
- }
- return(1);
- }
-
-
- char *string_to_key(char *asckey)
- {
- register char *p;
- register int i;
- char k1[8], k2[8];
- char *key = NULL;
-
- if (!(key = (char *)malloc(8)))
- {
- fprintf(stderr,"key\n");
- return(NULL);
- }
- if (DESINIT == FALSE) {
- if (desinit(0) < 0)
- {
- fprintf(stderr,"desinit failed\n");
- free(key);
- return(NULL);
- }
-
- DESINIT = TRUE;
- }
-
-
- for (i = 0; i < 8; i++)
- {
- k1[i] = k2[i] = 0;
- }
- for (i = 0, p = asckey; *p; p++, i++)
- {
- i %= 8;
- k1[i] |= *p;
- k2[i] |= *p;
- setdeskey((char *)des_hash_key1);
- endes(k1);
- setdeskey((char *)des_hash_key2);
- endes(k2);
- }
- for (i = 0; i < 8; i++)
- {
- key[i] = k1[i] ^ k2[i];
- }
- return(key);
- }
-
-
- int desinit()
- {
- #ifdef DEBUG
- fprintf(stderr," desinit \n");
- #endif
- if(sp != NULL)
- {
- /* Already initialized */
- return 0;
- }
-
- if((sp = (long (*)[64])malloc(sizeof(long) * 8 * 64)) == NULL)
- {
- return -1;
- }
- spinit();
- kn = (unsigned char (*)[8])malloc(sizeof(char) * 8 * 16);
- if(kn == NULL){
- free((char *)sp);
- return -1;
- }
-
- iperm = (char (*)[16][8])malloc(sizeof(char) * 16 * 16 * 8);
- if(iperm == NULL){
- free((char *)sp);
- free((char *)kn);
- return -1;
- }
- perminit(iperm,ip);
-
- fperm = (char (*)[16][8])malloc(sizeof(char) * 16 * 16 * 8);
- if(fperm == NULL)
- {
- free((char *)sp);
- free((char *)kn);
- free((char *)iperm);
- return -1;
- }
- perminit(fperm,fp);
- DESINIT = TRUE;
- return 0;
- }
-
- /* Free up storage used by DES */
-
- void desdone()
- {
- if(sp == NULL)
- return; /* Already done */
-
- free((char *)sp);
- free((char *)kn);
- if(iperm != NULL)
- free((char *)iperm);
- if(fperm != NULL)
- free((char *)fperm);
-
- sp = NULL;
- iperm = NULL;
- fperm = NULL;
- kn = NULL;
- }
-
-
-
- void get8(char *cp)
- {
- int i,t;
-
- for(i=0;i<8;i++){
- scanf("%2x",&t);
- if(feof(stdin))
- exit(0);
- *cp++ = t;
- }
- }
- void put8(char *cp)
- {
- int i;
-
- for(i=0;i<8;i++){
- printf("%02x",*cp++ & 0xff);
- }
- }
-
-
-
- /* Set key (initialize key schedule array) */
-
- void setdeskey(char *key) /* 64 bits (will use only 56) */
- {
- char pc1m[56]; /* place to modify pc1 into */
- char pcr[56]; /* place to rotate pc1 into */
- register int i,j,l;
- int m;
-
- /* Clear key schedule */
- for (i=0; i<16; i++)
- for (j=0; j<8; j++)
- kn[i][j]=0;
-
- for (j=0; j<56; j++) { /* convert pc1 to bits of key */
- l=pc1[j]-1; /* integer bit location */
- m = l & 07; /* find bit */
- pc1m[j]=(key[l>>3] & /* find which key byte l is in */
- bytebit[m]) /* and which bit of that byte */
- ? 1 : 0; /* and store 1-bit result */
- }
- for (i=0; i<16; i++) { /* key chunk for each iteration */
- for (j=0; j<56; j++) /* rotate pc1 the right amount */
- pcr[j] = pc1m[(l=j+totrot[i])<(j<28? 28 : 56) ? l: l-28];
- /* rotate left and right halves independently */
- for (j=0; j<48; j++){ /* select bits individually */
- /* check bit that goes to kn[j] */
- if (pcr[pc2[j]-1]){
- /* mask it in if it's there */
- l= j % 6;
- kn[i][j/6] |= bytebit[l] >> 2;
- }
- }
- }
- }
-
- /* In-place encryption of 64-bit block */
- static void endes(char *block)
- {
- register int i;
- unsigned long work[2]; /* Working data storage */
- long tmp;
-
- permute(block,iperm,(char *)work); /* Initial Permutation */
- #ifdef LITTLE_ENDIAN
- work[0] = byteswap(work[0]);
- work[1] = byteswap(work[1]);
- #endif
-
- /* Do the 16 rounds */
- for (i=0; i<16; i++)
- round(i,work);
-
- /* Left/right half swap */
- tmp = work[0];
- work[0] = work[1];
- work[1] = tmp;
-
- #ifdef LITTLE_ENDIAN
- work[0] = byteswap(work[0]);
- work[1] = byteswap(work[1]);
- #endif
- permute((char *)work,fperm,block); /* Inverse initial permutation */
- }
-
-
- /* In-place decryption of 64-bit block */
- static void dedes(char *block)
- {
- register int i;
- unsigned long work[2]; /* Working data storage */
- long tmp;
-
- permute(block,iperm,(char *)work); /* Initial permutation */
-
- #ifdef LITTLE_ENDIAN
- work[0] = byteswap(work[0]);
- work[1] = byteswap(work[1]);
- #endif
-
- /* Left/right half swap */
- tmp = work[0];
- work[0] = work[1];
- work[1] = tmp;
-
- /* Do the 16 rounds in reverse order */
- for (i=15; i >= 0; i--)
- round(i,work);
-
- #ifdef LITTLE_ENDIAN
- work[0] = byteswap(work[0]);
- work[1] = byteswap(work[1]);
- #endif
-
- permute((char *)work,fperm,block); /* Inverse initial permutation */
- }
-
- /* Permute inblock with perm */
- static void permute(char *inblock,char perm[16][16][8],char *outblock)
- {
- register int i,j;
- register char *ib, *ob; /* ptr to input or output block */
- register char *p, *q;
-
- if(perm == NULL){
- /* No permutation, just copy */
- for(i=8; i!=0; i--)
- *outblock++ = *inblock++;
- return;
- }
- /* Clear output block */
- for (i=8, ob = outblock; i != 0; i--)
- *ob++ = 0;
-
- ib = inblock;
- for (j = 0; j < 16; j += 2, ib++) { /* for each input nibble */
- ob = outblock;
- p = perm[j][(*ib >> 4) & 017];
- q = perm[j + 1][*ib & 017];
- for (i = 8; i != 0; i--){ /* and each output byte */
- *ob++ |= *p++ | *q++; /* OR the masks together*/
- }
- }
- }
-
- /* Do one DES cipher round */
- static void round(int num,unsigned long *block)
- {
- long f();
-
- /* The rounds are numbered from 0 to 15. On even rounds
- * the right half is fed to f() and the result exclusive-ORs
- * the left half; on odd rounds the reverse is done.
- */
- if(num & 1){
- block[1] ^= f(block[0],kn[num]);
- } else {
- block[0] ^= f(block[1],kn[num]);
- }
- }
- /* The nonlinear function f(r,k), the heart of DES */
- static long f(unsigned long r,unsigned char subkey[8])
- {
- register unsigned long rval,rt;
- #ifdef DES_DEBUG
- unsigned char *cp;
- int i;
-
- printf("f(%08lx, %02x %02x %02x %02x %02x %02x %02x %02x) = ",
- r,
- subkey[0], subkey[1], subkey[2],
- subkey[3], subkey[4], subkey[5],
- subkey[6], subkey[7]);
- #endif
- /* Run E(R) ^ K through the combined S & P boxes
- * This code takes advantage of a convenient regularity in
- * E, namely that each group of 6 bits in E(R) feeding
- * a single S-box is a contiguous segment of R.
- */
- rt = (r >> 1) | ((r & 1) ? 0x80000000 : 0);
- rval = 0;
- rval |= sp[0][((rt >> 26) ^ *subkey++) & 0x3f];
- rval |= sp[1][((rt >> 22) ^ *subkey++) & 0x3f];
- rval |= sp[2][((rt >> 18) ^ *subkey++) & 0x3f];
- rval |= sp[3][((rt >> 14) ^ *subkey++) & 0x3f];
- rval |= sp[4][((rt >> 10) ^ *subkey++) & 0x3f];
- rval |= sp[5][((rt >> 6) ^ *subkey++) & 0x3f];
- rval |= sp[6][((rt >> 2) ^ *subkey++) & 0x3f];
- rt = (r << 1) | ((r & 0x80000000) ? 1 : 0);
- rval |= sp[7][(rt ^ *subkey) & 0x3f];
- #ifdef DES_DEBUG
- fprintf(stderr," %08lx\n",rval);
- #endif
- return rval;
- }
- /* initialize a perm array */
- static void perminit(char perm[16][16][8],char p[64])
- {
- register int l, j, k;
- int i,m;
-
- /* Clear the permutation array */
- for (i=0; i<16; i++)
- for (j=0; j<16; j++)
- for (k=0; k<8; k++)
- perm[i][j][k]=0;
-
- for (i=0; i<16; i++) /* each input nibble position */
- for (j = 0; j < 16; j++)/* each possible input nibble */
- for (k = 0; k < 64; k++)/* each output bit position */
- { l = p[k] - 1; /* where does this bit come from*/
- if ((l >> 2) != i) /* does it come from input posn?*/
- continue; /* if not, bit k is 0 */
- if (!(j & nibblebit[l & 3]))
- continue; /* any such bit in input? */
- m = k & 07; /* which bit is this in the byte*/
- perm[i][j][k>>3] |= bytebit[m];
- }
- }
-
- /* Initialize the lookup table for the combined S and P boxes */
- static int spinit()
- {
- char pbox[32];
- int p,i,s,j,rowcol;
- long val;
-
- /* Compute pbox, the inverse of p32i.
- * This is easier to work with
- */
- for(p=0;p<32;p++){
- for(i=0;i<32;i++){
- if(p32i[i]-1 == p){
- pbox[p] = i;
- break;
- }
- }
- }
- for(s = 0; s < 8; s++){ /* For each S-box */
- for(i=0; i<64; i++){ /* For each possible input */
- val = 0;
- /* The row number is formed from the first and last
- * bits; the column number is from the middle 4
- */
- rowcol = (i & 32) | ((i & 1) ? 16 : 0) | ((i >> 1) & 0xf);
- for(j=0;j<4;j++){ /* For each output bit */
- if(si[s][rowcol] & (8 >> j)){
- val |= 1L << (31 - pbox[4*s + j]);
- }
- }
- sp[s][i] = val;
-
- #ifdef DES_DEBUG
- fprintf(stderr,"sp[%d][%2d] = %08lx\n",s,i,sp[s][i]);
- #endif
- }
- }
- return(0);
- }
-
-
- #ifdef LITTLE_ENDIAN
- /* Byte swap a long */
- static unsigned long byteswap(unsigned long x)
- {
- register char *cp,tmp;
-
- cp = (char *)&x;
- tmp = cp[3];
- cp[3] = cp[0];
- cp[0] = tmp;
-
- tmp = cp[2];
- cp[2] = cp[1];
- cp[1] = tmp;
-
- return x;
- }
- #endif
-
-
-
- static void endes_cbc(char *outblock)
- {
- register char *cp, *cp1;
- register int i;
-
- /* CBC mode; chain in last cipher word */
-
- cp = outblock;
- cp1 = iv;
- for (i = 8; i != 0; i--) *cp++ ^= *cp1++;
-
- endes_ecb(outblock); /* in-block encryption */
-
- /* Save outblockgoing ciphertext for chain */
-
- bcopy(outblock, iv, 8);
- }
-
- static void endes_ecb(char *outblock)
- {
- endes(outblock);
- return;
- }
-
- static void dedes_cbc(char *outblock)
- {
- char ivtmp[8];
- register char *cp, *cp1;
- register int i;
-
-
- /* Save incoming ciphertext for chain */
-
- bcopy(outblock, ivtmp, 8);
-
- dedes_ecb(outblock); /* in-block decryption */
-
- /* Unchain block, save ciphertext for next */
-
- cp = outblock;
- cp1 = iv;
- for (i = 8; i != 0; i--)
- *cp++ ^= *cp1++;
- bcopy(ivtmp, iv, 8);
- }
-
- static void dedes_ecb(char *outblock)
- {
- dedes(outblock);
- return;
- }
-
-
-