Release bumped to "gts4".
[tac_plus.git] / encrypt.c
1 /*
2    Copyright (c) 1995-1998 by Cisco systems, Inc.
3
4    Permission to use, copy, modify, and distribute this software for
5    any purpose and without fee is hereby granted, provided that this
6    copyright and permission notice appear on all copies of the
7    software and supporting documentation, the name of Cisco Systems,
8    Inc. not be used in advertising or publicity pertaining to
9    distribution of the program without specific prior permission, and
10    notice be given in supporting documentation that modification,
11    copying and distribution is by permission of Cisco Systems, Inc.
12
13    Cisco Systems, Inc. makes no representations about the suitability
14    of this software for any purpose.  THIS SOFTWARE IS PROVIDED ``AS
15    IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
16    WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17    FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20
21 #include "tac_plus.h"
22
23 #include <stdlib.h>
24 #include <netinet/in.h>         /* for ntohl() */
25
26 #include "encrypt.h"
27 #include "md5.h"
28 #include "utils.h"
29 #include "report.h"
30 #include "packet.h"
31 #include "main.h"
32
33
34 /*
35  * create_md5_hash(): create an md5 hash of the "session_id", "the user's
36  * key", "the version number", the "sequence number", and an optional
37  * 16 bytes of data (a previously calculated hash). If not present, this
38  * should be NULL pointer.
39  *
40  * Write resulting hash into the array pointed to by "hash".
41  *
42  * The caller must allocate sufficient space for the resulting hash
43  * (which is 16 bytes long). The resulting hash can safely be used as
44  * input to another call to create_md5_hash, as its contents are copied
45  * before the new hash is generated.
46  *
47  *
48  */
49
50 static void create_md5_hash TAC_ARGS((int session_id, const char *key, unsigned version, unsigned seq_no, u_char *prev_hash, u_char *hash));
51
52 static void
53 create_md5_hash(session_id, key, version, seq_no, prev_hash, hash)
54 int session_id;
55 const char *key;
56 unsigned version;                       /* promoted "u_char" type */
57 unsigned seq_no;                        /* promoted "u_char" type */
58 u_char *prev_hash;
59 u_char *hash;
60 {
61     u_char *md_stream, *mdp;
62     int md_len;
63     MD5_CTX mdcontext;
64     u_char version_uchar = version;
65     u_char seq_no_uchar = seq_no;
66
67     md_len = sizeof(session_id) + strlen(key) + sizeof(version_uchar) +
68         sizeof(seq_no_uchar);
69
70     if (prev_hash) {
71         md_len += MD5_LEN;
72     }
73     mdp = md_stream = (u_char *) tac_malloc(md_len);
74     bcopy(&session_id, mdp, sizeof(session_id));
75     mdp += sizeof(session_id);
76
77     bcopy(key, mdp, strlen(key));
78     mdp += strlen(key);
79
80     bcopy(&version_uchar, mdp, sizeof(version_uchar));
81     mdp += sizeof(version_uchar);
82
83     bcopy(&seq_no_uchar, mdp, sizeof(seq_no_uchar));
84     mdp += sizeof(seq_no_uchar);
85
86     if (prev_hash) {
87         bcopy(prev_hash, mdp, MD5_LEN);
88         mdp += MD5_LEN;
89     }
90     MD5Init(&mdcontext);
91     MD5Update(&mdcontext, md_stream, md_len);
92     MD5Final(hash, &mdcontext);
93     free(md_stream);
94     return;
95 }
96
97 /*
98  * Overwrite input data with en/decrypted version by generating an MD5 hash and
99  * xor'ing data with it.
100  *
101  * When more than 16 bytes of hash is needed, the MD5 hash is performed
102  * again with the same values as before, but with the previous hash value
103  * appended to the MD5 input stream.
104  *
105  * Return 0 on success, -1 on failure.
106  */
107
108 int md5_xor TAC_ARGS((HDR *hdr, u_char *data, const char *key));
109
110 int
111 md5_xor(hdr, data, key)
112 HDR *hdr;
113 u_char *data;
114 const char *key;
115 {
116     int i, j;
117     u_char hash[MD5_LEN];       /* the md5 hash */
118     u_char last_hash[MD5_LEN];  /* the last hash we generated */
119     u_char *prev_hashp = (u_char *) NULL;       /* pointer to last created
120                                                  * hash */
121     int data_len;
122     int session_id;
123     u_char version;
124     u_char seq_no;
125
126     data_len = ntohl(hdr->datalength);
127     session_id = hdr->session_id; /* always in network order for hashing */
128     version = hdr->version;
129     seq_no = hdr->seq_no;
130
131     if (!key)
132         return (0);
133
134     for (i = 0; i < data_len; i += 16) {
135
136         create_md5_hash(session_id, key, version, seq_no, prev_hashp, hash);
137
138         if (debug & DEBUG_MD5_HASH_FLAG) {
139             int k;
140
141             report(LOG_DEBUG,
142                    "hash: session_id=%u, key=%s, version=%d, seq_no=%d",
143                    session_id, key, version, seq_no);
144             if (prev_hashp) {
145                 report(LOG_DEBUG, "prev_hash:");
146                 for (k = 0; k < MD5_LEN; k++)
147                     report(LOG_DEBUG, "0x%x", prev_hashp[k]);
148             } else {
149                 report(LOG_DEBUG, "no prev. hash");
150             }
151
152             report(LOG_DEBUG, "hash: ");
153             for (k = 0; k < MD5_LEN; k++)
154                 report(LOG_DEBUG, "0x%x", hash[k]);
155         }                       /* debug */
156         bcopy(hash, last_hash, MD5_LEN);
157         prev_hashp = last_hash;
158
159         for (j = 0; j < 16; j++) {
160
161             if ((i + j) >= data_len) {
162                 hdr->encryption = (hdr->encryption == TAC_PLUS_CLEAR)
163                     ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR;
164                 return (0);
165             }
166             if (debug & DEBUG_XOR_FLAG) {
167                 report(LOG_DEBUG,
168                    "data[%d] = 0x%x, xor'ed with hash[%d] = 0x%x -> 0x%x\n",
169                        i + j,
170                        data[i + j],
171                        j,
172                        hash[j],
173                        data[i + j] ^ hash[j]);
174             }                   /* debug */
175             data[i + j] ^= hash[j];
176         }
177     }
178     hdr->encryption = (hdr->encryption == TAC_PLUS_CLEAR)
179         ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR;
180     return (0);
181 }