113e3f4d6SMark Murray /*-
213e3f4d6SMark Murray * Copyright (c) 1991, 1993
313e3f4d6SMark Murray * The Regents of the University of California. All rights reserved.
413e3f4d6SMark Murray *
513e3f4d6SMark Murray * Redistribution and use in source and binary forms, with or without
613e3f4d6SMark Murray * modification, are permitted provided that the following conditions
713e3f4d6SMark Murray * are met:
813e3f4d6SMark Murray * 1. Redistributions of source code must retain the above copyright
913e3f4d6SMark Murray * notice, this list of conditions and the following disclaimer.
1013e3f4d6SMark Murray * 2. Redistributions in binary form must reproduce the above copyright
1113e3f4d6SMark Murray * notice, this list of conditions and the following disclaimer in the
1213e3f4d6SMark Murray * documentation and/or other materials provided with the distribution.
1313e3f4d6SMark Murray * 3. All advertising materials mentioning features or use of this software
1413e3f4d6SMark Murray * must display the following acknowledgement:
1513e3f4d6SMark Murray * This product includes software developed by the University of
1613e3f4d6SMark Murray * California, Berkeley and its contributors.
1713e3f4d6SMark Murray * 4. Neither the name of the University nor the names of its contributors
1813e3f4d6SMark Murray * may be used to endorse or promote products derived from this software
1913e3f4d6SMark Murray * without specific prior written permission.
2013e3f4d6SMark Murray *
2113e3f4d6SMark Murray * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2213e3f4d6SMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2313e3f4d6SMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2413e3f4d6SMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2513e3f4d6SMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2613e3f4d6SMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2713e3f4d6SMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2813e3f4d6SMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2913e3f4d6SMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3013e3f4d6SMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3113e3f4d6SMark Murray * SUCH DAMAGE.
3213e3f4d6SMark Murray */
3313e3f4d6SMark Murray
3413e3f4d6SMark Murray #include <config.h>
3513e3f4d6SMark Murray
36c19800e8SDoug Rabson RCSID("$Id$");
3713e3f4d6SMark Murray
3813e3f4d6SMark Murray #if defined(AUTHENTICATION) && defined(ENCRYPTION) && defined(DES_ENCRYPTION)
3913e3f4d6SMark Murray #include <arpa/telnet.h>
4013e3f4d6SMark Murray #include <stdio.h>
4113e3f4d6SMark Murray #ifdef __STDC__
4213e3f4d6SMark Murray #include <stdlib.h>
4313e3f4d6SMark Murray #include <string.h>
4413e3f4d6SMark Murray #endif
4513e3f4d6SMark Murray #include <roken.h>
4613e3f4d6SMark Murray #ifdef SOCKS
4713e3f4d6SMark Murray #include <socks.h>
4813e3f4d6SMark Murray #endif
4913e3f4d6SMark Murray
5013e3f4d6SMark Murray #include "encrypt.h"
5113e3f4d6SMark Murray #include "misc-proto.h"
5213e3f4d6SMark Murray
530cadf2f4SJacques Vidrine #include "crypto-headers.h"
5413e3f4d6SMark Murray
5513e3f4d6SMark Murray extern int encrypt_debug_mode;
5613e3f4d6SMark Murray
5713e3f4d6SMark Murray #define CFB 0
5813e3f4d6SMark Murray #define OFB 1
5913e3f4d6SMark Murray
6013e3f4d6SMark Murray #define NO_SEND_IV 1
6113e3f4d6SMark Murray #define NO_RECV_IV 2
6213e3f4d6SMark Murray #define NO_KEYID 4
6313e3f4d6SMark Murray #define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID)
6413e3f4d6SMark Murray #define SUCCESS 0
6513e3f4d6SMark Murray #define FAILED -1
6613e3f4d6SMark Murray
6713e3f4d6SMark Murray
6813e3f4d6SMark Murray struct stinfo {
69c19800e8SDoug Rabson DES_cblock str_output;
70c19800e8SDoug Rabson DES_cblock str_feed;
71c19800e8SDoug Rabson DES_cblock str_iv;
72c19800e8SDoug Rabson DES_cblock str_ikey;
73c19800e8SDoug Rabson DES_key_schedule str_sched;
7413e3f4d6SMark Murray int str_index;
7513e3f4d6SMark Murray int str_flagshift;
7613e3f4d6SMark Murray };
7713e3f4d6SMark Murray
7813e3f4d6SMark Murray struct fb {
79c19800e8SDoug Rabson DES_cblock krbdes_key;
80c19800e8SDoug Rabson DES_key_schedule krbdes_sched;
81c19800e8SDoug Rabson DES_cblock temp_feed;
8213e3f4d6SMark Murray unsigned char fb_feed[64];
8313e3f4d6SMark Murray int need_start;
8413e3f4d6SMark Murray int state[2];
8513e3f4d6SMark Murray int keyid[2];
8613e3f4d6SMark Murray struct stinfo streams[2];
8713e3f4d6SMark Murray };
8813e3f4d6SMark Murray
8913e3f4d6SMark Murray static struct fb fb[2];
9013e3f4d6SMark Murray
9113e3f4d6SMark Murray struct keyidlist {
9213e3f4d6SMark Murray char *keyid;
9313e3f4d6SMark Murray int keyidlen;
9413e3f4d6SMark Murray char *key;
9513e3f4d6SMark Murray int keylen;
9613e3f4d6SMark Murray int flags;
9713e3f4d6SMark Murray } keyidlist [] = {
9813e3f4d6SMark Murray { "\0", 1, 0, 0, 0 }, /* default key of zero */
9913e3f4d6SMark Murray { 0, 0, 0, 0, 0 }
10013e3f4d6SMark Murray };
10113e3f4d6SMark Murray
10213e3f4d6SMark Murray #define KEYFLAG_MASK 03
10313e3f4d6SMark Murray
10413e3f4d6SMark Murray #define KEYFLAG_NOINIT 00
10513e3f4d6SMark Murray #define KEYFLAG_INIT 01
10613e3f4d6SMark Murray #define KEYFLAG_OK 02
10713e3f4d6SMark Murray #define KEYFLAG_BAD 03
10813e3f4d6SMark Murray
10913e3f4d6SMark Murray #define KEYFLAG_SHIFT 2
11013e3f4d6SMark Murray
11113e3f4d6SMark Murray #define SHIFT_VAL(a,b) (KEYFLAG_SHIFT*((a)+((b)*2)))
11213e3f4d6SMark Murray
11313e3f4d6SMark Murray #define FB64_IV 1
11413e3f4d6SMark Murray #define FB64_IV_OK 2
11513e3f4d6SMark Murray #define FB64_IV_BAD 3
11613e3f4d6SMark Murray
11713e3f4d6SMark Murray
11813e3f4d6SMark Murray void fb64_stream_iv (DES_cblock, struct stinfo *);
119c19800e8SDoug Rabson void fb64_init (struct fb *);
12013e3f4d6SMark Murray static int fb64_start (struct fb *, int, int);
12113e3f4d6SMark Murray int fb64_is (unsigned char *, int, struct fb *);
12213e3f4d6SMark Murray int fb64_reply (unsigned char *, int, struct fb *);
12313e3f4d6SMark Murray static void fb64_session (Session_Key *, int, struct fb *);
12413e3f4d6SMark Murray void fb64_stream_key (DES_cblock, struct stinfo *);
125c19800e8SDoug Rabson int fb64_keyid (int, unsigned char *, int *, struct fb *);
12613e3f4d6SMark Murray void fb64_printsub(unsigned char *, size_t ,
1274137ff4cSJacques Vidrine unsigned char *, size_t , char *);
1284137ff4cSJacques Vidrine
cfb64_init(int server)12913e3f4d6SMark Murray void cfb64_init(int server)
13013e3f4d6SMark Murray {
13113e3f4d6SMark Murray fb64_init(&fb[CFB]);
13213e3f4d6SMark Murray fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
13313e3f4d6SMark Murray fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
13413e3f4d6SMark Murray fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
13513e3f4d6SMark Murray }
13613e3f4d6SMark Murray
13713e3f4d6SMark Murray
ofb64_init(int server)13813e3f4d6SMark Murray void ofb64_init(int server)
13913e3f4d6SMark Murray {
14013e3f4d6SMark Murray fb64_init(&fb[OFB]);
14113e3f4d6SMark Murray fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
14213e3f4d6SMark Murray fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
14313e3f4d6SMark Murray fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
14413e3f4d6SMark Murray }
14513e3f4d6SMark Murray
fb64_init(struct fb * fbp)14613e3f4d6SMark Murray void fb64_init(struct fb *fbp)
14713e3f4d6SMark Murray {
14813e3f4d6SMark Murray memset(fbp,0, sizeof(*fbp));
14913e3f4d6SMark Murray fbp->state[0] = fbp->state[1] = FAILED;
15013e3f4d6SMark Murray fbp->fb_feed[0] = IAC;
15113e3f4d6SMark Murray fbp->fb_feed[1] = SB;
15213e3f4d6SMark Murray fbp->fb_feed[2] = TELOPT_ENCRYPT;
15313e3f4d6SMark Murray fbp->fb_feed[3] = ENCRYPT_IS;
15413e3f4d6SMark Murray }
15513e3f4d6SMark Murray
15613e3f4d6SMark Murray /*
15713e3f4d6SMark Murray * Returns:
15813e3f4d6SMark Murray * -1: some error. Negotiation is done, encryption not ready.
15913e3f4d6SMark Murray * 0: Successful, initial negotiation all done.
16013e3f4d6SMark Murray * 1: successful, negotiation not done yet.
16113e3f4d6SMark Murray * 2: Not yet. Other things (like getting the key from
16213e3f4d6SMark Murray * Kerberos) have to happen before we can continue.
16313e3f4d6SMark Murray */
cfb64_start(int dir,int server)16413e3f4d6SMark Murray int cfb64_start(int dir, int server)
16513e3f4d6SMark Murray {
16613e3f4d6SMark Murray return(fb64_start(&fb[CFB], dir, server));
16713e3f4d6SMark Murray }
16813e3f4d6SMark Murray
ofb64_start(int dir,int server)16913e3f4d6SMark Murray int ofb64_start(int dir, int server)
17013e3f4d6SMark Murray {
17113e3f4d6SMark Murray return(fb64_start(&fb[OFB], dir, server));
17213e3f4d6SMark Murray }
17313e3f4d6SMark Murray
fb64_start(struct fb * fbp,int dir,int server)17413e3f4d6SMark Murray static int fb64_start(struct fb *fbp, int dir, int server)
17513e3f4d6SMark Murray {
17613e3f4d6SMark Murray int x;
17713e3f4d6SMark Murray unsigned char *p;
17813e3f4d6SMark Murray int state;
17913e3f4d6SMark Murray
18013e3f4d6SMark Murray switch (dir) {
18113e3f4d6SMark Murray case DIR_DECRYPT:
18213e3f4d6SMark Murray /*
18313e3f4d6SMark Murray * This is simply a request to have the other side
18413e3f4d6SMark Murray * start output (our input). He will negotiate an
18513e3f4d6SMark Murray * IV so we need not look for it.
18613e3f4d6SMark Murray */
18713e3f4d6SMark Murray state = fbp->state[dir-1];
18813e3f4d6SMark Murray if (state == FAILED)
18913e3f4d6SMark Murray state = IN_PROGRESS;
19013e3f4d6SMark Murray break;
19113e3f4d6SMark Murray
19213e3f4d6SMark Murray case DIR_ENCRYPT:
19313e3f4d6SMark Murray state = fbp->state[dir-1];
19413e3f4d6SMark Murray if (state == FAILED)
19513e3f4d6SMark Murray state = IN_PROGRESS;
19613e3f4d6SMark Murray else if ((state & NO_SEND_IV) == 0) {
19713e3f4d6SMark Murray break;
19813e3f4d6SMark Murray }
19913e3f4d6SMark Murray
20013e3f4d6SMark Murray if (!VALIDKEY(fbp->krbdes_key)) {
20113e3f4d6SMark Murray fbp->need_start = 1;
20213e3f4d6SMark Murray break;
20313e3f4d6SMark Murray }
20413e3f4d6SMark Murray
20513e3f4d6SMark Murray state &= ~NO_SEND_IV;
20613e3f4d6SMark Murray state |= NO_RECV_IV;
20713e3f4d6SMark Murray if (encrypt_debug_mode)
20813e3f4d6SMark Murray printf("Creating new feed\r\n");
20913e3f4d6SMark Murray /*
21013e3f4d6SMark Murray * Create a random feed and send it over.
21113e3f4d6SMark Murray */
21213e3f4d6SMark Murray do {
21313e3f4d6SMark Murray if (RAND_bytes(fbp->temp_feed,
214c19800e8SDoug Rabson sizeof(*fbp->temp_feed)) != 1)
21513e3f4d6SMark Murray abort();
21613e3f4d6SMark Murray DES_set_odd_parity(&fbp->temp_feed);
21713e3f4d6SMark Murray } while(DES_is_weak_key(&fbp->temp_feed));
21813e3f4d6SMark Murray
21913e3f4d6SMark Murray p = fbp->fb_feed + 3;
22013e3f4d6SMark Murray *p++ = ENCRYPT_IS;
22113e3f4d6SMark Murray p++;
222c19800e8SDoug Rabson *p++ = FB64_IV;
223c19800e8SDoug Rabson for (x = 0; x < sizeof(DES_cblock); ++x) {
224c19800e8SDoug Rabson if ((*p++ = fbp->temp_feed[x]) == IAC)
22513e3f4d6SMark Murray *p++ = IAC;
226c19800e8SDoug Rabson }
22713e3f4d6SMark Murray *p++ = IAC;
228c19800e8SDoug Rabson *p++ = SE;
22913e3f4d6SMark Murray printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
23013e3f4d6SMark Murray telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
23113e3f4d6SMark Murray break;
23213e3f4d6SMark Murray default:
233c19800e8SDoug Rabson return(FAILED);
23413e3f4d6SMark Murray }
23513e3f4d6SMark Murray return(fbp->state[dir-1] = state);
23613e3f4d6SMark Murray }
23713e3f4d6SMark Murray
23813e3f4d6SMark Murray /*
23913e3f4d6SMark Murray * Returns:
24013e3f4d6SMark Murray * -1: some error. Negotiation is done, encryption not ready.
24113e3f4d6SMark Murray * 0: Successful, initial negotiation all done.
24213e3f4d6SMark Murray * 1: successful, negotiation not done yet.
24313e3f4d6SMark Murray */
24413e3f4d6SMark Murray
cfb64_is(unsigned char * data,int cnt)24513e3f4d6SMark Murray int cfb64_is(unsigned char *data, int cnt)
24613e3f4d6SMark Murray {
24713e3f4d6SMark Murray return(fb64_is(data, cnt, &fb[CFB]));
24813e3f4d6SMark Murray }
24913e3f4d6SMark Murray
ofb64_is(unsigned char * data,int cnt)25013e3f4d6SMark Murray int ofb64_is(unsigned char *data, int cnt)
25113e3f4d6SMark Murray {
25213e3f4d6SMark Murray return(fb64_is(data, cnt, &fb[OFB]));
25313e3f4d6SMark Murray }
25413e3f4d6SMark Murray
25513e3f4d6SMark Murray
fb64_is(unsigned char * data,int cnt,struct fb * fbp)25613e3f4d6SMark Murray int fb64_is(unsigned char *data, int cnt, struct fb *fbp)
25713e3f4d6SMark Murray {
25813e3f4d6SMark Murray unsigned char *p;
25913e3f4d6SMark Murray int state = fbp->state[DIR_DECRYPT-1];
26013e3f4d6SMark Murray
26113e3f4d6SMark Murray if (cnt-- < 1)
26213e3f4d6SMark Murray goto failure;
26313e3f4d6SMark Murray
26413e3f4d6SMark Murray switch (*data++) {
26513e3f4d6SMark Murray case FB64_IV:
26613e3f4d6SMark Murray if (cnt != sizeof(DES_cblock)) {
26713e3f4d6SMark Murray if (encrypt_debug_mode)
26813e3f4d6SMark Murray printf("CFB64: initial vector failed on size\r\n");
26913e3f4d6SMark Murray state = FAILED;
27013e3f4d6SMark Murray goto failure;
27113e3f4d6SMark Murray }
27213e3f4d6SMark Murray
27313e3f4d6SMark Murray if (encrypt_debug_mode)
27413e3f4d6SMark Murray printf("CFB64: initial vector received\r\n");
27513e3f4d6SMark Murray
276c19800e8SDoug Rabson if (encrypt_debug_mode)
27713e3f4d6SMark Murray printf("Initializing Decrypt stream\r\n");
27813e3f4d6SMark Murray
27913e3f4d6SMark Murray fb64_stream_iv(data, &fbp->streams[DIR_DECRYPT-1]);
28013e3f4d6SMark Murray
28113e3f4d6SMark Murray p = fbp->fb_feed + 3;
28213e3f4d6SMark Murray *p++ = ENCRYPT_REPLY;
28313e3f4d6SMark Murray p++;
28413e3f4d6SMark Murray *p++ = FB64_IV_OK;
28513e3f4d6SMark Murray *p++ = IAC;
28613e3f4d6SMark Murray *p++ = SE;
28713e3f4d6SMark Murray printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
28813e3f4d6SMark Murray telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
28913e3f4d6SMark Murray
29013e3f4d6SMark Murray state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
29113e3f4d6SMark Murray break;
29213e3f4d6SMark Murray
29313e3f4d6SMark Murray default:
29413e3f4d6SMark Murray if (encrypt_debug_mode) {
29513e3f4d6SMark Murray printf("Unknown option type: %d\r\n", *(data-1));
29613e3f4d6SMark Murray printd(data, cnt);
29713e3f4d6SMark Murray printf("\r\n");
29813e3f4d6SMark Murray }
29913e3f4d6SMark Murray /* FALL THROUGH */
30013e3f4d6SMark Murray failure:
30113e3f4d6SMark Murray /*
30213e3f4d6SMark Murray * We failed. Send an FB64_IV_BAD option
30313e3f4d6SMark Murray * to the other side so it will know that
30413e3f4d6SMark Murray * things failed.
30513e3f4d6SMark Murray */
30613e3f4d6SMark Murray p = fbp->fb_feed + 3;
30713e3f4d6SMark Murray *p++ = ENCRYPT_REPLY;
30813e3f4d6SMark Murray p++;
30913e3f4d6SMark Murray *p++ = FB64_IV_BAD;
31013e3f4d6SMark Murray *p++ = IAC;
31113e3f4d6SMark Murray *p++ = SE;
31213e3f4d6SMark Murray printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
31313e3f4d6SMark Murray telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
31413e3f4d6SMark Murray
31513e3f4d6SMark Murray break;
31613e3f4d6SMark Murray }
31713e3f4d6SMark Murray return(fbp->state[DIR_DECRYPT-1] = state);
31813e3f4d6SMark Murray }
31913e3f4d6SMark Murray
32013e3f4d6SMark Murray /*
32113e3f4d6SMark Murray * Returns:
32213e3f4d6SMark Murray * -1: some error. Negotiation is done, encryption not ready.
32313e3f4d6SMark Murray * 0: Successful, initial negotiation all done.
32413e3f4d6SMark Murray * 1: successful, negotiation not done yet.
32513e3f4d6SMark Murray */
32613e3f4d6SMark Murray
cfb64_reply(unsigned char * data,int cnt)32713e3f4d6SMark Murray int cfb64_reply(unsigned char *data, int cnt)
32813e3f4d6SMark Murray {
32913e3f4d6SMark Murray return(fb64_reply(data, cnt, &fb[CFB]));
33013e3f4d6SMark Murray }
33113e3f4d6SMark Murray
ofb64_reply(unsigned char * data,int cnt)33213e3f4d6SMark Murray int ofb64_reply(unsigned char *data, int cnt)
33313e3f4d6SMark Murray {
33413e3f4d6SMark Murray return(fb64_reply(data, cnt, &fb[OFB]));
33513e3f4d6SMark Murray }
33613e3f4d6SMark Murray
33713e3f4d6SMark Murray
fb64_reply(unsigned char * data,int cnt,struct fb * fbp)33813e3f4d6SMark Murray int fb64_reply(unsigned char *data, int cnt, struct fb *fbp)
33913e3f4d6SMark Murray {
34013e3f4d6SMark Murray int state = fbp->state[DIR_ENCRYPT-1];
34113e3f4d6SMark Murray
34213e3f4d6SMark Murray if (cnt-- < 1)
34313e3f4d6SMark Murray goto failure;
34413e3f4d6SMark Murray
34513e3f4d6SMark Murray switch (*data++) {
34613e3f4d6SMark Murray case FB64_IV_OK:
34713e3f4d6SMark Murray fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
34813e3f4d6SMark Murray if (state == FAILED)
34913e3f4d6SMark Murray state = IN_PROGRESS;
35013e3f4d6SMark Murray state &= ~NO_RECV_IV;
35113e3f4d6SMark Murray encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1);
35213e3f4d6SMark Murray break;
35313e3f4d6SMark Murray
35413e3f4d6SMark Murray case FB64_IV_BAD:
35513e3f4d6SMark Murray memset(fbp->temp_feed, 0, sizeof(DES_cblock));
35613e3f4d6SMark Murray fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
35713e3f4d6SMark Murray state = FAILED;
35813e3f4d6SMark Murray break;
35913e3f4d6SMark Murray
36013e3f4d6SMark Murray default:
36113e3f4d6SMark Murray if (encrypt_debug_mode) {
36213e3f4d6SMark Murray printf("Unknown option type: %d\r\n", data[-1]);
36313e3f4d6SMark Murray printd(data, cnt);
36413e3f4d6SMark Murray printf("\r\n");
365c19800e8SDoug Rabson }
36613e3f4d6SMark Murray /* FALL THROUGH */
36713e3f4d6SMark Murray failure:
36813e3f4d6SMark Murray state = FAILED;
36913e3f4d6SMark Murray break;
37013e3f4d6SMark Murray }
37113e3f4d6SMark Murray return(fbp->state[DIR_ENCRYPT-1] = state);
37213e3f4d6SMark Murray }
37313e3f4d6SMark Murray
cfb64_session(Session_Key * key,int server)37413e3f4d6SMark Murray void cfb64_session(Session_Key *key, int server)
37513e3f4d6SMark Murray {
37613e3f4d6SMark Murray fb64_session(key, server, &fb[CFB]);
37713e3f4d6SMark Murray }
37813e3f4d6SMark Murray
ofb64_session(Session_Key * key,int server)37913e3f4d6SMark Murray void ofb64_session(Session_Key *key, int server)
38013e3f4d6SMark Murray {
38113e3f4d6SMark Murray fb64_session(key, server, &fb[OFB]);
38213e3f4d6SMark Murray }
38313e3f4d6SMark Murray
fb64_session(Session_Key * key,int server,struct fb * fbp)38413e3f4d6SMark Murray static void fb64_session(Session_Key *key, int server, struct fb *fbp)
38513e3f4d6SMark Murray {
38613e3f4d6SMark Murray
38713e3f4d6SMark Murray if (!key || key->type != SK_DES) {
38813e3f4d6SMark Murray if (encrypt_debug_mode)
38913e3f4d6SMark Murray printf("Can't set krbdes's session key (%d != %d)\r\n",
39013e3f4d6SMark Murray key ? key->type : -1, SK_DES);
39113e3f4d6SMark Murray return;
39213e3f4d6SMark Murray }
39313e3f4d6SMark Murray memcpy(fbp->krbdes_key, key->data, sizeof(DES_cblock));
39413e3f4d6SMark Murray
39513e3f4d6SMark Murray fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
39613e3f4d6SMark Murray fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
39713e3f4d6SMark Murray
39813e3f4d6SMark Murray RAND_seed(key->data, key->length);
39913e3f4d6SMark Murray
40013e3f4d6SMark Murray DES_set_key_checked((DES_cblock *)&fbp->krbdes_key,
40113e3f4d6SMark Murray &fbp->krbdes_sched);
40213e3f4d6SMark Murray /*
403c19800e8SDoug Rabson * Now look to see if krbdes_start() was waiting for the key to
40413e3f4d6SMark Murray * show up. If so, go ahead an call it now that we have the key.
40513e3f4d6SMark Murray */
40613e3f4d6SMark Murray if (fbp->need_start) {
40713e3f4d6SMark Murray fbp->need_start = 0;
40813e3f4d6SMark Murray fb64_start(fbp, DIR_ENCRYPT, server);
4094137ff4cSJacques Vidrine }
410c19800e8SDoug Rabson }
41113e3f4d6SMark Murray
41213e3f4d6SMark Murray /*
41313e3f4d6SMark Murray * We only accept a keyid of 0. If we get a keyid of
414c19800e8SDoug Rabson * 0, then mark the state as SUCCESS.
415c19800e8SDoug Rabson */
41613e3f4d6SMark Murray
cfb64_keyid(int dir,unsigned char * kp,int * lenp)41713e3f4d6SMark Murray int cfb64_keyid(int dir, unsigned char *kp, int *lenp)
41813e3f4d6SMark Murray {
41913e3f4d6SMark Murray return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
42013e3f4d6SMark Murray }
42113e3f4d6SMark Murray
ofb64_keyid(int dir,unsigned char * kp,int * lenp)42213e3f4d6SMark Murray int ofb64_keyid(int dir, unsigned char *kp, int *lenp)
42313e3f4d6SMark Murray {
42413e3f4d6SMark Murray return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
42513e3f4d6SMark Murray }
42613e3f4d6SMark Murray
fb64_keyid(int dir,unsigned char * kp,int * lenp,struct fb * fbp)42713e3f4d6SMark Murray int fb64_keyid(int dir, unsigned char *kp, int *lenp, struct fb *fbp)
42813e3f4d6SMark Murray {
42913e3f4d6SMark Murray int state = fbp->state[dir-1];
43013e3f4d6SMark Murray
43113e3f4d6SMark Murray if (*lenp != 1 || (*kp != '\0')) {
43213e3f4d6SMark Murray *lenp = 0;
43313e3f4d6SMark Murray return(state);
43413e3f4d6SMark Murray }
43513e3f4d6SMark Murray
43613e3f4d6SMark Murray if (state == FAILED)
43713e3f4d6SMark Murray state = IN_PROGRESS;
43813e3f4d6SMark Murray
43913e3f4d6SMark Murray state &= ~NO_KEYID;
44013e3f4d6SMark Murray
44113e3f4d6SMark Murray return(fbp->state[dir-1] = state);
44213e3f4d6SMark Murray }
44313e3f4d6SMark Murray
fb64_printsub(unsigned char * data,size_t cnt,unsigned char * buf,size_t buflen,char * type)44413e3f4d6SMark Murray void fb64_printsub(unsigned char *data, size_t cnt,
44513e3f4d6SMark Murray unsigned char *buf, size_t buflen, char *type)
44613e3f4d6SMark Murray {
44713e3f4d6SMark Murray char lbuf[32];
44813e3f4d6SMark Murray int i;
44913e3f4d6SMark Murray char *cp;
45013e3f4d6SMark Murray
45113e3f4d6SMark Murray buf[buflen-1] = '\0'; /* make sure it's NULL terminated */
45213e3f4d6SMark Murray buflen -= 1;
45313e3f4d6SMark Murray
45413e3f4d6SMark Murray switch(data[2]) {
45513e3f4d6SMark Murray case FB64_IV:
45613e3f4d6SMark Murray snprintf(lbuf, sizeof(lbuf), "%s_IV", type);
45713e3f4d6SMark Murray cp = lbuf;
45813e3f4d6SMark Murray goto common;
45913e3f4d6SMark Murray
46013e3f4d6SMark Murray case FB64_IV_OK:
46113e3f4d6SMark Murray snprintf(lbuf, sizeof(lbuf), "%s_IV_OK", type);
46213e3f4d6SMark Murray cp = lbuf;
46313e3f4d6SMark Murray goto common;
46413e3f4d6SMark Murray
46513e3f4d6SMark Murray case FB64_IV_BAD:
46613e3f4d6SMark Murray snprintf(lbuf, sizeof(lbuf), "%s_IV_BAD", type);
46713e3f4d6SMark Murray cp = lbuf;
46813e3f4d6SMark Murray goto common;
46913e3f4d6SMark Murray
47013e3f4d6SMark Murray default:
47113e3f4d6SMark Murray snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[2]);
47213e3f4d6SMark Murray cp = lbuf;
47313e3f4d6SMark Murray common:
47413e3f4d6SMark Murray for (; (buflen > 0) && (*buf = *cp++); buf++)
47513e3f4d6SMark Murray buflen--;
47613e3f4d6SMark Murray for (i = 3; i < cnt; i++) {
47713e3f4d6SMark Murray snprintf(lbuf, sizeof(lbuf), " %d", data[i]);
47813e3f4d6SMark Murray for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
47913e3f4d6SMark Murray buflen--;
48013e3f4d6SMark Murray }
48113e3f4d6SMark Murray break;
48213e3f4d6SMark Murray }
48313e3f4d6SMark Murray }
48413e3f4d6SMark Murray
cfb64_printsub(unsigned char * data,size_t cnt,unsigned char * buf,size_t buflen)48513e3f4d6SMark Murray void cfb64_printsub(unsigned char *data, size_t cnt,
48613e3f4d6SMark Murray unsigned char *buf, size_t buflen)
48713e3f4d6SMark Murray {
48813e3f4d6SMark Murray fb64_printsub(data, cnt, buf, buflen, "CFB64");
48913e3f4d6SMark Murray }
49013e3f4d6SMark Murray
ofb64_printsub(unsigned char * data,size_t cnt,unsigned char * buf,size_t buflen)49113e3f4d6SMark Murray void ofb64_printsub(unsigned char *data, size_t cnt,
49213e3f4d6SMark Murray unsigned char *buf, size_t buflen)
49313e3f4d6SMark Murray {
49413e3f4d6SMark Murray fb64_printsub(data, cnt, buf, buflen, "OFB64");
49513e3f4d6SMark Murray }
49613e3f4d6SMark Murray
fb64_stream_iv(DES_cblock seed,struct stinfo * stp)49713e3f4d6SMark Murray void fb64_stream_iv(DES_cblock seed, struct stinfo *stp)
49813e3f4d6SMark Murray {
49913e3f4d6SMark Murray
50013e3f4d6SMark Murray memcpy(stp->str_iv, seed,sizeof(DES_cblock));
50113e3f4d6SMark Murray memcpy(stp->str_output, seed, sizeof(DES_cblock));
50213e3f4d6SMark Murray
50313e3f4d6SMark Murray DES_set_key_checked(&stp->str_ikey, &stp->str_sched);
50413e3f4d6SMark Murray
50513e3f4d6SMark Murray stp->str_index = sizeof(DES_cblock);
50613e3f4d6SMark Murray }
50713e3f4d6SMark Murray
fb64_stream_key(DES_cblock key,struct stinfo * stp)50813e3f4d6SMark Murray void fb64_stream_key(DES_cblock key, struct stinfo *stp)
50913e3f4d6SMark Murray {
51013e3f4d6SMark Murray memcpy(stp->str_ikey, key, sizeof(DES_cblock));
51113e3f4d6SMark Murray DES_set_key_checked((DES_cblock*)key, &stp->str_sched);
512c19800e8SDoug Rabson
51313e3f4d6SMark Murray memcpy(stp->str_output, stp->str_iv, sizeof(DES_cblock));
51413e3f4d6SMark Murray
515c19800e8SDoug Rabson stp->str_index = sizeof(DES_cblock);
516c19800e8SDoug Rabson }
51713e3f4d6SMark Murray
518c19800e8SDoug Rabson /*
51913e3f4d6SMark Murray * DES 64 bit Cipher Feedback
520c19800e8SDoug Rabson *
52113e3f4d6SMark Murray * key --->+-----+
52213e3f4d6SMark Murray * +->| DES |--+
523c19800e8SDoug Rabson * | +-----+ |
52413e3f4d6SMark Murray * | v
525c19800e8SDoug Rabson * INPUT --(--------->(+)+---> DATA
526c19800e8SDoug Rabson * | |
52713e3f4d6SMark Murray * +-------------+
528c19800e8SDoug Rabson *
52913e3f4d6SMark Murray *
530c19800e8SDoug Rabson * Given:
53113e3f4d6SMark Murray * iV: Initial vector, 64 bits (8 bytes) long.
53213e3f4d6SMark Murray * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
53313e3f4d6SMark Murray * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
53413e3f4d6SMark Murray *
53513e3f4d6SMark Murray * V0 = DES(iV, key)
53613e3f4d6SMark Murray * On = Dn ^ Vn
53713e3f4d6SMark Murray * V(n+1) = DES(On, key)
53813e3f4d6SMark Murray */
53913e3f4d6SMark Murray
cfb64_encrypt(unsigned char * s,int c)54013e3f4d6SMark Murray void cfb64_encrypt(unsigned char *s, int c)
54113e3f4d6SMark Murray {
54213e3f4d6SMark Murray struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
54313e3f4d6SMark Murray int index;
54413e3f4d6SMark Murray
54513e3f4d6SMark Murray index = stp->str_index;
54613e3f4d6SMark Murray while (c-- > 0) {
54713e3f4d6SMark Murray if (index == sizeof(DES_cblock)) {
54813e3f4d6SMark Murray DES_cblock b;
54913e3f4d6SMark Murray DES_ecb_encrypt(&stp->str_output, &b,&stp->str_sched, 1);
55013e3f4d6SMark Murray memcpy(stp->str_feed, b, sizeof(DES_cblock));
55113e3f4d6SMark Murray index = 0;
55213e3f4d6SMark Murray }
55313e3f4d6SMark Murray
55413e3f4d6SMark Murray /* On encryption, we store (feed ^ data) which is cypher */
55513e3f4d6SMark Murray *s = stp->str_output[index] = (stp->str_feed[index] ^ *s);
55613e3f4d6SMark Murray s++;
55713e3f4d6SMark Murray index++;
55813e3f4d6SMark Murray }
55913e3f4d6SMark Murray stp->str_index = index;
56013e3f4d6SMark Murray }
56113e3f4d6SMark Murray
cfb64_decrypt(int data)562c19800e8SDoug Rabson int cfb64_decrypt(int data)
563c19800e8SDoug Rabson {
564c19800e8SDoug Rabson struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1];
565c19800e8SDoug Rabson int index;
56613e3f4d6SMark Murray
56713e3f4d6SMark Murray if (data == -1) {
56813e3f4d6SMark Murray /*
56913e3f4d6SMark Murray * Back up one byte. It is assumed that we will
57013e3f4d6SMark Murray * never back up more than one byte. If we do, this
57113e3f4d6SMark Murray * may or may not work.
57213e3f4d6SMark Murray */
57313e3f4d6SMark Murray if (stp->str_index)
57413e3f4d6SMark Murray --stp->str_index;
57513e3f4d6SMark Murray return(0);
57613e3f4d6SMark Murray }
57713e3f4d6SMark Murray
57813e3f4d6SMark Murray index = stp->str_index++;
57913e3f4d6SMark Murray if (index == sizeof(DES_cblock)) {
58013e3f4d6SMark Murray DES_cblock b;
58113e3f4d6SMark Murray DES_ecb_encrypt(&stp->str_output,&b, &stp->str_sched, 1);
58213e3f4d6SMark Murray memcpy(stp->str_feed, b, sizeof(DES_cblock));
58313e3f4d6SMark Murray stp->str_index = 1; /* Next time will be 1 */
58413e3f4d6SMark Murray index = 0; /* But now use 0 */
58513e3f4d6SMark Murray }
58613e3f4d6SMark Murray
58713e3f4d6SMark Murray /* On decryption we store (data) which is cypher. */
58813e3f4d6SMark Murray stp->str_output[index] = data;
58913e3f4d6SMark Murray return(data ^ stp->str_feed[index]);
59013e3f4d6SMark Murray }
59113e3f4d6SMark Murray
59213e3f4d6SMark Murray /*
59313e3f4d6SMark Murray * DES 64 bit Output Feedback
594c19800e8SDoug Rabson *
595c19800e8SDoug Rabson * key --->+-----+
596c19800e8SDoug Rabson * +->| DES |--+
597c19800e8SDoug Rabson * | +-----+ |
59813e3f4d6SMark Murray * +-----------+
59913e3f4d6SMark Murray * v
60013e3f4d6SMark Murray * INPUT -------->(+) ----> DATA
60113e3f4d6SMark Murray *
60213e3f4d6SMark Murray * Given:
60313e3f4d6SMark Murray * iV: Initial vector, 64 bits (8 bytes) long.
60413e3f4d6SMark Murray * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
60513e3f4d6SMark Murray * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
60613e3f4d6SMark Murray *
60713e3f4d6SMark Murray * V0 = DES(iV, key)
60813e3f4d6SMark Murray * V(n+1) = DES(Vn, key)
60913e3f4d6SMark Murray * On = Dn ^ Vn
61013e3f4d6SMark Murray */
61113e3f4d6SMark Murray
ofb64_encrypt(unsigned char * s,int c)61213e3f4d6SMark Murray void ofb64_encrypt(unsigned char *s, int c)
61313e3f4d6SMark Murray {
61413e3f4d6SMark Murray struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
61513e3f4d6SMark Murray int index;
61613e3f4d6SMark Murray
61713e3f4d6SMark Murray index = stp->str_index;
61813e3f4d6SMark Murray while (c-- > 0) {
61913e3f4d6SMark Murray if (index == sizeof(DES_cblock)) {
62013e3f4d6SMark Murray DES_cblock b;
62113e3f4d6SMark Murray DES_ecb_encrypt(&stp->str_feed,&b, &stp->str_sched, 1);
62213e3f4d6SMark Murray memcpy(stp->str_feed, b, sizeof(DES_cblock));
62313e3f4d6SMark Murray index = 0;
62413e3f4d6SMark Murray }
62513e3f4d6SMark Murray *s++ ^= stp->str_feed[index];
62613e3f4d6SMark Murray index++;
62713e3f4d6SMark Murray }
62813e3f4d6SMark Murray stp->str_index = index;
62913e3f4d6SMark Murray }
63013e3f4d6SMark Murray
ofb64_decrypt(int data)63113e3f4d6SMark Murray int ofb64_decrypt(int data)
63213e3f4d6SMark Murray {
63313e3f4d6SMark Murray struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1];
634c19800e8SDoug Rabson int index;
635c19800e8SDoug Rabson
636c19800e8SDoug Rabson if (data == -1) {
637c19800e8SDoug Rabson /*
63813e3f4d6SMark Murray * Back up one byte. It is assumed that we will
63913e3f4d6SMark Murray * never back up more than one byte. If we do, this
64013e3f4d6SMark Murray * may or may not work.
64113e3f4d6SMark Murray */
64213e3f4d6SMark Murray if (stp->str_index)
64313e3f4d6SMark Murray --stp->str_index;
64413e3f4d6SMark Murray return(0);
64513e3f4d6SMark Murray }
64613e3f4d6SMark Murray
64713e3f4d6SMark Murray index = stp->str_index++;
64813e3f4d6SMark Murray if (index == sizeof(DES_cblock)) {
64913e3f4d6SMark Murray DES_cblock b;
65013e3f4d6SMark Murray DES_ecb_encrypt(&stp->str_feed,&b,&stp->str_sched, 1);
65113e3f4d6SMark Murray memcpy(stp->str_feed, b, sizeof(DES_cblock));
65213e3f4d6SMark Murray stp->str_index = 1; /* Next time will be 1 */
65313e3f4d6SMark Murray index = 0; /* But now use 0 */
65413e3f4d6SMark Murray }
65513e3f4d6SMark Murray
65613e3f4d6SMark Murray return(data ^ stp->str_feed[index]);
65713e3f4d6SMark Murray }
65813e3f4d6SMark Murray #endif
65913e3f4d6SMark Murray
66013e3f4d6SMark Murray