char *ckcrpv = "Encryption Engine, 8.0.109, 13 Sept 2000"; /* C K _ C R P . C - Cryptography for C-Kermit" Copyright (C) 1998, 2001, Trustees of Columbia University in the City of New York. The C-Kermit software may not be, in whole or in part, licensed or sold for profit as a software product itself, nor may it be included in or distributed with commercial products or otherwise distributed by commercial concerns to their clients or customers without written permission of the Office of Kermit Development and Distribution, Columbia University. This copyright notice must not be removed, altered, or obscured. Author: Jeffrey E Altman (jaltman@columbia.edu). */ #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 */ #include "ckucmd.h" /* For struct keytab definition */ #include "ckuath.h" #include "ckuat2.h" #ifdef MIT_CURRENT #include #endif /* MIT_CURRENT */ #include #include #ifdef OS2 #include #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 CK_ENCRYPTION #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; 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 #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 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 /* * 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 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("Kerberos 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("Kerberos authentication error!\n%s\n",buf); encrypt_send_request_end(); return(-1); } 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); } ttol(str_keyid, strp - str_keyid); 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); } ttol(str_start, p - str_start); /* * 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); } ttol(str_end, sizeof(str_end)); 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); } ttol(str_start, p - str_start); 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); } ttol(str_end, sizeof(str_end)); 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); } ttol(fbp->fb_feed, p - fbp->fb_feed); 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); } ttol(fbp->fb_feed, p - fbp->fb_feed); 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); } ttol(fbp->fb_feed, p - fbp->fb_feed); 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_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_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); } ttol(fbp->fb_feed, p - fbp->fb_feed); 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); } ttol(fbp->fb_feed, p - fbp->fb_feed); 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); } ttol(fbp->fb_feed, p - fbp->fb_feed); 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 des3_cfb64_reply(data, cnt) unsigned char *data; int cnt; { return(des3_fb64_reply(data, cnt, &des3_fb[CFB])); } int des3_ofb64_reply(data, cnt) unsigned char *data; int cnt; { return(des3_fb64_reply(data, cnt, &des3_fb[OFB])); } int des3_fb64_reply(data, cnt, fbp) unsigned char *data; int cnt; struct des3_fb *fbp; { register int state = fbp->state[DIR_ENCRYPT-1]; if (cnt-- < 1) goto failure; switch (*data++) { case FB64_IV_OK: des3_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)); des3_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 des3_cfb64_session(key, server) Session_Key *key; int server; { return(des3_fb64_session(key, server, &des3_fb[CFB])); } int des3_ofb64_session(key, server) Session_Key *key; int server; { return(des3_fb64_session(key, server, &des3_fb[OFB])); } static int des3_fb64_session(key, server, fbp) Session_Key *key; int server; struct des3_fb *fbp; { int rc=0,i=0; int keys2use=0; struct des3_stinfo * s_stream; struct des3_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]; } keys2use = key->length / sizeof(Block); if (!key || (key->type == SK_DES) || (keys2use < 2)) { CHAR buf[80]; sprintf(buf,"Can't set 3DES session key (%d < %d)", key ? key->length : 0, 2 * sizeof(Block)); /* safe */ #ifdef DEBUG if (encrypt_debug_mode) printf("%s\r\n",buf); #endif debug(F110,"des3_fb64_session",buf,0); return(-1); } debug(F111,"des3_fb64_session","keys2use",keys2use); /* Compute the first set of keys / key order */ switch ( keys2use ) { case 2: memcpy((void *)fbp->krbdes_key[0], (void *)key->data, sizeof(Block)); memcpy((void *) fbp->krbdes_key[1],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block)); break; case 3: default: memcpy((void *)fbp->krbdes_key[0], (void *)key->data, sizeof(Block)); memcpy((void *) fbp->krbdes_key[1],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *) fbp->krbdes_key[2], (void *) (key->data + 2*sizeof(Block)), sizeof(Block)); break; } hexdump("des3_session_key key->data",key->data,sizeof(Block)); hexdump("des3_session_key fbp->krbdes_key[0]", fbp->krbdes_key[0], sizeof(Block) ); if (fbp->once == 0) { des_set_random_generator_seed(fbp->krbdes_key[0]); fbp->once = 1; } for ( i=0;i<3;i++ ) des_fixup_key_parity(fbp->krbdes_key[i]); des3_fb64_stream_key(fbp->krbdes_key, s_stream); /* Compute the second set of keys / key order */ switch ( keys2use ) { case 2: memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[1], (void *)key->data, sizeof(Block)); memcpy((void *) fbp->krbdes_key[2],(void *)(key->data + sizeof(Block)), sizeof(Block)); break; case 3: memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *) fbp->krbdes_key[1], (void *) (key->data + 2*sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block)); break; case 4: memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *) fbp->krbdes_key[1], (void *) (key->data + 3*sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[2], (void *)key->data, sizeof(Block)); break; case 5: memcpy((void *) fbp->krbdes_key[0],(void *)(key->data + sizeof(Block)), sizeof(Block)); memcpy((void *) fbp->krbdes_key[1], (void *) (key->data + 3*sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[2], (void *)(key->data + 4*sizeof(Block)), sizeof(Block)); break; case 6: memcpy((void *) fbp->krbdes_key[0], (void *) (key->data + 3*sizeof(Block)), sizeof(Block)); memcpy((void *)fbp->krbdes_key[1], (void *)(key->data + 4*sizeof(Block)), sizeof(Block)); memcpy((void *) fbp->krbdes_key[2], (void *) (key->data + 5 *sizeof(Block)), sizeof(Block)); break; } for ( i=0;i<3;i++ ) des_fixup_key_parity(fbp->krbdes_key[i]); des3_fb64_stream_key(fbp->krbdes_key, c_stream); /* now use the second set of keys to build the default Key Schedule */ /* which is used for generating the IV. */ for ( i=0;i<3;i++ ) { memset(fbp->krbdes_sched[i],0,sizeof(Schedule)); rc = des_key_sched(fbp->krbdes_key[i], fbp->krbdes_sched[i]); if ( rc == -1 ) { printf("?Invalid DES key specified for encryption [DES3,%s]\r\n", server?"server":"client"); debug(F110,"des3_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,"des3_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,"des3_fb64_stream_iv", "Key Schedule not created by encryption",0); } hexdump("des3_fb64_session_key schedule",fbp->krbdes_sched[i],8*16); } /* * 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; des3_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 des3_cfb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(des3_fb64_keyid(dir, kp, lenp, &des3_fb[CFB])); } int des3_ofb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(des3_fb64_keyid(dir, kp, lenp, &des3_fb[OFB])); } int des3_fb64_keyid(dir, kp, lenp, fbp) int dir, *lenp; unsigned char *kp; struct des3_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 des3_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 des3_cfb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { des3_fb64_printsub(data, cnt, buf, buflen, "CFB64"); } void des3_ofb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { des3_fb64_printsub(data, cnt, buf, buflen, "OFB64"); } #endif void des3_fb64_stream_iv(seed, stp) Block seed; register struct des3_stinfo *stp; { int rc=0, i = 0;; memcpy(stp->str_iv, seed, sizeof(Block)); memcpy(stp->str_output, seed, sizeof(Block)); for ( i=0;i<3;i++ ) { memset(stp->str_sched[i],0,sizeof(Schedule)); hexdump("des3_fb64_stream_iv",stp->str_ikey[i],8); rc = des_key_sched(stp->str_ikey[i], stp->str_sched[i]); if ( rc == -1 ) { printf("?Invalid DES key specified for encryption [DES3 iv]\r\n"); debug(F110,"des3_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,"des3_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,"des3_fb64_stream_iv", "Key Schedule not created by encryption",0); } hexdump("des3_fb64_stream_iv schedule",stp->str_sched[i],8*16); } stp->str_index = sizeof(Block); } void des3_fb64_stream_key(key, stp) Block * key; register struct des3_stinfo *stp; { int rc = 0, i = 0; for ( i=0;i<3;i++ ) { memcpy(stp->str_ikey[i], key[i], sizeof(Block)); memset(stp->str_sched[i],0,sizeof(Schedule)); hexdump("des3_fb64_stream_key",key[i],8); rc = des_key_sched(key[i], stp->str_sched[i]); if ( rc == -1 ) { printf("?Invalid DES key specified for encryption [DES3 key]\r\n"); debug(F110,"des3_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,"des3_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,"des3_fb64_stream_iv", "Key Schedule not created by encryption",0); } hexdump("des3_fb64_stream_key schedule",stp->str_sched[i],8*16); } memcpy(stp->str_output, stp->str_iv, sizeof(Block)); stp->str_index = sizeof(Block); } /* * DES3 64 bit Cipher Feedback * * key1 key2 key3 * | | | * v v v * +-------+ +-------+ +-------+ * +->| DES-e |->| DES-d |->| DES-e |-- + * | +-------+ +-------+ +-------+ | * | 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-e(DES-d(DES-e(iV, key1),key2),key3) * On = Dn ^ Vn * V(n+1) = DES-e(DES-d(DES-e(On, key1),key2),key3) */ void des3_cfb64_encrypt(s, c) register unsigned char *s; int c; { register struct des3_stinfo *stp = &des3_fb[CFB].streams[DIR_ENCRYPT-1]; register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; #ifdef LIBDES des_ecb3_encrypt(stp->str_output, b, stp->str_sched[0], stp->str_sched[1], stp->str_sched[2], 1); #else /* LIBDES */ des_ecb_encrypt(stp->str_output, b, stp->str_sched[0], 1); des_ecb_encrypt(stp->str_output, b, stp->str_sched[1], 0); des_ecb_encrypt(stp->str_output, b, stp->str_sched[2], 1); #endif /* LIBDES */ 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 des3_cfb64_decrypt(data) int data; { register struct des3_stinfo *stp = &des3_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 LIBDES des_ecb3_encrypt(stp->str_output, b, stp->str_sched[0], stp->str_sched[1], stp->str_sched[2], 1); #else /* LIBDES */ des_ecb_encrypt(stp->str_output, b, stp->str_sched[0], 1); des_ecb_encrypt(stp->str_output, b, stp->str_sched[1], 0); des_ecb_encrypt(stp->str_output, b, stp->str_sched[2], 1); #endif /* LIBDES */ 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]); } /* * DES3 64 bit Output Feedback * * * key1 key2 key3 * | | | * v v v * +-------+ +-------+ +-------+ * +->| DES-e |->| DES-d |->| DES-e |-- + * | +-------+ +-------+ +-------+ | * +------------------------------------+ * 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-e(DES-d(DES-e(iV, key1),key2),key3) * V(n+1) = DES-e(DES-d(DES-e(Vn, key1),key2),key3) * On = Dn ^ Vn */ void des3_ofb64_encrypt(s, c) register unsigned char *s; int c; { register struct des3_stinfo *stp = &des3_fb[OFB].streams[DIR_ENCRYPT-1]; register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; #ifdef LIBDES des_ecb3_encrypt(stp->str_feed, b, stp->str_sched[0], stp->str_sched[1], stp->str_sched[2], 1); #else /* LIBDES */ des_ecb_encrypt(stp->str_output, b, stp->str_sched[0], 1); des_ecb_encrypt(stp->str_output, b, stp->str_sched[1], 0); des_ecb_encrypt(stp->str_output, b, stp->str_sched[2], 1); #endif /* LIBDES */ memcpy(stp->str_feed,b,sizeof(Block)); index = 0; } *s++ ^= stp->str_feed[index]; index++; } stp->str_index = index; } int des3_ofb64_decrypt(data) int data; { register struct des3_stinfo *stp = &des3_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 LIBDES des_ecb3_encrypt(stp->str_feed, b, stp->str_sched[0], stp->str_sched[1], stp->str_sched[2], 1); #else /* LIBDES */ des_ecb_encrypt(stp->str_output, b, stp->str_sched[0], 1); des_ecb_encrypt(stp->str_output, b, stp->str_sched[1], 0); des_ecb_encrypt(stp->str_output, b, stp->str_sched[2], 1); #endif /* LIBDES */ 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]); } #endif /* CK_DES */ #ifdef CK_CAST /*- * 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. */ /* * Copyright (c) 1997 Stanford University * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notices and this permission notice appear in * all copies of the software and related documentation. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #ifdef __STDC__ #include #endif /* * cast.h * Author: Tom Wu * * Type and function declarations for CAST. */ #ifndef _CAST_H_ #define _CAST_H_ #ifndef P #ifdef __STDC__ #define P(x) x #else #define P(x) () #endif /* __STDC__ */ #endif /* P */ #ifndef LITTLE_ENDIAN #ifndef BIG_ENDIAN #ifndef WORDS_BIGENDIAN #define LITTLE_ENDIAN 1 #endif /* WORDS_BIGENDIAN */ #endif /* BIG_ENDIAN */ #endif /* LITTLE_ENDIAN */ typedef unsigned int uint32; /* Must be 32 bits */ typedef uint32 * uint32p; typedef unsigned char uint8; typedef uint8 * uint8p; typedef struct { struct CastSubkeyPair { uint32 Km; uint32 Kr; } K[16]; int ksize; } CastKeySched; /* * cast*_key_sched(schedule, key) * * Initializes the CAST key schedule "schedule" according to the given key. * The different setup routines accept different length keys: * * ck_cast5_40_key_sched: 40-bit/5-byte (12 round) keys * ck_cast5_64_key_sched: 64-bit/8-byte (12 round) keys * ck_cast5_80_key_sched: 80-bit/10-byte (12 round) keys * ck_cast128_key_sched: 128-bit/16-byte (16 round) keys */ extern void ck_cast5_40_key_sched P((CastKeySched *, uint8 *)); extern void ck_cast5_64_key_sched P((CastKeySched *, uint8 *)); extern void ck_cast5_80_key_sched P((CastKeySched *, uint8 *)); extern void ck_cast128_key_sched P((CastKeySched *, uint8 *)); /* * ck_cast_ecb_encrypt(output, input, schedule, mode) * ck_cast_ecb_crypt(data, schedule, mode) * * Encrypts the 64-bit "input" according to the CAST key schedule * "schedule" and places the result in "output". If "mode" is 0, * ck_cast_ecb_encrypt will encrypt, otherwise it will decrypt. * "Output" and "input" can point to the same memory, in which case * en/decryption will be performed in place. * * ck_cast_ecb_crypt accepts input in the form of an array of two * 32-bit words and performs encryption/decryption in place. */ extern void ck_cast_ecb_encrypt P((uint8 *, uint8 *, CastKeySched *, int)); extern void ck_cast_ecb_crypt P((uint32 *, CastKeySched *, int)); #endif /* CAST_H */ extern encrypt_debug_mode; #define CFB_40 0 #define OFB_40 1 #ifdef CAST_EXPORT_ENCRYPTION #define FB_CNT 2 #else #define CFB_128 2 #define OFB_128 3 #define FB_CNT 4 #endif #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 cFAILED -1 struct cast_fb { Block temp_feed; unsigned char fb_feed[64]; int key_isset; int need_start; int state[2]; struct cast_stinfo { Block str_output; Block str_feed; Block str_iv; CastKeySched str_sched; int str_index; } streams[2]; }; static struct cast_fb cast_fb[FB_CNT]; #define FB64_IV 1 #define FB64_IV_OK 2 #define FB64_IV_BAD 3 static void cast_fb64_stream_iv P((Block, struct cast_stinfo *)); static void cast_fb64_init P((struct cast_fb *)); static int cast_fb64_start P((struct cast_fb *, int, int)); static int cast_fb64_is P((unsigned char *, int, struct cast_fb *)); static int cast_fb64_reply P((unsigned char *, int, struct cast_fb *)); static int cast_fb64_session P((Session_Key *, int, struct cast_fb *, int)); static void cast_fb64_stream_key P((Block, struct cast_stinfo *, int)); static int cast_fb64_keyid P((int, unsigned char *, int *, struct cast_fb *)); static void _cast_cfb64_encrypt P((unsigned char *,int, struct cast_stinfo *)); static int _cast_cfb64_decrypt P((int, struct cast_stinfo *)); static void _cast_ofb64_encrypt P((unsigned char *,int, struct cast_stinfo *)); static int _cast_ofb64_decrypt P((int, struct cast_stinfo *)); #ifndef CAST_EXPORT_ENCRYPTION void cast_cfb64_init(server) int server; { cast_fb64_init(&cast_fb[CFB_128]); cast_fb[CFB_128].fb_feed[4] = ENCTYPE_CAST128_CFB64; } void cast_ofb64_init(server) int server; { cast_fb64_init(&cast_fb[OFB_128]); cast_fb[OFB_128].fb_feed[4] = ENCTYPE_CAST128_OFB64; } #endif void castexp_cfb64_init(server) int server; { cast_fb64_init(&cast_fb[CFB_40]); cast_fb[CFB_40].fb_feed[4] = ENCTYPE_CAST5_40_CFB64; } void castexp_ofb64_init(server) int server; { cast_fb64_init(&cast_fb[OFB_40]); cast_fb[OFB_40].fb_feed[4] = ENCTYPE_CAST5_40_OFB64; } static void cast_fb64_init(fbp) register struct cast_fb *fbp; { memset((void *)fbp, 0, sizeof(*fbp)); fbp->key_isset = 0; fbp->state[0] = fbp->state[1] = cFAILED; 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. */ #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_start(dir, server) int dir; int server; { return(cast_fb64_start(&cast_fb[CFB_128], dir, server)); } int cast_ofb64_start(dir, server) int dir; int server; { return(cast_fb64_start(&cast_fb[OFB_128], dir, server)); } #endif int castexp_cfb64_start(dir, server) int dir; int server; { return(cast_fb64_start(&cast_fb[CFB_40], dir, server)); } int castexp_ofb64_start(dir, server) int dir; int server; { return(cast_fb64_start(&cast_fb[OFB_40], dir, server)); } static int cast_fb64_start(fbp, dir, server) struct cast_fb *fbp; int dir; int server; { Block b; 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 == cFAILED) state = IN_PROGRESS; break; case DIR_ENCRYPT: state = fbp->state[dir-1]; if (state == cFAILED) state = IN_PROGRESS; else if ((state & NO_SEND_IV) == 0) break; if (!fbp->key_isset) { fbp->need_start = 1; break; } state &= ~NO_SEND_IV; state |= NO_RECV_IV; #ifdef DEBUG if (encrypt_debug_mode) printf("Creating new feed\r\n"); #endif /* * Create a random feed and send it over. */ ck_cast_ecb_encrypt(fbp->temp_feed, fbp->temp_feed, &fbp->streams[dir-1].str_sched, 0); 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; ttol(fbp->fb_feed, p - fbp->fb_feed); break; default: return(cFAILED); } 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. */ #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_is(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_is(data, cnt, &cast_fb[CFB_128])); } int cast_ofb64_is(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_is(data, cnt, &cast_fb[OFB_128])); } #endif int castexp_cfb64_is(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_is(data, cnt, &cast_fb[CFB_40])); } int castexp_ofb64_is(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_is(data, cnt, &cast_fb[OFB_40])); } static int cast_fb64_is(data, cnt, fbp) unsigned char *data; int cnt; struct cast_fb *fbp; { int x; unsigned char *p; Block b; 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("FB64: initial vector failed on size\r\n"); #endif state = cFAILED; goto failure; } #ifdef DEBUG if (encrypt_debug_mode) printf("FB64: initial vector received\r\n"); if (encrypt_debug_mode) printf("Initializing Decrypt stream\r\n"); #endif cast_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; ttol(fbp->fb_feed, p - fbp->fb_feed); state = IN_PROGRESS; break; default: /* unknown option type */ /* 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; ttol(fbp->fb_feed, p - fbp->fb_feed); 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. */ #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_reply(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_reply(data, cnt, &cast_fb[CFB_128])); } int cast_ofb64_reply(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_reply(data, cnt, &cast_fb[OFB_128])); } #endif int castexp_cfb64_reply(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_reply(data, cnt, &cast_fb[CFB_40])); } int castexp_ofb64_reply(data, cnt) unsigned char *data; int cnt; { return(cast_fb64_reply(data, cnt, &cast_fb[OFB_40])); } static int cast_fb64_reply(data, cnt, fbp) unsigned char *data; int cnt; struct cast_fb *fbp; { int x; unsigned char *p; Block b; register int state = fbp->state[DIR_ENCRYPT-1]; if (cnt-- < 1) goto failure; switch (*data++) { case FB64_IV_OK: cast_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); if (state == cFAILED) 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)); cast_fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); state = cFAILED; break; default: #if 0 if (encrypt_debug_mode) { printf("Unknown option type: %d\r\n", data[-1]); printd(data, cnt); printf("\r\n"); } #endif /* FALL THROUGH */ failure: state = cFAILED; break; } return(fbp->state[DIR_ENCRYPT-1] = state); } #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_session(key, server) Session_Key *key; int server; { return(cast_fb64_session(key, server, &cast_fb[CFB_128], 1)); } int cast_ofb64_session(key, server) Session_Key *key; int server; { return(cast_fb64_session(key, server, &cast_fb[OFB_128], 1)); } #endif int castexp_cfb64_session(key, server) Session_Key *key; int server; { return(cast_fb64_session(key, server, &cast_fb[CFB_40], 0)); } int castexp_ofb64_session(key, server) Session_Key *key; int server; { return(cast_fb64_session(key, server, &cast_fb[OFB_40], 0)); } #define CAST128_KEYLEN 16 /* 128 bits */ #define CAST5_40_KEYLEN 5 /* 40 bits */ static int cast_fb64_session(key, server, fbp, fs) Session_Key *key; int server; struct cast_fb *fbp; int fs; { int klen; unsigned char * kptr; if(fs) klen = CAST128_KEYLEN; else klen = CAST5_40_KEYLEN; if (!key || key->length < klen) { CHAR buf[80]; sprintf(buf,"Can't set CAST session key (%d < %d)", key ? key->length : 0, klen); /* safe */ #ifdef DEBUG if (encrypt_debug_mode) printf("%s\r\n",buf); #endif debug(F110,"cast_fb64_session",buf,0); return(cFAILED); } if(key->length < 2 * klen) kptr = key->data; else kptr = key->data + klen; if(server) { cast_fb64_stream_key(kptr, &fbp->streams[DIR_ENCRYPT-1], fs); cast_fb64_stream_key(key->data, &fbp->streams[DIR_DECRYPT-1], fs); } else { cast_fb64_stream_key(kptr, &fbp->streams[DIR_DECRYPT-1], fs); cast_fb64_stream_key(key->data, &fbp->streams[DIR_ENCRYPT-1], fs); } /* Stuff leftovers into the feed */ if(key->length >= 2 * klen + sizeof(Block)) memcpy(fbp->temp_feed, key->data + 2 * klen, sizeof(Block)); else { #ifdef COMMENT /* This is a better way of erasing the password */ /* but we do not want to link in libsrp */ t_random(fbp->temp_feed, sizeof(Block)); #else memset(fbp->temp_feed, 0, sizeof(Block)); #endif } fbp->key_isset = 1; /* * Now look to see if cast_fb64_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; cast_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. */ #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[CFB_128])); } int cast_ofb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[OFB_128])); } #endif int castexp_cfb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[CFB_40])); } int castexp_ofb64_keyid(dir, kp, lenp) int dir, *lenp; unsigned char *kp; { return(cast_fb64_keyid(dir, kp, lenp, &cast_fb[OFB_40])); } static int cast_fb64_keyid(dir, kp, lenp, fbp) int dir, *lenp; unsigned char *kp; struct cast_fb *fbp; { register int state = fbp->state[dir-1]; if (*lenp != 1 || (*kp != '\0')) { *lenp = 0; return(state); } if (state == cFAILED) state = IN_PROGRESS; state &= ~NO_KEYID; return(fbp->state[dir-1] = state); } static void cast_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; 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 cast_cfb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { cast_fb64_printsub(data, cnt, buf, buflen, "CFB64"); } void cast_ofb64_printsub(data, cnt, buf, buflen) unsigned char *data, *buf; int cnt, buflen; { cast_fb64_printsub(data, cnt, buf, buflen, "OFB64"); } static void cast_fb64_stream_iv(seed, stp) Block seed; register struct cast_stinfo *stp; { memcpy((void *)stp->str_iv, (void *)seed, sizeof(Block)); memcpy((void *)stp->str_output, (void *)seed, sizeof(Block)); stp->str_index = sizeof(Block); } static void cast_fb64_stream_key(key, stp, fs) unsigned char * key; register struct cast_stinfo *stp; int fs; { #ifndef CAST_EXPORT_ENCRYPTION if(fs) ck_cast128_key_sched(&stp->str_sched, key); else #endif ck_cast5_40_key_sched(&stp->str_sched, key); memcpy((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block)); stp->str_index = sizeof(Block); } /* * CAST 64 bit Cipher Feedback * * key --->+------+ * +->| CAST |--+ * | +------+ | * | 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 = CAST(iV, key) * On = Dn ^ Vn * V(n+1) = CAST(On, key) */ #ifndef CAST_EXPORT_ENCRYPTION void cast_cfb64_encrypt(s, c) register unsigned char *s; int c; { _cast_cfb64_encrypt(s, c, &cast_fb[CFB_128].streams[DIR_ENCRYPT-1]); } #endif void castexp_cfb64_encrypt(s, c) register unsigned char *s; int c; { _cast_cfb64_encrypt(s, c, &cast_fb[CFB_40].streams[DIR_ENCRYPT-1]); } static void _cast_cfb64_encrypt(s, c, stp) register unsigned char *s; int c; register struct cast_stinfo *stp; { register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; ck_cast_ecb_encrypt(b, stp->str_output, &stp->str_sched, 0); memcpy((void *)stp->str_feed, (void *)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; } #ifndef CAST_EXPORT_ENCRYPTION int cast_cfb64_decrypt(data) int data; { return _cast_cfb64_decrypt(data, &cast_fb[CFB_128].streams[DIR_DECRYPT-1]); } #endif int castexp_cfb64_decrypt(data) int data; { return _cast_cfb64_decrypt(data, &cast_fb[CFB_40].streams[DIR_DECRYPT-1]); } static int _cast_cfb64_decrypt(data, stp) int data; register struct cast_stinfo *stp; { 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; ck_cast_ecb_encrypt(b, stp->str_output, &stp->str_sched, 0); memcpy((void *)stp->str_feed, (void *)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]); } /* * CAST 64 bit Output Feedback * * key --->+------+ * +->| CAST |--+ * | +------+ | * +------------+ * 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 = CAST(iV, key) * V(n+1) = CAST(Vn, key) * On = Dn ^ Vn */ #ifndef CAST_EXPORT_ENCRYPTION void cast_ofb64_encrypt(s, c) register unsigned char *s; int c; { _cast_ofb64_encrypt(s, c, &cast_fb[OFB_128].streams[DIR_ENCRYPT-1]); } #endif void castexp_ofb64_encrypt(s, c) register unsigned char *s; int c; { _cast_ofb64_encrypt(s, c, &cast_fb[OFB_40].streams[DIR_ENCRYPT-1]); } static void _cast_ofb64_encrypt(s, c, stp) register unsigned char *s; int c; register struct cast_stinfo *stp; { register int index; index = stp->str_index; while (c-- > 0) { if (index == sizeof(Block)) { Block b; ck_cast_ecb_encrypt(b, stp->str_feed, &stp->str_sched, 0); memcpy((void *)stp->str_feed, (void *)b, sizeof(Block)); index = 0; } *s++ ^= stp->str_feed[index]; index++; } stp->str_index = index; } #ifndef CAST_EXPORT_ENCRYPTION int cast_ofb64_decrypt(data) int data; { return _cast_ofb64_decrypt(data, &cast_fb[OFB_128].streams[DIR_DECRYPT-1]); } #endif int castexp_ofb64_decrypt(data) int data; { return _cast_ofb64_decrypt(data, &cast_fb[OFB_40].streams[DIR_DECRYPT-1]); } static int _cast_ofb64_decrypt(data, stp) int data; register struct cast_stinfo *stp; { 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; ck_cast_ecb_encrypt(b, stp->str_feed, &stp->str_sched, 0); memcpy((void *)stp->str_feed, (void *)b, sizeof(Block)); stp->str_index = 1; /* Next time will be 1 */ index = 0; /* But now use 0 */ } return(data ^ stp->str_feed[index]); } /* * Copyright (c) 1997 Stanford University * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notices and this permission notice appear in * all copies of the software and related documentation. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * cast.c * Author: Tom Wu * * An implementation of the CAST-128 encryption algorithm, as * specified in RFC 2144. */ /* The first four S-boxes are for encryption/decryption */ static uint32 S1[] = { 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf }; static uint32 S2[] = { 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 }; static uint32 S3[] = { 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 }; static uint32 S4[] = { 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 }; /* Encrypt/decrypt one 64-bit block of data */ void ck_cast_ecb_encrypt(out, in, sched, mode) uint8p out; uint8p in; CastKeySched * sched; int mode; /* zero means encrypt */ { uint32 t[2]; #ifdef LITTLE_ENDIAN t[0] = (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3]; t[1] = (in[4] << 24) | (in[5] << 16) | (in[6] << 8) | in[7]; #else t[0] = *(uint32p) in; t[1] = *(uint32p) (in + 4); #endif ck_cast_ecb_crypt(t, sched, mode); #ifdef LITTLE_ENDIAN out[0] = (t[0] >> 24) & 0xff; out[1] = (t[0] >> 16) & 0xff; out[2] = (t[0] >> 8) & 0xff; out[3] = t[0] & 0xff; out[4] = (t[1] >> 24) & 0xff; out[5] = (t[1] >> 16) & 0xff; out[6] = (t[1] >> 8) & 0xff; out[7] = t[1] & 0xff; #else *(uint32p) out = t[0]; *(uint32p) (out + 4) = t[1]; #endif } void ck_cast_ecb_crypt(data, sched, mode) uint32p data; CastKeySched * sched; int mode; { register uint32 L, R, temp; register struct CastSubkeyPair * kp; register uint8p Ia, Ib, Ic, Id; uint32 I; #ifdef LITTLE_ENDIAN Id = (uint8p) &I; Ic = Id + 1; Ib = Ic + 1; Ia = Ib + 1; #else Ia = (uint8p) &I; Ib = Ia + 1; Ic = Ib + 1; Id = Ic + 1; #endif L = data[0]; R = data[1]; #define type0(left,right) \ temp = kp->Km + right;\ I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\ left ^= ((S1[*Ia] ^ S2[*Ib]) - S3[*Ic]) + S4[*Id]; #define type1(left,right) \ temp = kp->Km ^ right;\ I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\ left ^= ((S1[*Ia] - S2[*Ib]) + S3[*Ic]) ^ S4[*Id]; #define type2(left,right) \ temp = kp->Km - right;\ I = (temp << kp->Kr) | (temp >> (32 - kp->Kr));\ left ^= ((S1[*Ia] + S2[*Ib]) ^ S3[*Ic]) - S4[*Id]; if(mode) { #ifndef CAST_EXPORT_ENCRYPTION if(sched->ksize > 10) { kp = &sched->K[15]; type0(L, R); --kp; type2(R, L); --kp; type1(L, R); --kp; type0(R, L); --kp; } else #endif kp = &sched->K[11]; type2(L, R); --kp; type1(R, L); --kp; type0(L, R); --kp; type2(R, L); --kp; type1(L, R); --kp; type0(R, L); --kp; type2(L, R); --kp; type1(R, L); --kp; type0(L, R); --kp; type2(R, L); --kp; type1(L, R); --kp; type0(R, L); } else { kp = &sched->K[0]; type0(L, R); ++kp; type1(R, L); ++kp; type2(L, R); ++kp; type0(R, L); ++kp; type1(L, R); ++kp; type2(R, L); ++kp; type0(L, R); ++kp; type1(R, L); ++kp; type2(L, R); ++kp; type0(R, L); ++kp; type1(L, R); ++kp; type2(R, L); ++kp; #ifndef CAST_EXPORT_ENCRYPTION if(sched->ksize > 10) { type0(L, R); ++kp; type1(R, L); ++kp; type2(L, R); ++kp; type0(R, L); } #endif } data[0] = R; data[1] = L; } /* The last four S-boxes are for key schedule setup */ static uint32 S5[] = { 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4 }; static uint32 S6[] = { 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f }; static uint32 S7[] = { 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3 }; static uint32 S8[] = { 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e }; /* Initialize a key schedule from a 128-bit key */ static void cast_key_sched(sched, key) CastKeySched * sched; uint8p key; { uint8p x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xA, xB, xC, xD, xE, xF; uint8p z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, zA, zB, zC, zD, zE, zF; uint32 X03, X47, X8B, XCF, Z03, Z47, Z8B, ZCF; #ifdef LITTLE_ENDIAN x3 = (uint8p) &X03; x2 = x3 + 1; x1 = x2 + 1; x0 = x1 + 1; x7 = (uint8p) &X47; x6 = x7 + 1; x5 = x6 + 1; x4 = x5 + 1; xB = (uint8p) &X8B; xA = xB + 1; x9 = xA + 1; x8 = x9 + 1; xF = (uint8p) &XCF; xE = xF + 1; xD = xE + 1; xC = xD + 1; z3 = (uint8p) &Z03; z2 = z3 + 1; z1 = z2 + 1; z0 = z1 + 1; z7 = (uint8p) &Z47; z6 = z7 + 1; z5 = z6 + 1; z4 = z5 + 1; zB = (uint8p) &Z8B; zA = zB + 1; z9 = zA + 1; z8 = z9 + 1; zF = (uint8p) &ZCF; zE = zF + 1; zD = zE + 1; zC = zD + 1; #else x0 = (uint8p) &X03; x1 = x0 + 1; x2 = x1 + 1; x3 = x2 + 1; x4 = (uint8p) &X47; x5 = x4 + 1; x6 = x5 + 1; x7 = x6 + 1; x8 = (uint8p) &X8B; x9 = x8 + 1; xA = x9 + 1; xB = xA + 1; xC = (uint8p) &XCF; xD = xC + 1; xE = xD + 1; xF = xE + 1; z0 = (uint8p) &Z03; z1 = z0 + 1; z2 = z1 + 1; z3 = z2 + 1; z4 = (uint8p) &Z47; z5 = z4 + 1; z6 = z5 + 1; z7 = z6 + 1; z8 = (uint8p) &Z8B; z9 = z8 + 1; zA = z9 + 1; zB = zA + 1; zC = (uint8p) &ZCF; zD = zC + 1; zE = zD + 1; zF = zE + 1; #endif #ifdef LITTLE_ENDIAN *x0 = key[0]; *x1 = key[1]; *x2 = key[2]; *x3 = key[3]; *x4 = key[4]; *x5 = key[5]; *x6 = key[6]; *x7 = key[7]; *x8 = key[8]; *x9 = key[9]; *xA = key[10]; *xB = key[11]; *xC = key[12]; *xD = key[13]; *xE = key[14]; *xF = key[15]; #else X03 = *(uint32p) key; X47 = *(uint32p) (key + 4); X8B = *(uint32p) (key + 8); XCF = *(uint32p) (key + 12); #endif /* First half of key schedule */ Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8]; Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA]; Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9]; ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB]; sched->K[0].Km = S5[*z8] ^ S6[*z9] ^ S7[*z7] ^ S8[*z6] ^ S5[*z2]; sched->K[1].Km = S5[*zA] ^ S6[*zB] ^ S7[*z5] ^ S8[*z4] ^ S6[*z6]; sched->K[2].Km = S5[*zC] ^ S6[*zD] ^ S7[*z3] ^ S8[*z2] ^ S7[*z9]; sched->K[3].Km = S5[*zE] ^ S6[*zF] ^ S7[*z1] ^ S8[*z0] ^ S8[*zC]; X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0]; X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2]; X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1]; XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3]; sched->K[4].Km = S5[*x3] ^ S6[*x2] ^ S7[*xC] ^ S8[*xD] ^ S5[*x8]; sched->K[5].Km = S5[*x1] ^ S6[*x0] ^ S7[*xE] ^ S8[*xF] ^ S6[*xD]; sched->K[6].Km = S5[*x7] ^ S6[*x6] ^ S7[*x8] ^ S8[*x9] ^ S7[*x3]; sched->K[7].Km = S5[*x5] ^ S6[*x4] ^ S7[*xA] ^ S8[*xB] ^ S8[*x7]; Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8]; Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA]; Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9]; ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB]; sched->K[8].Km = S5[*z3] ^ S6[*z2] ^ S7[*zC] ^ S8[*zD] ^ S5[*z9]; sched->K[9].Km = S5[*z1] ^ S6[*z0] ^ S7[*zE] ^ S8[*zF] ^ S6[*zC]; sched->K[10].Km = S5[*z7] ^ S6[*z6] ^ S7[*z8] ^ S8[*z9] ^ S7[*z2]; sched->K[11].Km = S5[*z5] ^ S6[*z4] ^ S7[*zA] ^ S8[*zB] ^ S8[*z6]; X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0]; X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2]; X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1]; XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3]; sched->K[12].Km = S5[*x8] ^ S6[*x9] ^ S7[*x7] ^ S8[*x6] ^ S5[*x3]; sched->K[13].Km = S5[*xA] ^ S6[*xB] ^ S7[*x5] ^ S8[*x4] ^ S6[*x7]; sched->K[14].Km = S5[*xC] ^ S6[*xD] ^ S7[*x3] ^ S8[*x2] ^ S7[*x8]; sched->K[15].Km = S5[*xE] ^ S6[*xF] ^ S7[*x1] ^ S8[*x0] ^ S8[*xD]; /* Second half of key schedule - just like first half */ Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8]; Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA]; Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9]; ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB]; sched->K[0].Kr = (S5[*z8] ^ S6[*z9] ^ S7[*z7] ^ S8[*z6] ^ S5[*z2]) & 0x1f; sched->K[1].Kr = (S5[*zA] ^ S6[*zB] ^ S7[*z5] ^ S8[*z4] ^ S6[*z6]) & 0x1f; sched->K[2].Kr = (S5[*zC] ^ S6[*zD] ^ S7[*z3] ^ S8[*z2] ^ S7[*z9]) & 0x1f; sched->K[3].Kr = (S5[*zE] ^ S6[*zF] ^ S7[*z1] ^ S8[*z0] ^ S8[*zC]) & 0x1f; X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0]; X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2]; X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1]; XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3]; sched->K[4].Kr = (S5[*x3] ^ S6[*x2] ^ S7[*xC] ^ S8[*xD] ^ S5[*x8]) & 0x1f; sched->K[5].Kr = (S5[*x1] ^ S6[*x0] ^ S7[*xE] ^ S8[*xF] ^ S6[*xD]) & 0x1f; sched->K[6].Kr = (S5[*x7] ^ S6[*x6] ^ S7[*x8] ^ S8[*x9] ^ S7[*x3]) & 0x1f; sched->K[7].Kr = (S5[*x5] ^ S6[*x4] ^ S7[*xA] ^ S8[*xB] ^ S8[*x7]) & 0x1f; Z03 = X03 ^ S5[*xD] ^ S6[*xF] ^ S7[*xC] ^ S8[*xE] ^ S7[*x8]; Z47 = X8B ^ S5[*z0] ^ S6[*z2] ^ S7[*z1] ^ S8[*z3] ^ S8[*xA]; Z8B = XCF ^ S5[*z7] ^ S6[*z6] ^ S7[*z5] ^ S8[*z4] ^ S5[*x9]; ZCF = X47 ^ S5[*zA] ^ S6[*z9] ^ S7[*zB] ^ S8[*z8] ^ S6[*xB]; sched->K[8].Kr = (S5[*z3] ^ S6[*z2] ^ S7[*zC] ^ S8[*zD] ^ S5[*z9]) & 0x1f; sched->K[9].Kr = (S5[*z1] ^ S6[*z0] ^ S7[*zE] ^ S8[*zF] ^ S6[*zC]) & 0x1f; sched->K[10].Kr = (S5[*z7] ^ S6[*z6] ^ S7[*z8] ^ S8[*z9] ^ S7[*z2]) & 0x1f; sched->K[11].Kr = (S5[*z5] ^ S6[*z4] ^ S7[*zA] ^ S8[*zB] ^ S8[*z6]) & 0x1f; X03 = Z8B ^ S5[*z5] ^ S6[*z7] ^ S7[*z4] ^ S8[*z6] ^ S7[*z0]; X47 = Z03 ^ S5[*x0] ^ S6[*x2] ^ S7[*x1] ^ S8[*x3] ^ S8[*z2]; X8B = Z47 ^ S5[*x7] ^ S6[*x6] ^ S7[*x5] ^ S8[*x4] ^ S5[*z1]; XCF = ZCF ^ S5[*xA] ^ S6[*x9] ^ S7[*xB] ^ S8[*x8] ^ S6[*z3]; sched->K[12].Kr = (S5[*x8] ^ S6[*x9] ^ S7[*x7] ^ S8[*x6] ^ S5[*x3]) & 0x1f; sched->K[13].Kr = (S5[*xA] ^ S6[*xB] ^ S7[*x5] ^ S8[*x4] ^ S6[*x7]) & 0x1f; sched->K[14].Kr = (S5[*xC] ^ S6[*xD] ^ S7[*x3] ^ S8[*x2] ^ S7[*x8]) & 0x1f; sched->K[15].Kr = (S5[*xE] ^ S6[*xF] ^ S7[*x1] ^ S8[*x0] ^ S8[*xD]) & 0x1f; } /* Initialize with a full-strength 128-bit key */ #ifndef CAST_EXPORT_ENCRYPTION void ck_cast128_key_sched(sched, key) CastKeySched * sched; uint8 * key; { sched->ksize = 16; cast_key_sched(sched, key); } #endif /* Handle reduced-keysize variants */ static void cast5_key_sched(sched, key, sz) CastKeySched * sched; uint8 * key; int sz; { uint8 buf[16]; sched->ksize = sz; memset(buf, 0, sizeof(buf)); memcpy(buf, key, sz); cast_key_sched(sched, buf); } /* 40, 64, and 80-bit keys - all use 12 rounds */ void ck_cast5_40_key_sched(sched, key) CastKeySched * sched; uint8 * key; { cast5_key_sched(sched, key, 5); } #ifndef CAST_EXPORT_ENCRYPTION void ck_cast5_64_key_sched(sched, key) CastKeySched * sched; uint8 * key; { cast5_key_sched(sched, key, 8); } void ck_cast5_80_key_sched(sched, key) CastKeySched * sched; uint8 * key; { cast5_key_sched(sched, key, 10); } #endif /* CAST_EXPORT_ENCRYPTION */ #endif /* CK_CAST */ #ifdef CRYPT_DLL static char * ck_crypt_dll_version() { return(ckcrpv); } int crypt_dll_init( struct _crypt_dll_init * init ) { #ifdef LIBDES extern int des_check_key; extern void libdes_dll_init(struct _crypt_dll_init *); des_check_key = 1; #endif /* LIBDES */ if ( init->version >= 1 ) { p_ttol = init->p_ttol; p_dodebug = init->p_dodebug; p_dohexdump = init->p_dohexdump; p_tn_debug = init->p_tn_debug; p_vscrnprintf = init->p_vscrnprintf; if ( init->version == 1 ) return(1); } if ( init->version >= 2 ) { /* This is a k5_context but we don't want to include krb5.h */ p_k5_context = (void *) init->p_k5_context; if ( init->version == 2 ) return(1); } if ( init->version >= 3 ) { init->p_install_funcs("encrypt_parse",encrypt_parse); init->p_install_funcs("encrypt_init",encrypt_init); init->p_install_funcs("encrypt_session_key",encrypt_session_key); init->p_install_funcs("encrypt_send_request_start", encrypt_send_request_start ); init->p_install_funcs("encrypt_request_start",encrypt_request_start); init->p_install_funcs("encrypt_send_request_end", encrypt_send_request_end ); init->p_install_funcs("encrypt_request_end",encrypt_request_end); init->p_install_funcs("encrypt_send_end",encrypt_send_end); init->p_install_funcs("encrypt_send_support",encrypt_send_support); init->p_install_funcs("encrypt_is_encrypting",encrypt_is_encrypting); init->p_install_funcs("encrypt_is_decrypting",encrypt_is_decrypting); init->p_install_funcs("get_crypt_table",get_crypt_table); init->p_install_funcs("des_is_weak_key",ck_des_is_weak_key); libdes_dll_init(init); if (init->version == 3) return(1); init->p_install_funcs("crypt_dll_version",ck_crypt_dll_version); if (init->version == 4) return(1); init->version = 4; return(1); } return(0); } #endif /* CRYPT_DLL */ #endif /* CK_ENCRYPTION */