summaryrefslogtreecommitdiffstats
path: root/src/windows/wintel/enc_des.c
diff options
context:
space:
mode:
authorRichard Basch <probe@mit.edu>1997-02-06 02:31:41 +0000
committerRichard Basch <probe@mit.edu>1997-02-06 02:31:41 +0000
commita0b9ce4bee60136363cfff7a93c4e42eab972c02 (patch)
tree400984337fe3766653ff4cc2cb6b7d3d7f87f3f4 /src/windows/wintel/enc_des.c
parenta9266b1dec31de9f33b0d032b885edd377a23ee5 (diff)
downloadkrb5-a0b9ce4bee60136363cfff7a93c4e42eab972c02.tar.gz
krb5-a0b9ce4bee60136363cfff7a93c4e42eab972c02.tar.xz
krb5-a0b9ce4bee60136363cfff7a93c4e42eab972c02.zip
Windows/NT integration (V1_0_WIN32_BRANCH merge)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@9788 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/windows/wintel/enc_des.c')
-rw-r--r--src/windows/wintel/enc_des.c725
1 files changed, 725 insertions, 0 deletions
diff --git a/src/windows/wintel/enc_des.c b/src/windows/wintel/enc_des.c
new file mode 100644
index 0000000000..8357dba7c1
--- /dev/null
+++ b/src/windows/wintel/enc_des.c
@@ -0,0 +1,725 @@
+/*-
+ * 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 */
+
+#ifdef ENCRYPTION
+
+#include "telnet_arpa.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "telnet.h"
+
+#include "encrypt.h"
+
+#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
+
+
+struct fb {
+ Block krbdes_key;
+ Schedule krbdes_sched;
+ Block temp_feed;
+ unsigned char fb_feed[64];
+ int need_start;
+ int state[2];
+ int keyid[2];
+ int once;
+ struct stinfo {
+ Block str_output;
+ Block str_feed;
+ Block str_iv;
+ Block str_ikey;
+ Schedule str_sched;
+ int str_index;
+ int str_flagshift;
+ } 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
+
+extern kstream EncryptKSGlobalHack;
+
+void fb64_stream_iv P((Block, struct stinfo *));
+void fb64_init P((struct fb *));
+static int fb64_start P((struct fb *, int, int));
+int fb64_is P((unsigned char *, int, struct fb *));
+int fb64_reply P((unsigned char *, int, struct fb *));
+static void fb64_session P((Session_Key *, int, struct fb *));
+void fb64_stream_key P((Block, struct stinfo *));
+int fb64_keyid P((int, unsigned char *, int *, struct fb *));
+
+ void
+cfb64_init(server)
+ 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(server)
+ 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(fbp)
+ register struct 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_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(dir, server)
+ int dir;
+ int server;
+{
+ return(fb64_start(&fb[CFB], dir, server));
+}
+ int
+ofb64_start(dir, server)
+ int dir;
+ int server;
+{
+ return(fb64_start(&fb[OFB], dir, server));
+}
+
+ static int
+fb64_start(fbp, dir, server)
+ struct 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)) {
+ 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);
+ 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(Block); ++x) {
+ if ((*p++ = fbp->temp_feed[x]) == IAC)
+ *p++ = IAC;
+ }
+ *p++ = IAC;
+ *p++ = SE;
+#ifdef DEBUG
+ printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+#endif
+ TelnetSend(EncryptKSGlobalHack, fbp->fb_feed, p - fbp->fb_feed, 0);
+ 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, &fb[CFB]));
+}
+ int
+ofb64_is(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(fb64_is(data, cnt, &fb[OFB]));
+}
+
+ int
+fb64_is(data, cnt, fbp)
+ unsigned char *data;
+ int cnt;
+ struct fb *fbp;
+{
+ unsigned char *p;
+ register int state = fbp->state[DIR_DECRYPT-1];
+
+ if (cnt-- < 1)
+ goto failure;
+
+ 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;
+#ifdef DEBUG
+ printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+#endif
+ TelnetSend(EncryptKSGlobalHack, fbp->fb_feed, p - fbp->fb_feed, 0);
+
+ state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
+ 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:
+ /*
+ * 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;
+#ifdef DEBUG
+ printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
+#endif
+ TelnetSend(EncryptKSGlobalHack, fbp->fb_feed, p - fbp->fb_feed, 0);
+
+ 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, &fb[CFB]));
+}
+ int
+ofb64_reply(data, cnt)
+ unsigned char *data;
+ int cnt;
+{
+ return(fb64_reply(data, cnt, &fb[OFB]));
+}
+
+
+ int
+fb64_reply(data, cnt, fbp)
+ unsigned char *data;
+ int cnt;
+ struct 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]);
+ printd(data, cnt);
+ printf("\r\n");
+ }
+#endif
+ /* FALL THROUGH */
+ failure:
+ state = xFAILED;
+ break;
+ }
+ return(fbp->state[DIR_ENCRYPT-1] = state);
+}
+
+ void
+cfb64_session(key, server)
+ Session_Key *key;
+ int server;
+{
+ fb64_session(key, server, &fb[CFB]);
+}
+
+ void
+ofb64_session(key, server)
+ Session_Key *key;
+ int server;
+{
+ fb64_session(key, server, &fb[OFB]);
+}
+
+ static void
+fb64_session(key, server, fbp)
+ Session_Key *key;
+ int server;
+ struct fb *fbp;
+{
+
+ if (!key || key->type != SK_DES) {
+#ifdef DEBUG
+ if (encrypt_debug_mode)
+ printf("Can't set krbdes's session key (%d != %d)\r\n",
+ key ? key->type : -1, SK_DES);
+#endif
+ return;
+ }
+ memcpy((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
+
+ 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) {
+ des_set_random_generator_seed(fbp->krbdes_key);
+ 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(dir, kp, lenp)
+ int dir, *lenp;
+ unsigned char *kp;
+{
+ return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
+}
+
+ int
+ofb64_keyid(dir, kp, lenp)
+ int dir, *lenp;
+ unsigned char *kp;
+{
+ return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
+}
+
+ int
+fb64_keyid(dir, kp, lenp, fbp)
+ int dir, *lenp;
+ unsigned char *kp;
+ struct 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[32];
+ 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
+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 stinfo *stp;
+{
+
+ memcpy((void *)stp->str_iv, (void *)seed, sizeof(Block));
+ memcpy((void *)stp->str_output, (void *)seed, sizeof(Block));
+
+ des_key_sched(stp->str_ikey, stp->str_sched);
+
+ stp->str_index = sizeof(Block);
+}
+
+ void
+fb64_stream_key(key, stp)
+ Block key;
+ register struct stinfo *stp;
+{
+ memcpy((void *)stp->str_ikey, (void *)key, sizeof(Block));
+ des_key_sched(key, stp->str_sched);
+
+ memcpy((void *)stp->str_output, (void *)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 stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
+ register int index;
+
+ index = stp->str_index;
+ while (c-- > 0) {
+ if (index == sizeof(Block)) {
+ Block b;
+ des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1);
+ 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;
+}
+
+ int
+cfb64_decrypt(data)
+ int data;
+{
+ register 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(Block)) {
+ Block b;
+ des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1);
+ 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]);
+}
+
+/*
+ * 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 stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
+ register int index;
+
+ index = stp->str_index;
+ while (c-- > 0) {
+ if (index == sizeof(Block)) {
+ Block b;
+ des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1);
+ memcpy((void *)stp->str_feed,(void *)b,sizeof(Block));
+ index = 0;
+ }
+ *s++ ^= stp->str_feed[index];
+ index++;
+ }
+ stp->str_index = index;
+}
+
+ int
+ofb64_decrypt(data)
+ int data;
+{
+ register 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(Block)) {
+ Block b;
+ des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1);
+ 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]);
+}
+
+#endif /* ENCRYPTION */