summaryrefslogtreecommitdiffstats
path: root/crypto/kerberosIV/appl/telnet/libtelnet/enc_des.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/kerberosIV/appl/telnet/libtelnet/enc_des.c')
-rw-r--r--crypto/kerberosIV/appl/telnet/libtelnet/enc_des.c671
1 files changed, 671 insertions, 0 deletions
diff --git a/crypto/kerberosIV/appl/telnet/libtelnet/enc_des.c b/crypto/kerberosIV/appl/telnet/libtelnet/enc_des.c
new file mode 100644
index 0000000..a24bfa7
--- /dev/null
+++ b/crypto/kerberosIV/appl/telnet/libtelnet/enc_des.c
@@ -0,0 +1,671 @@
+/*-
+ * 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.
+ */
+
+#include <config.h>
+
+RCSID("$Id: enc_des.c,v 1.16 1998/07/09 23:16:23 assar Exp $");
+
+#if defined(AUTHENTICATION) && defined(ENCRYPTION) && defined(DES_ENCRYPTION)
+#include <arpa/telnet.h>
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#endif
+#include <roken.h>
+#ifdef SOCKS
+#include <socks.h>
+#endif
+
+#include "encrypt.h"
+#include "misc-proto.h"
+
+#include <des.h>
+
+extern int encrypt_debug_mode;
+
+#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 FAILED -1
+
+
+struct stinfo {
+ des_cblock str_output;
+ des_cblock str_feed;
+ des_cblock str_iv;
+ des_cblock str_ikey;
+ des_key_schedule str_sched;
+ int str_index;
+ int str_flagshift;
+};
+
+struct fb {
+ des_cblock krbdes_key;
+ des_key_schedule krbdes_sched;
+ des_cblock temp_feed;
+ unsigned char fb_feed[64];
+ int need_start;
+ int state[2];
+ int keyid[2];
+ int once;
+ struct stinfo streams[2];
+};
+
+static struct fb 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
+
+
+void fb64_stream_iv (des_cblock, struct stinfo *);
+void fb64_init (struct fb *);
+static int fb64_start (struct fb *, int, int);
+int fb64_is (unsigned char *, int, struct fb *);
+int fb64_reply (unsigned char *, int, struct fb *);
+static void fb64_session (Session_Key *, int, struct fb *);
+void fb64_stream_key (des_cblock, struct stinfo *);
+int fb64_keyid (int, unsigned char *, int *, struct fb *);
+
+void cfb64_init(int server)
+{
+ fb64_init(&fb[CFB]);
+ fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
+ fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
+ fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
+}
+
+
+void ofb64_init(int server)
+{
+ fb64_init(&fb[OFB]);
+ fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
+ fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
+ fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
+}
+
+void fb64_init(struct fb *fbp)
+{
+ memset(fbp,0, sizeof(*fbp));
+ fbp->state[0] = fbp->state[1] = FAILED;
+ fbp->fb_feed[0] = IAC;
+ fbp->fb_feed[1] = SB;
+ fbp->fb_feed[2] = TELOPT_ENCRYPT;
+ 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(int dir, int server)
+{
+ return(fb64_start(&fb[CFB], dir, server));
+}
+
+int ofb64_start(int dir, int server)
+{
+ return(fb64_start(&fb[OFB], dir, server));
+}
+
+static int fb64_start(struct fb *fbp, int dir, int server)
+{
+ int x;
+ unsigned char *p;
+ 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 == FAILED)
+ state = IN_PROGRESS;
+ break;
+
+ case DIR_ENCRYPT:
+ state = fbp->state[dir-1];
+ if (state == FAILED)
+ state = IN_PROGRESS;
+ else if ((state & NO_SEND_IV) == 0) {
+ break;
+ }
+
+ if (!VALIDKEY(fbp->krbdes_key)) {
+ fbp->need_start = 1;
+ break;
+ }
+
+ state &= ~NO_SEND_IV;
+ state |= NO_RECV_IV;
+ if (encrypt_debug_mode)
+ printf("Creating new feed\r\n");
+ /*
+ * Create a random feed and send it over.
+ */
+#ifndef OLD_DES_RANDOM_KEY
+ des_new_random_key(&fbp->temp_feed);
+#else
+ /*
+ * From des_cryp.man "If the des_check_key flag is non-zero,
+ * des_set_key will check that the key passed is
+ * of odd parity and is not a week or semi-weak key."
+ */
+ do {
+ des_random_key(fbp->temp_feed);
+ des_set_odd_parity(fbp->temp_feed);
+ } while (des_is_weak_key(fbp->temp_feed));
+#endif
+ des_ecb_encrypt(&fbp->temp_feed,
+ &fbp->temp_feed,
+ fbp->krbdes_sched, 1);
+ p = fbp->fb_feed + 3;
+ *p++ = ENCRYPT_IS;
+ p++;
+ *p++ = FB64_IV;
+ for (x = 0; x < sizeof(des_cblock); ++x) {
+ if ((*p++ = fbp->temp_feed[x]) == IAC)
+ *p++ = IAC;
+ }
+ *p++ = IAC;
+ *p++ = SE;
+ printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+ telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
+ break;
+ default:
+ return(FAILED);
+ }
+ 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(unsigned char *data, int cnt)
+{
+ return(fb64_is(data, cnt, &fb[CFB]));
+}
+
+int ofb64_is(unsigned char *data, int cnt)
+{
+ return(fb64_is(data, cnt, &fb[OFB]));
+}
+
+
+int fb64_is(unsigned char *data, int cnt, struct fb *fbp)
+{
+ unsigned char *p;
+ int state = fbp->state[DIR_DECRYPT-1];
+
+ if (cnt-- < 1)
+ goto failure;
+
+ switch (*data++) {
+ case FB64_IV:
+ if (cnt != sizeof(des_cblock)) {
+ if (encrypt_debug_mode)
+ printf("CFB64: initial vector failed on size\r\n");
+ state = FAILED;
+ goto failure;
+ }
+
+ if (encrypt_debug_mode)
+ printf("CFB64: initial vector received\r\n");
+
+ if (encrypt_debug_mode)
+ printf("Initializing Decrypt stream\r\n");
+
+ fb64_stream_iv(data, &fbp->streams[DIR_DECRYPT-1]);
+
+ p = fbp->fb_feed + 3;
+ *p++ = ENCRYPT_REPLY;
+ p++;
+ *p++ = FB64_IV_OK;
+ *p++ = IAC;
+ *p++ = SE;
+ printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+ telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
+
+ state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
+ break;
+
+ default:
+ if (encrypt_debug_mode) {
+ printf("Unknown option type: %d\r\n", *(data-1));
+ printd(data, cnt);
+ printf("\r\n");
+ }
+ /* 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;
+ printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+ telnet_net_write(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(unsigned char *data, int cnt)
+{
+ return(fb64_reply(data, cnt, &fb[CFB]));
+}
+
+int ofb64_reply(unsigned char *data, int cnt)
+{
+ return(fb64_reply(data, cnt, &fb[OFB]));
+}
+
+
+int fb64_reply(unsigned char *data, int cnt, struct fb *fbp)
+{
+ 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 == FAILED)
+ 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(des_cblock));
+ fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
+ state = FAILED;
+ break;
+
+ default:
+ if (encrypt_debug_mode) {
+ printf("Unknown option type: %d\r\n", data[-1]);
+ printd(data, cnt);
+ printf("\r\n");
+ }
+ /* FALL THROUGH */
+ failure:
+ state = FAILED;
+ break;
+ }
+ return(fbp->state[DIR_ENCRYPT-1] = state);
+}
+
+void cfb64_session(Session_Key *key, int server)
+{
+ fb64_session(key, server, &fb[CFB]);
+}
+
+void ofb64_session(Session_Key *key, int server)
+{
+ fb64_session(key, server, &fb[OFB]);
+}
+
+static void fb64_session(Session_Key *key, int server, struct fb *fbp)
+{
+
+ if (!key || key->type != SK_DES) {
+ if (encrypt_debug_mode)
+ printf("Can't set krbdes's session key (%d != %d)\r\n",
+ key ? key->type : -1, SK_DES);
+ return;
+ }
+ memcpy(fbp->krbdes_key, key->data, sizeof(des_cblock));
+
+ fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
+ fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
+
+ if (fbp->once == 0) {
+#ifndef OLD_DES_RANDOM_KEY
+ des_init_random_number_generator(&fbp->krbdes_key);
+#endif
+ fbp->once = 1;
+ }
+ des_key_sched(&fbp->krbdes_key, fbp->krbdes_sched);
+ /*
+ * 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);
+ }
+}
+
+/*
+ * We only accept a keyid of 0. If we get a keyid of
+ * 0, then mark the state as SUCCESS.
+ */
+
+int cfb64_keyid(int dir, unsigned char *kp, int *lenp)
+{
+ return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
+}
+
+int ofb64_keyid(int dir, unsigned char *kp, int *lenp)
+{
+ return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
+}
+
+int fb64_keyid(int dir, unsigned char *kp, int *lenp, struct fb *fbp)
+{
+ int state = fbp->state[dir-1];
+
+ if (*lenp != 1 || (*kp != '\0')) {
+ *lenp = 0;
+ return(state);
+ }
+
+ if (state == FAILED)
+ state = IN_PROGRESS;
+
+ state &= ~NO_KEYID;
+
+ return(fbp->state[dir-1] = state);
+}
+
+void fb64_printsub(unsigned char *data, int cnt,
+ unsigned char *buf, int buflen, char *type)
+{
+ char lbuf[32];
+ int i;
+ char *cp;
+
+ buf[buflen-1] = '\0'; /* make sure it's NULL terminated */
+ buflen -= 1;
+
+ switch(data[2]) {
+ case FB64_IV:
+ snprintf(lbuf, sizeof(lbuf), "%s_IV", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_IV_OK:
+ snprintf(lbuf, sizeof(lbuf), "%s_IV_OK", type);
+ cp = lbuf;
+ goto common;
+
+ case FB64_IV_BAD:
+ snprintf(lbuf, sizeof(lbuf), "%s_IV_BAD", type);
+ cp = lbuf;
+ goto common;
+
+ default:
+ snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[2]);
+ cp = lbuf;
+ common:
+ for (; (buflen > 0) && (*buf = *cp++); buf++)
+ buflen--;
+ for (i = 3; i < cnt; i++) {
+ snprintf(lbuf, sizeof(lbuf), " %d", data[i]);
+ for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
+ buflen--;
+ }
+ break;
+ }
+}
+
+void cfb64_printsub(unsigned char *data, int cnt,
+ unsigned char *buf, int buflen)
+{
+ fb64_printsub(data, cnt, buf, buflen, "CFB64");
+}
+
+void ofb64_printsub(unsigned char *data, int cnt,
+ unsigned char *buf, int buflen)
+{
+ fb64_printsub(data, cnt, buf, buflen, "OFB64");
+}
+
+void fb64_stream_iv(des_cblock seed, struct stinfo *stp)
+{
+
+ memcpy(stp->str_iv, seed,sizeof(des_cblock));
+ memcpy(stp->str_output, seed, sizeof(des_cblock));
+
+ des_key_sched(&stp->str_ikey, stp->str_sched);
+
+ stp->str_index = sizeof(des_cblock);
+}
+
+void fb64_stream_key(des_cblock key, struct stinfo *stp)
+{
+ memcpy(stp->str_ikey, key, sizeof(des_cblock));
+ des_key_sched((des_cblock*)key, stp->str_sched);
+
+ memcpy(stp->str_output, stp->str_iv, sizeof(des_cblock));
+
+ stp->str_index = sizeof(des_cblock);
+}
+
+/*
+ * 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(unsigned char *s, int c)
+{
+ struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
+ int index;
+
+ index = stp->str_index;
+ while (c-- > 0) {
+ if (index == sizeof(des_cblock)) {
+ des_cblock b;
+ des_ecb_encrypt(&stp->str_output, &b,stp->str_sched, 1);
+ memcpy(stp->str_feed, b, sizeof(des_cblock));
+ 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(int data)
+{
+ struct stinfo *stp = &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(des_cblock)) {
+ des_cblock b;
+ des_ecb_encrypt(&stp->str_output,&b, stp->str_sched, 1);
+ memcpy(stp->str_feed, b, sizeof(des_cblock));
+ 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(unsigned char *s, int c)
+{
+ struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
+ int index;
+
+ index = stp->str_index;
+ while (c-- > 0) {
+ if (index == sizeof(des_cblock)) {
+ des_cblock b;
+ des_ecb_encrypt(&stp->str_feed,&b, stp->str_sched, 1);
+ memcpy(stp->str_feed, b, sizeof(des_cblock));
+ index = 0;
+ }
+ *s++ ^= stp->str_feed[index];
+ index++;
+ }
+ stp->str_index = index;
+}
+
+int ofb64_decrypt(int data)
+{
+ struct stinfo *stp = &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(des_cblock)) {
+ des_cblock b;
+ des_ecb_encrypt(&stp->str_feed,&b,stp->str_sched, 1);
+ memcpy(stp->str_feed, b, sizeof(des_cblock));
+ stp->str_index = 1; /* Next time will be 1 */
+ index = 0; /* But now use 0 */
+ }
+
+ return(data ^ stp->str_feed[index]);
+}
+#endif
+
OpenPOWER on IntegriCloud