/*----------------------------------------------------------------------------+
 |                                                                            |
 |   Package: krypto                                                          |
 |                                                                            |
 |      This code is based on code in Eric Young's libdes-4.01 code           |
 |   and was slightly modified to conform with libkrypto's interface.         |
 |   See copyright notice below.                                              |
 |                                                                            |
 +----------------------------------------------------------------------------*/

/* crypto/des/des_enc.c */
/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
 * All rights reserved.
 *
 * This package is an SSL cipher_impementation written
 * by Eric Young (eay@mincom.oz.au).
 * The cipher_impementation was written so as to conform with Netscapes SSL.
 * 
 * This library is free for commercial and non-commercial use as long as
 * the following conditions are aheared to.  The following conditions
 * apply to all code found in this distribution, be it the RC4, RSA,
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
 * included with this distribution is covered by the same copyright terms
 * except that the holder is Tim Hudson (tjh@mincom.oz.au).
 * 
 * Copyright remains Eric Young's, and as such any Copyright notices in
 * the code are not to be removed.
 * If this package is used in a product, Eric Young should be given attribution
 * as the author of the parts of the library used.
 * This can be in the form of a textual message at program startup or
 * in documentation (online or textual) provided with the package.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    "This product includes cryptographic software written by
 *     Eric Young (eay@mincom.oz.au)"
 *    The word 'cryptographic' can be left out if the rouines from the library
 *    being used are not cryptographic related :-).
 * 4. If you include any Windows specific code (or a derivative thereof) from 
 *    the apps directory (application code) you must include an acknowledgement:
 *    "This product includes software written by Tim Hudson (tjh@mincom.oz.au)"
 * 
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
 * The licence and distribution terms for any publically available version or
 * derivative of this code cannot be changed.  i.e. this code cannot scipher_impy be
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
 */

#ifndef NOENCRYPTION
#ifdef CIPHER_DES

#include "krypto.h"
#include "cipher_imp_des.h"

static void des_encrypt(data, ks, encrypt)
DES_LONG *data;
des_key_schedule ks;
int encrypt;
	{
	register DES_LONG l,r,t,u;
#ifdef DES_PTR
	register unsigned char *des_SP=(unsigned char *)des_SPtrans;
#endif
#ifndef DES_UNROLL
	register int i;
#endif
	register DES_LONG *s;

	r=data[0];
	l=data[1];

	IP(r,l);
	/* Things have been modified so that the initial rotate is
	 * done outside the loop.  This required the
	 * des_SPtrans values in sp.h to be rotated 1 bit to the right.
	 * One perl script later and things have a 5% speed up on a sparc2.
	 * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
	 * for pointing this out. */
	/* clear the top bits on machines with 8byte longs */
	/* shift left by 2 */
	r=ROTATE(r,29)&0xffffffffL;
	l=ROTATE(l,29)&0xffffffffL;

	s=(DES_LONG *)ks;
	/* I don't know if it is worth the effort of loop unrolling the
	 * inner loop */
	if (encrypt)
		{
#ifdef DES_UNROLL
		D_ENCRYPT(l,r, 0); /*  1 */
		D_ENCRYPT(r,l, 2); /*  2 */
		D_ENCRYPT(l,r, 4); /*  3 */
		D_ENCRYPT(r,l, 6); /*  4 */
		D_ENCRYPT(l,r, 8); /*  5 */
		D_ENCRYPT(r,l,10); /*  6 */
		D_ENCRYPT(l,r,12); /*  7 */
		D_ENCRYPT(r,l,14); /*  8 */
		D_ENCRYPT(l,r,16); /*  9 */
		D_ENCRYPT(r,l,18); /*  10 */
		D_ENCRYPT(l,r,20); /*  11 */
		D_ENCRYPT(r,l,22); /*  12 */
		D_ENCRYPT(l,r,24); /*  13 */
		D_ENCRYPT(r,l,26); /*  14 */
		D_ENCRYPT(l,r,28); /*  15 */
		D_ENCRYPT(r,l,30); /*  16 */
#else
		for (i=0; i<32; i+=8)
			{
			D_ENCRYPT(l,r,i+0); /*  1 */
			D_ENCRYPT(r,l,i+2); /*  2 */
			D_ENCRYPT(l,r,i+4); /*  3 */
			D_ENCRYPT(r,l,i+6); /*  4 */
			}
#endif
		}
	else
		{
#ifdef DES_UNROLL
		D_ENCRYPT(l,r,30); /* 16 */
		D_ENCRYPT(r,l,28); /* 15 */
		D_ENCRYPT(l,r,26); /* 14 */
		D_ENCRYPT(r,l,24); /* 13 */
		D_ENCRYPT(l,r,22); /* 12 */
		D_ENCRYPT(r,l,20); /* 11 */
		D_ENCRYPT(l,r,18); /* 10 */
		D_ENCRYPT(r,l,16); /*  9 */
		D_ENCRYPT(l,r,14); /*  8 */
		D_ENCRYPT(r,l,12); /*  7 */
		D_ENCRYPT(l,r,10); /*  6 */
		D_ENCRYPT(r,l, 8); /*  5 */
		D_ENCRYPT(l,r, 6); /*  4 */
		D_ENCRYPT(r,l, 4); /*  3 */
		D_ENCRYPT(l,r, 2); /*  2 */
		D_ENCRYPT(r,l, 0); /*  1 */
#else
		for (i=30; i>0; i-=8)
			{
			D_ENCRYPT(l,r,i-0); /* 16 */
			D_ENCRYPT(r,l,i-2); /* 15 */
			D_ENCRYPT(l,r,i-4); /* 14 */
			D_ENCRYPT(r,l,i-6); /* 13 */
			}
#endif
		}

	/* rotate and clear the top bits on machines with 8byte longs */
	l=ROTATE(l,3)&0xffffffffL;
	r=ROTATE(r,3)&0xffffffffL;

	FP(r,l);
	data[0]=l;
	data[1]=r;
	l=r=t=u=0;
	}

