/*
 * $Source: /afs/sipb.mit.edu/project/sipb-athena/repository/src/kerberos/lib/des/make_key_sched.c,v $
 * $Author: ghudson $
 *
 * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
 * of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 *
 * make_key_sched() pulled out of key_sched.c so it can be replaced by 
 * an alternate version, while still allowing des_key_sched() to do the
 * high level key quality checks.
 *
 *
 * This routine computes the DES key schedule given a key.  The
 * permutations and shifts have been done at compile time, resulting
 * in a direct one-step mapping from the input key to the key
 * schedule.
 *
 * Also checks parity and weak keys.
 *
 * Watch out for the subscripts -- most effectively start at 1 instead
 * of at zero.  Maybe some bugs in that area.
 *
 * DON'T change the data types for arrays and such, or it will either
 * break or run slower.  This was optimized for Uvax2.
 *
 * In case the user wants to cache the computed key schedule, it is
 * passed as an arg.  Also implies that caller has explicit control
 * over zeroing both the key schedule and the key.
 *
 * All registers labeled imply Vax using the Ultrix or 4.2bsd compiler.
 *
 * Originally written 6/85 by Steve Miller, MIT Project Athena.
 */

#ifndef	lint
static char rcsid_key_sched_c[] =
"$Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/kerberos/lib/des/make_key_sched.c,v 1.1 1996/06/02 07:36:59 ghudson Exp $";
#endif	lint

#include <mit-copyright.h>
#include "des_internal.h"
#include <stdio.h>

#include "des.h"
#include "key_perm.h"

extern int des_debug;
extern rev_swap_bit_pos_0();

typedef char key[64];
/* the following are really void but cc86 doesnt allow it */
extern int des_make_key_sched();
static int int_make_key_sched();

int
make_key_sched(k,schedule)
    register des_cblock k;
    des_key_schedule schedule;
{
    /* better pass 8 bytes, length not checked here */

    register int i, j, n;
    register unsigned int temp;
    static key k_char;
    register char *p_char = k_char;
    i = 8;
    n = 0;

#ifdef DEBUG
    if (des_debug)
	fprintf(stderr,"\n\ninput key, left to right = ");
#endif

    do {
	/* get next input key byte */
#ifdef DEBUG
	if (des_debug)
	    fprintf(stderr,"%02x ",*k & 0xff);
#endif
	temp = (unsigned int) ((unsigned char) *k++);
	j = 8;

	do {
	    *p_char++ = (int) temp & 01;
	    temp = temp >> 1;
	} while (--j > 0);
    } while (--i > 0);

#ifdef DEBUG
    if (des_debug) {
	p_char = k_char;
	fprintf(stderr,"\nKey bits, from zero to 63");
	for (i = 0; i <= 7; i++) {
	    fprintf(stderr,"\n\t");
	    for (j = 0; j <=7; j++)
		fprintf(stderr,"%d ",*p_char++);
	}
    }
#endif

    int_make_key_sched(k_char,schedule);

    /* if key was good, return 0 */
    return 0;
}


static int
int_make_key_sched(Key,Schedule)
    register key Key;
    des_key_schedule Schedule;
{
    /*
     * The key has been converted to an array to make this run faster;
     * on a microvax 2, this routine takes about 3.5ms.  The code and
     * size of the arrays has been played with to get it as fast as
     * possible.  Of course, this means it's probably pessimal for
     * anything people are really using these days.
     */

    register int iter = AUTH_DES_ITER ;
    register unsigned long *k;
    register int *kp;
    register unsigned long temp;

    kp = (int *) key_perm;
    k  = (unsigned long *) Schedule;

    do {
	/*
	 * create the Key schedule
	 *
	 * put into lsb first order (lsb is bit 0)
	 */

	temp = 0;

	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 0);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 1);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 2);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 3);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 4);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 5);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 6);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 7);

	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 8);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 9);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 10);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 11);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 12);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 13);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 14);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 15);

	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 16);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 17);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 18);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 19);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 20);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 21);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 22);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 23);

	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 24);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 25);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 26);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 27);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 28);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 29);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 30);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 31);

	*k++ = temp;
	temp = 0;

	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 0);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 1);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 2);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 3);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 4);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 5);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 6);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 7);

	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 8);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 9);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 10);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 11);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 12);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 13);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 14);
	if ((unsigned) Key[(int) *kp++]) temp |= (1<< 15);

	*k++ = temp;

    } while (--iter > 0);

#ifdef DEBUG
    if (des_debug) {
	char *n;
	int q;
	fprintf(stderr,"\nKey Schedule, left to right");
	for (i = 0; i < AUTH_DES_ITER; i++) {
	    n = (char *) &Schedule[i];
	    fprintf(stderr,"\n");
	    for (q = 0; q <= 7; q++)
		fprintf(stderr,"%02x ",*n++ & 0xff);
	}
	fprintf(stderr,"\n");
    }
#endif
}
