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