/*                               -*- Mode: C -*- 
 * ssldes3.c -- 
 * Copyright (c) 1995 Shaun Savage.
 * All rights reserved.
 *
 * Author          : Shaun Savage
 * Created On      : Sun May  7 17:20:50 1995
 * Last Modified By: Shaun Savage
 * Last Modified On: Sun May  7 17:21:13 1995
 * Update Count    : 1
 * Status          : Unknown, Use with caution!
 * PURPOSE
 * 	|>Description of modules purpose<|
 * TABLE OF CONTENTS
 * 
 */

#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "ssl.h"
#include "md5.h"
#include "d3des.h"

typedef struct _d3cx {
   u_long enKey[96];
   u_long deKey[96];
   short  remLen;
   u_char rem[8];
   u_char *rptr;
} d3cx;

static
int Init(crypto *crypt,u_char *key, int klen, u_char *arg, int alen, int type)
   {
   d3cx *cx = crypt->context;
   if (EN0 == type)
      use3key(cx->enKey);
   else if (DE1 == type)
      use3key(cx->deKey);
   else
      return sslError(-1,"");
   cx->remLen = 0;
   return 0;
   }

static
int Update(crypto *crypt, u_char *obuf, u_char *ibuf, int len)
   {
   int i, cnt;
   d3cx *cx = (d3cx*) crypt->context;
   u_char *iptr = ibuf, *optr = obuf;
   cnt = (len) / 8;
   for (i=0;i<cnt;i++)
      {
      Ddes(iptr, optr);
      iptr += 8;
      optr += 8;
      }
   cx->remLen = len % 8;
   cx->rptr = iptr;
   memcpy(cx->rem, iptr, cx->remLen);
   return 0;
   }

static
int Finish(crypto *crypt, u_char *buf, int len)
   {
   d3cx *cx = crypt->context;
   len = 0;
   if (cx->remLen)
      {
      memcpy(buf,cx->rem,cx->remLen);
      Ddes(buf,buf);
      memcpy(cx->rptr, buf, cx->remLen);
      len = 8 - cx->remLen;
      memmove(buf,buf+cx->remLen, len );
      }

   return len;
   }

static
int enCrypt(crypto *crypt, u_char *buf, int len)
   {
   u_char tbuf[8] = "HEMPHEMP";
   Init(crypt, crypt->mKey, crypt->mkeyLen, crypt->arg, crypt->argLen, EN0);
   Update(crypt, buf, buf, len);
   Finish(crypt, tbuf,0);
   return 0;
   }

static
int deCrypt(crypto *crypt, u_char *buf, int len)
   {
   u_char tbuf[8] = "HEMPHEMP";
   Init(crypt, crypt->mKey, crypt->mkeyLen, crypt->arg, crypt->argLen, DE1);
   Update(crypt, buf, buf, len);
   Finish(crypt, tbuf,0);
   return 0;
   }

static
int mkKey(ssllib *ssl, crypto *crypt, int srv)
   {
   sidRec *sid = ssl->sid;
   u_char km[3][MD5_LEN];
   u_char *rdptr, *wrptr;
   d3cx *cx;

   crypt->mKey = sid->key;
   crypt->mkeyLen = sid->keyLen;
   crypt->arg  = sid->arg;
   crypt->argLen  = sid->argLen;
   
   keyMaterial(ssl, km[0], "0");
   keyMaterial(ssl, km[1], "1");
   keyMaterial(ssl, km[2], "2");

   rdptr = (u_char*) malloc(crypt->keyLen);
   memcpy(rdptr, &km[0][0], 8);
   memcpy(rdptr+8, &km[0][8], 8);
   memcpy(rdptr+16, &km[1][0], 8);

   wrptr = (u_char*) malloc(crypt->keyLen);
   memcpy(wrptr, &km[1][8], 8);
   memcpy(wrptr+8, &km[2][0], 8);
   memcpy(wrptr+16, &km[2][8], 8);

   if (srv)
      {
      crypt->rdKey = wrptr;
      crypt->wrKey = rdptr;
      }
   else
      {
      crypt->wrKey = wrptr;
      crypt->rdKey = rdptr;
      }

   cx = (d3cx*) malloc(crypt->cxLen);
   crypt->context = cx;
   des3key(crypt->wrKey, EN0);
   cp3key(cx->enKey);
   des3key(crypt->rdKey, DE1);
   cp3key(cx->deKey);
   
   return 0;
   }

crypto des3Crypt = {
   {0x000700C0},
   7,
   0, NULL,
   0, NULL,
   24, NULL, NULL,
   sizeof(d3cx), NULL,
   Init,
   Update,
   Finish,
   enCrypt,
   deCrypt,
   mkKey
};

