Import of tac_plus.v8.tar.gz: 173206 bytes, md5:
[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 #include "tac_plus.h"
21 #include "md5.h"
22
23 /*
24  * create_md5_hash(): create an md5 hash of the "session_id", "the user's
25  * key", "the version number", the "sequence number", and an optional
26  * 16 bytes of data (a previously calculated hash). If not present, this
27  * should be NULL pointer.
28  *
29  * Write resulting hash into the array pointed to by "hash".
30  *
31  * The caller must allocate sufficient space for the resulting hash
32  * (which is 16 bytes long). The resulting hash can safely be used as
33  * input to another call to create_md5_hash, as its contents are copied
34  * before the new hash is generated.
35  *
36  *
37  */
38
39 void
40 create_md5_hash(session_id, key, version, seq_no, prev_hash, hash)
41 int session_id;
42 char *key;
43 u_char version;
44 u_char seq_no;
45 u_char *prev_hash;
46 u_char *hash;
47 {
48     u_char *md_stream, *mdp;
49     int md_len;
50     MD5_CTX mdcontext;
51
52     md_len = sizeof(session_id) + strlen(key) + sizeof(version) +
53         sizeof(seq_no);
54
55     if (prev_hash) {
56         md_len += MD5_LEN;
57     }
58     mdp = md_stream = (u_char *) tac_malloc(md_len);
59     bcopy(&session_id, mdp, sizeof(session_id));
60     mdp += sizeof(session_id);
61
62     bcopy(key, mdp, strlen(key));
63     mdp += strlen(key);
64
65     bcopy(&version, mdp, sizeof(version));
66     mdp += sizeof(version);
67
68     bcopy(&seq_no, mdp, sizeof(seq_no));
69     mdp += sizeof(seq_no);
70
71     if (prev_hash) {
72         bcopy(prev_hash, mdp, MD5_LEN);
73         mdp += MD5_LEN;
74     }
75     MD5Init(&mdcontext);
76     MD5Update(&mdcontext, md_stream, md_len);
77     MD5Final(hash, &mdcontext);
78     free(md_stream);
79     return;
80 }
81
82 /*
83  * Overwrite input data with en/decrypted version by generating an MD5 hash and
84  * xor'ing data with it.
85  *
86  * When more than 16 bytes of hash is needed, the MD5 hash is performed
87  * again with the same values as before, but with the previous hash value
88  * appended to the MD5 input stream.
89  *
90  * Return 0 on success, -1 on failure.
91  */
92
93 md5_xor(hdr, data, key)
94 HDR *hdr;
95 u_char *data;
96 char *key;
97 {
98     int i, j;
99     u_char hash[MD5_LEN];       /* the md5 hash */
100     u_char last_hash[MD5_LEN];  /* the last hash we generated */
101     u_char *prev_hashp = (u_char *) NULL;       /* pointer to last created
102                                                  * hash */
103     int data_len;
104     int session_id;
105     u_char version;
106     u_char seq_no;
107
108     data_len = ntohl(hdr->datalength);
109     session_id = hdr->session_id; /* always in network order for hashing */
110     version = hdr->version;
111     seq_no = hdr->seq_no;
112
113     if (!key)
114         return (0);
115
116     for (i = 0; i < data_len; i += 16) {
117
118         create_md5_hash(session_id, key, version, seq_no, prev_hashp, hash);
119
120         if (debug & DEBUG_MD5_HASH_FLAG) {
121             int k;
122
123             report(LOG_DEBUG, 
124                    "hash: session_id=%u, key=%s, version=%d, seq_no=%d",
125                    session_id, key, version, seq_no);
126             if (prev_hashp) {
127                 report(LOG_DEBUG, "prev_hash:");
128                 for (k = 0; k < MD5_LEN; k++)
129                     report(LOG_DEBUG, "0x%x", prev_hashp[k]);
130             } else {
131                 report(LOG_DEBUG, "no prev. hash");
132             }
133
134             report(LOG_DEBUG, "hash: ");
135             for (k = 0; k < MD5_LEN; k++)
136                 report(LOG_DEBUG, "0x%x", hash[k]);
137         }                       /* debug */
138         bcopy(hash, last_hash, MD5_LEN);
139         prev_hashp = last_hash;
140
141         for (j = 0; j < 16; j++) {
142
143             if ((i + j) >= data_len) {
144                 hdr->encryption = (hdr->encryption == TAC_PLUS_CLEAR) 
145                     ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR;
146                 return (0);
147             }
148             if (debug & DEBUG_XOR_FLAG) {
149                 report(LOG_DEBUG,
150                    "data[%d] = 0x%x, xor'ed with hash[%d] = 0x%x -> 0x%x\n",
151                        i + j,
152                        data[i + j],
153                        j,
154                        hash[j],
155                        data[i + j] ^ hash[j]);
156             }                   /* debug */
157             data[i + j] ^= hash[j];
158         }
159     }
160     hdr->encryption = (hdr->encryption == TAC_PLUS_CLEAR) 
161         ? TAC_PLUS_ENCRYPTED : TAC_PLUS_CLEAR;
162     return (0);
163 }