static void des_encrypt2(data, ks, encrypt)
DES_LONG *data;
des_key_schedule ks;
int encrypt;
	{
	register DES_LONG l,r,t,u;
#ifdef DES_PTR
	register unsigned char *des_SP=(unsigned char *)des_SPtrans;
#endif
#ifndef DES_UNROLL
	register int i;
#endif
	register DES_LONG *s;

	r=data[0];
	l=data[1];

	/* Things have been modified so that the initial rotate is
	 * done outside the loop.  This required the
	 * des_SPtrans values in sp.h to be rotated 1 bit to the right.
	 * One perl script later and things have a 5% speed up on a sparc2.
	 * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
	 * for pointing this out. */
	/* clear the top bits on machines with 8byte longs */
	r=ROTATE(r,29)&0xffffffff;
	l=ROTATE(l,29)&0xffffffff;

	s=(DES_LONG *)ks;
	/* I don't know if it is worth the effort of loop unrolling the
	 * inner loop */
	if (encrypt)
		{
#ifdef DES_UNROLL
		D_ENCRYPT(l,r, 0); /*  1 */
		D_ENCRYPT(r,l, 2); /*  2 */
		D_ENCRYPT(l,r, 4); /*  3 */
		D_ENCRYPT(r,l, 6); /*  4 */
		D_ENCRYPT(l,r, 8); /*  5 */
		D_ENCRYPT(r,l,10); /*  6 */
		D_ENCRYPT(l,r,12); /*  7 */
		D_ENCRYPT(r,l,14); /*  8 */
		D_ENCRYPT(l,r,16); /*  9 */
		D_ENCRYPT(r,l,18); /*  10 */
		D_ENCRYPT(l,r,20); /*  11 */
		D_ENCRYPT(r,l,22); /*  12 */
		D_ENCRYPT(l,r,24); /*  13 */
		D_ENCRYPT(r,l,26); /*  14 */
		D_ENCRYPT(l,r,28); /*  15 */
		D_ENCRYPT(r,l,30); /*  16 */
#else
		for (i=0; i<32; i+=8)
			{
			D_ENCRYPT(l,r,i+0); /*  1 */
			D_ENCRYPT(r,l,i+2); /*  2 */
			D_ENCRYPT(l,r,i+4); /*  3 */
			D_ENCRYPT(r,l,i+6); /*  4 */
			}
#endif
		}
	else
		{
#ifdef DES_UNROLL
		D_ENCRYPT(l,r,30); /* 16 */
		D_ENCRYPT(r,l,28); /* 15 */
		D_ENCRYPT(l,r,26); /* 14 */
		D_ENCRYPT(r,l,24); /* 13 */
		D_ENCRYPT(l,r,22); /* 12 */
		D_ENCRYPT(r,l,20); /* 11 */
		D_ENCRYPT(l,r,18); /* 10 */
		D_ENCRYPT(r,l,16); /*  9 */
		D_ENCRYPT(l,r,14); /*  8 */
		D_ENCRYPT(r,l,12); /*  7 */
		D_ENCRYPT(l,r,10); /*  6 */
		D_ENCRYPT(r,l, 8); /*  5 */
		D_ENCRYPT(l,r, 6); /*  4 */
		D_ENCRYPT(r,l, 4); /*  3 */
		D_ENCRYPT(l,r, 2); /*  2 */
		D_ENCRYPT(r,l, 0); /*  1 */
#else
		for (i=30; i>0; i-=8)
			{
			D_ENCRYPT(l,r,i-0); /* 16 */
			D_ENCRYPT(r,l,i-2); /* 15 */
			D_ENCRYPT(l,r,i-4); /* 14 */
			D_ENCRYPT(r,l,i-6); /* 13 */
			}
#endif
		}
	/* rotate and clear the top bits on machines with 8byte longs */
	data[0]=ROTATE(l,3)&0xffffffff;
	data[1]=ROTATE(r,3)&0xffffffff;
	l=r=t=u=0;
	}

