/*------------*/
/* cfb encryption */
#ifdef USEIDEA
#include <idea.h>
static IDEA_KEY_SCHEDULE iks;
#endif

#include <des.h>
static des_key_schedule desv[3];

#ifdef USECAST
#include <cast.h>
static CAST_KEY castkey;
#endif

#ifdef USEBF
#include <blowfish.h>
static BF_KEY bfkey;
#endif

#ifdef USESAFER
#include "safer.h"
static safer_key_t saferkey;
#endif

static unsigned int ivleft;
static unsigned char cfbivec[8];
static unsigned int localcipherno;

void cfbinit(unsigned char *key, unsigned char *iv0, int cipher)
{
  ivleft = 0;
  localcipherno = cipher;
  switch (cipher) {
#ifdef USEIDEA
  case 1:
    idea_set_encrypt_key(key, &iks);
    break;
#endif
  case 2:
    des_set_key((des_cblock *) key, desv[0]);
    des_set_key((des_cblock *) & key[8], desv[1]);
    des_set_key((des_cblock *) & key[16], desv[2]);
  case 0:
    break;
#ifdef USECAST
  case 3:
    CAST_set_key(&castkey, CAST_KEY_LENGTH, key);
    break;
#endif
#ifdef USEBF
  case 4:
    BF_set_key(&bfkey, 16, key);
    break;
#endif
#ifdef USESAFER
  case 6:
    Safer_Init_Module();
    Safer_Expand_Userkey(key, &key[8], SAFER_MAX_NOF_ROUNDS, 1, saferkey);
    break;
#endif
  default:
    exit(-1);
  }
  memcpy(cfbivec, iv0, 8);
}

void docfb(unsigned char *buf, int len, int enc)
{
  switch (localcipherno) {
#ifdef USEIDEA
  case 1:
    idea_cfb64_encrypt(buf, buf, len, &iks,
                       cfbivec, &ivleft, enc ? IDEA_ENCRYPT : IDEA_DECRYPT);
    break;
#endif
  case 2:
    des_ede3_cfb64_encrypt(buf, buf, len, desv[0], desv[1], desv[2],
            (des_cblock *) cfbivec, &ivleft, enc ? DES_ENCRYPT : DES_DECRYPT);
    break;
#ifdef USECAST
  case 3:
    CAST_cfb64_encrypt(buf, buf, len, &castkey,
                       cfbivec, &ivleft, enc ? CAST_ENCRYPT : CAST_DECRYPT);
    break;
#endif
#ifdef USEBF
  case 4:
    BF_cfb64_encrypt(buf, buf, len, &bfkey,
                     cfbivec, &ivleft, enc ? BF_ENCRYPT : BF_DECRYPT);
    break;
#endif
#ifdef USESAFER
  case 6:
#endif
  case 0:
  default:
    {
      int i, ilen;
      unsigned char liv;

      while (len) {
        ilen = len > 8 ? 8 : len;
        if (ivleft == 0)
          switch (localcipherno) {
#ifdef USESAFER
          case 6:
            Safer_Encrypt_Block(cfbivec, saferkey, cfbivec);
#endif
          default:
            break;
        } else if (ilen + ivleft > 8)
          ilen = 8 - ivleft;
        for (i = ivleft; i < ilen + ivleft; i++) {
          liv = *buf;
          *buf++ ^= cfbivec[i];
          if (enc)
            liv ^= cfbivec[i];
          cfbivec[i] = liv;
        }
        len -= ilen;
        ivleft = (ivleft + ilen) & 7;
      }
    }
  }
}

void cfbreset(unsigned char *save)
{
  memcpy(cfbivec, save, 8);
  ivleft = 0;
}
