blob: c35afd09ba58c9d58b2091f7ed9e986cbe14fc7d [file] [log] [blame]
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;