static void des_encrypt3(data,ks1,ks2,ks3)
DES_LONG *data;
des_key_schedule ks1;
des_key_schedule ks2;
des_key_schedule ks3;
	{
	register DES_LONG l,r;

	l=data[0];
	r=data[1];
	IP(l,r);
	data[0]=l;
	data[1]=r;
	des_encrypt2((DES_LONG *)data,ks1,DES_ENCRYPT);
	des_encrypt2((DES_LONG *)data,ks2,DES_DECRYPT);
	des_encrypt2((DES_LONG *)data,ks3,DES_ENCRYPT);
	l=data[0];
	r=data[1];
	FP(r,l);
	data[0]=l;
	data[1]=r;
	}

static void des_decrypt3(data,ks1,ks2,ks3)
DES_LONG *data;
des_key_schedule ks1;
des_key_schedule ks2;
des_key_schedule ks3;
	{
	register DES_LONG l,r;

	l=data[0];
	r=data[1];
	IP(l,r);
	data[0]=l;
	data[1]=r;
	des_encrypt2((DES_LONG *)data,ks3,DES_DECRYPT);
	des_encrypt2((DES_LONG *)data,ks2,DES_ENCRYPT);
	des_encrypt2((DES_LONG *)data,ks1,DES_DECRYPT);
	l=data[0];
	r=data[1];
	FP(r,l);
	data[0]=l;
	data[1]=r;
	}


/* crypto/des/set_key.c */
/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)
 * All rights reserved.
 *
 * This package is an SSL cipher_impementation written
 * by Eric Young (eay@mincom.oz.au).
 * The cipher_impementation was written so as to conform with Netscapes SSL.
 * 
 * This library is free for commercial and non-commercial use as long as
 * the following conditions are aheared to.  The following conditions
 * apply to all code found in this distribution, be it the RC4, RSA,
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
 * included with this distribution is covered by the same copyright terms
 * except that the holder is Tim Hudson (tjh@mincom.oz.au).
 * 
 * Copyright remains Eric Young's, and as such any Copyright notices in
 * the code are not to be removed.
 * If this package is used in a product, Eric Young should be given attribution
 * as the author of the parts of the library used.
 * This can be in the form of a textual message at program startup or
 * in documentation (online or textual) provided with the package.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    "This product includes cryptographic software written by
 *     Eric Young (eay@mincom.oz.au)"
 *    The word 'cryptographic' can be left out if the rouines from the library
 *    being used are not cryptographic related :-).
 * 4. If you include any Windows specific code (or a derivative thereof) from 
 *    the apps directory (application code) you must include an acknowledgement:
 *    "This product includes software written by Tim Hudson (tjh@mincom.oz.au)"
 * 
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
 * The licence and distribution terms for any publically available version or
 * derivative of this code cannot be changed.  i.e. this code cannot scipher_impy be
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
 */

/* set_key.c v 1.4 eay 24/9/91
 * 1.4 Speed up by 400% :-)
 * 1.3 added register declarations.
 * 1.2 unrolled make_key_sched a bit more
 * 1.1 added norm_expand_bits
 * 1.0 First working version
 */

