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
ecb_encrypt(struct stinfo * stp,Block in,Block out)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
cfb64_init(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
cfb64_start(int dir)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
cfb64_is(unsigned char * data,int cnt)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
cfb64_reply(unsigned char * data,int cnt)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
cfb64_session(Session_Key * key)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
cfb64_keyid(dir,kp,lenp)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
cfb64_printsub(unsigned char * data,int cnt,unsigned char * buf,int buflen)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
cfb64_stream_iv(Block seed,register struct stinfo * stp)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
cfb64_stream_key(Block key,register struct stinfo * stp)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
cfb64_encrypt(register unsigned char * s,int c)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
cfb64_decrypt(int data)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