#include <sys/types.h>
#include <sys/param.h>
#include <dirent.h>
#include <dlfcn.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/des_crypt.h>
#include <rpc/des.h>
#include "crypt.h"
typedef struct arcfour_key
{
unsigned char state[256];
unsigned char x;
unsigned char y;
} arcfour_key;
static void prepare_key(unsigned char *key_data_ptr,int key_data_len,
arcfour_key *key);
static void arcfour(unsigned char *buffer_ptr,int buffer_len,arcfour_key * key);
static void swap_byte(unsigned char *a, unsigned char *b);
static void
prepare_key(unsigned char *key_data_ptr, int key_data_len, arcfour_key *key)
{
unsigned char index1;
unsigned char index2;
unsigned char* state;
short counter;
state = &key->state[0];
for(counter = 0; counter < 256; counter++)
state[counter] = counter;
key->x = 0;
key->y = 0;
index1 = 0;
index2 = 0;
for(counter = 0; counter < 256; counter++)
{
index2 = (key_data_ptr[index1] + state[counter] +
index2) % 256;
swap_byte(&state[counter], &state[index2]);
index1 = (index1 + 1) % key_data_len;
}
}
static void
arcfour(unsigned char *buffer_ptr, int buffer_len, arcfour_key *key)
{
unsigned char x;
unsigned char y;
unsigned char* state;
unsigned char xorIndex;
short counter;
x = key->x;
y = key->y;
state = &key->state[0];
for(counter = 0; counter < buffer_len; counter ++)
{
x = (x + 1) % 256;
y = (state[x] + y) % 256;
swap_byte(&state[x], &state[y]);
xorIndex = (state[x] + state[y]) % 256;
buffer_ptr[counter] ^= state[xorIndex];
}
key->x = x;
key->y = y;
}
static void
swap_byte(unsigned char *a, unsigned char *b)
{
unsigned char swapByte;
swapByte = *a;
*a = *b;
*b = swapByte;
}
int
_arcfour_crypt(char *buf, int len, struct desparams *desp)
{
struct arcfour_key arcfourk;
prepare_key(desp->des_key, 5, &arcfourk);
arcfour(buf, len, &arcfourk);
return(DESERR_NOHWDEVICE);
}
int (*_my_crypt)(char *, int, struct desparams *) = NULL;
static void *dlhandle;
#ifndef _PATH_USRLIB
#define _PATH_USRLIB "/usr/lib"
#endif
#ifndef LIBCRYPTO
#define LIBCRYPTO "libcrypto.so.1"
#endif
void
load_des(int warn, char *libpath)
{
char dlpath[MAXPATHLEN];
if (libpath == NULL) {
snprintf(dlpath, sizeof(dlpath), "%s/%s", _PATH_USRLIB, LIBCRYPTO);
} else
snprintf(dlpath, sizeof(dlpath), "%s", libpath);
if (dlpath[0] != '\0' && (dlhandle = dlopen(dlpath, 0444)) != NULL)
_my_crypt = (int (*)())dlsym(dlhandle, "_des_crypt");
if (_my_crypt == NULL) {
if (dlhandle != NULL)
dlclose(dlhandle);
_my_crypt = &_arcfour_crypt;
if (warn) {
printf ("DES support disabled -- using ARCFOUR instead.\n");
printf ("Warning: ARCFOUR cipher is not compatible with ");
printf ("other Secure RPC implementations.\nInstall ");
printf ("the FreeBSD 'des' distribution to enable");
printf (" DES encryption.\n");
}
} else {
if (warn) {
printf ("DES support enabled\n");
printf ("Using %s shared object.\n", dlpath);
}
}
return;
}
desresp *
des_crypt_1_svc(desargs *argp, struct svc_req *rqstp)
{
static desresp result;
struct desparams dparm;
if (argp->desbuf.desbuf_len > DES_MAXDATA) {
result.stat = DESERR_BADPARAM;
return(&result);
}
bcopy(argp->des_key, dparm.des_key, 8);
bcopy(argp->des_ivec, dparm.des_ivec, 8);
dparm.des_mode = argp->des_mode;
dparm.des_dir = argp->des_dir;
#ifdef BROKEN_DES
dparm.UDES.UDES_buf = argp->desbuf.desbuf_val;
#endif
#ifdef BROKEN_DES
if (_my_crypt != &_arcfour_crypt && argp->des_mode == (des_mode)CBC) {
#else
if (_my_crypt != &_arcfour_crypt && argp->des_mode == ECB) {
#endif
int i;
char *dptr;
for (i = 0; i < argp->desbuf.desbuf_len / 8; i++) {
dptr = argp->desbuf.desbuf_val;
dptr += (i * 8);
#ifdef BROKEN_DES
dparm.UDES.UDES_buf = dptr;
#endif
result.stat = _my_crypt(dptr, 8, &dparm);
}
} else {
result.stat = _my_crypt(argp->desbuf.desbuf_val,
argp->desbuf.desbuf_len,
&dparm);
}
if (result.stat == DESERR_NONE || result.stat == DESERR_NOHWDEVICE) {
bcopy(dparm.des_ivec, result.des_ivec, 8);
result.desbuf.desbuf_len = argp->desbuf.desbuf_len;
result.desbuf.desbuf_val = argp->desbuf.desbuf_val;
}
return (&result);
}