/*
 * Unix crypt(1)-style interface.
 * Written by T.E.Dickey for vile (March 1999).
 *
 * $Header: /usr/build/vile/vile/RCS/ucrypt.c,v 1.15 2001/02/14 01:39:50 tom Exp $
 *
 */

# include	"estruct.h"
# include	"edef.h"

#if	OPT_ENCRYPT

#define MASKED(n) ((n)&(N_chars-1))

#define LEN_CLEAR 8
#define LEN_CRYPT 13

static unsigned	index_1;
static unsigned	index_2;

static char	table1[N_chars];
static char	table2[N_chars];
static char	table3[N_chars];

/*
 * Get the string to use as an encryption string.
 */
static int
get_encryption_key(		/* make encryption key */
char	*key,			/* where to write key */
UINT	len)
{
    int status;			/* return status */
    int save_vl_echo = vl_echo;
    char temp[NKEYLEN];

    /* turn command input echo off */
    vl_echo = FALSE;

    temp[0] = EOS;
    status = mlreply("-Encryption String: ", temp, len-1);
    vl_echo = save_vl_echo;

    if (status == TRUE)
	vl_make_encrypt_key(key, temp);

    mlerase();
    return(status);
}

void
vl_encrypt_blok(char *buf, UINT len)
{
    unsigned c1, c2;

    for (c2 = 0; c2 < len; c2++) {
	c1 = buf[c2];
	buf[c2] = table2[
		MASKED(table3[
		    MASKED(table1[
			MASKED(c1+index_1)] + index_2)
			    ] - index_2)
			] - index_1;
	if (++index_1 >= N_chars) {
	    index_1 = 0;
	    if(++index_2 >= N_chars)
		index_2 = 0;
	}
    }
}

int
vl_encrypt_char(int ch)
{
    char buffer[2];
    buffer[0] = (char) ch;
    vl_encrypt_blok(buffer, 1);
    return buffer[0];
}

/*
 * Calls to 'crypt()' are slow; do this only after we have gotten a new
 * key from the user.
 */
void
vl_make_encrypt_key (char *dst, const char *src)
{
    char key[LEN_CLEAR];
    char salt[2];

    memcpy(key,  src,  sizeof(key));
    memcpy(salt, src,  sizeof(salt));
    memcpy(dst, (char *)crypt(key, salt), LEN_CRYPT);
    dst[LEN_CRYPT] = 0;

    TRACE(("made encryption key(%s)\n", dst));
}

int
vl_resetkey(		/* set the buffer's encryption key if needed */
BUFFER	*bp,
const char *fname)
{
    register int s;	/* temporary return value */

    /* flag the buffer as not having encryption */
    ffdocrypt(FALSE);

    /* if we want to encrypt */
    if (b_val(bp, MDCRYPT)) {
	char temp[NFILEN];

	/* don't automatically inherit key from other buffers */
	if (bp->b_cryptkey[0] != EOS
	 && !b_is_argument(bp)
	 && strcmp(lengthen_path(strcpy(temp, fname)), bp->b_fname)) {
	    char	prompt[80];
	    (void)lsprintf(prompt, "Use crypt-key from %s", bp->b_bname);
	    s = mlyesno(prompt);
	    if (s != TRUE)
		return (s == FALSE);
	}

	/* make a key if we don't have one */
	if (bp->b_cryptkey[0] == EOS) {
	    s = get_encryption_key(bp->b_cryptkey, sizeof(bp->b_cryptkey));
	    if (s != TRUE)
		return (s == FALSE);
	}

	ffdocrypt(TRUE);
	vl_setup_encrypt(bp->b_cryptkey);
    }

    return TRUE;
}

/* change current buffer's encryption key */
/* ARGSUSED */
int
vl_setkey(
int f GCC_UNUSED,
int n GCC_UNUSED)
{
    char result[NKEYLEN];
    int rc = get_encryption_key(result, sizeof(result));

    if (rc == TRUE) {
	TRACE(("set key for %s\n", curbp->b_bname));
	(void)strcpy(curbp->b_cryptkey, result);
	make_local_b_val(curbp, MDCRYPT);
	set_b_val(curbp, MDCRYPT, TRUE);
	curwp->w_flag |= WFMODE;
    } else if (rc == FALSE) {
	if (curbp->b_cryptkey[0] != EOS) {
	    rc = mlyesno("Discard encryption key");
	    if (rc == TRUE) {
		TRACE(("reset key for %s\n", curbp->b_bname));
		curbp->b_cryptkey[0] = EOS;
		if (global_b_val(MDCRYPT)) {
		    make_local_b_val(curbp, MDCRYPT);
		    set_b_val(curbp, MDCRYPT, FALSE);
		    curwp->w_flag |= WFMODE;
		} else if (b_val(curbp,MDCRYPT)) {
		    make_global_val(curbp->b_values.bv, global_b_values.bv, MDCRYPT);
		    curwp->w_flag |= WFMODE;
		}
	    }
	}
    }
    return (rc);
}

/*
 * Call this function at the beginning of encrypting/decrypting a file, i.e.,
 * while writing or reading it.
 */
void
vl_setup_encrypt(char *encrypted_password)
{
    int j, c1, c2, temp;
    unsigned mixs;
    long myseed = seed;	/* this isn't a random number, it's a parameter */

    TRACE(("setup_encrypt(%s)\n", encrypted_password));

    for (j = 0; j < LEN_CRYPT; j++)
	myseed = myseed * encrypted_password[j] + j;

    for (j = 0; j < N_chars; j++)
	table1[j] = (char) j;
    memset(table3, 0, sizeof(table3));

    for (j = 0; j < N_chars; j++) {
	myseed = 5 * myseed + encrypted_password[j % LEN_CRYPT];
	mixs = myseed % 65521;
	c2   = N_chars-1 - j;
	c1   = MASKED(mixs) % (c2+1);
	mixs >>= 8;
	temp = table1[c2];
	table1[c2] = table1[c1];
	table1[c1] = temp;
	if (table3[c2] == 0) {
	    c1 = MASKED(mixs) % c2;
	    while (table3[c1] != 0)
		c1 = (c1+1) % c2;
	    table3[c2] = c1;
	    table3[c1] = c2;
	}
    }

    for(j = 0; j < N_chars; j++)
	table2[MASKED(table1[j])] = j;

    index_1 = 0;
    index_2 = 0;
}

#endif
