File: encrypt.c

package info (click to toggle)
tacacs%2B 4.0.4.27a-3
  • links: PTS, VCS
  • area: main
  • in suites: buster, stretch
  • size: 3,836 kB
  • ctags: 1,187
  • sloc: ansic: 20,991; sh: 11,092; python: 393; makefile: 72
file content (156 lines) | stat: -rw-r--r-- 4,697 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
 * $Id: encrypt.c,v 1.8 2009-03-17 18:38:12 heas Exp $
 *
 * Copyright (c) 1995-1998 by Cisco systems, Inc.
 *
 * Permission to use, copy, modify, and distribute this software for
 * any purpose and without fee is hereby granted, provided that this
 * copyright and permission notice appear on all copies of the
 * software and supporting documentation, the name of Cisco Systems,
 * Inc. not be used in advertising or publicity pertaining to
 * distribution of the program without specific prior permission, and
 * notice be given in supporting documentation that modification,
 * copying and distribution is by permission of Cisco Systems, Inc.
 *
 * Cisco Systems, Inc. makes no representations about the suitability
 * of this software for any purpose.  THIS SOFTWARE IS PROVIDED ``AS
 * IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "tac_plus.h"
#include "md5.h"

/*
 * create_md5_hash(): create an md5 hash of the "session_id", "the user's
 * key", "the version number", the "sequence number", and an optional
 * 16 bytes of data (a previously calculated hash). If not present, this
 * should be NULL pointer.
 *
 * Write resulting hash into the array pointed to by "hash".
 *
 * The caller must allocate sufficient space for the resulting hash
 * (which is 16 bytes long). The resulting hash can safely be used as
 * input to another call to create_md5_hash, as its contents are copied
 * before the new hash is generated.
 */
void
create_md5_hash(int session_id, char *key, u_char version, u_char seq_no,
		u_char *prev_hash, u_char *hash)
{
    u_char *md_stream, *mdp;
    int md_len;
    MD5_CTX mdcontext;

    md_len = sizeof(session_id) + strlen(key) + sizeof(version) +
	sizeof(seq_no);

    if (prev_hash) {
	md_len += TAC_MD5_DIGEST_LEN;
    }
    mdp = md_stream = (u_char *) tac_malloc(md_len);
    memcpy(mdp, &session_id, sizeof(session_id));
    mdp += sizeof(session_id);

    memcpy(mdp, key, strlen(key));
    mdp += strlen(key);

    memcpy(mdp, &version, sizeof(version));
    mdp += sizeof(version);

    memcpy(mdp, &seq_no, sizeof(seq_no));
    mdp += sizeof(seq_no);

    if (prev_hash) {
	memcpy(mdp, prev_hash, TAC_MD5_DIGEST_LEN);
	mdp += TAC_MD5_DIGEST_LEN;
    }
    MD5Init(&mdcontext);
    MD5Update(&mdcontext, md_stream, md_len);
    MD5Final(hash, &mdcontext);
    free(md_stream);
    return;
}

/*
 * Overwrite input data with en/decrypted version by generating an MD5 hash and
 * xor'ing data with it.
 *
 * When more than 16 bytes of hash is needed, the MD5 hash is performed
 * again with the same values as before, but with the previous hash value
 * appended to the MD5 input stream.
 *
 * Return 0 on success, -1 on failure.
 */
int
md5_xor(HDR *hdr, u_char *data, char *key)
{
    int i, j;
    u_char hash[TAC_MD5_DIGEST_LEN];	/* the md5 hash */
    u_char last_hash[TAC_MD5_DIGEST_LEN];	/* the last hash we generated */
    u_char *prev_hashp = (u_char *) NULL;	/* pointer to last created
						 * hash */
    int data_len;
    int session_id;
    u_char version;
    u_char seq_no;

    data_len = ntohl(hdr->datalength);
    session_id = hdr->session_id; /* always in network order for hashing */
    version = hdr->version;
    seq_no = hdr->seq_no;

    if (!key)
	return(0);

    for (i = 0; i < data_len; i += 16) {
	create_md5_hash(session_id, key, version, seq_no, prev_hashp, hash);

	if (debug & DEBUG_MD5_HASH_FLAG) {
	    int k;

	    report(LOG_DEBUG,
		   "hash: session_id=%u, key=%s, version=%d, seq_no=%d",
		   session_id, key, version, seq_no);
	    if (prev_hashp) {
		report(LOG_DEBUG, "prev_hash:");
		for (k = 0; k < TAC_MD5_DIGEST_LEN; k++)
		    report(LOG_DEBUG, "0x%x", prev_hashp[k]);
	    } else {
		report(LOG_DEBUG, "no prev. hash");
	    }

	    report(LOG_DEBUG, "hash: ");
	    for (k = 0; k < TAC_MD5_DIGEST_LEN; k++)
		report(LOG_DEBUG, "0x%x", hash[k]);
	}
	memcpy(last_hash, hash, TAC_MD5_DIGEST_LEN);
	prev_hashp = last_hash;

	for (j = 0; j < 16; j++) {
	    if ((i + j) >= data_len) {
		if (hdr->flags & TAC_PLUS_UNENCRYPTED)
		    hdr->flags &= ~TAC_PLUS_UNENCRYPTED;
		else
		    hdr->flags |= TAC_PLUS_UNENCRYPTED;
		return(0);
	    }
	    if (debug & DEBUG_XOR_FLAG) {
		report(LOG_DEBUG,
		       "data[%d] = 0x%x, xor'ed with hash[%d] = 0x%x -> 0x%x\n",
		       i + j,
		       data[i + j],
		       j,
		       hash[j],
		       data[i + j] ^ hash[j]);
	    }			/* debug */
	    data[i + j] ^= hash[j];
	}
    }
    if (hdr->flags & TAC_PLUS_UNENCRYPTED)
	hdr->flags &= ~TAC_PLUS_UNENCRYPTED;
    else
	hdr->flags |= TAC_PLUS_UNENCRYPTED;
    return(0);
}