#ifndef NOPROTO
static int check_parity(des_cblock (*key));
#else
static int check_parity();
#endif

int des_check_key=0;

static void des_set_odd_parity(key)
des_cblock (*key);
	{
	int i;

	for (i=0; i<DES_KEY_SZ; i++)
		(*key)[i]=odd_parity[(*key)[i]];
	}

static int check_parity(key)
des_cblock (*key);
	{
	int i;

	for (i=0; i<DES_KEY_SZ; i++)
		{
		if ((*key)[i] != odd_parity[(*key)[i]])
			return(0);
		}
	return(1);
	}

/* Weak and semi week keys as take from
 * %A D.W. Davies
 * %A W.L. Price
 * %T Security for Computer Networks
 * %I John Wiley & Sons
 * %D 1984
 * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference
 * (and actual cblock values).
 */
#define NUM_WEAK_KEY	16
static des_cblock weak_keys[NUM_WEAK_KEY]={
	/* weak keys */
	{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
	{0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE},
	{0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F},
	{0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0},
	/* semi-weak keys */
	{0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE},
	{0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01},
	{0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1},
	{0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E},
	{0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1},
	{0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01},
	{0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE},
	{0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E},
	{0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E},
	{0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01},
	{0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
	{0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}};

static int des_is_weak_key(key)
des_cblock (*key);
	{
	int i;

	for (i=0; i<NUM_WEAK_KEY; i++)
		/* Added == 0 to comparision, I obviously don't run
		 * this section very often :-(, thanks to
		 * engineering@MorningStar.Com for the fix
		 * eay 93/06/29 */
		if (memcmp(weak_keys[i],key,sizeof(key)) == 0) return(1);
	return(0);
	}

/* NOW DEFINED IN des_local.h
 * See ecb_encrypt.c for a pseudo description of these macros. 
 * #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
 * 	(b)^=(t),\
 * 	(a)=((a)^((t)<<(n))))
 */

#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
	(a)=(a)^(t)^(t>>(16-(n))))

/* return 0 if key parity is odd (correct),
 * return -1 if key parity error,
 * return -2 if illegal weak key.
 */
static int des_set_key(inkey, schedule)
des_cblock (*inkey);
des_key_schedule schedule;
	{
	static int shifts2[16]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0};
	register DES_LONG c,d,t,s,t2;
	register unsigned char *in;
	register DES_LONG *k;
	register int i;
	unsigned char key[8];

	memcpy (key, inkey, 8);

/*
	if (des_check_key)
		{
		if (!check_parity(key))
			return(-1);

		if (des_is_weak_key(key))
			return(-2);
		}
*/

	/* libkrypto: modification to always make odd parity */

	if (!check_parity((des_cblock *) key))
	  des_set_odd_parity((des_cblock *) key);

	k=(DES_LONG *)schedule;
	in=(unsigned char *)key;

	c2l(in,c);
	c2l(in,d);

	/* do PC1 in 60 scipher_impe operations */ 
/*	PERM_OP(d,c,t,4,0x0f0f0f0fL);
	HPERM_OP(c,t,-2, 0xcccc0000L);
	HPERM_OP(c,t,-1, 0xaaaa0000L);
	HPERM_OP(c,t, 8, 0x00ff0000L);
	HPERM_OP(c,t,-1, 0xaaaa0000L);
	HPERM_OP(d,t,-8, 0xff000000L);
	HPERM_OP(d,t, 8, 0x00ff0000L);
	HPERM_OP(d,t, 2, 0x33330000L);
	d=((d&0x00aa00aaL)<<7L)|((d&0x55005500L)>>7L)|(d&0xaa55aa55L);
	d=(d>>8)|((c&0xf0000000L)>>4);
	c&=0x0fffffffL; */

	/* I now do it in 47 scipher_impe operations :-)
	 * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
	 * for the inspiration. :-) */
	PERM_OP (d,c,t,4,0x0f0f0f0fL);
	HPERM_OP(c,t,-2,0xcccc0000L);
	HPERM_OP(d,t,-2,0xcccc0000L);
	PERM_OP (d,c,t,1,0x55555555L);
	PERM_OP (c,d,t,8,0x00ff00ffL);
	PERM_OP (d,c,t,1,0x55555555L);
	d=	(((d&0x000000ffL)<<16L)| (d&0x0000ff00L)     |
		 ((d&0x00ff0000L)>>16L)|((c&0xf0000000L)>>4L));
	c&=0x0fffffffL;

	for (i=0; i<ITERATIONS; i++)
		{
		if (shifts2[i])
			{ c=((c>>2L)|(c<<26L)); d=((d>>2L)|(d<<26L)); }
		else
			{ c=((c>>1L)|(c<<27L)); d=((d>>1L)|(d<<27L)); }
		c&=0x0fffffffL;
		d&=0x0fffffffL;
		/* could be a few less shifts but I am to lazy at this
		 * point in time to investigate */
		s=	des_skb[0][ (c    )&0x3f                ]|
			des_skb[1][((c>> 6)&0x03)|((c>> 7L)&0x3c)]|
			des_skb[2][((c>>13)&0x0f)|((c>>14L)&0x30)]|
			des_skb[3][((c>>20)&0x01)|((c>>21L)&0x06) |
						  ((c>>22L)&0x38)];
		t=	des_skb[4][ (d    )&0x3f                ]|
			des_skb[5][((d>> 7L)&0x03)|((d>> 8L)&0x3c)]|
			des_skb[6][ (d>>15L)&0x3f                ]|
			des_skb[7][((d>>21L)&0x0f)|((d>>22L)&0x30)];

		/* table contained 0213 4657 */
		t2=((t<<16L)|(s&0x0000ffffL))&0xffffffffL;
		*(k++)=ROTATE(t2,30)&0xffffffffL;

		t2=((s>>16L)|(t&0xffff0000L));
		*(k++)=ROTATE(t2,26)&0xffffffffL;
		}
	return(0);
	}

