1 1.18 kre /* $NetBSD: enc_des.c,v 1.18 2024/10/29 13:10:06 kre 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.18 kre __RCSID("$NetBSD: enc_des.c,v 1.18 2024/10/29 13:10:06 kre 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.18 kre 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.18 kre 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.18 kre if (encrypt_debug()) 267 1.1 cgd printf("CFB64: initial vector received\r\n"); 268 1.1 cgd 269 1.18 kre 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.18 kre 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.18 kre 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.18 kre 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.17 rillig * show up. If so, go ahead and 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