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