static int des_key_sched(key, schedule)
des_cblock (*key);
des_key_schedule schedule;
	{
	return(des_set_key(key,schedule));
	}

/* GLUE ROUTINES */


static void *
cipher_imp_des_init (key, klen)
  unsigned char *key;
  unsigned klen;
{
  des_key_schedule *des_key;

  if (klen < 8) return 0;

  des_key = (des_key_schedule *) malloc (sizeof (des_key_schedule));
  if (des_key == 0) return 0;

  des_set_key ((des_cblock *) key, *des_key);
  return (void *) des_key;
}

static void
cipher_imp_des_finish (c)
  void *c;
{
  if (c)
  {
    des_key_schedule *des_key = (des_key_schedule *) c;
    memset (des_key, 0, sizeof (des_key_schedule));
    free (c);
  }
}

static void
cipher_imp_des_crypt (des_key, data, len, state)
     des_key_schedule *des_key;
     unsigned char * data;
     unsigned len;
     unsigned state;
{
  unsigned char tmp[4], *c;
  DES_LONG l[2];

  /* change to characters loaded little endian */

  l[0] = ((DES_LONG *) data)[0];
  l[1] = ((DES_LONG *) data)[1];

  c = tmp; l2n (l[0], c);
  c = tmp; c2l (c, l[0]);
  c = tmp; l2n (l[1], c);
  c = tmp; c2l (c, l[1]);

  des_encrypt (l, *des_key, state);

  /* change back */

  c = tmp; l2c (l[0], c);
  c = tmp; n2l (c, l[0]);
  c = tmp; l2c (l[1], c);
  c = tmp; n2l (c, l[1]);

  ((DES_LONG *) data)[0] = l[0];
  ((DES_LONG *) data)[1] = l[1];
}


cipher_desc DES_ECBdesc =
{
  CIPHER_ID_DES_ECB,
  "DES_ECB",
  CIPHER_TYPE_BLOCK,
  CIPHER_MODE_ECB,
  8,
  8,
  8,
  cipher_imp_des_init,
  cipher_imp_des_crypt,
  cipher_imp_des_finish
};

cipher_desc DES_CBCdesc =
{
  CIPHER_ID_DES_CBC,
  "DES_CBC",
  CIPHER_TYPE_BLOCK,
  CIPHER_MODE_CBC,
  8,
  8,
  8,
  cipher_imp_des_init,
  cipher_imp_des_crypt,
  cipher_imp_des_finish
};

