Home | History | Annotate | Line # | Download | only in libtelnet
enc_des.c revision 1.16.34.1
      1  1.16.34.1    martin /*	$NetBSD: enc_des.c,v 1.16.34.1 2024/11/18 19:44:57 martin Exp $	*/
      2        1.4   thorpej 
      3        1.1       cgd /*-
      4        1.4   thorpej  * Copyright (c) 1991, 1993
      5        1.4   thorpej  *	The Regents of the University of California.  All rights reserved.
      6        1.1       cgd  *
      7        1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8        1.1       cgd  * modification, are permitted provided that the following conditions
      9        1.1       cgd  * are met:
     10        1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11        1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12        1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13        1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14        1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15       1.11       agc  * 3. Neither the name of the University nor the names of its contributors
     16        1.1       cgd  *    may be used to endorse or promote products derived from this software
     17        1.1       cgd  *    without specific prior written permission.
     18        1.1       cgd  *
     19        1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20        1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21        1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22        1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23        1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24        1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25        1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26        1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27        1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28        1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29        1.1       cgd  * SUCH DAMAGE.
     30        1.1       cgd  */
     31        1.1       cgd 
     32        1.4   thorpej #include <sys/cdefs.h>
     33        1.1       cgd #ifndef lint
     34        1.4   thorpej #if 0
     35        1.4   thorpej static char sccsid[] = "@(#)enc_des.c	8.3 (Berkeley) 5/30/95"; */
     36        1.4   thorpej #else
     37  1.16.34.1    martin __RCSID("$NetBSD: enc_des.c,v 1.16.34.1 2024/11/18 19:44:57 martin Exp $");
     38        1.4   thorpej #endif
     39        1.1       cgd #endif /* not lint */
     40        1.1       cgd 
     41        1.4   thorpej #ifdef	ENCRYPTION
     42        1.4   thorpej # ifdef	AUTHENTICATION
     43        1.4   thorpej #  ifdef DES_ENCRYPTION
     44        1.1       cgd #include <arpa/telnet.h>
     45        1.1       cgd #include <stdio.h>
     46        1.4   thorpej #include <string.h>
     47        1.1       cgd #include <stdlib.h>
     48        1.1       cgd 
     49        1.9    itojun #include <des.h>
     50        1.1       cgd #include "encrypt.h"
     51        1.1       cgd #include "key-proto.h"
     52        1.1       cgd #include "misc-proto.h"
     53        1.1       cgd 
     54        1.1       cgd #define	CFB	0
     55        1.1       cgd #define	OFB	1
     56        1.1       cgd 
     57        1.1       cgd #define	NO_SEND_IV	1
     58        1.1       cgd #define	NO_RECV_IV	2
     59        1.1       cgd #define	NO_KEYID	4
     60        1.1       cgd #define	IN_PROGRESS	(NO_SEND_IV|NO_RECV_IV|NO_KEYID)
     61        1.1       cgd #define	SUCCESS		0
     62        1.1       cgd #define	FAILED		-1
     63        1.1       cgd 
     64        1.1       cgd 
     65        1.1       cgd struct fb {
     66        1.1       cgd 	Block krbdes_key;
     67        1.1       cgd 	Schedule krbdes_sched;
     68        1.1       cgd 	Block temp_feed;
     69        1.1       cgd 	unsigned char fb_feed[64];
     70        1.1       cgd 	int need_start;
     71        1.1       cgd 	int state[2];
     72        1.1       cgd 	int keyid[2];
     73        1.1       cgd 	int once;
     74        1.1       cgd 	struct stinfo {
     75        1.1       cgd 		Block		str_output;
     76        1.1       cgd 		Block		str_feed;
     77        1.1       cgd 		Block		str_iv;
     78        1.1       cgd 		Block		str_ikey;
     79        1.1       cgd 		Schedule	str_sched;
     80        1.1       cgd 		int		str_index;
     81        1.1       cgd 		int		str_flagshift;
     82        1.1       cgd 	} streams[2];
     83        1.1       cgd };
     84        1.1       cgd 
     85        1.1       cgd static struct fb fb[2];
     86        1.1       cgd 
     87        1.1       cgd struct keyidlist {
     88       1.15  christos 	const char	*keyid;
     89        1.1       cgd 	int	keyidlen;
     90        1.1       cgd 	char	*key;
     91        1.1       cgd 	int	keylen;
     92        1.1       cgd 	int	flags;
     93        1.1       cgd } keyidlist [] = {
     94        1.1       cgd 	{ "\0", 1, 0, 0, 0 },		/* default key of zero */
     95        1.1       cgd 	{ 0, 0, 0, 0, 0 }
     96        1.1       cgd };
     97        1.1       cgd 
     98        1.1       cgd #define	KEYFLAG_MASK	03
     99        1.1       cgd 
    100        1.1       cgd #define	KEYFLAG_NOINIT	00
    101        1.1       cgd #define	KEYFLAG_INIT	01
    102        1.1       cgd #define	KEYFLAG_OK	02
    103        1.1       cgd #define	KEYFLAG_BAD	03
    104        1.1       cgd 
    105        1.1       cgd #define	KEYFLAG_SHIFT	2
    106        1.1       cgd 
    107        1.1       cgd #define	SHIFT_VAL(a,b)	(KEYFLAG_SHIFT*((a)+((b)*2)))
    108        1.1       cgd 
    109        1.1       cgd #define	FB64_IV		1
    110        1.1       cgd #define	FB64_IV_OK	2
    111        1.1       cgd #define	FB64_IV_BAD	3
    112        1.1       cgd 
    113        1.1       cgd 
    114       1.12     perry void fb64_stream_iv(Block, struct stinfo *);
    115       1.12     perry void fb64_init(struct fb *);
    116       1.12     perry static int fb64_start(struct fb *, int, int);
    117       1.12     perry int fb64_is(unsigned char *, int, struct fb *);
    118       1.12     perry int fb64_reply(unsigned char *, int, struct fb *);
    119       1.12     perry static void fb64_session(Session_Key *, int, struct fb *);
    120       1.12     perry void fb64_stream_key(Block *, struct stinfo *);
    121       1.12     perry int fb64_keyid(int, unsigned char *, int *, struct fb *);
    122        1.1       cgd 
    123       1.16      matt void
    124       1.16      matt cfb64_init(int server)
    125        1.1       cgd {
    126        1.1       cgd 	fb64_init(&fb[CFB]);
    127        1.1       cgd 	fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
    128        1.1       cgd 	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
    129        1.1       cgd 	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
    130        1.1       cgd }
    131        1.1       cgd 
    132       1.16      matt void
    133       1.16      matt ofb64_init(int server)
    134        1.1       cgd {
    135        1.1       cgd 	fb64_init(&fb[OFB]);
    136        1.1       cgd 	fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
    137        1.1       cgd 	fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
    138        1.1       cgd 	fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
    139        1.1       cgd }
    140        1.1       cgd 
    141       1.16      matt void
    142       1.16      matt fb64_init(register struct fb *fbp)
    143        1.1       cgd {
    144        1.4   thorpej 	memset((void *)fbp, 0, sizeof(*fbp));
    145        1.1       cgd 	fbp->state[0] = fbp->state[1] = FAILED;
    146        1.1       cgd 	fbp->fb_feed[0] = IAC;
    147        1.1       cgd 	fbp->fb_feed[1] = SB;
    148        1.1       cgd 	fbp->fb_feed[2] = TELOPT_ENCRYPT;
    149        1.1       cgd 	fbp->fb_feed[3] = ENCRYPT_IS;
    150        1.1       cgd }
    151        1.1       cgd 
    152        1.1       cgd /*
    153        1.1       cgd  * Returns:
    154        1.1       cgd  *	-1: some error.  Negotiation is done, encryption not ready.
    155        1.1       cgd  *	 0: Successful, initial negotiation all done.
    156        1.1       cgd  *	 1: successful, negotiation not done yet.
    157        1.1       cgd  *	 2: Not yet.  Other things (like getting the key from
    158        1.1       cgd  *	    Kerberos) have to happen before we can continue.
    159        1.1       cgd  */
    160       1.16      matt int
    161       1.16      matt cfb64_start(int dir, int server)
    162        1.1       cgd {
    163        1.1       cgd 	return(fb64_start(&fb[CFB], dir, server));
    164        1.1       cgd }
    165       1.16      matt 
    166       1.16      matt int
    167       1.16      matt ofb64_start(int dir, int server)
    168        1.1       cgd {
    169        1.1       cgd 	return(fb64_start(&fb[OFB], dir, server));
    170        1.1       cgd }
    171        1.1       cgd 
    172       1.16      matt static int
    173       1.16      matt fb64_start(struct fb *fbp, int dir, int server)
    174        1.1       cgd {
    175       1.15  christos 	size_t x;
    176        1.1       cgd 	unsigned char *p;
    177        1.1       cgd 	register int state;
    178        1.1       cgd 
    179        1.1       cgd 	switch (dir) {
    180        1.1       cgd 	case DIR_DECRYPT:
    181        1.1       cgd 		/*
    182        1.1       cgd 		 * This is simply a request to have the other side
    183        1.1       cgd 		 * start output (our input).  He will negotiate an
    184        1.1       cgd 		 * IV so we need not look for it.
    185        1.1       cgd 		 */
    186        1.1       cgd 		state = fbp->state[dir-1];
    187        1.1       cgd 		if (state == FAILED)
    188        1.1       cgd 			state = IN_PROGRESS;
    189        1.1       cgd 		break;
    190        1.1       cgd 
    191        1.1       cgd 	case DIR_ENCRYPT:
    192        1.1       cgd 		state = fbp->state[dir-1];
    193        1.1       cgd 		if (state == FAILED)
    194        1.1       cgd 			state = IN_PROGRESS;
    195        1.1       cgd 		else if ((state & NO_SEND_IV) == 0)
    196        1.1       cgd 			break;
    197        1.1       cgd 
    198        1.1       cgd 		if (!VALIDKEY(fbp->krbdes_key)) {
    199        1.1       cgd 			fbp->need_start = 1;
    200        1.1       cgd 			break;
    201        1.1       cgd 		}
    202        1.1       cgd 		state &= ~NO_SEND_IV;
    203        1.1       cgd 		state |= NO_RECV_IV;
    204  1.16.34.1    martin 		if (encrypt_debug())
    205        1.1       cgd 			printf("Creating new feed\r\n");
    206        1.1       cgd 		/*
    207        1.1       cgd 		 * Create a random feed and send it over.
    208        1.1       cgd 		 */
    209        1.4   thorpej 		des_new_random_key(&fbp->temp_feed);
    210        1.4   thorpej 		des_ecb_encrypt(&fbp->temp_feed, &fbp->temp_feed,
    211        1.1       cgd 				fbp->krbdes_sched, 1);
    212        1.1       cgd 		p = fbp->fb_feed + 3;
    213        1.1       cgd 		*p++ = ENCRYPT_IS;
    214        1.1       cgd 		p++;
    215        1.1       cgd 		*p++ = FB64_IV;
    216        1.1       cgd 		for (x = 0; x < sizeof(Block); ++x) {
    217        1.1       cgd 			if ((*p++ = fbp->temp_feed[x]) == IAC)
    218        1.1       cgd 				*p++ = IAC;
    219        1.1       cgd 		}
    220        1.1       cgd 		*p++ = IAC;
    221        1.1       cgd 		*p++ = SE;
    222        1.1       cgd 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
    223        1.4   thorpej 		telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
    224        1.1       cgd 		break;
    225        1.1       cgd 	default:
    226        1.1       cgd 		return(FAILED);
    227        1.1       cgd 	}
    228        1.1       cgd 	return(fbp->state[dir-1] = state);
    229        1.1       cgd }
    230        1.1       cgd 
    231        1.1       cgd /*
    232        1.1       cgd  * Returns:
    233        1.1       cgd  *	-1: some error.  Negotiation is done, encryption not ready.
    234        1.1       cgd  *	 0: Successful, initial negotiation all done.
    235        1.1       cgd  *	 1: successful, negotiation not done yet.
    236        1.1       cgd  */
    237       1.16      matt int
    238       1.16      matt cfb64_is(unsigned char *data, int cnt)
    239        1.1       cgd {
    240        1.1       cgd 	return(fb64_is(data, cnt, &fb[CFB]));
    241        1.1       cgd }
    242       1.16      matt int
    243       1.16      matt ofb64_is(unsigned char *data, int cnt)
    244        1.1       cgd {
    245        1.1       cgd 	return(fb64_is(data, cnt, &fb[OFB]));
    246        1.1       cgd }
    247        1.1       cgd 
    248       1.16      matt int
    249       1.16      matt fb64_is(unsigned char *data, int cnt, struct fb *fbp)
    250        1.1       cgd {
    251        1.1       cgd 	unsigned char *p;
    252        1.1       cgd 	register int state = fbp->state[DIR_DECRYPT-1];
    253        1.1       cgd 
    254        1.1       cgd 	if (cnt-- < 1)
    255        1.1       cgd 		goto failure;
    256        1.1       cgd 
    257        1.1       cgd 	switch (*data++) {
    258        1.1       cgd 	case FB64_IV:
    259        1.1       cgd 		if (cnt != sizeof(Block)) {
    260  1.16.34.1    martin 			if (encrypt_debug())
    261        1.1       cgd 				printf("CFB64: initial vector failed on size\r\n");
    262        1.1       cgd 			state = FAILED;
    263        1.1       cgd 			goto failure;
    264        1.1       cgd 		}
    265        1.1       cgd 
    266  1.16.34.1    martin 		if (encrypt_debug())
    267        1.1       cgd 			printf("CFB64: initial vector received\r\n");
    268        1.1       cgd 
    269  1.16.34.1    martin 		if (encrypt_debug())
    270        1.1       cgd 			printf("Initializing Decrypt stream\r\n");
    271        1.1       cgd 
    272        1.1       cgd 		fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
    273        1.1       cgd 
    274        1.1       cgd 		p = fbp->fb_feed + 3;
    275        1.1       cgd 		*p++ = ENCRYPT_REPLY;
    276        1.1       cgd 		p++;
    277        1.1       cgd 		*p++ = FB64_IV_OK;
    278        1.1       cgd 		*p++ = IAC;
    279        1.1       cgd 		*p++ = SE;
    280        1.1       cgd 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
    281        1.4   thorpej 		telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
    282        1.1       cgd 
    283        1.1       cgd 		state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
    284        1.1       cgd 		break;
    285        1.1       cgd 
    286        1.1       cgd 	default:
    287  1.16.34.1    martin 		if (encrypt_debug()) {
    288        1.1       cgd 			printf("Unknown option type: %d\r\n", *(data-1));
    289        1.1       cgd 			printd(data, cnt);
    290        1.1       cgd 			printf("\r\n");
    291        1.1       cgd 		}
    292        1.1       cgd 		/* FALL THROUGH */
    293        1.1       cgd 	failure:
    294        1.1       cgd 		/*
    295        1.1       cgd 		 * We failed.  Send an FB64_IV_BAD option
    296        1.1       cgd 		 * to the other side so it will know that
    297        1.1       cgd 		 * things failed.
    298        1.1       cgd 		 */
    299        1.1       cgd 		p = fbp->fb_feed + 3;
    300        1.1       cgd 		*p++ = ENCRYPT_REPLY;
    301        1.1       cgd 		p++;
    302        1.1       cgd 		*p++ = FB64_IV_BAD;
    303        1.1       cgd 		*p++ = IAC;
    304        1.1       cgd 		*p++ = SE;
    305        1.1       cgd 		printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
    306        1.4   thorpej 		telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
    307        1.1       cgd 
    308        1.1       cgd 		break;
    309        1.1       cgd 	}
    310        1.1       cgd 	return(fbp->state[DIR_DECRYPT-1] = state);
    311        1.1       cgd }
    312        1.1       cgd 
    313        1.1       cgd /*
    314        1.1       cgd  * Returns:
    315        1.1       cgd  *	-1: some error.  Negotiation is done, encryption not ready.
    316        1.1       cgd  *	 0: Successful, initial negotiation all done.
    317        1.1       cgd  *	 1: successful, negotiation not done yet.
    318        1.1       cgd  */
    319       1.16      matt int
    320       1.16      matt cfb64_reply(unsigned char *data, int cnt)
    321        1.1       cgd {
    322        1.1       cgd 	return(fb64_reply(data, cnt, &fb[CFB]));
    323        1.1       cgd }
    324       1.16      matt int
    325       1.16      matt ofb64_reply(unsigned char *data, int cnt)
    326        1.1       cgd {
    327        1.1       cgd 	return(fb64_reply(data, cnt, &fb[OFB]));
    328        1.1       cgd }
    329        1.1       cgd 
    330       1.16      matt int
    331       1.16      matt fb64_reply(unsigned char *data, int cnt, struct fb *fbp)
    332        1.1       cgd {
    333        1.1       cgd 	register int state = fbp->state[DIR_ENCRYPT-1];
    334        1.1       cgd 
    335        1.1       cgd 	if (cnt-- < 1)
    336        1.1       cgd 		goto failure;
    337        1.1       cgd 
    338        1.1       cgd 	switch (*data++) {
    339        1.1       cgd 	case FB64_IV_OK:
    340        1.1       cgd 		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
    341        1.1       cgd 		if (state == FAILED)
    342        1.1       cgd 			state = IN_PROGRESS;
    343        1.1       cgd 		state &= ~NO_RECV_IV;
    344       1.15  christos 		encrypt_send_keyid(DIR_ENCRYPT, (const unsigned char *)"\0", 1, 1);
    345        1.1       cgd 		break;
    346        1.1       cgd 
    347        1.1       cgd 	case FB64_IV_BAD:
    348        1.4   thorpej 		memset(fbp->temp_feed, 0, sizeof(Block));
    349        1.1       cgd 		fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
    350        1.1       cgd 		state = FAILED;
    351        1.1       cgd 		break;
    352        1.1       cgd 
    353        1.1       cgd 	default:
    354  1.16.34.1    martin 		if (encrypt_debug()) {
    355        1.1       cgd 			printf("Unknown option type: %d\r\n", data[-1]);
    356        1.1       cgd 			printd(data, cnt);
    357        1.1       cgd 			printf("\r\n");
    358        1.1       cgd 		}
    359        1.1       cgd 		/* FALL THROUGH */
    360        1.1       cgd 	failure:
    361        1.1       cgd 		state = FAILED;
    362        1.1       cgd 		break;
    363        1.1       cgd 	}
    364        1.1       cgd 	return(fbp->state[DIR_ENCRYPT-1] = state);
    365        1.1       cgd }
    366        1.1       cgd 
    367       1.16      matt void
    368       1.16      matt cfb64_session(Session_Key *key, int server)
    369        1.1       cgd {
    370        1.1       cgd 	fb64_session(key, server, &fb[CFB]);
    371        1.1       cgd }
    372        1.1       cgd 
    373       1.16      matt void
    374       1.16      matt ofb64_session( Session_Key *key, int server)
    375        1.1       cgd {
    376        1.1       cgd 	fb64_session(key, server, &fb[OFB]);
    377        1.1       cgd }
    378        1.1       cgd 
    379       1.16      matt static void
    380       1.16      matt fb64_session(Session_Key *key, int server, struct fb *fbp)
    381        1.1       cgd {
    382        1.1       cgd 
    383        1.1       cgd 	if (!key || key->type != SK_DES) {
    384  1.16.34.1    martin 		if (encrypt_debug())
    385        1.1       cgd 			printf("Can't set krbdes's session key (%d != %d)\r\n",
    386        1.1       cgd 				key ? key->type : -1, SK_DES);
    387        1.1       cgd 		return;
    388        1.1       cgd 	}
    389        1.4   thorpej 	memmove((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
    390        1.1       cgd 
    391        1.4   thorpej 	fb64_stream_key(&fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
    392        1.4   thorpej 	fb64_stream_key(&fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
    393        1.1       cgd 
    394        1.1       cgd 	if (fbp->once == 0) {
    395        1.4   thorpej 		des_init_random_number_generator(&fbp->krbdes_key);
    396        1.1       cgd 		fbp->once = 1;
    397        1.1       cgd 	}
    398        1.4   thorpej 	des_key_sched(&fbp->krbdes_key, fbp->krbdes_sched);
    399        1.1       cgd 	/*
    400       1.14   mbalmer 	 * Now look to see if krbdes_start() was waiting for the key to
    401       1.14   mbalmer 	 * show up.  If so, go ahead an call it now that we have the key.
    402        1.1       cgd 	 */
    403        1.1       cgd 	if (fbp->need_start) {
    404        1.1       cgd 		fbp->need_start = 0;
    405        1.1       cgd 		fb64_start(fbp, DIR_ENCRYPT, server);
    406        1.1       cgd 	}
    407        1.1       cgd }
    408        1.1       cgd 
    409        1.1       cgd /*
    410        1.1       cgd  * We only accept a keyid of 0.  If we get a keyid of
    411        1.1       cgd  * 0, then mark the state as SUCCESS.
    412        1.1       cgd  */
    413       1.16      matt int
    414       1.16      matt cfb64_keyid(int dir, unsigned char *kp, int *lenp)
    415        1.1       cgd {
    416        1.1       cgd 	return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
    417        1.1       cgd }
    418        1.1       cgd 
    419        1.1       cgd 	int
    420       1.16      matt ofb64_keyid(int dir, unsigned char *kp, int *lenp)
    421        1.1       cgd {
    422        1.1       cgd 	return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
    423        1.1       cgd }
    424        1.1       cgd 
    425       1.16      matt int
    426       1.16      matt fb64_keyid(int dir, unsigned char *kp, int *lenp, struct fb *fbp)
    427        1.1       cgd {
    428        1.1       cgd 	register int state = fbp->state[dir-1];
    429        1.1       cgd 
    430        1.1       cgd 	if (*lenp != 1 || (*kp != '\0')) {
    431        1.1       cgd 		*lenp = 0;
    432        1.1       cgd 		return(state);
    433        1.1       cgd 	}
    434        1.1       cgd 
    435        1.1       cgd 	if (state == FAILED)
    436        1.1       cgd 		state = IN_PROGRESS;
    437        1.1       cgd 
    438        1.1       cgd 	state &= ~NO_KEYID;
    439        1.1       cgd 
    440        1.1       cgd 	return(fbp->state[dir-1] = state);
    441        1.1       cgd }
    442        1.1       cgd 
    443       1.16      matt void
    444       1.15  christos fb64_printsub(const unsigned char *data, int cnt, unsigned char *buf,
    445       1.15  christos     int buflen, const unsigned char *type)
    446        1.1       cgd {
    447        1.1       cgd 	char lbuf[32];
    448        1.1       cgd 	register int i;
    449        1.1       cgd 	char *cp;
    450        1.1       cgd 
    451        1.1       cgd 	buf[buflen-1] = '\0';		/* make sure it's NULL terminated */
    452        1.1       cgd 	buflen -= 1;
    453        1.1       cgd 
    454        1.1       cgd 	switch(data[2]) {
    455        1.1       cgd 	case FB64_IV:
    456       1.10    itojun 		snprintf(lbuf, sizeof(lbuf), "%s_IV", type);
    457        1.1       cgd 		cp = lbuf;
    458        1.1       cgd 		goto common;
    459        1.1       cgd 
    460        1.1       cgd 	case FB64_IV_OK:
    461       1.10    itojun 		snprintf(lbuf, sizeof(lbuf), "%s_IV_OK", type);
    462        1.1       cgd 		cp = lbuf;
    463        1.1       cgd 		goto common;
    464        1.1       cgd 
    465        1.1       cgd 	case FB64_IV_BAD:
    466       1.10    itojun 		snprintf(lbuf, sizeof(lbuf), "%s_IV_BAD", type);
    467        1.1       cgd 		cp = lbuf;
    468        1.1       cgd 		goto common;
    469        1.1       cgd 
    470        1.1       cgd 	default:
    471       1.10    itojun 		snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[2]);
    472        1.1       cgd 		cp = lbuf;
    473        1.1       cgd 	common:
    474        1.1       cgd 		for (; (buflen > 0) && (*buf = *cp++); buf++)
    475        1.1       cgd 			buflen--;
    476        1.1       cgd 		for (i = 3; i < cnt; i++) {
    477       1.10    itojun 			snprintf(lbuf, sizeof(lbuf), " %d", data[i]);
    478        1.1       cgd 			for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
    479        1.1       cgd 				buflen--;
    480        1.1       cgd 		}
    481        1.1       cgd 		break;
    482        1.1       cgd 	}
    483        1.1       cgd }
    484        1.1       cgd 
    485       1.16      matt void
    486       1.16      matt cfb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
    487        1.1       cgd {
    488        1.1       cgd 	fb64_printsub(data, cnt, buf, buflen, "CFB64");
    489        1.1       cgd }
    490        1.1       cgd 
    491        1.1       cgd 	void
    492       1.16      matt ofb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
    493        1.1       cgd {
    494        1.1       cgd 	fb64_printsub(data, cnt, buf, buflen, "OFB64");
    495        1.1       cgd }
    496        1.1       cgd 
    497       1.16      matt void
    498       1.16      matt fb64_stream_iv(Block seed, struct stinfo *stp)
    499        1.1       cgd {
    500        1.1       cgd 
    501        1.4   thorpej 	memmove((void *)stp->str_iv, (void *)seed, sizeof(Block));
    502        1.4   thorpej 	memmove((void *)stp->str_output, (void *)seed, sizeof(Block));
    503        1.1       cgd 
    504        1.4   thorpej 	des_key_sched(&stp->str_ikey, stp->str_sched);
    505        1.1       cgd 
    506        1.1       cgd 	stp->str_index = sizeof(Block);
    507        1.1       cgd }
    508        1.1       cgd 
    509       1.16      matt void
    510       1.16      matt fb64_stream_key(Block *key, struct stinfo *stp)
    511        1.1       cgd {
    512        1.4   thorpej 	memmove((void *)stp->str_ikey, (void *)key, sizeof(Block));
    513        1.1       cgd 	des_key_sched(key, stp->str_sched);
    514        1.1       cgd 
    515        1.4   thorpej 	memmove((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
    516        1.1       cgd 
    517        1.1       cgd 	stp->str_index = sizeof(Block);
    518        1.1       cgd }
    519        1.1       cgd 
    520        1.1       cgd /*
    521        1.1       cgd  * DES 64 bit Cipher Feedback
    522        1.1       cgd  *
    523        1.1       cgd  *     key --->+-----+
    524        1.1       cgd  *          +->| DES |--+
    525        1.1       cgd  *          |  +-----+  |
    526        1.1       cgd  *	    |           v
    527        1.1       cgd  *  INPUT --(--------->(+)+---> DATA
    528        1.1       cgd  *          |             |
    529        1.1       cgd  *	    +-------------+
    530        1.4   thorpej  *
    531        1.1       cgd  *
    532        1.1       cgd  * Given:
    533        1.1       cgd  *	iV: Initial vector, 64 bits (8 bytes) long.
    534        1.1       cgd  *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
    535        1.1       cgd  *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
    536        1.1       cgd  *
    537        1.1       cgd  *	V0 = DES(iV, key)
    538        1.1       cgd  *	On = Dn ^ Vn
    539        1.1       cgd  *	V(n+1) = DES(On, key)
    540        1.1       cgd  */
    541        1.1       cgd 
    542       1.16      matt void
    543       1.16      matt cfb64_encrypt(unsigned char *s, int c)
    544        1.1       cgd {
    545        1.1       cgd 	register struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
    546        1.6     lukem 	register int idx;
    547        1.1       cgd 
    548        1.6     lukem 	idx = stp->str_index;
    549        1.1       cgd 	while (c-- > 0) {
    550        1.6     lukem 		if (idx == sizeof(Block)) {
    551        1.1       cgd 			Block b;
    552        1.4   thorpej 			des_ecb_encrypt(&stp->str_output, &b, stp->str_sched, 1);
    553        1.4   thorpej 			memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
    554        1.6     lukem 			idx = 0;
    555        1.1       cgd 		}
    556        1.1       cgd 
    557        1.1       cgd 		/* On encryption, we store (feed ^ data) which is cypher */
    558        1.6     lukem 		*s = stp->str_output[idx] = (stp->str_feed[idx] ^ *s);
    559        1.1       cgd 		s++;
    560        1.6     lukem 		idx++;
    561        1.1       cgd 	}
    562        1.6     lukem 	stp->str_index = idx;
    563        1.1       cgd }
    564        1.1       cgd 
    565       1.16      matt int
    566       1.16      matt cfb64_decrypt(int data)
    567        1.1       cgd {
    568        1.1       cgd 	register struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1];
    569        1.6     lukem 	int idx;
    570        1.1       cgd 
    571        1.1       cgd 	if (data == -1) {
    572        1.1       cgd 		/*
    573        1.1       cgd 		 * Back up one byte.  It is assumed that we will
    574        1.1       cgd 		 * never back up more than one byte.  If we do, this
    575        1.1       cgd 		 * may or may not work.
    576        1.1       cgd 		 */
    577        1.1       cgd 		if (stp->str_index)
    578        1.1       cgd 			--stp->str_index;
    579        1.1       cgd 		return(0);
    580        1.1       cgd 	}
    581        1.1       cgd 
    582        1.6     lukem 	idx = stp->str_index++;
    583        1.6     lukem 	if (idx == sizeof(Block)) {
    584        1.1       cgd 		Block b;
    585        1.4   thorpej 		des_ecb_encrypt(&stp->str_output, &b, stp->str_sched, 1);
    586        1.4   thorpej 		memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
    587        1.1       cgd 		stp->str_index = 1;	/* Next time will be 1 */
    588        1.6     lukem 		idx = 0;		/* But now use 0 */
    589        1.1       cgd 	}
    590        1.1       cgd 
    591        1.1       cgd 	/* On decryption we store (data) which is cypher. */
    592        1.6     lukem 	stp->str_output[idx] = data;
    593        1.6     lukem 	return(data ^ stp->str_feed[idx]);
    594        1.1       cgd }
    595        1.1       cgd 
    596        1.1       cgd /*
    597        1.1       cgd  * DES 64 bit Output Feedback
    598        1.1       cgd  *
    599        1.1       cgd  * key --->+-----+
    600        1.1       cgd  *	+->| DES |--+
    601        1.1       cgd  *	|  +-----+  |
    602        1.1       cgd  *	+-----------+
    603        1.1       cgd  *	            v
    604        1.1       cgd  *  INPUT -------->(+) ----> DATA
    605        1.1       cgd  *
    606        1.1       cgd  * Given:
    607        1.1       cgd  *	iV: Initial vector, 64 bits (8 bytes) long.
    608        1.1       cgd  *	Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
    609        1.1       cgd  *	On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
    610        1.1       cgd  *
    611        1.1       cgd  *	V0 = DES(iV, key)
    612        1.1       cgd  *	V(n+1) = DES(Vn, key)
    613        1.1       cgd  *	On = Dn ^ Vn
    614        1.1       cgd  */
    615       1.16      matt void
    616       1.16      matt ofb64_encrypt(unsigned char *s, int c)
    617        1.1       cgd {
    618        1.1       cgd 	register struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
    619        1.6     lukem 	register int idx;
    620        1.1       cgd 
    621        1.6     lukem 	idx = stp->str_index;
    622        1.1       cgd 	while (c-- > 0) {
    623        1.6     lukem 		if (idx == sizeof(Block)) {
    624        1.1       cgd 			Block b;
    625        1.4   thorpej 			des_ecb_encrypt(&stp->str_feed, &b, stp->str_sched, 1);
    626        1.4   thorpej 			memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
    627        1.6     lukem 			idx = 0;
    628        1.1       cgd 		}
    629        1.6     lukem 		*s++ ^= stp->str_feed[idx];
    630        1.6     lukem 		idx++;
    631        1.1       cgd 	}
    632        1.6     lukem 	stp->str_index = idx;
    633        1.1       cgd }
    634        1.1       cgd 
    635       1.16      matt int
    636       1.16      matt ofb64_decrypt(int data)
    637        1.1       cgd {
    638        1.1       cgd 	register struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1];
    639        1.6     lukem 	int idx;
    640        1.1       cgd 
    641        1.1       cgd 	if (data == -1) {
    642        1.1       cgd 		/*
    643        1.1       cgd 		 * Back up one byte.  It is assumed that we will
    644        1.1       cgd 		 * never back up more than one byte.  If we do, this
    645        1.1       cgd 		 * may or may not work.
    646        1.1       cgd 		 */
    647        1.1       cgd 		if (stp->str_index)
    648        1.1       cgd 			--stp->str_index;
    649        1.1       cgd 		return(0);
    650        1.1       cgd 	}
    651        1.1       cgd 
    652        1.6     lukem 	idx = stp->str_index++;
    653        1.6     lukem 	if (idx == sizeof(Block)) {
    654        1.1       cgd 		Block b;
    655        1.4   thorpej 		des_ecb_encrypt(&stp->str_feed, &b, stp->str_sched, 1);
    656        1.4   thorpej 		memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
    657        1.1       cgd 		stp->str_index = 1;	/* Next time will be 1 */
    658        1.6     lukem 		idx = 0;		/* But now use 0 */
    659        1.1       cgd 	}
    660        1.1       cgd 
    661        1.6     lukem 	return(data ^ stp->str_feed[idx]);
    662        1.1       cgd }
    663        1.4   thorpej #  endif /* DES_ENCRYPTION */
    664        1.4   thorpej # endif	/* AUTHENTICATION */
    665        1.4   thorpej #endif	/* ENCRYPTION */
    666