/*
 * Copyright 2002 Christopher SEKIYA <wileyc@rezrov.net>
 * portions copyright 1997-2000 by Pawel Krawczyk <kravietz@ceti.pl>
 *
 * crypt.c  TACACS+ encryption related functions
 *
 */

#include "tacshell.h"

#include "md5.h"

unsigned char  *
tac_md5_pad(int len, struct tacacs_header * hdr)
{
	int             n, i, bufsize;
	int             bp = 0;	/* buffer pointer */
	int             pp = 0;	/* pad pointer */
	unsigned char  *pad;
	unsigned char  *buf;
	MD5_CTX         mdcontext;

	/* make pseudo pad */
	n = (int) (len / 16) + 1;	/* number of MD5 runs */
	bufsize = sizeof(hdr->session_id) + strlen(server_secret) + sizeof(hdr->version)
		+ sizeof(hdr->seq_no) + MD5_LEN + 10;
	buf = (unsigned char *) calloc(1, bufsize);
	pad = (unsigned char *) calloc(n, MD5_LEN);

	for (i = 0; i < n; i++) {
		/*
		 * MD5_1 = MD5{session_id, secret, version, seq_no} MD5_2 =
		 * MD5{session_id, secret, version, seq_no, MD5_1}
		 */

		/* place session_id, key, version and seq_no in buffer */
		bp = 0;
		bcopy(&hdr->session_id, buf, sizeof(session_id));
		bp += sizeof(session_id);
		bcopy(server_secret, buf + bp, strlen(server_secret));
		bp += strlen(server_secret);
		bcopy(&hdr->version, buf + bp, sizeof(hdr->version));
		bp += sizeof(hdr->version);
		bcopy(&hdr->seq_no, buf + bp, sizeof(hdr->seq_no));
		bp += sizeof(hdr->seq_no);

		/* append previous pad if this is not the first run */
		if (i) {
			bcopy(pad + ((i - 1) * MD5_LEN), buf + bp, MD5_LEN);
			bp += MD5_LEN;
		}
		MD5Init(&mdcontext);
		MD5Update(&mdcontext, buf, bp);

		MD5Final(pad + pp, &mdcontext);	/* correct for pppd-2.3.4 */

		pp += MD5_LEN;
	}

	free(buf);
	return (pad);

}

/*
 * Perform encryption/decryption on buffer. This means simply XORing each
 * byte from buffer with according byte from pseudo-random pad.
 */
void
tac_crypt(unsigned char *buf, struct tacacs_header * th, int length)
{
	int             i;
	unsigned char  *pad;

	/* null operation if no encryption requested */
	if (th->encryption == TAC_PLUS_ENCRYPTED) {

		pad = tac_md5_pad(length, th);

		for (i = 0; i < length; i++) {
			*(buf + i) ^= pad[i];
		}

		free(pad);

	} else {
		fprintf(stderr, "tacshell: not using TACACS+ encryption\n");
	}
}


syntax highlighted by Code2HTML, v. 0.9.1