/* Copyright 1989, 1990 by James Aspnes, David Applegate, and Bennet Yee */
/* See the file COPYING for distribution information */
#include "db.h"
const char *alphabet =
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
#ifdef USE_UNIX_CRYPT
extern const char *crypt(const char *, const char *);
#define do_crypt crypt
#else /* USE_UNIX_CRYPT */
#define mask(x) ((1 << (x)) - 1)
#define extract0(p) alphabet[bits[p] & mask(6)]
/* don't even try to understand it */
/* and don't use it outside bits2alpha */
/* WARNING: Dec 3100 (pmax) cc botches the constant-folding in this macro! */
#define extract(p, shift) \
    alphabet[((bits[(p)] >> (shift)) & mask(8 - (shift))) \
	     | ((bits[(p)+1] << ((shift) - 4)) \
		& (mask(10 - (shift)) << ((shift) - 4)))]
/* converts 64 bits to 11 characters of the 6-bit code */
static const char *bits2alpha(unsigned const char *bits)
{
    static char alpha[12];
    alpha[0] = extract0(0);
    alpha[1] = extract(0, 6);
    alpha[2] = extract(1, 4);
    alpha[3] = extract(2, 2);
    alpha[4] = extract0(3);
    alpha[5] = extract(3, 6);
    alpha[6] = extract(4, 4);
    alpha[7] = extract(5, 2);
    alpha[8] = extract0(6);
    alpha[9] = extract(6, 6);
    alpha[10] = alphabet[(bits[7] >> 4) & 0xf];
    alpha[11] = '\0';
    return alpha;
}
static const char *do_crypt(const char *password, const char *salt) 
{
    static int initialized = 0;	/* already called desinit */
    int i;
    unsigned char cbuf[8];	/* thing to encrypt */
    char key[8];		/* key */
    static char buf[14];	/* 2 bytes of salt + 11 bytes of text + term */
    for(i = 0; i < 8; i+= 2) {
	cbuf[i] = salt[0];
	cbuf[i+1] = salt[1];
    }
    for(i = 0; i < 8 && password[i]; i++) {
	key[i] = password[i] << 1;
    }
    while(i < 8) key[i++] = 0;
    if(!initialized) {
	desinit(1);		/* ignore initial and final permutations */
	initialized = 1;
    }
    setkey(key);
    endes(cbuf);
    /* construct the salted string in buf */
    buf[0] = salt[0];
    buf[1] = salt[1];
    strcpy(buf + 2, bits2alpha(cbuf));
    return buf;
}
#endif /* USE_UNIX_CRYPT */
const char *encrypt_password(const char *password)
{
    char salt[3];
    salt[0] = alphabet[RAND() % 64];
    salt[1] = alphabet[RAND() % 64];
    salt[2] = '\0';
    return do_crypt(password, salt);
}
int check_password(const char *clear, const char *encrypted)
{
    return !strcmp(encrypted, do_crypt(clear, encrypted));
}