/* * Copyright 2002 Christopher SEKIYA * portions copyright 1997-2000 by Pawel Krawczyk * * 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"); } }