/*
 * Create a C program which is a des key definition for 
 * key represesting the output from desMakeKey with the passphrase supplied
 * by the user.
 */
#define _POSIX_SOURCE
#include <unistd.h>	/* close getlogin */
#include <stdlib.h>	/* atexit exit */
#include <stdio.h>
#include <string.h>
#include "des.h"
#include "desdefs.h"

extern int  optind;
extern char *optarg;

static char ident[] = 
" @(#) gendeskd.c   version 1.00 14-Jun-94 Copyright 1994 by Dave Barrett(barrett@asgard.cs.Colorado.EDU)\n";
static char RCSid[] = 
   " @(#) gendeskd.c  RCS: $Revision: 1.4 $ $Date: 94/06/14 10:05:05 $\n";

char *progName;
int  debug = 0;
int  verbose = 0;

#if defined(__STDC__) || defined(__cplusplus)
extern int getkey(char *, char *, unsigned);
#else
extern int getkey();
#endif

typedef unsigned char block[DES_BLOCKSIZE];

/*
 * Keys which could accidently reproduce the plaintext with multiple-encryption
 */
block badKeys[16] = {
   { 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00 },
   { 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0 }, 
   { 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e },
   { 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe }, 
   { 0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e },
   { 0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0 }, 
   { 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe },
   { 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00 },
   { 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e },
   { 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00 }, 
   { 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe },
   { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0 }, 
   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },	/* self-dual */
   { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },	/* self-dual */
   { 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0 },	/* self-dual */
   { 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e },	/* self-dual */
};

/*
 * Return nonzero if the key is one of the well-known "weak" keys (FIPS Pub 74)
 */
int weakKey(keybits)
   char *keybits;
{
   register block *keyp = &(badKeys[0]);	/* common compiler bug here */
   register unsigned count = sizeof(badKeys) / sizeof(badKeys[0]);
   register unsigned i;

   do {
      for (i = 0; i < DES_BLOCKSIZE; i++) {
	 if ((((*keyp)[i] ^ keybits[i]) & 0xfe) != 0) goto notfound;
      }
      break;
notfound:
      keyp++;
   } while (--count != 0);
   return count;
}

/*
 * Because we are using CFB, we always encrypt.  Since we'd like to be
 * able to run the chips in either mode, perhaps CBC would be better.
 * If CBC is used though, the last block must be handled in OFB mode.  Sigh.
 *
 * Returns:  
 *  -1 - out of memory (program exits, and error reported)
 *   0 - success
 *   1 - key is a weak key
 */
int setKey(kp, keybits, keystr, mode)
   register keyType *kp;
   char *keybits, *keystr;
   int  mode;
{
   register int res;

   if (keystr != (char *) 0) {
      desKey(keybits, keystr, ' ');		/* space padded */
      memset(keystr, '\0', strlen(keystr));	/* blank out key asap */
   }

   res = weakKey(keybits);

   desMakeKey(kp, keybits, DES_BLOCKSIZE, mode); /* 0 means encrypt mode */
   memset(keybits, '\0', DES_BLOCKSIZE);	 /* zero out bits asap */

   if (*kp == (keyType) 0) {
      fprintf(stderr, "%s: couldn't allocate memory for encryption key\n",
	 progName);
      exit(1);
   }
   return res;
}

#define KEYBUFLEN 255

int main(argc, argv)
   int argc;
   char *argv[];
{
   int 	    i, ch, j, size;
   unsigned char *uchp;
   int      keystrlen = 0;
   char	    *chp;
   char     keybuf[KEYBUFLEN], keybits[DES_BLOCKSIZE];
   keyType  key = 0;

   progName = *argv;
   if ((chp = strrchr(progName, '/')) != (char *) 0) progName = chp + 1;

   while ((ch = getopt(argc, argv, "-d")) != EOF) switch (ch) {
   case 'd':
      debug++;
      break;
   default:
      fprintf(stderr, "usage: %s [-d]\n", progName);
      exit(1);
   }
   argc -= optind;
   argv += optind;

   keystrlen = getkey("Input Default UserFile PassPhrase: ", 
       keybuf, KEYBUFLEN-1);
   if (keystrlen == 0) {
      fprintf(stderr, "%s: must specify a non-null key\n", progName);
      return 1;
   }
   keybuf[keystrlen] = '\0';
   i = setKey(&key, keybits, keybuf, 0);
   if (i) {
      fprintf(stderr, "%s: weak key selected, use another.\n", progName);
      return 1;
   }

   size = (sizeof (desKeyType)) - (sizeof (unsigned long));
   printf("struct { unsigned long align; unsigned char bytes[%u]; }\n",
      size);
   printf ("defaultKey = { 0x%lx, {", * (unsigned long *) key);
   j = 0;
   uchp = (unsigned char *) &((unsigned long *) key)[1];
   for (i = 0; i < size; i++) {
      if (i % 14 == 0) {
	 printf("\n   ");
      }
      printf("0x%.2x", *uchp++);
      if (i != size) {
	 printf(",");
      }
   }
   printf("\n}};\n");

   return 0;
}
