| char *ckcrpv = "Encryption Engine, 8.0.114, 9 Oct 2003"; |
| /* |
| C K _ C R P . C - Cryptography for C-Kermit" |
| |
| Copyright (C) 1998, 2004, |
| Trustees of Columbia University in the City of New York. |
| All rights reserved. See the C-Kermit COPYING.TXT file or the |
| copyright text in the ckcmai.c module for disclaimer and permissions. |
| |
| Author: |
| Jeffrey E Altman (jaltman@secure-endpoints.com) |
| Secure Endpoints Inc., New York City |
| */ |
| |
| #define CK_CRP_C |
| #ifdef CK_DES |
| #ifdef CK_SSL |
| #ifndef LIBDES |
| #define LIBDES |
| #endif /* LIBDES */ |
| #endif /* CK_SSL */ |
| #endif /* CK_DES */ |
| |
| #ifdef CRYPT_DLL |
| #define CK_AUTHENTICATION |
| #define CK_ENCRYPTION |
| #define CK_DES |
| #define CK_CAST |
| #ifndef LIBDES |
| #define LIBDES |
| #endif /* LIBDES */ |
| |
| #define TELCMDS /* to define name array */ |
| #define TELOPTS /* to define name array */ |
| #define ENCRYPT_NAMES |
| #endif /* CRYPT_DLL */ |
| |
| #include "ckcsym.h" |
| #include "ckcdeb.h" |
| #include "ckcnet.h" |
| |
| #ifdef DEBUG |
| #undef DEBUG |
| #endif /* DEBUG */ |
| |
| #ifdef CK_AUTHENTICATION |
| #ifdef CK_ENCRYPTION |
| #define ENCRYPTION |
| #ifdef CK_DES |
| #define DES_ENCRYPTION |
| #endif /* CK_DES */ |
| #ifdef CK_CAST |
| #define CAST_ENCRYPTION |
| #endif /* CK_CAST */ |
| #ifdef COMMENT |
| #define CAST_EXPORT_ENCRYPTION |
| #endif /* COMMENT */ |
| #endif /* CK_ENCRYPTION */ |
| #endif /* CK_AUTHENTICATION */ |
| |
| #ifdef CK_ENCRYPTION |
| |
| #include "ckucmd.h" /* For struct keytab definition */ |
| #include "ckuath.h" |
| #include "ckuat2.h" |
| #ifdef MIT_CURRENT |
| #include <krb5.h> |
| #endif /* MIT_CURRENT */ |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #ifdef OS2 |
| #include <stdarg.h> |
| #ifdef OS2ONLY |
| #include <os2.h> |
| #endif /* OS2ONLY */ |
| #include "ckosyn.h" |
| #else /* OS2 */ |
| static char * tmpstring = NULL; |
| #endif /* OS2 */ |
| |
| #ifndef CAST_OR_EXPORT |
| #ifdef CAST_ENCRYPTION |
| #define CAST_OR_EXPORT |
| #endif /* CAST_ENCRYPTION */ |
| #ifdef CAST_EXPORT_ENCRYPTION |
| #define CAST_OR_EXPORT |
| #endif /* CAST_EXPORT_ENCRYPTION */ |
| #endif /* CAST_OR_EXPORT */ |
| |
| #ifdef CRYPT_DLL |
| int cmd_quoting = 0; |
| |
| #ifndef TELOPT_MACRO |
| int |
| telopt_index(opt) int opt; { |
| if ( opt >= 0 && opt <= TELOPT_SEND_URL ) |
| return(opt); |
| else if ( opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT ) |
| return(opt-89); |
| else |
| return(NTELOPTS); |
| } |
| |
| int |
| telopt_ok(opt) int opt; { |
| return((opt >= TELOPT_BINARY && opt <= TELOPT_SEND_URL) || |
| (opt >= TELOPT_PRAGMA_LOGON && opt <= TELOPT_PRAGMA_HEARTBEAT)); |
| } |
| |
| CHAR * |
| telopt(opt) int opt; { |
| if ( telopt_ok(opt) ) |
| return(telopts[telopt_index(opt)]); |
| else |
| return("UNKNOWN"); |
| } |
| #endif /* TELOPT_MACRO */ |
| |
| static int (*p_ttol)(char *,int)=NULL; |
| static int (*p_dodebug)(int,char *,char *,long)=NULL; |
| static int (*p_dohexdump)(char *,char *,int)=NULL; |
| static void (*p_tn_debug)(char *)=NULL; |
| static int (*p_vscrnprintf)(char *, ...)=NULL; |
| static void * p_k5_context=NULL; |
| static unsigned long (*p_reqtelmutex)(unsigned long)=NULL; |
| static unsigned long (*p_reltelmutex)(void)=NULL; |
| |
| unsigned long |
| RequestTelnetMutex(unsigned long x) |
| { |
| if ( p_reqtelmutex ) |
| return p_reqtelmutex(x); |
| return 0; |
| } |
| |
| unsigned long |
| ReleaseTelnetMutex(void) |
| { |
| if ( p_reltelmutex ) |
| return p_reltelmutex(); |
| return 0; |
| } |
| |
| int |
| ttol(char * s, int n) |
| { |
| if ( p_ttol ) |
| return(p_ttol(s,n)); |
| else |
| return(-1); |
| } |
| |
| int |
| dodebug(int flag, char * s1, char * s2, long n) |
| { |
| if ( p_dodebug ) |
| return(p_dodebug(flag,s1,s2,n)); |
| else |
| return(-1); |
| } |
| |
| int |
| dohexdump( char * s1, char * s2, int n ) |
| { |
| if ( p_dohexdump ) |
| p_dohexdump(s1,s2,n); |
| return(0); |
| } |
| |
| void |
| tn_debug( char * s ) |
| { |
| if ( p_tn_debug ) |
| p_tn_debug(s); |
| } |
| |
| static char myprtfstr[4096]; |
| int |
| Vscrnprintf(const char * format, ...) { |
| int i, len, rc=0; |
| char *cp; |
| va_list ap; |
| |
| va_start(ap, format); |
| #ifdef NT |
| rc = _vsnprintf(myprtfstr, sizeof(myprtfstr)-1, format, ap); |
| #else /* NT */ |
| rc = vsprintf(myprtfstr, format, ap); |
| #endif /* NT */ |
| va_end(ap); |
| |
| if ( p_vscrnprintf ) |
| return(p_vscrnprintf(myprtfstr)); |
| else |
| return(-1); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| tn_hex(CHAR * buf, int buflen, CHAR * data, int datalen) |
| #else /* CK_ANSIC */ |
| tn_hex(buf, buflen, data, datalen) |
| CHAR * buf; |
| int buflen; |
| CHAR * data; |
| int datalen; |
| #endif /* CK_ANSIC */ |
| { |
| int i = 0, j = 0, k = 0; |
| CHAR tmp[8]; |
| #ifdef COMMENT |
| int was_hex = 1; |
| |
| for (k=0; k < datalen; k++) { |
| if (data[k] < 32 || data[k] >= 127) { |
| sprintf(tmp,"%s%02X ",was_hex?"":"\" ",data[k]); |
| was_hex = 1; |
| } else { |
| sprintf(tmp,"%s%c",was_hex?"\"":"",data[k]); |
| was_hex = 0; |
| } |
| ckstrncat(buf,tmp,buflen); |
| } |
| if (!was_hex) |
| ckstrncat(buf,"\" ",buflen); |
| #else /* COMMENT */ |
| if (datalen <= 0 || data == NULL) |
| return(0); |
| |
| for (i = 0; i < datalen; i++) { |
| ckstrncat(buf,"\r\n ",buflen); |
| for (j = 0 ; (j < 16); j++) { |
| if ((i + j) < datalen) |
| sprintf(tmp, |
| "%s%02x ", |
| (j == 8 ? "| " : ""), |
| (CHAR) data[i + j] |
| ); |
| else |
| sprintf(tmp, |
| "%s ", |
| (j == 8 ? "| " : "") |
| ); |
| ckstrncat(buf,tmp,buflen); |
| } |
| ckstrncat(buf," ",buflen); |
| for (k = 0; (k < 16) && ((i + k) < datalen); k++) { |
| sprintf(tmp, |
| "%s%c", |
| (k == 8 ? " " : ""), |
| isprint(data[i + k]) ? data[i + k] : '.' |
| ); |
| ckstrncat(buf,tmp,buflen); |
| } |
| i += j - 1; |
| } /* end for */ |
| ckstrncat(buf,"\r\n ",buflen); |
| #endif /* COMMENT */ |
| return(strlen(buf)); |
| } |
| |
| #ifdef COMMENT |
| #define ttol dll_ttol |
| #define dodebug dll_dodebug |
| #define dohexdump dll_dohexdump |
| #define tn_debug dll_tn_debug |
| #define Vscrnprintf dll_vscrnprintf |
| #endif /* COMMENT */ |
| |
| char tn_msg[TN_MSG_LEN], hexbuf[TN_MSG_LEN]; /* from ckcnet.c */ |
| int deblog=1, debses=1, tn_deb=1; |
| #else /* CRYPT_DLL */ |
| extern char tn_msg[], hexbuf[]; /* from ckcnet.c */ |
| extern int deblog, debses, tn_deb; |
| #ifdef MIT_CURRENT |
| extern krb5_context k5_context; |
| #endif /* MIT_CURRENT */ |
| #endif /* CRYPT_DLL */ |
| |
| #ifdef LIBDES |
| #ifndef UNIX |
| #define des_new_random_key des_random_key |
| #define des_set_random_generator_seed des_random_seed |
| #endif /* UNIX */ |
| #define des_fixup_key_parity des_set_odd_parity |
| #ifdef OPENSSL_097 |
| #define OPENSSL_ENABLE_OLD_DES_SUPPORT |
| #include <openssl/des.h> |
| #endif /* OPENSSL_097 */ |
| #else /* LIBDES */ |
| #ifdef UNIX |
| #define des_set_random_generator_seed(x) des_init_random_number_generator(x) |
| #endif /* UNIX */ |
| #ifdef OS2 |
| #define des_new_random_key ck_des_new_random_key |
| #define des_set_random_generator_seed ck_des_set_random_generator_seed |
| #define des_key_sched ck_des_key_sched |
| #define des_ecb_encrypt ck_des_ecb_encrypt |
| #define des_string_to_key ck_des_string_to_key |
| #define des_fixup_key_parity ck_des_fixup_key_parity |
| #endif /* OS2 */ |
| #endif /* LIBDES */ |
| |
| #ifdef CK_DES |
| /* This code comes from Eric Young's libdes package and is not part */ |
| /* of the standard MIT DES library that is part of Kerberos. However, */ |
| /* it is extremely useful. So we add it here. */ |
| |
| |
| /* Weak and semi week keys as take from |
| * %A D.W. Davies |
| * %A W.L. Price |
| * %T Security for Computer Networks |
| * %I John Wiley & Sons |
| * %D 1984 |
| * Many thanks to smb@ulysses.att.com (Steven Bellovin) for the reference |
| * (and actual cblock values). |
| */ |
| #define NUM_WEAK_KEY 16 |
| static Block weak_keys[NUM_WEAK_KEY]={ |
| /* weak keys */ |
| {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}, |
| {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE}, |
| {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}, |
| {0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0,0xE0}, |
| /* semi-weak keys */ |
| {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE}, |
| {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01}, |
| {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1}, |
| {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E}, |
| {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1}, |
| {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01}, |
| {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE}, |
| {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E}, |
| {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E}, |
| {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01}, |
| {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE}, |
| {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1}}; |
| |
| int |
| ck_des_is_weak_key(key) |
| Block key; |
| { |
| int i; |
| |
| for (i=0; i<NUM_WEAK_KEY; i++) { |
| /* Added == 0 to comparision, I obviously don't run |
| * this section very often :-(, thanks to |
| * engineering@MorningStar.Com for the fix |
| * eay 93/06/29 |
| * Another problem, I was comparing only the first 4 |
| * bytes, 97/03/18 */ |
| if (memcmp(weak_keys[i],key,sizeof(Block)) == 0) |
| return(1); |
| } |
| return(0); |
| } |
| |
| #ifdef UNIX |
| #ifdef LIBDES |
| /* These functions are not part of Eric Young's DES library */ |
| /* _unix_time_gmt_unixsec */ |
| /* _des_set_random_generator_seed */ |
| /* _des_fixup_key_parity (added in 0.9.5) */ |
| /* _des_new_random_key */ |
| #include <sys/time.h> |
| |
| unsigned long |
| unix_time_gmt_unixsec (usecptr) |
| unsigned long *usecptr; |
| { |
| struct timeval now; |
| |
| (void) gettimeofday (&now, (struct timezone *)0); |
| if (usecptr) |
| *usecptr = now.tv_usec; |
| return now.tv_sec; |
| } |
| |
| void |
| des_set_random_generator_seed(Block B) |
| { |
| des_random_seed(B); |
| return; |
| } |
| |
| #ifdef COMMENT |
| /* added to openssl in 0.9.5 */ |
| void |
| des_fixup_key_parity(Block B) |
| { |
| des_set_odd_parity(B); |
| return; |
| } |
| #endif /* COMMENT */ |
| int |
| des_new_random_key(Block B) |
| { |
| int rc=0; |
| rc = des_random_key(B); |
| return(rc); |
| } |
| |
| #endif /* LIBDES */ |
| #endif /* UNIX */ |
| #endif /* CK_DES */ |
| |
| /* |
| * Copyright (c) 1991, 1993 |
| * The Regents of the University of California. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. All advertising materials mentioning features or use of this software |
| * must display the following acknowledgement: |
| * This product includes software developed by the University of |
| * California, Berkeley and its contributors. |
| * 4. Neither the name of the University nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| */ |
| |
| /* based on @(#)encrypt.c 8.1 (Berkeley) 6/4/93 */ |
| |
| /* |
| * Copyright (C) 1990 by the Massachusetts Institute of Technology |
| * |
| * Export of this software from the United States of America may |
| * require a specific license from the United States Government. |
| * It is the responsibility of any person or organization contemplating |
| * export to obtain such a license before exporting. |
| * |
| * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and |
| * distribute this software and its documentation for any purpose and |
| * without fee is hereby granted, provided that the above copyright |
| * notice appear in all copies and that both that copyright notice and |
| * this permission notice appear in supporting documentation, and that |
| * the name of M.I.T. not be used in advertising or publicity pertaining |
| * to distribution of the software without specific, written prior |
| * permission. M.I.T. makes no representations about the suitability of |
| * this software for any purpose. It is provided "as is" without express |
| * or implied warranty. |
| */ |
| |
| #include <stdio.h> |
| |
| /* |
| * These function pointers point to the current routines |
| * for encrypting and decrypting data. |
| */ |
| static VOID (*encrypt_output) P((unsigned char *, int)); |
| static int (*decrypt_input) P((int)); |
| |
| #ifdef DEBUG |
| static int encrypt_debug_mode = 1; |
| static int encrypt_verbose = 1; |
| #else |
| static int encrypt_verbose = 1; |
| static int encrypt_debug_mode = 0; |
| #endif |
| |
| static char dbgbuf [16384]; |
| |
| static int decrypt_mode = 0; |
| static int encrypt_mode = 0; |
| static int autoencrypt = 1; |
| static int autodecrypt = 1; |
| static int havesessionkey = 0; |
| |
| static kstream EncryptKSGlobalHack = NULL; |
| static int EncryptType = ENCTYPE_ANY; |
| |
| #define typemask(x) ((x) > 0 ? 1 << ((x)-1) : 0) |
| |
| static long i_support_encrypt = |
| typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64); |
| static long i_support_decrypt = |
| typemask(ENCTYPE_DES_CFB64) | typemask(ENCTYPE_DES_OFB64); |
| static long i_wont_support_encrypt = 0; |
| static long i_wont_support_decrypt = 0; |
| #define I_SUPPORT_ENCRYPT (i_support_encrypt & ~i_wont_support_encrypt) |
| #define I_SUPPORT_DECRYPT (i_support_decrypt & ~i_wont_support_decrypt) |
| |
| static long remote_supports_encrypt = 0; |
| static long remote_supports_decrypt = 0; |
| |
| /* Make sure that this list is in order of algorithm strength */ |
| /* as it determines the search order for selecting specific */ |
| /* encryption choices. All CFB modes must come before OFB modes. */ |
| static Encryptions encryptions[] = { |
| #ifdef DES_ENCRYPTION |
| { "DES3_CFB64", |
| ENCTYPE_DES3_CFB64, |
| des3_cfb64_encrypt, |
| des3_cfb64_decrypt, |
| des3_cfb64_init, |
| des3_cfb64_start, |
| des3_cfb64_is, |
| des3_cfb64_reply, |
| des3_cfb64_session, |
| des3_cfb64_keyid, |
| NULL }, |
| #endif /* DES_ENCRYPTION */ |
| #ifdef CAST_ENCRYPTION |
| #ifndef CAST_EXPORT_ENCRYPTION |
| { "CAST128_CFB64", ENCTYPE_CAST128_CFB64, |
| cast_cfb64_encrypt, |
| cast_cfb64_decrypt, |
| cast_cfb64_init, |
| cast_cfb64_start, |
| cast_cfb64_is, |
| cast_cfb64_reply, |
| cast_cfb64_session, |
| cast_cfb64_keyid, |
| NULL }, |
| #endif |
| #endif |
| #ifdef DES_ENCRYPTION |
| { "DES_CFB64", |
| ENCTYPE_DES_CFB64, |
| cfb64_encrypt, |
| cfb64_decrypt, |
| cfb64_init, |
| cfb64_start, |
| cfb64_is, |
| cfb64_reply, |
| cfb64_session, |
| cfb64_keyid, |
| NULL }, |
| #endif /* DES_ENCRYPTION */ |
| #if defined (CAST_EXPORT_ENCRYPTION) || defined(CAST_ENCRYPTION) |
| { "CAST5_40_CFB64", ENCTYPE_CAST5_40_CFB64, |
| castexp_cfb64_encrypt, |
| castexp_cfb64_decrypt, |
| castexp_cfb64_init, |
| castexp_cfb64_start, |
| castexp_cfb64_is, |
| castexp_cfb64_reply, |
| castexp_cfb64_session, |
| castexp_cfb64_keyid, |
| NULL }, |
| #endif /* CAST_ENCRYPTION */ |
| #ifdef DES_ENCRYPTION |
| { "DES3_OFB64", |
| ENCTYPE_DES3_OFB64, |
| des3_ofb64_encrypt, |
| des3_ofb64_decrypt, |
| des3_ofb64_init, |
| des3_ofb64_start, |
| des3_ofb64_is, |
| des3_ofb64_reply, |
| des3_ofb64_session, |
| des3_ofb64_keyid, |
| NULL }, |
| #endif /* DES_ENCRYPTION */ |
| #ifdef CAST_ENCRYPTION |
| #ifndef CAST_EXPORT_ENCRYPTION |
| { "CAST128_OFB64", ENCTYPE_CAST128_OFB64, |
| cast_ofb64_encrypt, |
| cast_ofb64_decrypt, |
| cast_ofb64_init, |
| cast_ofb64_start, |
| cast_ofb64_is, |
| cast_ofb64_reply, |
| cast_ofb64_session, |
| cast_ofb64_keyid, |
| NULL }, |
| #endif |
| #endif |
| #ifdef DES_ENCRYPTION |
| { "DES_OFB64", |
| ENCTYPE_DES_OFB64, |
| ofb64_encrypt, |
| ofb64_decrypt, |
| ofb64_init, |
| ofb64_start, |
| ofb64_is, |
| ofb64_reply, |
| ofb64_session, |
| ofb64_keyid, |
| NULL }, |
| #endif /* DES_ENCRYPTION */ |
| #if defined (CAST_EXPORT_ENCRYPTION) || defined(CAST_ENCRYPTION) |
| { "CAST5_40_OFB64", ENCTYPE_CAST5_40_OFB64, |
| castexp_ofb64_encrypt, |
| castexp_ofb64_decrypt, |
| castexp_ofb64_init, |
| castexp_ofb64_start, |
| castexp_ofb64_is, |
| castexp_ofb64_reply, |
| castexp_ofb64_session, |
| castexp_ofb64_keyid, |
| NULL }, |
| #endif /* CAST_ENCRYPTION */ |
| { 0,0,0,0,0,0,0,0,0,0,0 } |
| }; |
| |
| int |
| get_crypt_table( struct keytab ** pTable, int * pN ) |
| { |
| int i=0,n=0; |
| |
| if ( *pTable ) |
| { |
| for ( i=0 ; i < *pN ; i++ ) |
| free( (*pTable)[i].kwd ) ; |
| free ( *pTable ) ; |
| } |
| *pTable = NULL; |
| *pN = 0; |
| |
| /* How many encryption types do we have? */ |
| while ( encryptions[n].name ) |
| n++; |
| |
| if ( n ) |
| { |
| *pTable = malloc( sizeof(struct keytab) * (n+2) ) ; |
| if ( !(*pTable) ) |
| return(0); |
| |
| #ifdef OS2 |
| (*pTable)[0].kwd =strdup("automatic"); |
| #else /* OS2 */ |
| makestr(&tmpstring,"automatic"); |
| (*pTable)[0].kwd = tmpstring; |
| tmpstring = NULL; |
| #endif /* OS2 */ |
| (*pTable)[0].kwval = ENCTYPE_ANY; |
| (*pTable)[0].flgs = 0; |
| #ifdef OS2 |
| (*pTable)[1].kwd =strdup("none"); |
| #else /* OS2 */ |
| makestr(&tmpstring,"none"); |
| (*pTable)[1].kwd = tmpstring; |
| tmpstring = NULL; |
| #endif /* OS2 */ |
| (*pTable)[1].kwval = 999; |
| (*pTable)[1].flgs = 0; |
| (*pN) = 2; |
| |
| for ( i=0 ; i < n ; i++ ) { |
| char * newstr = NULL, * p; |
| int newval = encryptions[i].type; |
| int j = 0, len = 0; |
| |
| #ifdef OS2 |
| newstr = strdup(encryptions[i].name); |
| strlwr(newstr); |
| #else /* OS2 */ |
| makestr(&tmpstring,encryptions[i].name); |
| newstr = tmpstring; |
| tmpstring = NULL; |
| for (p = newstr; *p; p++) if (isupper(*p)) *p = tolower(*p); |
| #endif /* OS2 */ |
| |
| for (j = 0; j < (*pN); j++) { |
| int tempval = 0; |
| char * tempstr = NULL; |
| |
| if ( strcmp( (*pTable)[j].kwd, newstr ) > 0 ) |
| { |
| tempval = (*pTable)[j].kwval; |
| tempstr = (*pTable)[j].kwd; |
| (*pTable)[j].kwd = newstr ; |
| (*pTable)[j].kwval = newval; |
| newval = tempval; |
| newstr = tempstr; |
| (*pTable)[j].flgs = 0; |
| } |
| } |
| (*pTable)[*pN].kwd = newstr ; |
| (*pTable)[*pN].kwval = newval; |
| (*pTable)[*pN].flgs = 0 ; |
| (*pN)++ ; |
| } |
| } else { |
| *pTable = malloc( sizeof(struct keytab) * 2 ) ; |
| if ( !(*pTable) ) |
| return(0); |
| |
| #ifdef OS2 |
| (*pTable)[0].kwd =strdup("automatic"); |
| #else /* OS2 */ |
| makestr(&tmpstring,"automatic"); |
| (*pTable)[0].kwd = tmpstring; |
| tmpstring = NULL; |
| #endif /* OS2 */ |
| (*pTable)[0].kwval = ENCTYPE_ANY; |
| (*pTable)[0].flgs = 0; |
| #ifdef OS2 |
| (*pTable)[1].kwd =strdup("none"); |
| #else /* OS2 */ |
| makestr(&tmpstring,"none"); |
| (*pTable)[1].kwd = tmpstring; |
| tmpstring = NULL; |
| #endif /* OS2 */ |
| (*pTable)[1].kwval = 999; |
| (*pTable)[1].flgs = 0; |
| (*pN) = 2; |
| } |
| return(*pN); |
| } |
| |
| static unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPTION, |
| ENCRYPT_SUPPORT }; |
| static unsigned char str_suplen = 0; |
| static unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPTION }; |
| static unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPTION, 0, IAC, SE }; |
| |
| _PROTOTYP(int encrypt_request_end, (VOID)); |
| _PROTOTYP(int encrypt_request_start, (VOID)); |
| _PROTOTYP(int encrypt_enc_keyid, (unsigned char *, int)); |
| _PROTOTYP(int encrypt_dec_keyid, (unsigned char *, int)); |
| _PROTOTYP(int encrypt_support, (unsigned char *, int)); |
| _PROTOTYP(int encrypt_start, (unsigned char *, int)); |
| _PROTOTYP(int encrypt_end, (VOID)); |
| |
| _PROTOTYP(int encrypt_ks_stream,(struct kstream_data_block *, /* output */ |
| struct kstream_data_block *)); /* input */ |
| |
| _PROTOTYP(int decrypt_ks_stream,(struct kstream_data_block *, /* output */ |
| struct kstream_data_block *)); /* input */ |
| |
| int |
| #ifdef CK_ANSIC |
| encrypt_ks_stream(struct kstream_data_block *i, |
| struct kstream_data_block *o) |
| #else |
| encrypt_ks_stream(i,o) |
| struct kstream_data_block *i; struct kstream_data_block *o; |
| #endif |
| { |
| /* |
| * this is really quite bogus, since it does an in-place encryption... |
| */ |
| if (encrypt_output) { |
| encrypt_output(i->ptr, i->length); |
| return 1; |
| } |
| return 0; |
| } |
| |
| |
| int |
| #ifdef CK_ANSIC |
| decrypt_ks_stream(struct kstream_data_block *i, |
| struct kstream_data_block *o) |
| #else |
| decrypt_ks_stream(i,o) |
| struct kstream_data_block *i; struct kstream_data_block *o; |
| #endif |
| { |
| unsigned int len; |
| /* |
| * this is really quite bogus, since it does an in-place decryption... |
| */ |
| if (decrypt_input) { |
| for (len = 0 ; len < i->length ; len++) |
| ((unsigned char *)i->ptr)[len] |
| = decrypt_input(((unsigned char *)i->ptr)[len]); |
| return 1; |
| } |
| return 0; |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| decrypt_ks_hack(unsigned char *buf, int cnt) |
| #else |
| decrypt_ks_hack(buf,cnt) unsigned char *buf; int cnt; |
| #endif |
| { |
| int len; |
| /* |
| * this is really quite bogus, since it does an in-place decryption... |
| */ |
| for (len = 0 ; len < cnt ; len++) |
| buf[len] = decrypt_input(buf[len]); |
| |
| #ifdef DEBUG |
| hexdump("decrypt ks hack", buf, cnt); |
| #endif |
| return 1; |
| } |
| |
| |
| /* |
| * parsedat[0] == the suboption we might be negotiating, |
| */ |
| int |
| #ifdef CK_ANSIC |
| encrypt_parse(unsigned char *parsedat, int end_sub) |
| #else |
| encrypt_parse(parsedat,end_sub) unsigned char *parsedat; int end_sub; |
| #endif |
| { |
| int rc = 0; |
| |
| switch(parsedat[1]) { |
| case ENCRYPT_START: |
| rc = encrypt_start(parsedat + 2, end_sub - 2); |
| break; |
| case ENCRYPT_END: |
| rc = encrypt_end(); |
| break; |
| case ENCRYPT_SUPPORT: |
| rc = encrypt_support(parsedat + 2, end_sub - 2); |
| break; |
| case ENCRYPT_REQSTART: |
| rc = encrypt_request_start(); |
| break; |
| case ENCRYPT_REQEND: |
| /* |
| * We can always send an REQEND so that we cannot |
| * get stuck encrypting. We should only get this |
| * if we have been able to get in the correct mode |
| * anyhow. |
| */ |
| rc = encrypt_request_end(); |
| break; |
| case ENCRYPT_IS: |
| rc = encrypt_is(parsedat + 2, end_sub - 2); |
| break; |
| case ENCRYPT_REPLY: |
| rc = encrypt_reply(parsedat + 2, end_sub - 2); |
| break; |
| case ENCRYPT_ENC_KEYID: |
| rc = encrypt_enc_keyid(parsedat + 2, end_sub - 2); |
| break; |
| case ENCRYPT_DEC_KEYID: |
| rc = encrypt_dec_keyid(parsedat + 2, end_sub - 2); |
| break; |
| default: |
| rc = -1; |
| break; |
| } |
| return(rc); |
| } |
| |
| /* XXX */ |
| Encryptions * |
| #ifdef CK_ANSIC |
| findencryption(int type) |
| #else |
| findencryption(type) int type; |
| #endif |
| { |
| Encryptions *ep = encryptions; |
| |
| if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & typemask(type))) |
| return(0); |
| while (ep->type && ep->type != type) |
| ++ep; |
| return(ep->type ? ep : 0); |
| } |
| |
| Encryptions * |
| #ifdef CK_ANSIC |
| finddecryption(int type) |
| #else |
| finddecryption(type) int type; |
| #endif |
| { |
| Encryptions *ep = encryptions; |
| |
| if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & typemask(type))) |
| return(0); |
| while (ep->type && ep->type != type) |
| ++ep; |
| return(ep->type ? ep : 0); |
| } |
| |
| #define MAXKEYLEN 64 |
| |
| static struct key_info { |
| unsigned char keyid[MAXKEYLEN]; |
| int keylen; |
| int dir; |
| int *modep; |
| Encryptions *(*getcrypt)(); |
| } ki[2] = { |
| { { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption }, |
| { { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption }, |
| }; |
| |
| VOID |
| #ifdef CK_ANSIC |
| encrypt_init(kstream iks, int type) |
| #else |
| encrypt_init(iks, type) kstream iks; int type; |
| #endif |
| { |
| Encryptions *ep = encryptions; |
| |
| i_support_encrypt = i_support_decrypt = 0; |
| remote_supports_encrypt = remote_supports_decrypt = 0; |
| i_wont_support_encrypt = i_wont_support_decrypt = 0; |
| encrypt_mode = 0; |
| decrypt_mode = 0; |
| encrypt_output = NULL; |
| decrypt_input = NULL; |
| ki[0].keylen = 0; |
| memset(ki[0].keyid,0,MAXKEYLEN); |
| ki[1].keylen = 0; |
| memset(ki[1].keyid,0,MAXKEYLEN); |
| havesessionkey = 0; |
| autoencrypt = 1; |
| autodecrypt = 1; |
| |
| EncryptKSGlobalHack = iks; |
| EncryptType = type; |
| |
| str_send[0] = IAC; |
| str_send[1] = SB; |
| str_send[2] = TELOPT_ENCRYPTION; |
| str_send[3] = ENCRYPT_SUPPORT; |
| str_suplen = 4; |
| |
| while (ep->type) { |
| if ( EncryptType == ENCTYPE_ANY || |
| EncryptType == ep->type ) { |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>I will support %s\n", |
| ENCTYPE_NAME(ep->type)); /* safe */ |
| debug(F110,"encrypt_init",dbgbuf,0); |
| } |
| #endif |
| i_support_encrypt |= typemask(ep->type); |
| i_support_decrypt |= typemask(ep->type); |
| if ((i_wont_support_decrypt & typemask(ep->type)) == 0) |
| if ((str_send[str_suplen++] = ep->type) == IAC) |
| str_send[str_suplen++] = IAC; |
| } |
| if (ep->init) |
| (*ep->init)(0); |
| ++ep; |
| } |
| str_send[str_suplen++] = IAC; |
| str_send[str_suplen++] = SE; |
| } |
| |
| VOID |
| #ifdef CK_ANSIC |
| encrypt_send_support(VOID) |
| #else |
| encrypt_send_support() |
| #endif |
| { |
| Encryptions *ep = encryptions; |
| |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) |
| return; |
| #endif /* CK_SSL */ |
| |
| str_send[0] = IAC; |
| str_send[1] = SB; |
| str_send[2] = TELOPT_ENCRYPTION; |
| str_send[3] = ENCRYPT_SUPPORT; |
| str_suplen = 4; |
| |
| while (ep->type) { |
| if ( EncryptType == ENCTYPE_ANY || |
| EncryptType == ep->type ) { |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>I will support %s\n", |
| ENCTYPE_NAME(ep->type)); /* safe */ |
| debug(F110,"encrypt_send_support",dbgbuf,0); |
| } |
| #endif |
| if ((i_wont_support_decrypt & typemask(ep->type)) == 0) |
| if ((str_send[str_suplen++] = ep->type) == IAC) |
| str_send[str_suplen++] = IAC; |
| } |
| ++ep; |
| } |
| str_send[str_suplen++] = IAC; |
| str_send[str_suplen++] = SE; |
| |
| /* |
| * If the user has requested that decryption start |
| * immediatly, then send a "REQUEST START" before |
| * we negotiate the type. |
| */ |
| if (autodecrypt) |
| encrypt_send_request_start(); |
| |
| if (deblog || tn_deb || debses) { |
| int i; |
| sprintf(tn_msg,"TELNET SENT SB %s SUPPORT ", |
| TELOPT(TELOPT_ENCRYPTION)); /* safe */ |
| for ( i=4;i<str_suplen-2;i++ ) { |
| if ( str_send[i] == IAC ) { |
| ckstrncat(tn_msg,"IAC ",TN_MSG_LEN); |
| i++; |
| } |
| ckstrncat(tn_msg,ENCTYPE_NAME(str_send[i]),TN_MSG_LEN); |
| ckstrncat(tn_msg," ",TN_MSG_LEN); |
| } |
| ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); |
| debug(F100,tn_msg,"",0); |
| if (tn_deb || debses) tn_debug(tn_msg); |
| } |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| ttol(str_send, str_suplen); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| |
| str_suplen = 0; |
| } |
| |
| /* |
| * Called when ENCRYPT SUPPORT is received. |
| */ |
| int |
| #ifdef CK_ANSIC |
| encrypt_support(unsigned char *_typelist, int _cnt) |
| #else |
| encrypt_support(_typelist, _cnt) unsigned char * _typelist; int _cnt; |
| #endif |
| { |
| register int type, use_type = 0; |
| unsigned char * typelist = _typelist; |
| int cnt = _cnt; |
| Encryptions *ep; |
| |
| debug(F111,"encrypt_support","cnt",cnt); |
| |
| /* |
| * Forget anything the other side has previously told us. |
| */ |
| remote_supports_decrypt = 0; |
| |
| while (cnt-- > 0) { |
| type = *typelist++; |
| if ( EncryptType == ENCTYPE_ANY || |
| EncryptType == type ) { |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>Remote supports %s (%d)\n", |
| ENCTYPE_NAME(type), type); /* safe */ |
| debug(F110,"encrypt_support",dbgbuf,0); |
| } |
| #endif |
| if ((type < ENCTYPE_CNT) && |
| (I_SUPPORT_ENCRYPT & typemask(type))) { |
| remote_supports_decrypt |= typemask(type); |
| if (use_type == 0) |
| use_type = type; |
| } |
| } |
| } |
| if (use_type) { |
| ep = findencryption(use_type); |
| if (!ep) { |
| debug(F111,"encrypt_support","findencryption == NULL",use_type); |
| return(-1); |
| } |
| type = ep->start ? (*ep->start)(DIR_ENCRYPT, 0) : 0; |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>(*ep->start)() %s returned %d (%s)\n", |
| ENCTYPE_NAME(use_type), type, |
| ENCRYPT_NAME(type)); /* safe */ |
| debug(F110,"encrypt_support",dbgbuf,0); |
| } |
| #endif |
| if (type < 0) { |
| debug(F111,"encrypt_support","type < 0",type); |
| return(-1); |
| } |
| encrypt_mode = use_type; |
| if (type == 0) |
| encrypt_start_output(use_type); |
| debug(F111,"encrypt_support","success",type); |
| return(0); |
| } |
| debug(F111,"encrypt_support","failed",use_type); |
| return(-1); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| encrypt_is(unsigned char *data, int cnt) |
| #else |
| encrypt_is(data, cnt) unsigned char *data; int cnt; |
| #endif /* CK_ANSIC */ |
| { |
| Encryptions *ep; |
| register int type, ret; |
| |
| if (--cnt < 0) |
| return(-1); |
| type = *data++; |
| if (type < ENCTYPE_CNT) |
| remote_supports_encrypt |= typemask(type); |
| if (!(ep = finddecryption(type))) { |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>encrypt_is: " |
| "Can't find type %s (%d) for initial negotiation\n", |
| ENCTYPE_NAME_OK(type) |
| ? ENCTYPE_NAME(type) : "(unknown)", |
| type); /* safe */ |
| debug(F110,"encrypt_is",dbgbuf,0); |
| } |
| #endif |
| return(-1); |
| } |
| if (!ep->is) { |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>encrypt_is: " |
| "No initial negotiation needed for type %s (%d)\n", |
| ENCTYPE_NAME_OK(type) |
| ? ENCTYPE_NAME(type) : "(unknown)", |
| type); /* safe */ |
| debug(F110,"encrypt_is",dbgbuf,0); |
| } |
| #endif |
| ret = 0; |
| } else { |
| ret = (*ep->is)(data, cnt); |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, "encrypt_is: " |
| "(*ep->is)(%x, %d) returned %s(%d)\n", data, cnt, |
| (ret < 0) ? "FAIL " : |
| (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); /* safe */ |
| debug(F110,"encrypt_is",dbgbuf,0); |
| } |
| #endif |
| } |
| if (ret < 0) { |
| autodecrypt = 0; |
| return(-1); |
| } else { |
| decrypt_mode = type; |
| if (ret == 0 && autodecrypt) { |
| encrypt_send_request_start(); |
| } |
| } |
| return(0); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| encrypt_reply(unsigned char *data, int cnt) |
| #else |
| encrypt_reply(data, cnt) unsigned char *data; int cnt; |
| #endif |
| { |
| Encryptions *ep; |
| register int ret, type; |
| |
| if (--cnt < 0) |
| return(-1); |
| type = *data++; |
| if (!(ep = findencryption(type))) { |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, |
| ">>>Can't find type %s (%d) for initial negotiation\n", |
| ENCTYPE_NAME_OK(type) |
| ? ENCTYPE_NAME(type) : "(unknown)", |
| type); /* safe */ |
| debug(F110,"encrypt_reply",dbgbuf,0); |
| } |
| #endif |
| return(-1); |
| } |
| if (!ep->reply) { |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>No initial negotiation needed for type %s (%d)\n", |
| ENCTYPE_NAME_OK(type) |
| ? ENCTYPE_NAME(type) : "(unknown)", |
| type); /* safe */ |
| debug(F110,"encrypt_reply",dbgbuf,0); |
| } |
| #endif |
| ret = 0; |
| } else { |
| ret = (*ep->reply)(data, cnt); |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, "(*ep->reply)(%x, %d) returned %s(%d)\n", |
| data, cnt, |
| (ret < 0) ? "FAIL " : |
| (ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret); /* safe */ |
| debug(F110,"encrypt_reply",dbgbuf,0); |
| } |
| #endif |
| } |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>encrypt_reply returned %d\n", ret); /* safe */ |
| debug(F110,"encrypt_reply",dbgbuf,0); |
| } |
| #endif |
| if (ret < 0) { |
| autoencrypt = 0; |
| return(-1); |
| } else { |
| encrypt_mode = type; |
| if (ret == 0 && autoencrypt) |
| encrypt_start_output(type); |
| } |
| return(0); |
| } |
| |
| /* |
| * Called when a ENCRYPT START command is received. |
| */ |
| int |
| #ifdef CK_ANSIC |
| encrypt_start(unsigned char *data, int cnt) |
| #else |
| encrypt_start(data, cnt) unsigned char *data; int cnt; |
| #endif |
| { |
| Encryptions *ep; |
| |
| if (!decrypt_mode) { |
| /* |
| * Something is wrong. We should not get a START |
| * command without having already picked our |
| * decryption scheme. Send a REQUEST-END to |
| * attempt to clear the channel... |
| */ |
| encrypt_send_request_end(); |
| printf("Authentication error!\n%s\n", |
| "Warning, Cannot decrypt input stream!!!"); |
| return(-1); |
| } |
| |
| if (ep = finddecryption(decrypt_mode)) { |
| if ( decrypt_input != ep->input ) { |
| decrypt_input = ep->input; |
| EncryptKSGlobalHack->decrypt = decrypt_ks_stream; |
| EncryptKSGlobalHack->decrypt_type = ep->type; |
| |
| if (encrypt_verbose) { |
| sprintf(dbgbuf, "Input is now decrypted with type %s", |
| ENCTYPE_NAME(decrypt_mode)); /* safe */ |
| debug(F110,"encrypt_start",dbgbuf,0); |
| printf("%s\n",dbgbuf); |
| } |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>Start to decrypt input with type %s", |
| ENCTYPE_NAME(decrypt_mode)); /* safe */ |
| debug(F110,"ck_crp",dbgbuf,0); |
| } |
| #endif |
| } |
| } else { |
| char buf[1024]; |
| sprintf(buf, "Warning, Cannot decrypt type %s (%d)!!!", |
| ENCTYPE_NAME_OK(decrypt_mode) |
| ? ENCTYPE_NAME(decrypt_mode) : "(unknown)", |
| decrypt_mode); /* safe */ |
| printf("Authentication error!\n%s\n",buf); |
| encrypt_send_request_end(); |
| return(-1); |
| } |
| return(0); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| encrypt_dont_support(int type) |
| #else |
| encrypt_dont_support(type) int type; |
| #endif |
| { |
| i_wont_support_encrypt |= typemask(type); |
| i_wont_support_decrypt |= typemask(type); |
| return(0); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| encrypt_session_key(Session_Key *key, int server) |
| #else |
| encrypt_session_key(key, server) Session_Key *key; int server; |
| #endif |
| { |
| Encryptions *ep = encryptions; |
| |
| if (havesessionkey) |
| return(0); |
| |
| havesessionkey = 1; |
| |
| while (ep->type) { |
| debug(F111,"encrypt_session_key",ep->name,ep->type); |
| if (ep->session) { |
| if ((*ep->session)(key, server) < 0) { |
| i_wont_support_encrypt |= typemask(ep->type); |
| i_wont_support_decrypt |= typemask(ep->type); |
| } |
| } |
| ++ep; |
| } |
| debug(F111,"encrypt_session_key (done)",ep->name,ep->type); |
| return(0); |
| } |
| |
| /* |
| * Called when ENCRYPT END is received. |
| */ |
| int |
| #ifdef CK_ANSIC |
| encrypt_end(VOID) |
| #else |
| encrypt_end() |
| #endif |
| { |
| decrypt_input = NULL; |
| EncryptKSGlobalHack->decrypt = NULL; |
| EncryptKSGlobalHack->decrypt_type = ENCTYPE_ANY; |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>Input is back to clear text"); /* safe */ |
| debug(F110,"encrypt_end",dbgbuf,0); |
| } |
| #endif |
| if (encrypt_verbose) { |
| sprintf(dbgbuf, "Input is now clear text"); /* safe */ |
| debug(F110,"encrypt_end",dbgbuf,0); |
| printf("%s\n",dbgbuf); |
| } |
| return(0); |
| } |
| |
| /* |
| * Called when ENCRYPT REQUEST-END is received. |
| */ |
| int |
| #ifdef CK_ANSIC |
| encrypt_request_end(VOID) |
| #else |
| encrypt_request_end() |
| #endif |
| { |
| encrypt_send_end(); |
| return(0); |
| } |
| |
| /* |
| * Called when ENCRYPT REQUEST-START is received. If we receive |
| * this before a type is picked, then that indicates that the |
| * other side wants us to start encrypting data as soon as we |
| * can. |
| */ |
| int |
| #ifdef CK_ANSIC |
| encrypt_request_start(VOID) |
| #else |
| encrypt_request_start() |
| #endif |
| { |
| if (encrypt_mode != 0) |
| encrypt_start_output(encrypt_mode); |
| return(0); |
| } |
| |
| static unsigned char str_keyid[(MAXKEYLEN*2)+5] = { |
| IAC, SB, TELOPT_ENCRYPTION |
| }; |
| _PROTOTYP(int encrypt_keyid,(struct key_info *,unsigned char *,int)); |
| |
| int |
| #ifdef CK_ANSIC |
| encrypt_enc_keyid(unsigned char *keyid, int len) |
| #else |
| encrypt_enc_keyid(keyid, len) unsigned char *keyid; int len; |
| #endif |
| { |
| return(encrypt_keyid(&ki[1], keyid, len)); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| encrypt_dec_keyid(unsigned char *keyid, int len) |
| #else |
| encrypt_dec_keyid(keyid, len) unsigned char *keyid; int len; |
| #endif /* CK_ANSIC */ |
| { |
| return(encrypt_keyid(&ki[0], keyid, len)); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| encrypt_keyid(struct key_info *kp, unsigned char *keyid, int len) |
| #else |
| encrypt_keyid(kp, keyid, len) |
| struct key_info *kp; unsigned char *keyid; int len; |
| #endif |
| { |
| Encryptions *ep; |
| int dir = kp->dir; |
| register int ret = 0; |
| |
| if (!(ep = (*kp->getcrypt)(*kp->modep))) { |
| if (len == 0) |
| return(-1); |
| kp->keylen = 0; |
| } else if (len == 0 || len > MAXKEYLEN) { |
| /* |
| * Empty option or Key too long, indicates a failure. |
| */ |
| if (kp->keylen == 0) |
| return(-1); |
| kp->keylen = 0; |
| if (ep->keyid) |
| (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); |
| |
| } else if ((len != kp->keylen) || (memcmp(keyid, kp->keyid, len) != 0)) { |
| /* |
| * Length or contents are different |
| */ |
| kp->keylen = len; |
| memcpy(kp->keyid, keyid, len); /* length < MAXKEYLEN */ |
| if (ep->keyid) |
| (void)(*ep->keyid)(dir, kp->keyid, &kp->keylen); |
| } else { |
| if (ep->keyid) |
| ret = (*ep->keyid)(dir, kp->keyid, &kp->keylen); |
| if ((ret == 0) && (dir == DIR_ENCRYPT) && autoencrypt) |
| encrypt_start_output(*kp->modep); |
| return(0); |
| } |
| |
| encrypt_send_keyid(dir, kp->keyid, kp->keylen, 0); |
| return(0); |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| encrypt_send_keyid(int dir, unsigned char *keyid, int keylen, int saveit) |
| #else |
| encrypt_send_keyid(dir, keyid, keylen, saveit) |
| int dir; unsigned char *keyid; int keylen; int saveit; |
| #endif |
| { |
| unsigned char *strp; |
| |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) |
| return(0); |
| #endif /* CK_SSL */ |
| |
| str_keyid[3] = (dir == DIR_ENCRYPT) |
| ? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID; |
| if (saveit && keylen <= MAXKEYLEN) { |
| struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1]; |
| memcpy(kp->keyid, keyid, keylen); |
| kp->keylen = keylen; |
| } |
| |
| for (strp = &str_keyid[4]; keylen > 0; --keylen) { |
| if ((*strp++ = *keyid++) == IAC) |
| *strp++ = IAC; |
| } |
| *strp++ = IAC; |
| *strp++ = SE; |
| |
| if (deblog || tn_deb || debses) { |
| int i; |
| sprintf(tn_msg,"TELNET SENT SB %s %s ", |
| TELOPT(TELOPT_ENCRYPTION), |
| (dir == DIR_ENCRYPT) ? "ENC-KEYID" : "DEC-KEYID"); /* safe */ |
| tn_hex(tn_msg,TN_MSG_LEN,&str_keyid[4],strp-str_keyid-2-4); |
| ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); |
| debug(F100,tn_msg,"",0); |
| if (tn_deb || debses) tn_debug(tn_msg); |
| } |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| ttol(str_keyid, strp - str_keyid); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| return(0); |
| } |
| |
| VOID |
| #ifdef CK_ANSIC |
| encrypt_auto(int on) |
| #else |
| encrypt_auto(on) int on; |
| #endif |
| { |
| if (on < 0) |
| autoencrypt ^= 1; |
| else |
| autoencrypt = on ? 1 : 0; |
| } |
| |
| VOID |
| #ifdef CK_ANSIC |
| decrypt_auto(int on) |
| #else |
| decrypt_auto(on) int on; |
| #endif |
| { |
| if (on < 0) |
| autodecrypt ^= 1; |
| else |
| autodecrypt = on ? 1 : 0; |
| } |
| |
| VOID |
| #ifdef CK_ANSIC |
| encrypt_start_output(int type) |
| #else |
| encrypt_start_output(type) int type; |
| #endif |
| { |
| Encryptions *ep; |
| register unsigned char *p; |
| register int i; |
| |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) |
| return; |
| #endif /* CK_SSL */ |
| |
| if (!(ep = findencryption(type))) { |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>Can't encrypt with type %s (%d)\n", |
| ENCTYPE_NAME_OK(type) |
| ? ENCTYPE_NAME(type) : "(unknown)", |
| type); /* safe */ |
| debug(F110,"encrypt_start_output",dbgbuf,0); |
| } |
| #endif |
| return; |
| } |
| if (ep->start) { |
| i = (*ep->start)(DIR_ENCRYPT, 0); |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>Encrypt start: %s (%d) %s\n", |
| (i < 0) ? "failed" : |
| "initial negotiation in progress", |
| i, ENCTYPE_NAME(type)); /* safe */ |
| debug(F110,"encrypt_start_output",dbgbuf,0); |
| } |
| #endif |
| if (i) |
| return; |
| } |
| |
| if ( encrypt_output != ep->output ) { |
| p = str_start; |
| *p++ = IAC; |
| *p++ = SB; |
| *p++ = TELOPT_ENCRYPTION; |
| *p++ = ENCRYPT_START; |
| for (i = 0; i < ki[0].keylen; ++i) { |
| if (( *p++ = ki[0].keyid[i]) == IAC) |
| *p++ = IAC; |
| } |
| *p++ = IAC; |
| *p++ = SE; |
| |
| if (deblog || tn_deb || debses) { |
| int i; |
| sprintf(tn_msg,"TELNET SENT SB %s START ", |
| TELOPT(TELOPT_ENCRYPTION)); /* safe */ |
| tn_hex(tn_msg,TN_MSG_LEN,&str_start[4],p-str_start-2-4); |
| ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); |
| debug(F100,tn_msg,"",0); |
| if (tn_deb || debses) tn_debug(tn_msg); |
| } |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| ttol(str_start, p - str_start); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| |
| /* |
| * If we are already encrypting in some mode, then |
| * encrypt the ring (which includes our request) in |
| * the old mode, mark it all as "clear text" and then |
| * switch to the new mode. |
| */ |
| encrypt_output = ep->output; |
| EncryptKSGlobalHack->encrypt = encrypt_ks_stream; |
| EncryptKSGlobalHack->encrypt_type = type; |
| encrypt_mode = type; |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>Started to encrypt output with type %s", |
| ENCTYPE_NAME(type)); /* safe */ |
| debug(F110,"encrypt_start_output",dbgbuf,0); |
| } |
| #endif |
| if (encrypt_verbose) { |
| sprintf(dbgbuf, "Output is now encrypted with type %s", |
| ENCTYPE_NAME(type)); /* safe */ |
| debug(F110,"encrypt_start_output",dbgbuf,0); |
| printf("%s\n",dbgbuf); |
| } |
| } |
| } |
| |
| VOID |
| #ifdef CK_ANSIC |
| encrypt_send_end(VOID) |
| #else |
| encrypt_send_end() |
| #endif |
| { |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) |
| return; |
| #endif /* CK_SSL */ |
| |
| if (!encrypt_output) |
| return; |
| |
| str_end[0] = IAC; |
| str_end[1] = SB; |
| str_end[2] = TELOPT_ENCRYPTION; |
| str_end[3] = ENCRYPT_END; |
| str_end[4] = IAC; |
| str_end[5] = SE; |
| |
| if (deblog || tn_deb || debses) { |
| int i; |
| sprintf(tn_msg,"TELNET SENT SB %s END IAC SE", |
| TELOPT(TELOPT_ENCRYPTION)); /* safe */ |
| debug(F100,tn_msg,"",0); |
| if (tn_deb || debses) tn_debug(tn_msg); |
| } |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| ttol(str_end, sizeof(str_end)); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| |
| encrypt_output = 0; |
| EncryptKSGlobalHack->encrypt = NULL; |
| EncryptKSGlobalHack->encrypt_type = ENCTYPE_ANY; |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>Output is back to clear text"); /* safe */ |
| debug(F110,"encrypt_send_end",dbgbuf,0); |
| } |
| #endif |
| if (encrypt_verbose) { |
| sprintf(dbgbuf, "Output is now clear text"); /* safe */ |
| debug(F110,"encrypt_send_end",dbgbuf,0); |
| printf("%s\n",dbgbuf); |
| } |
| } |
| |
| VOID |
| #ifdef CK_ANSIC |
| encrypt_send_request_start(VOID) |
| #else |
| encrypt_send_request_start() |
| #endif |
| { |
| register unsigned char *p; |
| register int i; |
| |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) |
| return; |
| #endif /* CK_SSL */ |
| |
| p = str_start; |
| *p++ = IAC; |
| *p++ = SB; |
| *p++ = TELOPT_ENCRYPTION; |
| *p++ = ENCRYPT_REQSTART; |
| for (i = 0; i < ki[1].keylen; ++i) { |
| if (( *p++ = ki[1].keyid[i]) == IAC) |
| *p++ = IAC; |
| } |
| *p++ = IAC; |
| *p++ = SE; |
| |
| if (deblog || tn_deb || debses) { |
| int i; |
| sprintf(tn_msg,"TELNET SENT SB %s REQUEST-START ", |
| TELOPT(TELOPT_ENCRYPTION)); /* safe */ |
| tn_hex(tn_msg,TN_MSG_LEN,&str_start[4],p-str_start-2-4); |
| ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); |
| debug(F100,tn_msg,"",0); |
| if (tn_deb || debses) tn_debug(tn_msg); |
| } |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| ttol(str_start, p - str_start); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>Request input to be encrypted\n"); /* safe */ |
| debug(F110,"encrypt_send_request_start",dbgbuf,0); |
| } |
| } |
| |
| VOID |
| #ifdef CK_ANSIC |
| encrypt_send_request_end(VOID) |
| #else |
| encrypt_send_request_end() |
| #endif |
| { |
| #ifdef CK_SSL |
| if (TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) |
| return; |
| #endif /* CK_SSL */ |
| |
| str_end[0] = IAC; |
| str_end[1] = SB; |
| str_end[2] = TELOPT_ENCRYPTION; |
| str_end[3] = ENCRYPT_REQEND; |
| str_end[4] = IAC; |
| str_end[5] = SE; |
| |
| if (deblog || tn_deb || debses) { |
| int i; |
| sprintf(tn_msg,"TELNET SENT SB %s REQEND IAC SE", |
| TELOPT(TELOPT_ENCRYPTION)); /* safe */ |
| debug(F100,tn_msg,"",0); |
| if (tn_deb || debses) tn_debug(tn_msg); |
| } |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| ttol(str_end, sizeof(str_end)); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| |
| if (encrypt_debug_mode) { |
| sprintf(dbgbuf, ">>>Request input to be clear text\n"); /* safe */ |
| debug(F110,"encrypt_send_request_end",dbgbuf,0); |
| } |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| encrypt_is_encrypting(VOID) |
| #else |
| encrypt_is_encrypting() |
| #endif |
| { |
| if (encrypt_output) |
| return 1; |
| return 0; |
| } |
| |
| int |
| #ifdef CK_ANSIC |
| encrypt_is_decrypting(VOID) |
| #else |
| encrypt_is_decrypting() |
| #endif |
| { |
| if (decrypt_input) |
| return 1; |
| return 0; |
| } |
| |
| #ifdef DEBUG |
| void |
| encrypt_debug(mode) |
| int mode; |
| { |
| encrypt_debug_mode = mode; |
| } |
| #endif |
| |
| #ifdef CK_DES |
| /*- |
| * Copyright (c) 1991, 1993 |
| * The Regents of the University of California. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. All advertising materials mentioning features or use of this software |
| * must display the following acknowledgement: |
| * This product includes software developed by the University of |
| * California, Berkeley and its contributors. |
| * 4. Neither the name of the University nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| */ |
| |
| /* based on @(#)enc_des.c 8.1 (Berkeley) 6/4/93 */ |
| |
| #define CFB 0 |
| #define OFB 1 |
| |
| #define NO_SEND_IV 1 |
| #define NO_RECV_IV 2 |
| #define NO_KEYID 4 |
| #define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID) |
| #define SUCCESS 0 |
| #define xFAILED -1 |
| |
| Schedule test_sched; |
| |
| struct des_stinfo { |
| Block str_output; |
| Block str_feed; |
| Block str_iv; |
| Block str_ikey; |
| #ifdef MIT_CURRENT |
| unsigned char str_keybytes[8]; |
| krb5_keyblock str_key; |
| #else /* MIT_CURRENT */ |
| Schedule str_sched; |
| int str_index; |
| #endif /* MIT_CURRENT */ |
| int str_flagshift; |
| }; |
| |
| struct des_fb { |
| #ifndef MIT_CURRENT |
| Block krbdes_key; |
| Schedule krbdes_sched; |
| #endif /* MIT_CURRENT */ |
| Block temp_feed; |
| unsigned char fb_feed[64]; |
| int need_start; |
| int state[2]; |
| int keyid[2]; |
| int once; |
| #ifdef MIT_CURRENT |
| int validkey; |
| #endif /* MIT_CURRENT */ |
| struct des_stinfo streams[2]; |
| }; |
| static struct des_fb des_fb[2]; |
| |
| struct des3_stinfo { |
| Block str_output; |
| Block str_feed; |
| Block str_iv; |
| Block str_ikey[3]; |
| Schedule str_sched[3]; |
| int str_index; |
| int str_flagshift; |
| }; |
| |
| struct des3_fb { |
| #ifndef MIT_CURRENT |
| Block krbdes_key[3]; |
| Schedule krbdes_sched[3]; |
| #endif /* MIT_CURRENT */ |
| Block temp_feed; |
| unsigned char fb_feed[64]; |
| int need_start; |
| int state[2]; |
| int keyid[2]; |
| int once; |
| #ifdef MIT_CURRENT |
| int validkey; |
| #endif /* MIT_CURRENT */ |
| struct des3_stinfo streams[2]; |
| }; |
| static struct des3_fb des3_fb[2]; |
| |
| struct keyidlist { |
| char *keyid; |
| int keyidlen; |
| char *key; |
| int keylen; |
| int flags; |
| } keyidlist [] = { |
| { "\0", 1, 0, 0, 0 }, /* default key of zero */ |
| { 0, 0, 0, 0, 0 } |
| }; |
| |
| #define KEYFLAG_MASK 03 |
| |
| #define KEYFLAG_NOINIT 00 |
| #define KEYFLAG_INIT 01 |
| #define KEYFLAG_OK 02 |
| #define KEYFLAG_BAD 03 |
| |
| #define KEYFLAG_SHIFT 2 |
| |
| #define SHIFT_VAL(a,b) (KEYFLAG_SHIFT*((a)+((b)*2))) |
| |
| #define FB64_IV 1 |
| #define FB64_IV_OK 2 |
| #define FB64_IV_BAD 3 |
| #define FB64_CHALLENGE 4 |
| #define FB64_RESPONSE 5 |
| |
| void fb64_stream_iv P((Block, struct des_stinfo *)); |
| void fb64_init P((struct des_fb *)); |
| static int fb64_start P((struct des_fb *, int, int)); |
| int fb64_is P((unsigned char *, int, struct des_fb *)); |
| int fb64_reply P((unsigned char *, int, struct des_fb *)); |
| static int fb64_session P((Session_Key *, int, struct des_fb *)); |
| void fb64_stream_key P((Block, struct des_stinfo *)); |
| int fb64_keyid P((int, unsigned char *, int *, struct des_fb *)); |
| |
| #ifdef MIT_CURRENT |
| static void |
| #ifdef CK_ANSIC |
| ecb_encrypt(struct des_stinfo *stp, Block in, Block out) |
| #else /* CKANSIC */ |
| ecb_encrypt(stp, in, out) |
| struct des_stinfo *stp; |
| Block in; |
| Block out; |
| #endif /* CK_ANSIC */ |
| { |
| krb5_error_code code; |
| krb5_data din; |
| krb5_enc_data dout; |
| |
| din.length = 8; |
| din.data = in; |
| |
| dout.ciphertext.length = 8; |
| dout.ciphertext.data = out; |
| dout.enctype = ENCTYPE_UNKNOWN; |
| |
| #ifdef CRYPT_DLL |
| code = krb5_c_encrypt(*p_k5_context, &stp->str_key, 0, 0, |
| &din, &dout); |
| #else /* CRYPT_DLL */ |
| code = krb5_c_encrypt(k5_context, &stp->str_key, 0, 0, |
| &din, &dout); |
| #endif /* CRYPT_DLL */ |
| /* XXX I'm not sure what to do if this fails */ |
| if (code) |
| com_err("libtelnet", code, "encrypting stream data"); |
| } |
| #endif /* MIT_CURRENT */ |
| |
| void |
| cfb64_init(server) |
| int server; |
| { |
| fb64_init(&des_fb[CFB]); |
| des_fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64; |
| des_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB); |
| des_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB); |
| } |
| |
| void |
| ofb64_init(server) |
| int server; |
| { |
| fb64_init(&des_fb[OFB]); |
| des_fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64; |
| des_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB); |
| des_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB); |
| } |
| |
| void |
| fb64_init(fbp) |
| register struct des_fb *fbp; |
| { |
| memset((void *)fbp, 0, sizeof(*fbp)); |
| fbp->state[0] = fbp->state[1] = xFAILED; |
| fbp->fb_feed[0] = IAC; |
| fbp->fb_feed[1] = SB; |
| fbp->fb_feed[2] = TELOPT_ENCRYPTION; |
| fbp->fb_feed[3] = ENCRYPT_IS; |
| } |
| |
| /* |
| * Returns: |
| * -1: some error. Negotiation is done, encryption not ready. |
| * 0: Successful, initial negotiation all done. |
| * 1: successful, negotiation not done yet. |
| * 2: Not yet. Other things (like getting the key from |
| * Kerberos) have to happen before we can continue. |
| */ |
| int |
| cfb64_start(dir, server) |
| int dir; |
| int server; |
| { |
| return(fb64_start(&des_fb[CFB], dir, server)); |
| } |
| int |
| ofb64_start(dir, server) |
| int dir; |
| int server; |
| { |
| return(fb64_start(&des_fb[OFB], dir, server)); |
| } |
| |
| static int |
| fb64_start(fbp, dir, server) |
| struct des_fb *fbp; |
| int dir; |
| int server; |
| { |
| int x; |
| unsigned char *p; |
| register int state; |
| |
| switch (dir) { |
| case DIR_DECRYPT: |
| /* |
| * This is simply a request to have the other side |
| * start output (our input). He will negotiate an |
| * IV so we need not look for it. |
| */ |
| state = fbp->state[dir-1]; |
| if (state == xFAILED) |
| state = IN_PROGRESS; |
| break; |
| |
| case DIR_ENCRYPT: |
| state = fbp->state[dir-1]; |
| if (state == xFAILED) |
| state = IN_PROGRESS; |
| else if ((state & NO_SEND_IV) == 0) |
| break; |
| |
| #ifdef MIT_CURRENT |
| if (!fbp->validkey) { |
| fbp->need_start = 1; |
| break; |
| } |
| #else /* MIT_CURRENT */ |
| if (!VALIDKEY(fbp->krbdes_key)) { |
| fbp->need_start = 1; |
| break; |
| } |
| #endif /* MIT_CURRENT */ |
| state &= ~NO_SEND_IV; |
| state |= NO_RECV_IV; |
| /* |
| * Create a random feed and send it over. |
| */ |
| #ifdef MIT_CURRENT |
| { |
| krb5_data d; |
| krb5_error_code code; |
| |
| d.data = fbp->temp_feed; |
| d.length = sizeof(fbp->temp_feed); |
| |
| #ifdef CRYPT_DLL |
| if (code = krb5_c_random_make_octets(*p_k5_context,&d)) |
| return(xFAILED); |
| #else /* CRYPT_DLL */ |
| if (code = krb5_c_random_make_octets(k5_context,&d)) |
| return(xFAILED); |
| #endif /* CRYPT_DLL */ |
| } |
| |
| #else /* MIT_CURRENT */ |
| des_new_random_key(fbp->temp_feed); |
| des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, |
| fbp->krbdes_sched, 1); |
| #endif /* MIT_CURRENT */ |
| p = fbp->fb_feed + 3; |
| *p++ = ENCRYPT_IS; |
| p++; |
| *p++ = FB64_IV; |
| for (x = 0; x < sizeof(Block); ++x) { |
| if (( *p++ = fbp->temp_feed[x]) == IAC) |
| *p++ = IAC; |
| } |
| *p++ = IAC; |
| *p++ = SE; |
| |
| if (deblog || tn_deb || debses) { |
| int i; |
| sprintf(tn_msg, |
| "TELNET SENT SB %s IS %s FB64_IV ", |
| TELOPT(fbp->fb_feed[2]), |
| enctype_names[fbp->fb_feed[4]]); /* safe */ |
| tn_hex(tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],(p-fbp->fb_feed)-2-6); |
| ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); |
| debug(F100,tn_msg,"",0); |
| if (tn_deb || debses) tn_debug(tn_msg); |
| } |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| ttol(fbp->fb_feed, p - fbp->fb_feed); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| break; |
| default: |
| return(xFAILED); |
| } |
| return(fbp->state[dir-1] = state); |
| } |
| |
| /* |
| * Returns: |
| * -1: some error. Negotiation is done, encryption not ready. |
| * 0: Successful, initial negotiation all done. |
| * 1: successful, negotiation not done yet. |
| */ |
| int |
| cfb64_is(data, cnt) |
| unsigned char *data; |
| int cnt; |
| { |
| return(fb64_is(data, cnt, &des_fb[CFB])); |
| } |
| |
| int |
| ofb64_is(data, cnt) |
| unsigned char *data; |
| int cnt; |
| { |
| return(fb64_is(data, cnt, &des_fb[OFB])); |
| } |
| |
| int |
| fb64_is(data, cnt, fbp) |
| unsigned char *data; |
| int cnt; |
| struct des_fb *fbp; |
| { |
| unsigned char *p; |
| register int state = fbp->state[DIR_DECRYPT-1]; |
| |
| if (cnt-- < 1) |
| goto failure; |
| |
| #ifdef CK_SSL |
| if (!TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) |
| #endif /* CK_SSL */ |
| switch (*data++) { |
| case FB64_IV: |
| if (cnt != sizeof(Block)) { |
| #ifdef DEBUG |
| if (encrypt_debug_mode) |
| printf("CFB64: initial vector failed on size\r\n"); |
| #endif |
| state = xFAILED; |
| goto failure; |
| } |
| |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| printf("CFB64: initial vector received\r\n"); |
| printf("Initializing Decrypt stream\r\n"); |
| } |
| #endif |
| fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]); |
| |
| p = fbp->fb_feed + 3; |
| *p++ = ENCRYPT_REPLY; |
| p++; |
| *p++ = FB64_IV_OK; |
| *p++ = IAC; |
| *p++ = SE; |
| |
| if (deblog || tn_deb || debses) { |
| int i; |
| sprintf(tn_msg, |
| "TELNET SENT SB %s REPLY %s FB64_IV_OK ", |
| TELOPT(fbp->fb_feed[2]), |
| enctype_names[fbp->fb_feed[4]]); /* safe */ |
| tn_hex(tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],(p-fbp->fb_feed)-2-6); |
| ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); |
| debug(F100,tn_msg,"",0); |
| if (tn_deb || debses) tn_debug(tn_msg); |
| } |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| ttol(fbp->fb_feed, p - fbp->fb_feed); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| state = IN_PROGRESS; |
| break; |
| |
| default: |
| #if 0 |
| if (encrypt_debug_mode) { |
| printf("Unknown option type: %d\r\n", *(data-1)); |
| printf("\r\n"); |
| } |
| #endif |
| /* FALL THROUGH */ |
| failure: |
| /* |
| * We failed. Send an FB64_IV_BAD option |
| * to the other side so it will know that |
| * things failed. |
| */ |
| p = fbp->fb_feed + 3; |
| *p++ = ENCRYPT_REPLY; |
| p++; |
| *p++ = FB64_IV_BAD; |
| *p++ = IAC; |
| *p++ = SE; |
| |
| if (deblog || tn_deb || debses) { |
| int i; |
| sprintf(tn_msg, |
| "TELNET SENT SB %s REPLY %s FB64_IV_BAD ", |
| TELOPT(fbp->fb_feed[2]), |
| enctype_names[fbp->fb_feed[4]]); /* safe */ |
| tn_hex(tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],(p-fbp->fb_feed)-2-6); |
| ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); |
| debug(F100,tn_msg,"",0); |
| if (tn_deb || debses) tn_debug(tn_msg); |
| } |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| ttol(fbp->fb_feed, p - fbp->fb_feed); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| break; |
| } |
| return(fbp->state[DIR_DECRYPT-1] = state); |
| } |
| |
| /* |
| * Returns: |
| * -1: some error. Negotiation is done, encryption not ready. |
| * 0: Successful, initial negotiation all done. |
| * 1: successful, negotiation not done yet. |
| */ |
| int |
| cfb64_reply(data, cnt) |
| unsigned char *data; |
| int cnt; |
| { |
| return(fb64_reply(data, cnt, &des_fb[CFB])); |
| } |
| int |
| ofb64_reply(data, cnt) |
| unsigned char *data; |
| int cnt; |
| { |
| return(fb64_reply(data, cnt, &des_fb[OFB])); |
| } |
| |
| |
| int |
| fb64_reply(data, cnt, fbp) |
| unsigned char *data; |
| int cnt; |
| struct des_fb *fbp; |
| { |
| register int state = fbp->state[DIR_ENCRYPT-1]; |
| |
| if (cnt-- < 1) |
| goto failure; |
| |
| switch (*data++) { |
| case FB64_IV_OK: |
| fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); |
| if (state == xFAILED) |
| state = IN_PROGRESS; |
| state &= ~NO_RECV_IV; |
| encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1); |
| break; |
| |
| case FB64_IV_BAD: |
| memset(fbp->temp_feed, 0, sizeof(Block)); |
| fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); |
| state = xFAILED; |
| break; |
| |
| default: |
| #if 0 |
| if (encrypt_debug_mode) { |
| printf("Unknown option type: %d\r\n", data[-1]); |
| printf("\r\n"); |
| } |
| #endif |
| /* FALL THROUGH */ |
| failure: |
| state = xFAILED; |
| break; |
| } |
| return(fbp->state[DIR_ENCRYPT-1] = state); |
| } |
| |
| int |
| cfb64_session(key, server) |
| Session_Key *key; |
| int server; |
| { |
| return(fb64_session(key, server, &des_fb[CFB])); |
| } |
| |
| int |
| ofb64_session(key, server) |
| Session_Key *key; |
| int server; |
| { |
| return(fb64_session(key, server, &des_fb[OFB])); |
| } |
| |
| static int |
| fb64_session(key, server, fbp) |
| Session_Key *key; |
| int server; |
| struct des_fb *fbp; |
| { |
| int rc=0; |
| int use2keys; |
| struct des_stinfo * s_stream; |
| struct des_stinfo * c_stream; |
| |
| if(server) { |
| s_stream = &fbp->streams[DIR_ENCRYPT-1]; |
| c_stream = &fbp->streams[DIR_DECRYPT-1]; |
| } |
| else { |
| s_stream = &fbp->streams[DIR_DECRYPT-1]; |
| c_stream = &fbp->streams[DIR_ENCRYPT-1]; |
| } |
| |
| if (!key || key->length < sizeof(Block)) { |
| CHAR buf[80]; |
| sprintf(buf,"Can't set DES session key (%d < %d)", |
| key ? key->length : 0, sizeof(Block)); /* safe */ |
| #ifdef DEBUG |
| if (encrypt_debug_mode) |
| printf("%s\r\n",buf); |
| #endif |
| debug(F110,"fb64_session",buf,0); |
| return(-1); |
| } |
| use2keys = (key->type == SK_DES || |
| key->length < 2 * sizeof(Block)) ? 0 : 1; |
| #ifdef MIT_CURRENT |
| if(use2keys) { |
| memcpy((void *) fbp->keybytes, |
| (void *) (key->data + sizeof(Block)), sizeof(Block)); |
| des_fixup_key_parity(fbp->); |
| fb64_stream_key(fbp->krbdes_key, s_stream); |
| } |
| |
| memcpy((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block)); |
| if (key->type != SK_DES) |
| des_fixup_key_parity(fbp->krbdes_key); |
| |
| if(!use2keys) |
| fb64_stream_key(fbp->krbdes_key, s_stream); |
| fb64_stream_key(fbp->krbdes_key, c_stream); |
| fbp->validkey = 1; |
| |
| fb64_stream_key(key->data, &fbp->streams[DIR_ENCRYPT-1]); |
| fb64_stream_key(key->data, &fbp->streams[DIR_DECRYPT-1]); |
| #else /* MIT_CURRENT */ |
| if(use2keys) { |
| memcpy((void *) fbp->krbdes_key, |
| (void *) (key->data + sizeof(Block)), sizeof(Block)); |
| des_fixup_key_parity(fbp->krbdes_key); |
| fb64_stream_key(fbp->krbdes_key, s_stream); |
| } |
| |
| memcpy((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block)); |
| if (key->type != SK_DES) |
| des_fixup_key_parity(fbp->krbdes_key); |
| |
| if(!use2keys) |
| fb64_stream_key(fbp->krbdes_key, s_stream); |
| fb64_stream_key(fbp->krbdes_key, c_stream); |
| |
| if (fbp->once == 0) { |
| des_set_random_generator_seed(fbp->krbdes_key); |
| fbp->once = 1; |
| } |
| |
| memset(fbp->krbdes_sched,0,sizeof(Schedule)); |
| hexdump("fb64_session_key",fbp->krbdes_key,8); |
| |
| rc = des_key_sched(fbp->krbdes_key, fbp->krbdes_sched); |
| if ( rc == -1 ) { |
| printf("?Invalid DES key specified for encryption\n"); |
| debug(F110,"fb64_session_key", |
| "invalid DES Key specified for encryption",0); |
| } else if ( rc == -2 ) { |
| printf("?Weak DES key specified for encryption\n"); |
| debug(F110,"fb64_session_key", |
| "weak DES Key specified for encryption",0); |
| } else if ( rc != 0 ) { |
| printf("?Key Schedule not created by encryption\n"); |
| debug(F110,"fb64_session_key", |
| "Key Schedule not created by encryption",0); |
| } |
| |
| hexdump("fb64_session_key schedule",fbp->krbdes_sched,8*16); |
| #endif /* MIT_CURRENT */ |
| /* |
| * Now look to see if krbdes_start() was was waiting for |
| * the key to show up. If so, go ahead an call it now |
| * that we have the key. |
| */ |
| if (fbp->need_start) { |
| fbp->need_start = 0; |
| fb64_start(fbp, DIR_ENCRYPT, server); |
| } |
| return(0); |
| } |
| |
| /* |
| * We only accept a keyid of 0. If we get a keyid of |
| * 0, then mark the state as SUCCESS. |
| */ |
| int |
| cfb64_keyid(dir, kp, lenp) |
| int dir, *lenp; |
| unsigned char *kp; |
| { |
| return(fb64_keyid(dir, kp, lenp, &des_fb[CFB])); |
| } |
| |
| int |
| ofb64_keyid(dir, kp, lenp) |
| int dir, *lenp; |
| unsigned char *kp; |
| { |
| return(fb64_keyid(dir, kp, lenp, &des_fb[OFB])); |
| } |
| |
| int |
| fb64_keyid(dir, kp, lenp, fbp) |
| int dir, *lenp; |
| unsigned char *kp; |
| struct des_fb *fbp; |
| { |
| register int state = fbp->state[dir-1]; |
| |
| if (*lenp != 1 || (*kp != '\0')) { |
| *lenp = 0; |
| return(state); |
| } |
| |
| if (state == xFAILED) |
| state = IN_PROGRESS; |
| |
| state &= ~NO_KEYID; |
| |
| return(fbp->state[dir-1] = state); |
| } |
| |
| #if 0 |
| void |
| fb64_printsub(data, cnt, buf, buflen, type) |
| unsigned char *data, *buf, *type; |
| int cnt, buflen; |
| { |
| char lbuf[64]; |
| register int i; |
| char *cp; |
| |
| buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ |
| buflen -= 1; |
| |
| switch(data[2]) { |
| case FB64_IV: |
| sprintf(lbuf, "%s_IV", type); |
| cp = lbuf; |
| goto common; |
| |
| case FB64_IV_OK: |
| sprintf(lbuf, "%s_IV_OK", type); |
| cp = lbuf; |
| goto common; |
| |
| case FB64_IV_BAD: |
| sprintf(lbuf, "%s_IV_BAD", type); |
| cp = lbuf; |
| goto common; |
| |
| case FB64_CHALLENGE: |
| sprintf(lbuf, "%s_CHALLENGE", type); |
| cp = lbuf; |
| goto common; |
| |
| case FB64_RESPONSE: |
| sprintf(lbuf, "%s_RESPONSE", type); |
| cp = lbuf; |
| goto common; |
| |
| default: |
| sprintf(lbuf, " %d (unknown)", data[2]); |
| cp = lbuf; |
| common: |
| for (; (buflen > 0) && (*buf = *cp++); buf++) |
| buflen--; |
| for (i = 3; i < cnt; i++) { |
| sprintf(lbuf, " %d", data[i]); |
| for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++) |
| buflen--; |
| } |
| break; |
| } |
| } |
| |
| void |
| cfb64_printsub(data, cnt, buf, buflen) |
| unsigned char *data, *buf; |
| int cnt, buflen; |
| { |
| fb64_printsub(data, cnt, buf, buflen, "CFB64"); |
| } |
| |
| void |
| ofb64_printsub(data, cnt, buf, buflen) |
| unsigned char *data, *buf; |
| int cnt, buflen; |
| { |
| fb64_printsub(data, cnt, buf, buflen, "OFB64"); |
| } |
| #endif |
| |
| void |
| fb64_stream_iv(seed, stp) |
| Block seed; |
| register struct des_stinfo *stp; |
| { |
| int rc=0; |
| |
| memcpy(stp->str_iv, seed, sizeof(Block)); |
| memcpy(stp->str_output, seed, sizeof(Block)); |
| |
| memset(stp->str_sched,0,sizeof(Schedule)); |
| |
| hexdump("fb64_stream_iv",stp->str_ikey,8); |
| |
| #ifndef MIT_CURRENT |
| rc = des_key_sched(stp->str_ikey, stp->str_sched); |
| if ( rc == -1 ) { |
| printf("?Invalid DES key specified for encryption\r\n"); |
| debug(F110,"fb64_stream_iv", |
| "invalid DES Key specified for encryption",0); |
| } else if ( rc == -2 ) { |
| printf("?Weak DES key specified for encryption\r\n"); |
| debug(F110,"fb64_stream_iv", |
| "weak DES Key specified for encryption",0); |
| } else if ( rc != 0 ) { |
| printf("?Key Schedule not created by encryption\r\n"); |
| debug(F110,"fb64_stream_iv", |
| "Key Schedule not created by encryption",0); |
| } |
| hexdump("fb64_stream_iv schedule",stp->str_sched,8*16); |
| #endif /* MIT_CURRENT */ |
| |
| stp->str_index = sizeof(Block); |
| } |
| |
| void |
| fb64_stream_key(key, stp) |
| Block key; |
| register struct des_stinfo *stp; |
| { |
| int rc = 0; |
| |
| #ifdef MIT_CURRENT |
| memcpy(stp->str_keybytes, key, sizeof(Block)); |
| stp->str_key.length = 8; |
| stp->str_key.contents = stp->str_keybytes; |
| /* the original version of this code uses des ecb mode, but |
| it only ever does one block at a time. cbc with a zero iv |
| is identical */ |
| stp->str_key.enctype = ENCTYPE_DES_CBC_RAW; |
| #else /* MIT_CURRENT */ |
| memcpy(stp->str_ikey, key, sizeof(Block)); |
| |
| memset(stp->str_sched,0,sizeof(Schedule)); |
| |
| hexdump("fb64_stream_key",key,8); |
| |
| rc = des_key_sched(key, stp->str_sched); |
| if ( rc == -1 ) { |
| printf("?Invalid DES key specified for encryption\r\n"); |
| debug(F110,"fb64_stream_key", |
| "invalid DES Key specified for encryption",0); |
| } else if ( rc == -2 ) { |
| printf("?Weak DES key specified for encryption\r\n"); |
| debug(F110,"fb64_stream_key", |
| "weak DES Key specified for encryption",0); |
| } else if ( rc != 0 ) { |
| printf("?Key Schedule not created by encryption\r\n"); |
| debug(F110,"fb64_stream_key", |
| "Key Schedule not created by encryption",0); |
| } |
| hexdump("fb64_stream_key schedule",stp->str_sched,8*16); |
| #endif /* MIT_CURRENT */ |
| |
| memcpy(stp->str_output, stp->str_iv, sizeof(Block)); |
| |
| stp->str_index = sizeof(Block); |
| } |
| |
| /* |
| * DES 64 bit Cipher Feedback |
| * |
| * key --->+-----+ |
| * +->| DES |--+ |
| * | +-----+ | |
| * | v |
| * INPUT --(--------->(+)+---> DATA |
| * | | |
| * +-------------+ |
| * |
| * |
| * Given: |
| * iV: Initial vector, 64 bits (8 bytes) long. |
| * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). |
| * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. |
| * |
| * V0 = DES(iV, key) |
| * On = Dn ^ Vn |
| * V(n+1) = DES(On, key) |
| */ |
| |
| void |
| cfb64_encrypt(s, c) |
| register unsigned char *s; |
| int c; |
| { |
| register struct des_stinfo *stp = &des_fb[CFB].streams[DIR_ENCRYPT-1]; |
| register int index; |
| |
| index = stp->str_index; |
| while (c-- > 0) { |
| if (index == sizeof(Block)) { |
| Block b; |
| #ifdef MIT_CURRENT |
| ecb_encrypt(stp, stp->str_output, b); |
| #else /* MIT_CURRENT */ |
| des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1); |
| #endif /* MIT_CURRENT */ |
| memcpy(stp->str_feed,b,sizeof(Block)); |
| index = 0; |
| } |
| |
| /* On encryption, we store (feed ^ data) which is cypher */ |
| *s = stp->str_output[index] = (stp->str_feed[index] ^ *s); |
| s++; |
| index++; |
| } |
| stp->str_index = index; |
| } |
| |
| int |
| cfb64_decrypt(data) |
| int data; |
| { |
| register struct des_stinfo *stp = &des_fb[CFB].streams[DIR_DECRYPT-1]; |
| int index; |
| |
| if (data == -1) { |
| /* |
| * Back up one byte. It is assumed that we will |
| * never back up more than one byte. If we do, this |
| * may or may not work. |
| */ |
| if (stp->str_index) |
| --stp->str_index; |
| return(0); |
| } |
| |
| index = stp->str_index++; |
| if (index == sizeof(Block)) { |
| Block b; |
| #ifdef MIT_CURRENT |
| ecb_encrypt(stp, stp->str_output, b); |
| #else /* MIT_CURRENT */ |
| des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1); |
| #endif /* MIT_CURRENT */ |
| memcpy(stp->str_feed, b, sizeof(Block)); |
| stp->str_index = 1; /* Next time will be 1 */ |
| index = 0; /* But now use 0 */ |
| } |
| |
| /* On decryption we store (data) which is cypher. */ |
| stp->str_output[index] = data; |
| return(data ^ stp->str_feed[index]); |
| } |
| |
| /* |
| * DES 64 bit Output Feedback |
| * |
| * key --->+-----+ |
| * +->| DES |--+ |
| * | +-----+ | |
| * +-----------+ |
| * v |
| * INPUT -------->(+) ----> DATA |
| * |
| * Given: |
| * iV: Initial vector, 64 bits (8 bytes) long. |
| * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). |
| * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. |
| * |
| * V0 = DES(iV, key) |
| * V(n+1) = DES(Vn, key) |
| * On = Dn ^ Vn |
| */ |
| void |
| ofb64_encrypt(s, c) |
| register unsigned char *s; |
| int c; |
| { |
| register struct des_stinfo *stp = &des_fb[OFB].streams[DIR_ENCRYPT-1]; |
| register int index; |
| |
| index = stp->str_index; |
| while (c-- > 0) { |
| if (index == sizeof(Block)) { |
| Block b; |
| #ifdef MIT_CURRENT |
| ecb_encrypt(stp, stp->str_feed, b); |
| #else /* MIT_CURRENT */ |
| des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1); |
| #endif /* MIT_CURRENT */ |
| memcpy(stp->str_feed,b,sizeof(Block)); |
| index = 0; |
| } |
| *s++ ^= stp->str_feed[index]; |
| index++; |
| } |
| stp->str_index = index; |
| } |
| |
| int |
| ofb64_decrypt(data) |
| int data; |
| { |
| register struct des_stinfo *stp = &des_fb[OFB].streams[DIR_DECRYPT-1]; |
| int index; |
| |
| if (data == -1) { |
| /* |
| * Back up one byte. It is assumed that we will |
| * never back up more than one byte. If we do, this |
| * may or may not work. |
| */ |
| if (stp->str_index) |
| --stp->str_index; |
| return(0); |
| } |
| |
| index = stp->str_index++; |
| if (index == sizeof(Block)) { |
| Block b; |
| #ifdef MIT_CURRENT |
| ecb_encrypt(stp, stp->str_feed, b); |
| #else /* MIT_CURRENT */ |
| des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1); |
| #endif /* MIT_CURRENT */ |
| memcpy(stp->str_feed, b, sizeof(Block)); |
| stp->str_index = 1; /* Next time will be 1 */ |
| index = 0; /* But now use 0 */ |
| } |
| |
| return(data ^ stp->str_feed[index]); |
| } |
| |
| |
| void des3_fb64_stream_iv P((Block, struct des3_stinfo *)); |
| void des3_fb64_init P((struct des3_fb *)); |
| static int des3_fb64_start P((struct des3_fb *, int, int)); |
| int des3_fb64_is P((unsigned char *, int, struct des3_fb *)); |
| int des3_fb64_reply P((unsigned char *, int, struct des3_fb *)); |
| static int des3_fb64_session P((Session_Key *, int, struct des3_fb *)); |
| void des3_fb64_stream_key P((Block *, struct des3_stinfo *)); |
| int des3_fb64_keyid P((int, unsigned char *, int *, struct des3_fb *)); |
| |
| void |
| des3_cfb64_init(server) |
| int server; |
| { |
| des3_fb64_init(&des3_fb[CFB]); |
| des3_fb[CFB].fb_feed[4] = ENCTYPE_DES3_CFB64; |
| des3_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB); |
| des3_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB); |
| } |
| |
| void |
| des3_ofb64_init(server) |
| int server; |
| { |
| des3_fb64_init(&des3_fb[OFB]); |
| des3_fb[OFB].fb_feed[4] = ENCTYPE_DES3_OFB64; |
| des3_fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB); |
| des3_fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB); |
| } |
| |
| void |
| des3_fb64_init(fbp) |
| register struct des3_fb *fbp; |
| { |
| memset((void *)fbp, 0, sizeof(*fbp)); |
| fbp->state[0] = fbp->state[1] = xFAILED; |
| fbp->fb_feed[0] = IAC; |
| fbp->fb_feed[1] = SB; |
| fbp->fb_feed[2] = TELOPT_ENCRYPTION; |
| fbp->fb_feed[3] = ENCRYPT_IS; |
| } |
| |
| /* |
| * Returns: |
| * -1: some error. Negotiation is done, encryption not ready. |
| * 0: Successful, initial negotiation all done. |
| * 1: successful, negotiation not done yet. |
| * 2: Not yet. Other things (like getting the key from |
| * Kerberos) have to happen before we can continue. |
| */ |
| int |
| des3_cfb64_start(dir, server) |
| int dir; |
| int server; |
| { |
| return(des3_fb64_start(&des3_fb[CFB], dir, server)); |
| } |
| int |
| des3_ofb64_start(dir, server) |
| int dir; |
| int server; |
| { |
| return(des3_fb64_start(&des3_fb[OFB], dir, server)); |
| } |
| |
| static int |
| des3_fb64_start(fbp, dir, server) |
| struct des3_fb *fbp; |
| int dir; |
| int server; |
| { |
| int x; |
| unsigned char *p; |
| register int state; |
| |
| switch (dir) { |
| case DIR_DECRYPT: |
| /* |
| * This is simply a request to have the other side |
| * start output (our input). He will negotiate an |
| * IV so we need not look for it. |
| */ |
| state = fbp->state[dir-1]; |
| if (state == xFAILED) |
| state = IN_PROGRESS; |
| break; |
| |
| case DIR_ENCRYPT: |
| state = fbp->state[dir-1]; |
| if (state == xFAILED) |
| state = IN_PROGRESS; |
| else if ((state & NO_SEND_IV) == 0) |
| break; |
| |
| if (!VALIDKEY(fbp->krbdes_key[0]) || |
| !VALIDKEY(fbp->krbdes_key[1]) || |
| !VALIDKEY(fbp->krbdes_key[2]) ) { |
| fbp->need_start = 1; |
| break; |
| } |
| state &= ~NO_SEND_IV; |
| state |= NO_RECV_IV; |
| /* |
| * Create a random feed and send it over. |
| */ |
| des_new_random_key(fbp->temp_feed); |
| #ifdef LIBDES |
| des_ecb3_encrypt(fbp->temp_feed, fbp->temp_feed, |
| fbp->krbdes_sched[0], |
| fbp->krbdes_sched[1], |
| fbp->krbdes_sched[2], |
| 1); |
| #else /* LIBDES */ |
| des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, |
| fbp->krbdes_sched[0], 1); |
| des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, |
| fbp->krbdes_sched[1], 0); |
| des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, |
| fbp->krbdes_sched[2], 1); |
| #endif /* LIBDES */ |
| |
| p = fbp->fb_feed + 3; |
| *p++ = ENCRYPT_IS; |
| p++; |
| *p++ = FB64_IV; |
| for (x = 0; x < sizeof(Block); ++x) { |
| if (( *p++ = fbp->temp_feed[x]) == IAC) |
| *p++ = IAC; |
| } |
| *p++ = IAC; |
| *p++ = SE; |
| |
| if (deblog || tn_deb || debses) { |
| int i; |
| sprintf(tn_msg, |
| "TELNET SENT SB %s IS %s FB64_IV ", |
| TELOPT(fbp->fb_feed[2]), |
| enctype_names[fbp->fb_feed[4]]); /* safe */ |
| tn_hex(tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],(p-fbp->fb_feed)-2-6); |
| ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); |
| debug(F100,tn_msg,"",0); |
| if (tn_deb || debses) tn_debug(tn_msg); |
| } |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| ttol(fbp->fb_feed, p - fbp->fb_feed); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| break; |
| default: |
| return(xFAILED); |
| } |
| return(fbp->state[dir-1] = state); |
| } |
| |
| /* |
| * Returns: |
| * -1: some error. Negotiation is done, encryption not ready. |
| * 0: Successful, initial negotiation all done. |
| * 1: successful, negotiation not done yet. |
| */ |
| int |
| des3_cfb64_is(data, cnt) |
| unsigned char *data; |
| int cnt; |
| { |
| return(des3_fb64_is(data, cnt, &des3_fb[CFB])); |
| } |
| |
| int |
| des3_ofb64_is(data, cnt) |
| unsigned char *data; |
| int cnt; |
| { |
| return(des3_fb64_is(data, cnt, &des3_fb[OFB])); |
| } |
| |
| int |
| des3_fb64_is(data, cnt, fbp) |
| unsigned char *data; |
| int cnt; |
| struct des3_fb *fbp; |
| { |
| unsigned char *p; |
| register int state = fbp->state[DIR_DECRYPT-1]; |
| |
| if (cnt-- < 1) |
| goto failure; |
| |
| #ifdef CK_SSL |
| if (!TELOPT_SB(TELOPT_START_TLS).start_tls.me_follows) |
| #endif /* CK_SSL */ |
| switch (*data++) { |
| case FB64_IV: |
| if (cnt != sizeof(Block)) { |
| #ifdef DEBUG |
| if (encrypt_debug_mode) |
| printf("DES3_FB64: initial vector failed on size\r\n"); |
| #endif |
| state = xFAILED; |
| goto failure; |
| } |
| |
| #ifdef DEBUG |
| if (encrypt_debug_mode) { |
| printf("DES3_FB64: initial vector received\r\n"); |
| printf("Initializing Decrypt stream\r\n"); |
| } |
| #endif |
| des3_fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]); |
| |
| p = fbp->fb_feed + 3; |
| *p++ = ENCRYPT_REPLY; |
| p++; |
| *p++ = FB64_IV_OK; |
| *p++ = IAC; |
| *p++ = SE; |
| |
| if (deblog || tn_deb || debses) { |
| int i; |
| sprintf(tn_msg, |
| "TELNET SENT SB %s REPLY %s FB64_IV_OK ", |
| TELOPT(fbp->fb_feed[2]), |
| enctype_names[fbp->fb_feed[4]]); /* safe */ |
| tn_hex(tn_msg,TN_MSG_LEN,&fbp->fb_feed[6],(p-fbp->fb_feed)-2-6); |
| ckstrncat(tn_msg,"IAC SE",TN_MSG_LEN); |
| debug(F100,tn_msg,"",0); |
| if (tn_deb || debses) tn_debug(tn_msg); |
| } |
| #ifdef OS2 |
| RequestTelnetMutex( SEM_INDEFINITE_WAIT ); |
| #endif |
| ttol(fbp->fb_feed, p - fbp->fb_feed); |
| #ifdef OS2 |
| ReleaseTelnetMutex(); |
| #endif |
| state = IN_PROGRESS; |
| break; |
| |
| default: |
| #if 0 |
| if (encrypt_debug_mode) { |
| printf("Unknown option type: %d\r\n", *(data-1)); |
| printf("\r\n"); |
| } |
| #endif |
| /* FALL THROUGH */ |
| failure: |
| /* |
| * We failed. Send an FB64_IV_BAD option |
| * to the other side so it will know that |
| * things failed. |
| */ |
| p = fbp->fb_feed + 3; |
|