xref: /titanic_51/usr/src/cmd/cmd-inet/usr.bin/telnet/enc_des.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate /*
9*7c478bd9Sstevel@tonic-gate  * usr/src/cmd/cmd-inet/usr.bin/telnet/enc_des.c
10*7c478bd9Sstevel@tonic-gate  */
11*7c478bd9Sstevel@tonic-gate 
12*7c478bd9Sstevel@tonic-gate /*
13*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1991, 1993
14*7c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
15*7c478bd9Sstevel@tonic-gate  *
16*7c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
17*7c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
18*7c478bd9Sstevel@tonic-gate  * are met:
19*7c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
20*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
21*7c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
22*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
23*7c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
24*7c478bd9Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
25*7c478bd9Sstevel@tonic-gate  *    must display the following acknowledgement:
26*7c478bd9Sstevel@tonic-gate  *	This product includes software developed by the University of
27*7c478bd9Sstevel@tonic-gate  *	California, Berkeley and its contributors.
28*7c478bd9Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
29*7c478bd9Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
30*7c478bd9Sstevel@tonic-gate  *    without specific prior written permission.
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33*7c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34*7c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35*7c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36*7c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37*7c478bd9Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38*7c478bd9Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39*7c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40*7c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41*7c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42*7c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
43*7c478bd9Sstevel@tonic-gate  */
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate /*
46*7c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
47*7c478bd9Sstevel@tonic-gate  *
48*7c478bd9Sstevel@tonic-gate  * All rights reserved.
49*7c478bd9Sstevel@tonic-gate  *
50*7c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may require
51*7c478bd9Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
52*7c478bd9Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
53*7c478bd9Sstevel@tonic-gate  * obtain such a license before exporting.
54*7c478bd9Sstevel@tonic-gate  *
55*7c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
56*7c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
57*7c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
58*7c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
59*7c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
60*7c478bd9Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
61*7c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
62*7c478bd9Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
63*7c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
64*7c478bd9Sstevel@tonic-gate  * or implied warranty.
65*7c478bd9Sstevel@tonic-gate  *
66*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
67*7c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
68*7c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
69*7c478bd9Sstevel@tonic-gate  */
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /* based on @(#)enc_des.c	8.1 (Berkeley) 6/4/93 */
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate #include <krb5.h>
74*7c478bd9Sstevel@tonic-gate #include <stdio.h>
75*7c478bd9Sstevel@tonic-gate #include <arpa/telnet.h>
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate #ifdef	__STDC__
78*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
79*7c478bd9Sstevel@tonic-gate #endif
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate #include "externs.h"
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate extern	boolean_t encrypt_debug_mode;
84*7c478bd9Sstevel@tonic-gate extern	krb5_context telnet_context;
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate #define	KEYFLAG_SHIFT	2
87*7c478bd9Sstevel@tonic-gate #define	SHIFT_VAL(a, b) (KEYFLAG_SHIFT*((a)+((b)*2)))
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate static	struct _fb {
90*7c478bd9Sstevel@tonic-gate 	Block temp_feed;
91*7c478bd9Sstevel@tonic-gate 	int state[2];		/* state for each direction */
92*7c478bd9Sstevel@tonic-gate 	int keyid[2];		/* keyid for each direction */
93*7c478bd9Sstevel@tonic-gate 	int once;
94*7c478bd9Sstevel@tonic-gate 	unsigned char fb_feed[64];
95*7c478bd9Sstevel@tonic-gate 	boolean_t need_start;
96*7c478bd9Sstevel@tonic-gate 	boolean_t validkey;
97*7c478bd9Sstevel@tonic-gate 	struct stinfo {
98*7c478bd9Sstevel@tonic-gate 		Block		str_output;
99*7c478bd9Sstevel@tonic-gate 		Block		str_feed;
100*7c478bd9Sstevel@tonic-gate 		Block		str_iv;
101*7c478bd9Sstevel@tonic-gate 		unsigned char	str_keybytes[DES_BLOCKSIZE];
102*7c478bd9Sstevel@tonic-gate 		krb5_keyblock	str_key;
103*7c478bd9Sstevel@tonic-gate 		int		str_index;
104*7c478bd9Sstevel@tonic-gate 		int		str_flagshift;
105*7c478bd9Sstevel@tonic-gate 	} streams[2];		/* one for encrypt, one for decrypt */
106*7c478bd9Sstevel@tonic-gate } des_cfb;
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate static	void cfb64_stream_iv(Block, struct stinfo *);
109*7c478bd9Sstevel@tonic-gate static	void cfb64_stream_key(Block, struct stinfo *);
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate static void
112*7c478bd9Sstevel@tonic-gate ecb_encrypt(struct stinfo *stp, Block in, Block out)
113*7c478bd9Sstevel@tonic-gate {
114*7c478bd9Sstevel@tonic-gate 	krb5_error_code code;
115*7c478bd9Sstevel@tonic-gate 	krb5_data din;
116*7c478bd9Sstevel@tonic-gate 	krb5_enc_data dout;
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	din.length = DES_BLOCKSIZE;
119*7c478bd9Sstevel@tonic-gate 	din.data = (char *)in;
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	dout.ciphertext.length = DES_BLOCKSIZE;
122*7c478bd9Sstevel@tonic-gate 	dout.ciphertext.data = (char *)out;
123*7c478bd9Sstevel@tonic-gate 	/* this is a kerberos enctype, not a telopt enctype */
124*7c478bd9Sstevel@tonic-gate 	dout.enctype = ENCTYPE_UNKNOWN;
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	code = krb5_c_encrypt(telnet_context, &stp->str_key, NULL, NULL,
127*7c478bd9Sstevel@tonic-gate 		&din, &dout);
128*7c478bd9Sstevel@tonic-gate 	if (code)
129*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
130*7c478bd9Sstevel@tonic-gate 			"Error encrypting stream data (%s)\r\n"), code);
131*7c478bd9Sstevel@tonic-gate }
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate void
134*7c478bd9Sstevel@tonic-gate cfb64_init(void)
135*7c478bd9Sstevel@tonic-gate {
136*7c478bd9Sstevel@tonic-gate 	register struct _fb *fbp = &des_cfb;
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	(void) memset((void *)fbp, 0, sizeof (*fbp));
139*7c478bd9Sstevel@tonic-gate 	fbp->state[0] = des_cfb.state[1] = ENCR_STATE_FAILED;
140*7c478bd9Sstevel@tonic-gate 	fbp->fb_feed[0] = IAC;
141*7c478bd9Sstevel@tonic-gate 	fbp->fb_feed[1] = SB;
142*7c478bd9Sstevel@tonic-gate 	fbp->fb_feed[2] = TELOPT_ENCRYPT;
143*7c478bd9Sstevel@tonic-gate 	fbp->fb_feed[3] = ENCRYPT_IS;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	fbp->fb_feed[4] = TELOPT_ENCTYPE_DES_CFB64;
146*7c478bd9Sstevel@tonic-gate 	fbp->streams[TELNET_DIR_DECRYPT].str_flagshift =
147*7c478bd9Sstevel@tonic-gate 		SHIFT_VAL(0, CFB);
148*7c478bd9Sstevel@tonic-gate 	fbp->streams[TELNET_DIR_ENCRYPT].str_flagshift =
149*7c478bd9Sstevel@tonic-gate 		SHIFT_VAL(1, CFB);
150*7c478bd9Sstevel@tonic-gate }
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate /*
154*7c478bd9Sstevel@tonic-gate  * Returns:
155*7c478bd9Sstevel@tonic-gate  *	-1: some error.  Negotiation is done, encryption not ready.
156*7c478bd9Sstevel@tonic-gate  *	 0: Successful, initial negotiation all done.
157*7c478bd9Sstevel@tonic-gate  *	 1: successful, negotiation not done yet.
158*7c478bd9Sstevel@tonic-gate  *	 2: Not yet.  Other things (like getting the key from
159*7c478bd9Sstevel@tonic-gate  *	    Kerberos) have to happen before we can continue.
160*7c478bd9Sstevel@tonic-gate  */
161*7c478bd9Sstevel@tonic-gate int
162*7c478bd9Sstevel@tonic-gate cfb64_start(int dir)
163*7c478bd9Sstevel@tonic-gate {
164*7c478bd9Sstevel@tonic-gate 	struct _fb *fbp = &des_cfb;
165*7c478bd9Sstevel@tonic-gate 	int x;
166*7c478bd9Sstevel@tonic-gate 	unsigned char *p;
167*7c478bd9Sstevel@tonic-gate 	register int state;
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	switch (dir) {
170*7c478bd9Sstevel@tonic-gate 	case TELNET_DIR_DECRYPT:
171*7c478bd9Sstevel@tonic-gate 		/*
172*7c478bd9Sstevel@tonic-gate 		 * This is simply a request to have the other side
173*7c478bd9Sstevel@tonic-gate 		 * start output (our input).  He will negotiate an
174*7c478bd9Sstevel@tonic-gate 		 * IV so we need not look for it.
175*7c478bd9Sstevel@tonic-gate 		 */
176*7c478bd9Sstevel@tonic-gate 		state = fbp->state[dir];
177*7c478bd9Sstevel@tonic-gate 		if (state == ENCR_STATE_FAILED)
178*7c478bd9Sstevel@tonic-gate 			state = ENCR_STATE_IN_PROGRESS;
179*7c478bd9Sstevel@tonic-gate 		break;
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	case TELNET_DIR_ENCRYPT:
182*7c478bd9Sstevel@tonic-gate 		state = fbp->state[dir];
183*7c478bd9Sstevel@tonic-gate 		if (state == ENCR_STATE_FAILED)
184*7c478bd9Sstevel@tonic-gate 			state = ENCR_STATE_IN_PROGRESS;
185*7c478bd9Sstevel@tonic-gate 		else if ((state & ENCR_STATE_NO_SEND_IV) == 0)
186*7c478bd9Sstevel@tonic-gate 			break;
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 		if (!fbp->validkey) {
189*7c478bd9Sstevel@tonic-gate 			fbp->need_start = B_TRUE;
190*7c478bd9Sstevel@tonic-gate 			break;
191*7c478bd9Sstevel@tonic-gate 		}
192*7c478bd9Sstevel@tonic-gate 		state &= ~ENCR_STATE_NO_SEND_IV;
193*7c478bd9Sstevel@tonic-gate 		state |= ENCR_STATE_NO_RECV_IV;
194*7c478bd9Sstevel@tonic-gate 		if (encrypt_debug_mode)
195*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Creating new feed\r\n"));
196*7c478bd9Sstevel@tonic-gate 		/*
197*7c478bd9Sstevel@tonic-gate 		 * Create a random feed and send it over.
198*7c478bd9Sstevel@tonic-gate 		 */
199*7c478bd9Sstevel@tonic-gate 		{
200*7c478bd9Sstevel@tonic-gate 			krb5_data d;
201*7c478bd9Sstevel@tonic-gate 			krb5_error_code code;
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 			d.data = (char *)fbp->temp_feed;
204*7c478bd9Sstevel@tonic-gate 			d.length = sizeof (fbp->temp_feed);
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 			code = krb5_c_random_make_octets(telnet_context, &d);
207*7c478bd9Sstevel@tonic-gate 			if (code != 0)
208*7c478bd9Sstevel@tonic-gate 				return (ENCR_STATE_FAILED);
209*7c478bd9Sstevel@tonic-gate 		}
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 		p = fbp->fb_feed + 3;
212*7c478bd9Sstevel@tonic-gate 		*p++ = ENCRYPT_IS;
213*7c478bd9Sstevel@tonic-gate 		p++;
214*7c478bd9Sstevel@tonic-gate 		*p++ = FB64_IV;
215*7c478bd9Sstevel@tonic-gate 		for (x = 0; x < sizeof (Block); ++x) {
216*7c478bd9Sstevel@tonic-gate 			if ((*p++ = fbp->temp_feed[x]) == IAC)
217*7c478bd9Sstevel@tonic-gate 				*p++ = IAC;
218*7c478bd9Sstevel@tonic-gate 		}
219*7c478bd9Sstevel@tonic-gate 		*p++ = IAC;
220*7c478bd9Sstevel@tonic-gate 		*p++ = SE;
221*7c478bd9Sstevel@tonic-gate 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
222*7c478bd9Sstevel@tonic-gate 		(void) net_write(fbp->fb_feed, p - fbp->fb_feed);
223*7c478bd9Sstevel@tonic-gate 		break;
224*7c478bd9Sstevel@tonic-gate 	default:
225*7c478bd9Sstevel@tonic-gate 		return (ENCR_STATE_FAILED);
226*7c478bd9Sstevel@tonic-gate 	}
227*7c478bd9Sstevel@tonic-gate 	return (fbp->state[dir] = state);
228*7c478bd9Sstevel@tonic-gate }
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate /*
231*7c478bd9Sstevel@tonic-gate  * Returns:
232*7c478bd9Sstevel@tonic-gate  *	-1: some error.  Negotiation is done, encryption not ready.
233*7c478bd9Sstevel@tonic-gate  *	 0: Successful, initial negotiation all done.
234*7c478bd9Sstevel@tonic-gate  *	 1: successful, negotiation not done yet.
235*7c478bd9Sstevel@tonic-gate  */
236*7c478bd9Sstevel@tonic-gate int
237*7c478bd9Sstevel@tonic-gate cfb64_is(unsigned char *data, int cnt)
238*7c478bd9Sstevel@tonic-gate {
239*7c478bd9Sstevel@tonic-gate 	unsigned char *p;
240*7c478bd9Sstevel@tonic-gate 	struct _fb *fbp = &des_cfb;
241*7c478bd9Sstevel@tonic-gate 	register int state = fbp->state[TELNET_DIR_DECRYPT];
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	if (cnt-- < 1)
244*7c478bd9Sstevel@tonic-gate 		goto failure;
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	switch (*data++) {
247*7c478bd9Sstevel@tonic-gate 	case FB64_IV:
248*7c478bd9Sstevel@tonic-gate 		if (cnt != sizeof (Block)) {
249*7c478bd9Sstevel@tonic-gate 			if (encrypt_debug_mode)
250*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext(
251*7c478bd9Sstevel@tonic-gate 					"CFB64: initial vector failed "
252*7c478bd9Sstevel@tonic-gate 					"on size\r\n"));
253*7c478bd9Sstevel@tonic-gate 			state = ENCR_STATE_FAILED;
254*7c478bd9Sstevel@tonic-gate 			goto failure;
255*7c478bd9Sstevel@tonic-gate 		}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 		if (encrypt_debug_mode)
258*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
259*7c478bd9Sstevel@tonic-gate 				"CFB64: initial vector received\r\n"));
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 		if (encrypt_debug_mode)
262*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
263*7c478bd9Sstevel@tonic-gate 				"Initializing Decrypt stream\r\n"));
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 		cfb64_stream_iv((void *)data,
266*7c478bd9Sstevel@tonic-gate 			&fbp->streams[TELNET_DIR_DECRYPT]);
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 		p = fbp->fb_feed + 3;
269*7c478bd9Sstevel@tonic-gate 		*p++ = ENCRYPT_REPLY;
270*7c478bd9Sstevel@tonic-gate 		p++;
271*7c478bd9Sstevel@tonic-gate 		*p++ = FB64_IV_OK;
272*7c478bd9Sstevel@tonic-gate 		*p++ = IAC;
273*7c478bd9Sstevel@tonic-gate 		*p++ = SE;
274*7c478bd9Sstevel@tonic-gate 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
275*7c478bd9Sstevel@tonic-gate 		(void) net_write(fbp->fb_feed, p - fbp->fb_feed);
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 		state = fbp->state[TELNET_DIR_DECRYPT] = ENCR_STATE_IN_PROGRESS;
278*7c478bd9Sstevel@tonic-gate 		break;
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	default:
281*7c478bd9Sstevel@tonic-gate 		if (encrypt_debug_mode) {
282*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
283*7c478bd9Sstevel@tonic-gate 				"Unknown option type: %d\r\n"), *(data-1));
284*7c478bd9Sstevel@tonic-gate 			printd(data, cnt);
285*7c478bd9Sstevel@tonic-gate 			(void) printf("\r\n");
286*7c478bd9Sstevel@tonic-gate 		}
287*7c478bd9Sstevel@tonic-gate 		/* FALL THROUGH */
288*7c478bd9Sstevel@tonic-gate 	failure:
289*7c478bd9Sstevel@tonic-gate 		/*
290*7c478bd9Sstevel@tonic-gate 		 * We failed.  Send an FB64_IV_BAD option
291*7c478bd9Sstevel@tonic-gate 		 * to the other side so it will know that
292*7c478bd9Sstevel@tonic-gate 		 * things failed.
293*7c478bd9Sstevel@tonic-gate 		 */
294*7c478bd9Sstevel@tonic-gate 		p = fbp->fb_feed + 3;
295*7c478bd9Sstevel@tonic-gate 		*p++ = ENCRYPT_REPLY;
296*7c478bd9Sstevel@tonic-gate 		p++;
297*7c478bd9Sstevel@tonic-gate 		*p++ = FB64_IV_BAD;
298*7c478bd9Sstevel@tonic-gate 		*p++ = IAC;
299*7c478bd9Sstevel@tonic-gate 		*p++ = SE;
300*7c478bd9Sstevel@tonic-gate 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
301*7c478bd9Sstevel@tonic-gate 		(void) net_write(fbp->fb_feed, p - fbp->fb_feed);
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 		break;
304*7c478bd9Sstevel@tonic-gate 	}
305*7c478bd9Sstevel@tonic-gate 	return (fbp->state[TELNET_DIR_DECRYPT] = state);
306*7c478bd9Sstevel@tonic-gate }
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate /*
309*7c478bd9Sstevel@tonic-gate  * Returns:
310*7c478bd9Sstevel@tonic-gate  *	-1: some error.  Negotiation is done, encryption not ready.
311*7c478bd9Sstevel@tonic-gate  *	 0: Successful, initial negotiation all done.
312*7c478bd9Sstevel@tonic-gate  *	 1: successful, negotiation not done yet.
313*7c478bd9Sstevel@tonic-gate  */
314*7c478bd9Sstevel@tonic-gate int
315*7c478bd9Sstevel@tonic-gate cfb64_reply(unsigned char *data, int cnt)
316*7c478bd9Sstevel@tonic-gate {
317*7c478bd9Sstevel@tonic-gate 	struct _fb *fbp = &des_cfb;
318*7c478bd9Sstevel@tonic-gate 	register int state = fbp->state[TELNET_DIR_ENCRYPT];
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	if (cnt-- < 1)
321*7c478bd9Sstevel@tonic-gate 		goto failure;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	switch (*data++) {
324*7c478bd9Sstevel@tonic-gate 	case FB64_IV_OK:
325*7c478bd9Sstevel@tonic-gate 		cfb64_stream_iv(fbp->temp_feed,
326*7c478bd9Sstevel@tonic-gate 			&fbp->streams[TELNET_DIR_ENCRYPT]);
327*7c478bd9Sstevel@tonic-gate 		if (state == ENCR_STATE_FAILED)
328*7c478bd9Sstevel@tonic-gate 			state = ENCR_STATE_IN_PROGRESS;
329*7c478bd9Sstevel@tonic-gate 		state &= ~ENCR_STATE_NO_RECV_IV;
330*7c478bd9Sstevel@tonic-gate 		encrypt_send_keyid(TELNET_DIR_ENCRYPT,
331*7c478bd9Sstevel@tonic-gate 			(unsigned char *)"\0", 1, 1);
332*7c478bd9Sstevel@tonic-gate 		break;
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	case FB64_IV_BAD:
335*7c478bd9Sstevel@tonic-gate 		(void) memset(fbp->temp_feed, 0, sizeof (Block));
336*7c478bd9Sstevel@tonic-gate 		cfb64_stream_iv(fbp->temp_feed,
337*7c478bd9Sstevel@tonic-gate 			&fbp->streams[TELNET_DIR_ENCRYPT]);
338*7c478bd9Sstevel@tonic-gate 		state = ENCR_STATE_FAILED;
339*7c478bd9Sstevel@tonic-gate 		break;
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	default:
342*7c478bd9Sstevel@tonic-gate 		if (encrypt_debug_mode) {
343*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext(
344*7c478bd9Sstevel@tonic-gate 				"Unknown option type: %d\r\n"), data[-1]);
345*7c478bd9Sstevel@tonic-gate 			printd(data, cnt);
346*7c478bd9Sstevel@tonic-gate 			(void) printf("\r\n");
347*7c478bd9Sstevel@tonic-gate 		}
348*7c478bd9Sstevel@tonic-gate 		/* FALL THROUGH */
349*7c478bd9Sstevel@tonic-gate 	failure:
350*7c478bd9Sstevel@tonic-gate 		state = ENCR_STATE_FAILED;
351*7c478bd9Sstevel@tonic-gate 		break;
352*7c478bd9Sstevel@tonic-gate 	}
353*7c478bd9Sstevel@tonic-gate 	return (fbp->state[TELNET_DIR_ENCRYPT] = state);
354*7c478bd9Sstevel@tonic-gate }
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate void
357*7c478bd9Sstevel@tonic-gate cfb64_session(Session_Key *key)
358*7c478bd9Sstevel@tonic-gate {
359*7c478bd9Sstevel@tonic-gate 	struct _fb *fbp = &des_cfb;
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	if (!key || key->type != SK_DES) {
362*7c478bd9Sstevel@tonic-gate 		if (encrypt_debug_mode)
363*7c478bd9Sstevel@tonic-gate 		    (void) printf(gettext(
364*7c478bd9Sstevel@tonic-gate 			"Can't set DES's session key (%d != %d)\r\n"),
365*7c478bd9Sstevel@tonic-gate 			key ? key->type : -1, SK_DES);
366*7c478bd9Sstevel@tonic-gate 		return;
367*7c478bd9Sstevel@tonic-gate 	}
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	fbp->validkey = B_TRUE;
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	cfb64_stream_key(key->data, &fbp->streams[TELNET_DIR_ENCRYPT]);
372*7c478bd9Sstevel@tonic-gate 	cfb64_stream_key(key->data, &fbp->streams[TELNET_DIR_DECRYPT]);
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	/*
375*7c478bd9Sstevel@tonic-gate 	 * Now look to see if cfb64_start() was was waiting for
376*7c478bd9Sstevel@tonic-gate 	 * the key to show up.  If so, go ahead an call it now
377*7c478bd9Sstevel@tonic-gate 	 * that we have the key.
378*7c478bd9Sstevel@tonic-gate 	 */
379*7c478bd9Sstevel@tonic-gate 	if (fbp->need_start) {
380*7c478bd9Sstevel@tonic-gate 		fbp->need_start = B_FALSE;
381*7c478bd9Sstevel@tonic-gate 		(void) cfb64_start(TELNET_DIR_ENCRYPT);
382*7c478bd9Sstevel@tonic-gate 	}
383*7c478bd9Sstevel@tonic-gate }
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate /*
386*7c478bd9Sstevel@tonic-gate  * We only accept a keyid of 0.  If we get a keyid of
387*7c478bd9Sstevel@tonic-gate  * 0, then mark the state as SUCCESS.
388*7c478bd9Sstevel@tonic-gate  */
389*7c478bd9Sstevel@tonic-gate int
390*7c478bd9Sstevel@tonic-gate cfb64_keyid(dir, kp, lenp)
391*7c478bd9Sstevel@tonic-gate 	int dir, *lenp;
392*7c478bd9Sstevel@tonic-gate 	unsigned char *kp;
393*7c478bd9Sstevel@tonic-gate {
394*7c478bd9Sstevel@tonic-gate 	struct _fb *fbp = &des_cfb;
395*7c478bd9Sstevel@tonic-gate 	register int state = fbp->state[dir];
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	if (*lenp != 1 || (*kp != '\0')) {
398*7c478bd9Sstevel@tonic-gate 		*lenp = 0;
399*7c478bd9Sstevel@tonic-gate 		return (state);
400*7c478bd9Sstevel@tonic-gate 	}
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	if (state == ENCR_STATE_FAILED)
403*7c478bd9Sstevel@tonic-gate 		state = ENCR_STATE_IN_PROGRESS;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	state &= ~ENCR_STATE_NO_KEYID;
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	return (fbp->state[dir] = state);
408*7c478bd9Sstevel@tonic-gate }
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate /*
411*7c478bd9Sstevel@tonic-gate  * Print ENCRYPT suboptions to NetTrace when "set opt" is used
412*7c478bd9Sstevel@tonic-gate  */
413*7c478bd9Sstevel@tonic-gate void
414*7c478bd9Sstevel@tonic-gate cfb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
415*7c478bd9Sstevel@tonic-gate {
416*7c478bd9Sstevel@tonic-gate 	char lbuf[ENCR_LBUF_BUFSIZ];
417*7c478bd9Sstevel@tonic-gate 	register int i;
418*7c478bd9Sstevel@tonic-gate 	char *cp;
419*7c478bd9Sstevel@tonic-gate 	unsigned char type[] = "CFB64";
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	buf[buflen-1] = '\0';		/* make sure it's NULL terminated */
422*7c478bd9Sstevel@tonic-gate 	buflen -= 1;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	switch (data[2]) {
425*7c478bd9Sstevel@tonic-gate 	case FB64_IV:
426*7c478bd9Sstevel@tonic-gate 		(void) snprintf(lbuf, ENCR_LBUF_BUFSIZ, "%s_IV", type);
427*7c478bd9Sstevel@tonic-gate 		cp = lbuf;
428*7c478bd9Sstevel@tonic-gate 		goto common;
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	case FB64_IV_OK:
431*7c478bd9Sstevel@tonic-gate 		(void) snprintf(lbuf, ENCR_LBUF_BUFSIZ, "%s_IV_OK", type);
432*7c478bd9Sstevel@tonic-gate 		cp = lbuf;
433*7c478bd9Sstevel@tonic-gate 		goto common;
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	case FB64_IV_BAD:
436*7c478bd9Sstevel@tonic-gate 		(void) snprintf(lbuf, ENCR_LBUF_BUFSIZ, "%s_IV_BAD", type);
437*7c478bd9Sstevel@tonic-gate 		cp = lbuf;
438*7c478bd9Sstevel@tonic-gate 		goto common;
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 	default:
441*7c478bd9Sstevel@tonic-gate 		(void) snprintf(lbuf, ENCR_LBUF_BUFSIZ, " %d (unknown)",
442*7c478bd9Sstevel@tonic-gate 			data[2]);
443*7c478bd9Sstevel@tonic-gate 		cp = lbuf;
444*7c478bd9Sstevel@tonic-gate 	common:
445*7c478bd9Sstevel@tonic-gate 		for (; (buflen > 0) && (*buf = *cp++); buf++)
446*7c478bd9Sstevel@tonic-gate 			buflen--;
447*7c478bd9Sstevel@tonic-gate 		for (i = 3; i < cnt; i++) {
448*7c478bd9Sstevel@tonic-gate 			(void) snprintf(lbuf, ENCR_LBUF_BUFSIZ, " %d", data[i]);
449*7c478bd9Sstevel@tonic-gate 			for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
450*7c478bd9Sstevel@tonic-gate 				buflen--;
451*7c478bd9Sstevel@tonic-gate 		}
452*7c478bd9Sstevel@tonic-gate 		break;
453*7c478bd9Sstevel@tonic-gate 	}
454*7c478bd9Sstevel@tonic-gate }
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate static void
458*7c478bd9Sstevel@tonic-gate cfb64_stream_iv(Block seed, register struct stinfo *stp)
459*7c478bd9Sstevel@tonic-gate {
460*7c478bd9Sstevel@tonic-gate 	(void) memcpy((void *)stp->str_iv,	(void *)seed, sizeof (Block));
461*7c478bd9Sstevel@tonic-gate 	(void) memcpy((void *)stp->str_output,	(void *)seed, sizeof (Block));
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	stp->str_index = sizeof (Block);
464*7c478bd9Sstevel@tonic-gate }
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate void
467*7c478bd9Sstevel@tonic-gate cfb64_stream_key(Block key, register struct stinfo *stp)
468*7c478bd9Sstevel@tonic-gate {
469*7c478bd9Sstevel@tonic-gate 	(void) memcpy((void *)stp->str_keybytes, (void *)key, sizeof (Block));
470*7c478bd9Sstevel@tonic-gate 	stp->str_key.length = DES_BLOCKSIZE;
471*7c478bd9Sstevel@tonic-gate 	stp->str_key.contents = stp->str_keybytes;
472*7c478bd9Sstevel@tonic-gate 	/*
473*7c478bd9Sstevel@tonic-gate 	 * the original version of this code uses des ecb mode, but
474*7c478bd9Sstevel@tonic-gate 	 * it only ever does one block at a time.  cbc with a zero iv
475*7c478bd9Sstevel@tonic-gate 	 * is identical
476*7c478bd9Sstevel@tonic-gate 	 */
477*7c478bd9Sstevel@tonic-gate 	/* this is a kerberos enctype, not a telopt enctype */
478*7c478bd9Sstevel@tonic-gate 	stp->str_key.enctype = ENCTYPE_DES_CBC_RAW;
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	(void) memcpy((void *)stp->str_output, (void *)stp->str_iv,
481*7c478bd9Sstevel@tonic-gate 	    sizeof (Block));
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	stp->str_index = sizeof (Block);
484*7c478bd9Sstevel@tonic-gate }
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate /*
487*7c478bd9Sstevel@tonic-gate  * DES 64 bit Cipher Feedback
488*7c478bd9Sstevel@tonic-gate  *
489*7c478bd9Sstevel@tonic-gate  *     key --->+-----+
490*7c478bd9Sstevel@tonic-gate  *          +->| DES |--+
491*7c478bd9Sstevel@tonic-gate  *          |  +-----+  |
492*7c478bd9Sstevel@tonic-gate  *	    |           v
493*7c478bd9Sstevel@tonic-gate  *  INPUT --(--------->(+)+---> DATA
494*7c478bd9Sstevel@tonic-gate  *          |             |
495*7c478bd9Sstevel@tonic-gate  *	    +-------------+
496*7c478bd9Sstevel@tonic-gate  *
497*7c478bd9Sstevel@tonic-gate  *
498*7c478bd9Sstevel@tonic-gate  * Given:
499*7c478bd9Sstevel@tonic-gate  *	iV: Initial vector, 64 bits (8 bytes) long.
500*7c478bd9Sstevel@tonic-gate  *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
501*7c478bd9Sstevel@tonic-gate  *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
502*7c478bd9Sstevel@tonic-gate  *
503*7c478bd9Sstevel@tonic-gate  *	V0 = DES(iV, key)
504*7c478bd9Sstevel@tonic-gate  *	On = Dn ^ Vn
505*7c478bd9Sstevel@tonic-gate  *	V(n+1) = DES(On, key)
506*7c478bd9Sstevel@tonic-gate  */
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate void
509*7c478bd9Sstevel@tonic-gate cfb64_encrypt(register unsigned char *s, int c)
510*7c478bd9Sstevel@tonic-gate {
511*7c478bd9Sstevel@tonic-gate 	register struct stinfo *stp =
512*7c478bd9Sstevel@tonic-gate 		&des_cfb.streams[TELNET_DIR_ENCRYPT];
513*7c478bd9Sstevel@tonic-gate 	register int index;
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	index = stp->str_index;
516*7c478bd9Sstevel@tonic-gate 	while (c-- > 0) {
517*7c478bd9Sstevel@tonic-gate 		if (index == sizeof (Block)) {
518*7c478bd9Sstevel@tonic-gate 			Block b;
519*7c478bd9Sstevel@tonic-gate 			ecb_encrypt(stp, stp->str_output, b);
520*7c478bd9Sstevel@tonic-gate 			(void) memcpy((void *)stp->str_feed, (void *)b,
521*7c478bd9Sstevel@tonic-gate 				sizeof (Block));
522*7c478bd9Sstevel@tonic-gate 			index = 0;
523*7c478bd9Sstevel@tonic-gate 		}
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 		/* On encryption, we store (feed ^ data) which is cypher */
526*7c478bd9Sstevel@tonic-gate 		*s = stp->str_output[index] = (stp->str_feed[index] ^ *s);
527*7c478bd9Sstevel@tonic-gate 		s++;
528*7c478bd9Sstevel@tonic-gate 		index++;
529*7c478bd9Sstevel@tonic-gate 	}
530*7c478bd9Sstevel@tonic-gate 	stp->str_index = index;
531*7c478bd9Sstevel@tonic-gate }
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate int
534*7c478bd9Sstevel@tonic-gate cfb64_decrypt(int data)
535*7c478bd9Sstevel@tonic-gate {
536*7c478bd9Sstevel@tonic-gate 	register struct stinfo *stp =
537*7c478bd9Sstevel@tonic-gate 		&des_cfb.streams[TELNET_DIR_DECRYPT];
538*7c478bd9Sstevel@tonic-gate 	int index;
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	if (data == -1) {
541*7c478bd9Sstevel@tonic-gate 		/*
542*7c478bd9Sstevel@tonic-gate 		 * Back up one byte.  It is assumed that we will
543*7c478bd9Sstevel@tonic-gate 		 * never back up more than one byte.  If we do, this
544*7c478bd9Sstevel@tonic-gate 		 * may or may not work.
545*7c478bd9Sstevel@tonic-gate 		 */
546*7c478bd9Sstevel@tonic-gate 		if (stp->str_index)
547*7c478bd9Sstevel@tonic-gate 			--stp->str_index;
548*7c478bd9Sstevel@tonic-gate 		return (0);
549*7c478bd9Sstevel@tonic-gate 	}
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 	index = stp->str_index++;
552*7c478bd9Sstevel@tonic-gate 	if (index == sizeof (Block)) {
553*7c478bd9Sstevel@tonic-gate 		Block b;
554*7c478bd9Sstevel@tonic-gate 		ecb_encrypt(stp, stp->str_output, b);
555*7c478bd9Sstevel@tonic-gate 		(void) memcpy((void *)stp->str_feed, (void *)b, sizeof (Block));
556*7c478bd9Sstevel@tonic-gate 		stp->str_index = 1;	/* Next time will be 1 */
557*7c478bd9Sstevel@tonic-gate 		index = 0;		/* But now use 0 */
558*7c478bd9Sstevel@tonic-gate 	}
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	/* On decryption we store (data) which is cypher. */
561*7c478bd9Sstevel@tonic-gate 	stp->str_output[index] = data;
562*7c478bd9Sstevel@tonic-gate 	return (data ^ stp->str_feed[index]);
563*7c478bd9Sstevel@tonic-gate }
564