157416Smarkm/*- 257416Smarkm * Copyright (c) 1991, 1993 357416Smarkm * The Regents of the University of California. All rights reserved. 457416Smarkm * 557416Smarkm * Redistribution and use in source and binary forms, with or without 657416Smarkm * modification, are permitted provided that the following conditions 757416Smarkm * are met: 857416Smarkm * 1. Redistributions of source code must retain the above copyright 957416Smarkm * notice, this list of conditions and the following disclaimer. 1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157416Smarkm * notice, this list of conditions and the following disclaimer in the 1257416Smarkm * documentation and/or other materials provided with the distribution. 1357416Smarkm * 3. All advertising materials mentioning features or use of this software 1457416Smarkm * must display the following acknowledgement: 1557416Smarkm * This product includes software developed by the University of 1657416Smarkm * California, Berkeley and its contributors. 1757416Smarkm * 4. Neither the name of the University nor the names of its contributors 1857416Smarkm * may be used to endorse or promote products derived from this software 1957416Smarkm * without specific prior written permission. 2057416Smarkm * 2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2457416Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3157416Smarkm * SUCH DAMAGE. 3257416Smarkm */ 3357416Smarkm 3457416Smarkm#include <config.h> 3557416Smarkm 36233294SstasRCSID("$Id$"); 3757416Smarkm 3857416Smarkm#if defined(AUTHENTICATION) && defined(ENCRYPTION) && defined(DES_ENCRYPTION) 3957416Smarkm#include <arpa/telnet.h> 4057416Smarkm#include <stdio.h> 4157416Smarkm#ifdef __STDC__ 4257416Smarkm#include <stdlib.h> 4357416Smarkm#include <string.h> 4457416Smarkm#endif 4557416Smarkm#include <roken.h> 4657416Smarkm#ifdef SOCKS 4757416Smarkm#include <socks.h> 4857416Smarkm#endif 4957416Smarkm 5057416Smarkm#include "encrypt.h" 5157416Smarkm#include "misc-proto.h" 5257416Smarkm 53103423Snectar#include "crypto-headers.h" 5457416Smarkm 5557416Smarkmextern int encrypt_debug_mode; 5657416Smarkm 5757416Smarkm#define CFB 0 5857416Smarkm#define OFB 1 5957416Smarkm 6057416Smarkm#define NO_SEND_IV 1 6157416Smarkm#define NO_RECV_IV 2 6257416Smarkm#define NO_KEYID 4 6357416Smarkm#define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID) 6457416Smarkm#define SUCCESS 0 6557416Smarkm#define FAILED -1 6657416Smarkm 6757416Smarkm 6857416Smarkmstruct stinfo { 69178825Sdfr DES_cblock str_output; 70178825Sdfr DES_cblock str_feed; 71178825Sdfr DES_cblock str_iv; 72178825Sdfr DES_cblock str_ikey; 73178825Sdfr DES_key_schedule str_sched; 7457416Smarkm int str_index; 7557416Smarkm int str_flagshift; 7657416Smarkm}; 7757416Smarkm 7857416Smarkmstruct fb { 79178825Sdfr DES_cblock krbdes_key; 80178825Sdfr DES_key_schedule krbdes_sched; 81178825Sdfr DES_cblock temp_feed; 8257416Smarkm unsigned char fb_feed[64]; 8357416Smarkm int need_start; 8457416Smarkm int state[2]; 8557416Smarkm int keyid[2]; 8657416Smarkm struct stinfo streams[2]; 8757416Smarkm}; 8857416Smarkm 8957416Smarkmstatic struct fb fb[2]; 9057416Smarkm 9157416Smarkmstruct keyidlist { 9257416Smarkm char *keyid; 9357416Smarkm int keyidlen; 9457416Smarkm char *key; 9557416Smarkm int keylen; 9657416Smarkm int flags; 9757416Smarkm} keyidlist [] = { 9857416Smarkm { "\0", 1, 0, 0, 0 }, /* default key of zero */ 9957416Smarkm { 0, 0, 0, 0, 0 } 10057416Smarkm}; 10157416Smarkm 10257416Smarkm#define KEYFLAG_MASK 03 10357416Smarkm 10457416Smarkm#define KEYFLAG_NOINIT 00 10557416Smarkm#define KEYFLAG_INIT 01 10657416Smarkm#define KEYFLAG_OK 02 10757416Smarkm#define KEYFLAG_BAD 03 10857416Smarkm 10957416Smarkm#define KEYFLAG_SHIFT 2 11057416Smarkm 11157416Smarkm#define SHIFT_VAL(a,b) (KEYFLAG_SHIFT*((a)+((b)*2))) 11257416Smarkm 11357416Smarkm#define FB64_IV 1 11457416Smarkm#define FB64_IV_OK 2 11557416Smarkm#define FB64_IV_BAD 3 11657416Smarkm 11757416Smarkm 118178825Sdfrvoid fb64_stream_iv (DES_cblock, struct stinfo *); 11957416Smarkmvoid fb64_init (struct fb *); 12057416Smarkmstatic int fb64_start (struct fb *, int, int); 12157416Smarkmint fb64_is (unsigned char *, int, struct fb *); 12257416Smarkmint fb64_reply (unsigned char *, int, struct fb *); 12357416Smarkmstatic void fb64_session (Session_Key *, int, struct fb *); 124178825Sdfrvoid fb64_stream_key (DES_cblock, struct stinfo *); 12557416Smarkmint fb64_keyid (int, unsigned char *, int *, struct fb *); 126233294Sstasvoid fb64_printsub(unsigned char *, size_t , 127233294Sstas unsigned char *, size_t , char *); 12857416Smarkm 12957416Smarkmvoid cfb64_init(int server) 13057416Smarkm{ 13157416Smarkm fb64_init(&fb[CFB]); 13257416Smarkm fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64; 13357416Smarkm fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB); 13457416Smarkm fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB); 13557416Smarkm} 13657416Smarkm 13757416Smarkm 13857416Smarkmvoid ofb64_init(int server) 13957416Smarkm{ 14057416Smarkm fb64_init(&fb[OFB]); 14157416Smarkm fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64; 14257416Smarkm fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB); 14357416Smarkm fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB); 14457416Smarkm} 14557416Smarkm 14657416Smarkmvoid fb64_init(struct fb *fbp) 14757416Smarkm{ 14857416Smarkm memset(fbp,0, sizeof(*fbp)); 14957416Smarkm fbp->state[0] = fbp->state[1] = FAILED; 15057416Smarkm fbp->fb_feed[0] = IAC; 15157416Smarkm fbp->fb_feed[1] = SB; 15257416Smarkm fbp->fb_feed[2] = TELOPT_ENCRYPT; 15357416Smarkm fbp->fb_feed[3] = ENCRYPT_IS; 15457416Smarkm} 15557416Smarkm 15657416Smarkm/* 15757416Smarkm * Returns: 15857416Smarkm * -1: some error. Negotiation is done, encryption not ready. 15957416Smarkm * 0: Successful, initial negotiation all done. 16057416Smarkm * 1: successful, negotiation not done yet. 16157416Smarkm * 2: Not yet. Other things (like getting the key from 16257416Smarkm * Kerberos) have to happen before we can continue. 16357416Smarkm */ 16457416Smarkmint cfb64_start(int dir, int server) 16557416Smarkm{ 16657416Smarkm return(fb64_start(&fb[CFB], dir, server)); 16757416Smarkm} 16857416Smarkm 16957416Smarkmint ofb64_start(int dir, int server) 17057416Smarkm{ 17157416Smarkm return(fb64_start(&fb[OFB], dir, server)); 17257416Smarkm} 17357416Smarkm 17457416Smarkmstatic int fb64_start(struct fb *fbp, int dir, int server) 17557416Smarkm{ 17657416Smarkm int x; 17757416Smarkm unsigned char *p; 17857416Smarkm int state; 17957416Smarkm 18057416Smarkm switch (dir) { 18157416Smarkm case DIR_DECRYPT: 18257416Smarkm /* 18357416Smarkm * This is simply a request to have the other side 18457416Smarkm * start output (our input). He will negotiate an 18557416Smarkm * IV so we need not look for it. 18657416Smarkm */ 18757416Smarkm state = fbp->state[dir-1]; 18857416Smarkm if (state == FAILED) 18957416Smarkm state = IN_PROGRESS; 19057416Smarkm break; 19157416Smarkm 19257416Smarkm case DIR_ENCRYPT: 19357416Smarkm state = fbp->state[dir-1]; 19457416Smarkm if (state == FAILED) 19557416Smarkm state = IN_PROGRESS; 19657416Smarkm else if ((state & NO_SEND_IV) == 0) { 19757416Smarkm break; 19857416Smarkm } 19957416Smarkm 20057416Smarkm if (!VALIDKEY(fbp->krbdes_key)) { 20157416Smarkm fbp->need_start = 1; 20257416Smarkm break; 20357416Smarkm } 20457416Smarkm 20557416Smarkm state &= ~NO_SEND_IV; 20657416Smarkm state |= NO_RECV_IV; 20757416Smarkm if (encrypt_debug_mode) 20857416Smarkm printf("Creating new feed\r\n"); 20957416Smarkm /* 21057416Smarkm * Create a random feed and send it over. 21157416Smarkm */ 21257416Smarkm do { 213233294Sstas if (RAND_bytes(fbp->temp_feed, 214233294Sstas sizeof(*fbp->temp_feed)) != 1) 215233294Sstas abort(); 216233294Sstas DES_set_odd_parity(&fbp->temp_feed); 217233294Sstas } while(DES_is_weak_key(&fbp->temp_feed)); 218233294Sstas 21957416Smarkm p = fbp->fb_feed + 3; 22057416Smarkm *p++ = ENCRYPT_IS; 22157416Smarkm p++; 22257416Smarkm *p++ = FB64_IV; 223178825Sdfr for (x = 0; x < sizeof(DES_cblock); ++x) { 22457416Smarkm if ((*p++ = fbp->temp_feed[x]) == IAC) 22557416Smarkm *p++ = IAC; 22657416Smarkm } 22757416Smarkm *p++ = IAC; 22857416Smarkm *p++ = SE; 22957416Smarkm printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); 23057416Smarkm telnet_net_write(fbp->fb_feed, p - fbp->fb_feed); 23157416Smarkm break; 23257416Smarkm default: 23357416Smarkm return(FAILED); 23457416Smarkm } 23557416Smarkm return(fbp->state[dir-1] = state); 23657416Smarkm} 23757416Smarkm 23857416Smarkm/* 23957416Smarkm * Returns: 24057416Smarkm * -1: some error. Negotiation is done, encryption not ready. 24157416Smarkm * 0: Successful, initial negotiation all done. 24257416Smarkm * 1: successful, negotiation not done yet. 24357416Smarkm */ 24457416Smarkm 24557416Smarkmint cfb64_is(unsigned char *data, int cnt) 24657416Smarkm{ 24757416Smarkm return(fb64_is(data, cnt, &fb[CFB])); 24857416Smarkm} 24957416Smarkm 25057416Smarkmint ofb64_is(unsigned char *data, int cnt) 25157416Smarkm{ 25257416Smarkm return(fb64_is(data, cnt, &fb[OFB])); 25357416Smarkm} 25457416Smarkm 25557416Smarkm 25657416Smarkmint fb64_is(unsigned char *data, int cnt, struct fb *fbp) 25757416Smarkm{ 25857416Smarkm unsigned char *p; 25957416Smarkm int state = fbp->state[DIR_DECRYPT-1]; 26057416Smarkm 26157416Smarkm if (cnt-- < 1) 26257416Smarkm goto failure; 26357416Smarkm 26457416Smarkm switch (*data++) { 26557416Smarkm case FB64_IV: 266178825Sdfr if (cnt != sizeof(DES_cblock)) { 26757416Smarkm if (encrypt_debug_mode) 26857416Smarkm printf("CFB64: initial vector failed on size\r\n"); 26957416Smarkm state = FAILED; 27057416Smarkm goto failure; 27157416Smarkm } 27257416Smarkm 27357416Smarkm if (encrypt_debug_mode) 27457416Smarkm printf("CFB64: initial vector received\r\n"); 27557416Smarkm 27657416Smarkm if (encrypt_debug_mode) 27757416Smarkm printf("Initializing Decrypt stream\r\n"); 27857416Smarkm 27957416Smarkm fb64_stream_iv(data, &fbp->streams[DIR_DECRYPT-1]); 28057416Smarkm 28157416Smarkm p = fbp->fb_feed + 3; 28257416Smarkm *p++ = ENCRYPT_REPLY; 28357416Smarkm p++; 28457416Smarkm *p++ = FB64_IV_OK; 28557416Smarkm *p++ = IAC; 28657416Smarkm *p++ = SE; 28757416Smarkm printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); 28857416Smarkm telnet_net_write(fbp->fb_feed, p - fbp->fb_feed); 28957416Smarkm 29057416Smarkm state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS; 29157416Smarkm break; 29257416Smarkm 29357416Smarkm default: 29457416Smarkm if (encrypt_debug_mode) { 29557416Smarkm printf("Unknown option type: %d\r\n", *(data-1)); 29657416Smarkm printd(data, cnt); 29757416Smarkm printf("\r\n"); 29857416Smarkm } 29957416Smarkm /* FALL THROUGH */ 30057416Smarkm failure: 30157416Smarkm /* 30257416Smarkm * We failed. Send an FB64_IV_BAD option 30357416Smarkm * to the other side so it will know that 30457416Smarkm * things failed. 30557416Smarkm */ 30657416Smarkm p = fbp->fb_feed + 3; 30757416Smarkm *p++ = ENCRYPT_REPLY; 30857416Smarkm p++; 30957416Smarkm *p++ = FB64_IV_BAD; 31057416Smarkm *p++ = IAC; 31157416Smarkm *p++ = SE; 31257416Smarkm printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]); 31357416Smarkm telnet_net_write(fbp->fb_feed, p - fbp->fb_feed); 31457416Smarkm 31557416Smarkm break; 31657416Smarkm } 31757416Smarkm return(fbp->state[DIR_DECRYPT-1] = state); 31857416Smarkm} 31957416Smarkm 32057416Smarkm/* 32157416Smarkm * Returns: 32257416Smarkm * -1: some error. Negotiation is done, encryption not ready. 32357416Smarkm * 0: Successful, initial negotiation all done. 32457416Smarkm * 1: successful, negotiation not done yet. 32557416Smarkm */ 32657416Smarkm 32757416Smarkmint cfb64_reply(unsigned char *data, int cnt) 32857416Smarkm{ 32957416Smarkm return(fb64_reply(data, cnt, &fb[CFB])); 33057416Smarkm} 33157416Smarkm 33257416Smarkmint ofb64_reply(unsigned char *data, int cnt) 33357416Smarkm{ 33457416Smarkm return(fb64_reply(data, cnt, &fb[OFB])); 33557416Smarkm} 33657416Smarkm 33757416Smarkm 33857416Smarkmint fb64_reply(unsigned char *data, int cnt, struct fb *fbp) 33957416Smarkm{ 34057416Smarkm int state = fbp->state[DIR_ENCRYPT-1]; 34157416Smarkm 34257416Smarkm if (cnt-- < 1) 34357416Smarkm goto failure; 34457416Smarkm 34557416Smarkm switch (*data++) { 34657416Smarkm case FB64_IV_OK: 34757416Smarkm fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); 34857416Smarkm if (state == FAILED) 34957416Smarkm state = IN_PROGRESS; 35057416Smarkm state &= ~NO_RECV_IV; 35157416Smarkm encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1); 35257416Smarkm break; 35357416Smarkm 35457416Smarkm case FB64_IV_BAD: 355178825Sdfr memset(fbp->temp_feed, 0, sizeof(DES_cblock)); 35657416Smarkm fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]); 35757416Smarkm state = FAILED; 35857416Smarkm break; 35957416Smarkm 36057416Smarkm default: 36157416Smarkm if (encrypt_debug_mode) { 36257416Smarkm printf("Unknown option type: %d\r\n", data[-1]); 36357416Smarkm printd(data, cnt); 36457416Smarkm printf("\r\n"); 36557416Smarkm } 36657416Smarkm /* FALL THROUGH */ 36757416Smarkm failure: 36857416Smarkm state = FAILED; 36957416Smarkm break; 37057416Smarkm } 37157416Smarkm return(fbp->state[DIR_ENCRYPT-1] = state); 37257416Smarkm} 37357416Smarkm 37457416Smarkmvoid cfb64_session(Session_Key *key, int server) 37557416Smarkm{ 37657416Smarkm fb64_session(key, server, &fb[CFB]); 37757416Smarkm} 37857416Smarkm 37957416Smarkmvoid ofb64_session(Session_Key *key, int server) 38057416Smarkm{ 38157416Smarkm fb64_session(key, server, &fb[OFB]); 38257416Smarkm} 38357416Smarkm 38457416Smarkmstatic void fb64_session(Session_Key *key, int server, struct fb *fbp) 38557416Smarkm{ 38657416Smarkm 38757416Smarkm if (!key || key->type != SK_DES) { 38857416Smarkm if (encrypt_debug_mode) 38957416Smarkm printf("Can't set krbdes's session key (%d != %d)\r\n", 39057416Smarkm key ? key->type : -1, SK_DES); 39157416Smarkm return; 39257416Smarkm } 393178825Sdfr memcpy(fbp->krbdes_key, key->data, sizeof(DES_cblock)); 39457416Smarkm 39557416Smarkm fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]); 39657416Smarkm fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]); 39757416Smarkm 398233294Sstas RAND_seed(key->data, key->length); 399233294Sstas 400178825Sdfr DES_set_key_checked((DES_cblock *)&fbp->krbdes_key, 401178825Sdfr &fbp->krbdes_sched); 40257416Smarkm /* 403233294Sstas * Now look to see if krbdes_start() was waiting for the key to 404233294Sstas * show up. If so, go ahead an call it now that we have the key. 40557416Smarkm */ 40657416Smarkm if (fbp->need_start) { 40757416Smarkm fbp->need_start = 0; 40857416Smarkm fb64_start(fbp, DIR_ENCRYPT, server); 40957416Smarkm } 41057416Smarkm} 41157416Smarkm 41257416Smarkm/* 41357416Smarkm * We only accept a keyid of 0. If we get a keyid of 41457416Smarkm * 0, then mark the state as SUCCESS. 41557416Smarkm */ 41657416Smarkm 41757416Smarkmint cfb64_keyid(int dir, unsigned char *kp, int *lenp) 41857416Smarkm{ 41957416Smarkm return(fb64_keyid(dir, kp, lenp, &fb[CFB])); 42057416Smarkm} 42157416Smarkm 42257416Smarkmint ofb64_keyid(int dir, unsigned char *kp, int *lenp) 42357416Smarkm{ 42457416Smarkm return(fb64_keyid(dir, kp, lenp, &fb[OFB])); 42557416Smarkm} 42657416Smarkm 42757416Smarkmint fb64_keyid(int dir, unsigned char *kp, int *lenp, struct fb *fbp) 42857416Smarkm{ 42957416Smarkm int state = fbp->state[dir-1]; 43057416Smarkm 43157416Smarkm if (*lenp != 1 || (*kp != '\0')) { 43257416Smarkm *lenp = 0; 43357416Smarkm return(state); 43457416Smarkm } 43557416Smarkm 43657416Smarkm if (state == FAILED) 43757416Smarkm state = IN_PROGRESS; 43857416Smarkm 43957416Smarkm state &= ~NO_KEYID; 44057416Smarkm 44157416Smarkm return(fbp->state[dir-1] = state); 44257416Smarkm} 44357416Smarkm 444233294Sstasvoid fb64_printsub(unsigned char *data, size_t cnt, 445233294Sstas unsigned char *buf, size_t buflen, char *type) 44657416Smarkm{ 44757416Smarkm char lbuf[32]; 44857416Smarkm int i; 44957416Smarkm char *cp; 45057416Smarkm 45157416Smarkm buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ 45257416Smarkm buflen -= 1; 45357416Smarkm 45457416Smarkm switch(data[2]) { 45557416Smarkm case FB64_IV: 45657416Smarkm snprintf(lbuf, sizeof(lbuf), "%s_IV", type); 45757416Smarkm cp = lbuf; 45857416Smarkm goto common; 45957416Smarkm 46057416Smarkm case FB64_IV_OK: 46157416Smarkm snprintf(lbuf, sizeof(lbuf), "%s_IV_OK", type); 46257416Smarkm cp = lbuf; 46357416Smarkm goto common; 46457416Smarkm 46557416Smarkm case FB64_IV_BAD: 46657416Smarkm snprintf(lbuf, sizeof(lbuf), "%s_IV_BAD", type); 46757416Smarkm cp = lbuf; 46857416Smarkm goto common; 46957416Smarkm 47057416Smarkm default: 47157416Smarkm snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[2]); 47257416Smarkm cp = lbuf; 47357416Smarkm common: 47457416Smarkm for (; (buflen > 0) && (*buf = *cp++); buf++) 47557416Smarkm buflen--; 47657416Smarkm for (i = 3; i < cnt; i++) { 47757416Smarkm snprintf(lbuf, sizeof(lbuf), " %d", data[i]); 47857416Smarkm for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++) 47957416Smarkm buflen--; 48057416Smarkm } 48157416Smarkm break; 48257416Smarkm } 48357416Smarkm} 48457416Smarkm 485233294Sstasvoid cfb64_printsub(unsigned char *data, size_t cnt, 486233294Sstas unsigned char *buf, size_t buflen) 48757416Smarkm{ 48857416Smarkm fb64_printsub(data, cnt, buf, buflen, "CFB64"); 48957416Smarkm} 49057416Smarkm 491233294Sstasvoid ofb64_printsub(unsigned char *data, size_t cnt, 492233294Sstas unsigned char *buf, size_t buflen) 49357416Smarkm{ 49457416Smarkm fb64_printsub(data, cnt, buf, buflen, "OFB64"); 49557416Smarkm} 49657416Smarkm 497178825Sdfrvoid fb64_stream_iv(DES_cblock seed, struct stinfo *stp) 49857416Smarkm{ 49957416Smarkm 500178825Sdfr memcpy(stp->str_iv, seed,sizeof(DES_cblock)); 501178825Sdfr memcpy(stp->str_output, seed, sizeof(DES_cblock)); 50257416Smarkm 503178825Sdfr DES_set_key_checked(&stp->str_ikey, &stp->str_sched); 50457416Smarkm 505178825Sdfr stp->str_index = sizeof(DES_cblock); 50657416Smarkm} 50757416Smarkm 508178825Sdfrvoid fb64_stream_key(DES_cblock key, struct stinfo *stp) 50957416Smarkm{ 510178825Sdfr memcpy(stp->str_ikey, key, sizeof(DES_cblock)); 511178825Sdfr DES_set_key_checked((DES_cblock*)key, &stp->str_sched); 51257416Smarkm 513178825Sdfr memcpy(stp->str_output, stp->str_iv, sizeof(DES_cblock)); 51457416Smarkm 515178825Sdfr stp->str_index = sizeof(DES_cblock); 51657416Smarkm} 51757416Smarkm 51857416Smarkm/* 51957416Smarkm * DES 64 bit Cipher Feedback 52057416Smarkm * 52157416Smarkm * key --->+-----+ 52257416Smarkm * +->| DES |--+ 52357416Smarkm * | +-----+ | 52457416Smarkm * | v 52557416Smarkm * INPUT --(--------->(+)+---> DATA 52657416Smarkm * | | 52757416Smarkm * +-------------+ 52857416Smarkm * 529233294Sstas * 53057416Smarkm * Given: 53157416Smarkm * iV: Initial vector, 64 bits (8 bytes) long. 53257416Smarkm * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). 53357416Smarkm * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. 53457416Smarkm * 53557416Smarkm * V0 = DES(iV, key) 53657416Smarkm * On = Dn ^ Vn 53757416Smarkm * V(n+1) = DES(On, key) 53857416Smarkm */ 53957416Smarkm 54057416Smarkmvoid cfb64_encrypt(unsigned char *s, int c) 54157416Smarkm{ 54257416Smarkm struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1]; 54357416Smarkm int index; 54457416Smarkm 54557416Smarkm index = stp->str_index; 54657416Smarkm while (c-- > 0) { 547178825Sdfr if (index == sizeof(DES_cblock)) { 548178825Sdfr DES_cblock b; 549178825Sdfr DES_ecb_encrypt(&stp->str_output, &b,&stp->str_sched, 1); 550178825Sdfr memcpy(stp->str_feed, b, sizeof(DES_cblock)); 55157416Smarkm index = 0; 55257416Smarkm } 55357416Smarkm 55457416Smarkm /* On encryption, we store (feed ^ data) which is cypher */ 55557416Smarkm *s = stp->str_output[index] = (stp->str_feed[index] ^ *s); 55657416Smarkm s++; 55757416Smarkm index++; 55857416Smarkm } 55957416Smarkm stp->str_index = index; 56057416Smarkm} 56157416Smarkm 56257416Smarkmint cfb64_decrypt(int data) 56357416Smarkm{ 56457416Smarkm struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1]; 56557416Smarkm int index; 56657416Smarkm 56757416Smarkm if (data == -1) { 56857416Smarkm /* 56957416Smarkm * Back up one byte. It is assumed that we will 57057416Smarkm * never back up more than one byte. If we do, this 57157416Smarkm * may or may not work. 57257416Smarkm */ 57357416Smarkm if (stp->str_index) 57457416Smarkm --stp->str_index; 57557416Smarkm return(0); 57657416Smarkm } 57757416Smarkm 57857416Smarkm index = stp->str_index++; 579178825Sdfr if (index == sizeof(DES_cblock)) { 580178825Sdfr DES_cblock b; 581178825Sdfr DES_ecb_encrypt(&stp->str_output,&b, &stp->str_sched, 1); 582178825Sdfr memcpy(stp->str_feed, b, sizeof(DES_cblock)); 58357416Smarkm stp->str_index = 1; /* Next time will be 1 */ 584233294Sstas index = 0; /* But now use 0 */ 58557416Smarkm } 58657416Smarkm 58757416Smarkm /* On decryption we store (data) which is cypher. */ 58857416Smarkm stp->str_output[index] = data; 58957416Smarkm return(data ^ stp->str_feed[index]); 59057416Smarkm} 59157416Smarkm 59257416Smarkm/* 59357416Smarkm * DES 64 bit Output Feedback 59457416Smarkm * 59557416Smarkm * key --->+-----+ 59657416Smarkm * +->| DES |--+ 59757416Smarkm * | +-----+ | 59857416Smarkm * +-----------+ 59957416Smarkm * v 60057416Smarkm * INPUT -------->(+) ----> DATA 60157416Smarkm * 60257416Smarkm * Given: 60357416Smarkm * iV: Initial vector, 64 bits (8 bytes) long. 60457416Smarkm * Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt). 60557416Smarkm * On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output. 60657416Smarkm * 60757416Smarkm * V0 = DES(iV, key) 60857416Smarkm * V(n+1) = DES(Vn, key) 60957416Smarkm * On = Dn ^ Vn 61057416Smarkm */ 61157416Smarkm 61257416Smarkmvoid ofb64_encrypt(unsigned char *s, int c) 61357416Smarkm{ 61457416Smarkm struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1]; 61557416Smarkm int index; 61657416Smarkm 61757416Smarkm index = stp->str_index; 61857416Smarkm while (c-- > 0) { 619178825Sdfr if (index == sizeof(DES_cblock)) { 620178825Sdfr DES_cblock b; 621178825Sdfr DES_ecb_encrypt(&stp->str_feed,&b, &stp->str_sched, 1); 622178825Sdfr memcpy(stp->str_feed, b, sizeof(DES_cblock)); 62357416Smarkm index = 0; 62457416Smarkm } 62557416Smarkm *s++ ^= stp->str_feed[index]; 62657416Smarkm index++; 62757416Smarkm } 62857416Smarkm stp->str_index = index; 62957416Smarkm} 63057416Smarkm 63157416Smarkmint ofb64_decrypt(int data) 63257416Smarkm{ 63357416Smarkm struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1]; 63457416Smarkm int index; 63557416Smarkm 63657416Smarkm if (data == -1) { 63757416Smarkm /* 63857416Smarkm * Back up one byte. It is assumed that we will 63957416Smarkm * never back up more than one byte. If we do, this 64057416Smarkm * may or may not work. 64157416Smarkm */ 64257416Smarkm if (stp->str_index) 64357416Smarkm --stp->str_index; 64457416Smarkm return(0); 64557416Smarkm } 64657416Smarkm 64757416Smarkm index = stp->str_index++; 648178825Sdfr if (index == sizeof(DES_cblock)) { 649178825Sdfr DES_cblock b; 650178825Sdfr DES_ecb_encrypt(&stp->str_feed,&b,&stp->str_sched, 1); 651178825Sdfr memcpy(stp->str_feed, b, sizeof(DES_cblock)); 65257416Smarkm stp->str_index = 1; /* Next time will be 1 */ 653233294Sstas index = 0; /* But now use 0 */ 65457416Smarkm } 65557416Smarkm 65657416Smarkm return(data ^ stp->str_feed[index]); 65757416Smarkm} 65857416Smarkm#endif 65957416Smarkm 660