cipher_desc DES_CFB64desc =
{
  CIPHER_ID_DES_CFB64,
  "DES_CFB64",
  CIPHER_TYPE_BLOCK,
  CIPHER_MODE_CFB64,
  8,
  8,
  1,
  cipher_imp_des_init,
  cipher_imp_des_crypt,
  cipher_imp_des_finish
};

cipher_desc DES_OFB64desc =
{
  CIPHER_ID_DES_OFB64,
  "DES_OFB64",
  CIPHER_TYPE_BLOCK,
  CIPHER_MODE_OFB64,
  8,
  8,
  1,
  cipher_imp_des_init,
  cipher_imp_des_crypt,
  cipher_imp_des_finish
};


typedef struct
{
  des_key_schedule key1;
  des_key_schedule key2;
  des_key_schedule key3;
} DES3_CTX, *DES3_CTXP;


static void *
cipher_imp_des3_init (key, klen)
  unsigned char *key;
  unsigned klen;
{
  DES3_CTXP ctxt;

  if (klen < 16) return 0;

  ctxt = (DES3_CTXP) malloc (sizeof (DES3_CTX));
  if (ctxt == (DES3_CTXP) 0) return (void *) ctxt;

  des_set_key ((des_cblock *) key, ctxt->key1);
  des_set_key ((des_cblock *) (key+8), ctxt->key2);
  if (klen >= 24)
    des_set_key ((des_cblock *) (key+16), ctxt->key3);
  else
    des_set_key ((des_cblock *) key, ctxt->key3);

  return (void *) ctxt;
}

static void
cipher_imp_des3_finish (c)
  void *c;
{
  if (c)
  {
    DES3_CTXP ctxt = (DES3_CTXP) c;
    memset (ctxt, 0, sizeof (DES3_CTX));
    free (c);
  }
}

static void
cipher_imp_des3_crypt (ctxt, data, len, state)
     DES3_CTXP ctxt;
     unsigned char * data;
     unsigned len;
     unsigned state;
{
  unsigned char tmp[4], *c;
  DES_LONG l[2];

  /* change to characters loaded little endian */

  l[0] = ((DES_LONG *) data)[0];
  l[1] = ((DES_LONG *) data)[1];

  c = tmp; l2n (l[0], c);
  c = tmp; c2l (c, l[0]);
  c = tmp; l2n (l[1], c);
  c = tmp; c2l (c, l[1]);

  if (state == CIPHER_STATE_ENCRYPT)
    des_encrypt3 (l, ctxt->key1, ctxt->key2, ctxt->key3);
  else
    des_decrypt3 (l, ctxt->key1, ctxt->key2, ctxt->key3);

  /* change back */

  c = tmp; l2c (l[0], c);
  c = tmp; n2l (c, l[0]);
  c = tmp; l2c (l[1], c);
  c = tmp; n2l (c, l[1]);

  ((DES_LONG *) data)[0] = l[0];
  ((DES_LONG *) data)[1] = l[1];
}


cipher_desc DES3_ECBdesc =
{
  CIPHER_ID_DES3_ECB,
  "DES3_ECB",
  CIPHER_TYPE_BLOCK,
  CIPHER_MODE_ECB,
  8,
  16,
  8,
  cipher_imp_des3_init,
  cipher_imp_des3_crypt,
  cipher_imp_des3_finish
};

cipher_desc DES3_CBCdesc =
{
  CIPHER_ID_DES3_CBC,
  "DES3_CBC",
  CIPHER_TYPE_BLOCK,
  CIPHER_MODE_CBC,
  8,
  16,
  8,
  cipher_imp_des3_init,
  cipher_imp_des3_crypt,
  cipher_imp_des3_finish
};

cipher_desc DES3_CFB64desc =
{
  CIPHER_ID_DES3_CFB64,
  "DES3_CFB64",
  CIPHER_TYPE_BLOCK,
  CIPHER_MODE_CFB64,
  8,
  16,
  1,
  cipher_imp_des3_init,
  cipher_imp_des3_crypt,
  cipher_imp_des3_finish
};

cipher_desc DES3_OFB64desc =
{
  CIPHER_ID_DES3_OFB64,
  "DES3_OFB64",
  CIPHER_TYPE_BLOCK,
  CIPHER_MODE_OFB64,
  8,
  16,
  1,
  cipher_imp_des3_init,
  cipher_imp_des3_crypt,
  cipher_imp_des3_finish
};

#endif
#endif
