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