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