1 /* crypto/des/des.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
4 *
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
8 *
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to. The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 *
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 * must display the following acknowledgement:
33 * "This product includes cryptographic software written by
34 * Eric Young (eay@cryptsoft.com)"
35 * The word 'cryptographic' can be left out if the rouines from the library
36 * being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 * the apps directory (application code) you must include an acknowledgement:
39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed. i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
57 */
58
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <openssl/opensslconf.h>
63 #ifndef OPENSSL_SYS_MSDOS
64 # ifndef OPENSSL_SYS_VMS
65 # include <unistd.h>
66 # else /* OPENSSL_SYS_VMS */
67 # ifdef __DECC
68 # include <unistd.h>
69 # else /* not __DECC */
70 # include <math.h>
71 # endif /* __DECC */
72 # endif /* OPENSSL_SYS_VMS */
73 #else /* OPENSSL_SYS_MSDOS */
74 # include <io.h>
75 #endif
76
77 #include <time.h>
78 #include "des_ver.h"
79
80 #ifdef OPENSSL_SYS_VMS
81 # include <types.h>
82 # include <stat.h>
83 #else
84 # ifndef _IRIX
85 # include <sys/types.h>
86 # endif
87 # include <sys/stat.h>
88 #endif
89 #include <openssl/des.h>
90 #include <openssl/rand.h>
91 #include <openssl/ui_compat.h>
92
93 void usage(void);
94 void doencryption(void);
95 int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp);
96 void uufwriteEnd(FILE *fp);
97 int uufread(unsigned char *out, int size, unsigned int num, FILE *fp);
98 int uuencode(unsigned char *in, int num, unsigned char *out);
99 int uudecode(unsigned char *in, int num, unsigned char *out);
100 void DES_3cbc_encrypt(DES_cblock *input, DES_cblock *output, long length,
101 DES_key_schedule sk1, DES_key_schedule sk2,
102 DES_cblock *ivec1, DES_cblock *ivec2, int enc);
103 #ifdef OPENSSL_SYS_VMS
104 # define EXIT(a) exit(a&0x10000000L)
105 #else
106 # define EXIT(a) exit(a)
107 #endif
108
109 #define BUFSIZE (8*1024)
110 #define VERIFY 1
111 #define KEYSIZ 8
112 #define KEYSIZB 1024 /* should hit tty line limit first :-) */
113 char key[KEYSIZB + 1];
114 int do_encrypt, longk = 0;
115 FILE *DES_IN, *DES_OUT, *CKSUM_OUT;
116 char uuname[200];
117 unsigned char uubuf[50];
118 int uubufnum = 0;
119 #define INUUBUFN (45*100)
120 #define OUTUUBUF (65*100)
121 unsigned char b[OUTUUBUF];
122 unsigned char bb[300];
123 DES_cblock cksum = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
124
125 char cksumname[200] = "";
126
127 int vflag, cflag, eflag, dflag, kflag, bflag, fflag, sflag, uflag, flag3,
128 hflag, error;
129
main(int argc,char ** argv)130 int main(int argc, char **argv)
131 {
132 int i;
133 struct stat ins, outs;
134 char *p;
135 char *in = NULL, *out = NULL;
136
137 vflag = cflag = eflag = dflag = kflag = hflag = bflag = fflag = sflag =
138 uflag = flag3 = 0;
139 error = 0;
140 memset(key, 0, sizeof(key));
141
142 for (i = 1; i < argc; i++) {
143 p = argv[i];
144 if ((p[0] == '-') && (p[1] != '\0')) {
145 p++;
146 while (*p) {
147 switch (*(p++)) {
148 case '3':
149 flag3 = 1;
150 longk = 1;
151 break;
152 case 'c':
153 cflag = 1;
154 strncpy(cksumname, p, 200);
155 cksumname[sizeof(cksumname) - 1] = '\0';
156 p += strlen(cksumname);
157 break;
158 case 'C':
159 cflag = 1;
160 longk = 1;
161 strncpy(cksumname, p, 200);
162 cksumname[sizeof(cksumname) - 1] = '\0';
163 p += strlen(cksumname);
164 break;
165 case 'e':
166 eflag = 1;
167 break;
168 case 'v':
169 vflag = 1;
170 break;
171 case 'E':
172 eflag = 1;
173 longk = 1;
174 break;
175 case 'd':
176 dflag = 1;
177 break;
178 case 'D':
179 dflag = 1;
180 longk = 1;
181 break;
182 case 'b':
183 bflag = 1;
184 break;
185 case 'f':
186 fflag = 1;
187 break;
188 case 's':
189 sflag = 1;
190 break;
191 case 'u':
192 uflag = 1;
193 strncpy(uuname, p, 200);
194 uuname[sizeof(uuname) - 1] = '\0';
195 p += strlen(uuname);
196 break;
197 case 'h':
198 hflag = 1;
199 break;
200 case 'k':
201 kflag = 1;
202 if ((i + 1) == argc) {
203 fputs("must have a key with the -k option\n", stderr);
204 error = 1;
205 } else {
206 int j;
207
208 i++;
209 strncpy(key, argv[i], KEYSIZB);
210 for (j = strlen(argv[i]) - 1; j >= 0; j--)
211 argv[i][j] = '\0';
212 }
213 break;
214 default:
215 fprintf(stderr, "'%c' unknown flag\n", p[-1]);
216 error = 1;
217 break;
218 }
219 }
220 } else {
221 if (in == NULL)
222 in = argv[i];
223 else if (out == NULL)
224 out = argv[i];
225 else
226 error = 1;
227 }
228 }
229 if (error)
230 usage();
231 /*-
232 * We either
233 * do checksum or
234 * do encrypt or
235 * do decrypt or
236 * do decrypt then ckecksum or
237 * do checksum then encrypt
238 */
239 if (((eflag + dflag) == 1) || cflag) {
240 if (eflag)
241 do_encrypt = DES_ENCRYPT;
242 if (dflag)
243 do_encrypt = DES_DECRYPT;
244 } else {
245 if (vflag) {
246 #ifndef _Windows
247 fprintf(stderr, "des(1) built with %s\n", libdes_version);
248 #endif
249 EXIT(1);
250 } else
251 usage();
252 }
253
254 #ifndef _Windows
255 if (vflag)
256 fprintf(stderr, "des(1) built with %s\n", libdes_version);
257 #endif
258 if ((in != NULL) && (out != NULL) &&
259 #ifndef OPENSSL_SYS_MSDOS
260 (stat(in, &ins) != -1) &&
261 (stat(out, &outs) != -1) &&
262 (ins.st_dev == outs.st_dev) && (ins.st_ino == outs.st_ino))
263 #else /* OPENSSL_SYS_MSDOS */
264 (strcmp(in, out) == 0))
265 #endif
266 {
267 fputs("input and output file are the same\n", stderr);
268 EXIT(3);
269 }
270
271 if (!kflag)
272 if (des_read_pw_string
273 (key, KEYSIZB + 1, "Enter key:", eflag ? VERIFY : 0)) {
274 fputs("password error\n", stderr);
275 EXIT(2);
276 }
277
278 if (in == NULL)
279 DES_IN = stdin;
280 else if ((DES_IN = fopen(in, "r")) == NULL) {
281 perror("opening input file");
282 EXIT(4);
283 }
284
285 CKSUM_OUT = stdout;
286 if (out == NULL) {
287 DES_OUT = stdout;
288 CKSUM_OUT = stderr;
289 } else if ((DES_OUT = fopen(out, "w")) == NULL) {
290 perror("opening output file");
291 EXIT(5);
292 }
293 #ifdef OPENSSL_SYS_MSDOS
294 /* This should set the file to binary mode. */
295 {
296 # include <fcntl.h>
297 if (!(uflag && dflag))
298 setmode(fileno(DES_IN), O_BINARY);
299 if (!(uflag && eflag))
300 setmode(fileno(DES_OUT), O_BINARY);
301 }
302 #endif
303
304 doencryption();
305 fclose(DES_IN);
306 fclose(DES_OUT);
307 EXIT(0);
308 }
309
usage(void)310 void usage(void)
311 {
312 char **u;
313 static const char *Usage[] = {
314 "des <options> [input-file [output-file]]",
315 "options:",
316 "-v : des(1) version number",
317 "-e : encrypt using SunOS compatible user key to DES key conversion.",
318 "-E : encrypt ",
319 "-d : decrypt using SunOS compatible user key to DES key conversion.",
320 "-D : decrypt ",
321 "-c[ckname] : generate a cbc_cksum using SunOS compatible user key to",
322 " DES key conversion and output to ckname (stdout default,",
323 " stderr if data being output on stdout). The checksum is",
324 " generated before encryption and after decryption if used",
325 " in conjunction with -[eEdD].",
326 "-C[ckname] : generate a cbc_cksum as for -c but compatible with -[ED].",
327 "-k key : use key 'key'",
328 "-h : the key that is entered will be a hexadecimal number",
329 " that is used directly as the des key",
330 "-u[uuname] : input file is uudecoded if -[dD] or output uuencoded data if -[eE]",
331 " (uuname is the filename to put in the uuencode header).",
332 "-b : encrypt using DES in ecb encryption mode, the default is cbc mode.",
333 "-3 : encrypt using triple DES encryption. This uses 2 keys",
334 " generated from the input key. If the input key is less",
335 " than 8 characters long, this is equivalent to normal",
336 " encryption. Default is triple cbc, -b makes it triple ecb.",
337 NULL
338 };
339 for (u = (char **)Usage; *u; u++) {
340 fputs(*u, stderr);
341 fputc('\n', stderr);
342 }
343
344 EXIT(1);
345 }
346
doencryption(void)347 void doencryption(void)
348 {
349 #ifdef _LIBC
350 extern unsigned long time();
351 #endif
352
353 register int i;
354 DES_key_schedule ks, ks2;
355 DES_cblock iv, iv2;
356 char *p;
357 int num = 0, j, k, l, rem, ll, len, last, ex = 0;
358 DES_cblock kk, k2;
359 FILE *O;
360 int Exit = 0;
361 #ifndef OPENSSL_SYS_MSDOS
362 static unsigned char buf[BUFSIZE + 8], obuf[BUFSIZE + 8];
363 #else
364 static unsigned char *buf = NULL, *obuf = NULL;
365
366 if (buf == NULL) {
367 if (((buf = OPENSSL_malloc(BUFSIZE + 8)) == NULL) ||
368 ((obuf = OPENSSL_malloc(BUFSIZE + 8)) == NULL)) {
369 fputs("Not enough memory\n", stderr);
370 Exit = 10;
371 goto problems;
372 }
373 }
374 #endif
375
376 if (hflag) {
377 j = (flag3 ? 16 : 8);
378 p = key;
379 for (i = 0; i < j; i++) {
380 k = 0;
381 if ((*p <= '9') && (*p >= '0'))
382 k = (*p - '0') << 4;
383 else if ((*p <= 'f') && (*p >= 'a'))
384 k = (*p - 'a' + 10) << 4;
385 else if ((*p <= 'F') && (*p >= 'A'))
386 k = (*p - 'A' + 10) << 4;
387 else {
388 fputs("Bad hex key\n", stderr);
389 Exit = 9;
390 goto problems;
391 }
392 p++;
393 if ((*p <= '9') && (*p >= '0'))
394 k |= (*p - '0');
395 else if ((*p <= 'f') && (*p >= 'a'))
396 k |= (*p - 'a' + 10);
397 else if ((*p <= 'F') && (*p >= 'A'))
398 k |= (*p - 'A' + 10);
399 else {
400 fputs("Bad hex key\n", stderr);
401 Exit = 9;
402 goto problems;
403 }
404 p++;
405 if (i < 8)
406 kk[i] = k;
407 else
408 k2[i - 8] = k;
409 }
410 DES_set_key_unchecked(&k2, &ks2);
411 OPENSSL_cleanse(k2, sizeof(k2));
412 } else if (longk || flag3) {
413 if (flag3) {
414 DES_string_to_2keys(key, &kk, &k2);
415 DES_set_key_unchecked(&k2, &ks2);
416 OPENSSL_cleanse(k2, sizeof(k2));
417 } else
418 DES_string_to_key(key, &kk);
419 } else
420 for (i = 0; i < KEYSIZ; i++) {
421 l = 0;
422 k = key[i];
423 for (j = 0; j < 8; j++) {
424 if (k & 1)
425 l++;
426 k >>= 1;
427 }
428 if (l & 1)
429 kk[i] = key[i] & 0x7f;
430 else
431 kk[i] = key[i] | 0x80;
432 }
433
434 DES_set_key_unchecked(&kk, &ks);
435 OPENSSL_cleanse(key, sizeof(key));
436 OPENSSL_cleanse(kk, sizeof(kk));
437 /* woops - A bug that does not showup under unix :-( */
438 memset(iv, 0, sizeof(iv));
439 memset(iv2, 0, sizeof(iv2));
440
441 l = 1;
442 rem = 0;
443 /* first read */
444 if (eflag || (!dflag && cflag)) {
445 for (;;) {
446 num = l = fread(&(buf[rem]), 1, BUFSIZE, DES_IN);
447 l += rem;
448 num += rem;
449 if (l < 0) {
450 perror("read error");
451 Exit = 6;
452 goto problems;
453 }
454
455 rem = l % 8;
456 len = l - rem;
457 if (feof(DES_IN)) {
458 for (i = 7 - rem; i > 0; i--) {
459 if (RAND_pseudo_bytes(buf + l++, 1) < 0)
460 goto problems;
461 }
462 buf[l++] = rem;
463 ex = 1;
464 len += rem;
465 } else
466 l -= rem;
467
468 if (cflag) {
469 DES_cbc_cksum(buf, &cksum, (long)len, &ks, &cksum);
470 if (!eflag) {
471 if (feof(DES_IN))
472 break;
473 else
474 continue;
475 }
476 }
477
478 if (bflag && !flag3)
479 for (i = 0; i < l; i += 8)
480 DES_ecb_encrypt((DES_cblock *)&(buf[i]),
481 (DES_cblock *)&(obuf[i]),
482 &ks, do_encrypt);
483 else if (flag3 && bflag)
484 for (i = 0; i < l; i += 8)
485 DES_ecb2_encrypt((DES_cblock *)&(buf[i]),
486 (DES_cblock *)&(obuf[i]),
487 &ks, &ks2, do_encrypt);
488 else if (flag3 && !bflag) {
489 char tmpbuf[8];
490
491 if (rem)
492 memcpy(tmpbuf, &(buf[l]), (unsigned int)rem);
493 DES_3cbc_encrypt((DES_cblock *)buf, (DES_cblock *)obuf,
494 (long)l, ks, ks2, &iv, &iv2, do_encrypt);
495 if (rem)
496 memcpy(&(buf[l]), tmpbuf, (unsigned int)rem);
497 } else {
498 DES_cbc_encrypt(buf, obuf, (long)l, &ks, &iv, do_encrypt);
499 if (l >= 8)
500 memcpy(iv, &(obuf[l - 8]), 8);
501 }
502 if (rem)
503 memcpy(buf, &(buf[l]), (unsigned int)rem);
504
505 i = 0;
506 while (i < l) {
507 if (uflag)
508 j = uufwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
509 else
510 j = fwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
511 if (j == -1) {
512 perror("Write error");
513 Exit = 7;
514 goto problems;
515 }
516 i += j;
517 }
518 if (feof(DES_IN)) {
519 if (uflag)
520 uufwriteEnd(DES_OUT);
521 break;
522 }
523 }
524 } else { /* decrypt */
525
526 ex = 1;
527 for (;;) {
528 if (ex) {
529 if (uflag)
530 l = uufread(buf, 1, BUFSIZE, DES_IN);
531 else
532 l = fread(buf, 1, BUFSIZE, DES_IN);
533 ex = 0;
534 rem = l % 8;
535 l -= rem;
536 }
537 if (l < 0) {
538 perror("read error");
539 Exit = 6;
540 goto problems;
541 }
542
543 if (bflag && !flag3)
544 for (i = 0; i < l; i += 8)
545 DES_ecb_encrypt((DES_cblock *)&(buf[i]),
546 (DES_cblock *)&(obuf[i]),
547 &ks, do_encrypt);
548 else if (flag3 && bflag)
549 for (i = 0; i < l; i += 8)
550 DES_ecb2_encrypt((DES_cblock *)&(buf[i]),
551 (DES_cblock *)&(obuf[i]),
552 &ks, &ks2, do_encrypt);
553 else if (flag3 && !bflag) {
554 DES_3cbc_encrypt((DES_cblock *)buf, (DES_cblock *)obuf,
555 (long)l, ks, ks2, &iv, &iv2, do_encrypt);
556 } else {
557 DES_cbc_encrypt(buf, obuf, (long)l, &ks, &iv, do_encrypt);
558 if (l >= 8)
559 memcpy(iv, &(buf[l - 8]), 8);
560 }
561
562 if (uflag)
563 ll = uufread(&(buf[rem]), 1, BUFSIZE, DES_IN);
564 else
565 ll = fread(&(buf[rem]), 1, BUFSIZE, DES_IN);
566 ll += rem;
567 rem = ll % 8;
568 ll -= rem;
569 if (feof(DES_IN) && (ll == 0)) {
570 last = obuf[l - 1];
571
572 if ((last > 7) || (last < 0)) {
573 fputs("The file was not decrypted correctly.\n", stderr);
574 Exit = 8;
575 last = 0;
576 }
577 l = l - 8 + last;
578 }
579 i = 0;
580 if (cflag)
581 DES_cbc_cksum(obuf,
582 (DES_cblock *)cksum, (long)l / 8 * 8, &ks,
583 (DES_cblock *)cksum);
584 while (i != l) {
585 j = fwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
586 if (j == -1) {
587 perror("Write error");
588 Exit = 7;
589 goto problems;
590 }
591 i += j;
592 }
593 l = ll;
594 if ((l == 0) && feof(DES_IN))
595 break;
596 }
597 }
598 if (cflag) {
599 l = 0;
600 if (cksumname[0] != '\0') {
601 if ((O = fopen(cksumname, "w")) != NULL) {
602 CKSUM_OUT = O;
603 l = 1;
604 }
605 }
606 for (i = 0; i < 8; i++)
607 fprintf(CKSUM_OUT, "%02X", cksum[i]);
608 fprintf(CKSUM_OUT, "\n");
609 if (l)
610 fclose(CKSUM_OUT);
611 }
612 problems:
613 OPENSSL_cleanse(buf, sizeof(buf));
614 OPENSSL_cleanse(obuf, sizeof(obuf));
615 OPENSSL_cleanse(&ks, sizeof(ks));
616 OPENSSL_cleanse(&ks2, sizeof(ks2));
617 OPENSSL_cleanse(iv, sizeof(iv));
618 OPENSSL_cleanse(iv2, sizeof(iv2));
619 OPENSSL_cleanse(kk, sizeof(kk));
620 OPENSSL_cleanse(k2, sizeof(k2));
621 OPENSSL_cleanse(uubuf, sizeof(uubuf));
622 OPENSSL_cleanse(b, sizeof(b));
623 OPENSSL_cleanse(bb, sizeof(bb));
624 OPENSSL_cleanse(cksum, sizeof(cksum));
625 if (Exit)
626 EXIT(Exit);
627 }
628
629 /* We ignore this parameter but it should be > ~50 I believe */
uufwrite(unsigned char * data,int size,unsigned int num,FILE * fp)630 int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp)
631 {
632 int i, j, left, rem, ret = num;
633 static int start = 1;
634
635 if (start) {
636 fprintf(fp, "begin 600 %s\n",
637 (uuname[0] == '\0') ? "text.d" : uuname);
638 start = 0;
639 }
640
641 if (uubufnum) {
642 if (uubufnum + num < 45) {
643 memcpy(&(uubuf[uubufnum]), data, (unsigned int)num);
644 uubufnum += num;
645 return (num);
646 } else {
647 i = 45 - uubufnum;
648 memcpy(&(uubuf[uubufnum]), data, (unsigned int)i);
649 j = uuencode((unsigned char *)uubuf, 45, b);
650 fwrite(b, 1, (unsigned int)j, fp);
651 uubufnum = 0;
652 data += i;
653 num -= i;
654 }
655 }
656
657 for (i = 0; i < (((int)num) - INUUBUFN); i += INUUBUFN) {
658 j = uuencode(&(data[i]), INUUBUFN, b);
659 fwrite(b, 1, (unsigned int)j, fp);
660 }
661 rem = (num - i) % 45;
662 left = (num - i - rem);
663 if (left) {
664 j = uuencode(&(data[i]), left, b);
665 fwrite(b, 1, (unsigned int)j, fp);
666 i += left;
667 }
668 if (i != num) {
669 memcpy(uubuf, &(data[i]), (unsigned int)rem);
670 uubufnum = rem;
671 }
672 return (ret);
673 }
674
uufwriteEnd(FILE * fp)675 void uufwriteEnd(FILE *fp)
676 {
677 int j;
678 static const char *end = " \nend\n";
679
680 if (uubufnum != 0) {
681 uubuf[uubufnum] = '\0';
682 uubuf[uubufnum + 1] = '\0';
683 uubuf[uubufnum + 2] = '\0';
684 j = uuencode(uubuf, uubufnum, b);
685 fwrite(b, 1, (unsigned int)j, fp);
686 }
687 fwrite(end, 1, strlen(end), fp);
688 }
689
690 /*
691 * int size: should always be > ~ 60; I actually ignore this parameter :-)
692 */
uufread(unsigned char * out,int size,unsigned int num,FILE * fp)693 int uufread(unsigned char *out, int size, unsigned int num, FILE *fp)
694 {
695 int i, j, tot;
696 static int done = 0;
697 static int valid = 0;
698 static int start = 1;
699
700 if (start) {
701 for (;;) {
702 b[0] = '\0';
703 fgets((char *)b, 300, fp);
704 if (b[0] == '\0') {
705 fprintf(stderr, "no 'begin' found in uuencoded input\n");
706 return (-1);
707 }
708 if (strncmp((char *)b, "begin ", 6) == 0)
709 break;
710 }
711 start = 0;
712 }
713 if (done)
714 return (0);
715 tot = 0;
716 if (valid) {
717 memcpy(out, bb, (unsigned int)valid);
718 tot = valid;
719 valid = 0;
720 }
721 for (;;) {
722 b[0] = '\0';
723 fgets((char *)b, 300, fp);
724 if (b[0] == '\0')
725 break;
726 i = strlen((char *)b);
727 if ((b[0] == 'e') && (b[1] == 'n') && (b[2] == 'd')) {
728 done = 1;
729 while (!feof(fp)) {
730 fgets((char *)b, 300, fp);
731 }
732 break;
733 }
734 i = uudecode(b, i, bb);
735 if (i < 0)
736 break;
737 if ((i + tot + 8) > num) {
738 /* num to copy to make it a multiple of 8 */
739 j = (num / 8 * 8) - tot - 8;
740 memcpy(&(out[tot]), bb, (unsigned int)j);
741 tot += j;
742 memcpy(bb, &(bb[j]), (unsigned int)i - j);
743 valid = i - j;
744 break;
745 }
746 memcpy(&(out[tot]), bb, (unsigned int)i);
747 tot += i;
748 }
749 return (tot);
750 }
751
752 #define ccc2l(c,l) (l =((DES_LONG)(*((c)++)))<<16, \
753 l|=((DES_LONG)(*((c)++)))<< 8, \
754 l|=((DES_LONG)(*((c)++))))
755
756 #define l2ccc(l,c) (*((c)++)=(unsigned char)(((l)>>16)&0xff), \
757 *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
758 *((c)++)=(unsigned char)(((l) )&0xff))
759
uuencode(unsigned char * in,int num,unsigned char * out)760 int uuencode(unsigned char *in, int num, unsigned char *out)
761 {
762 int j, i, n, tot = 0;
763 DES_LONG l;
764 register unsigned char *p;
765 p = out;
766
767 for (j = 0; j < num; j += 45) {
768 if (j + 45 > num)
769 i = (num - j);
770 else
771 i = 45;
772 *(p++) = i + ' ';
773 for (n = 0; n < i; n += 3) {
774 ccc2l(in, l);
775 *(p++) = ((l >> 18) & 0x3f) + ' ';
776 *(p++) = ((l >> 12) & 0x3f) + ' ';
777 *(p++) = ((l >> 6) & 0x3f) + ' ';
778 *(p++) = ((l) & 0x3f) + ' ';
779 tot += 4;
780 }
781 *(p++) = '\n';
782 tot += 2;
783 }
784 *p = '\0';
785 l = 0;
786 return (tot);
787 }
788
uudecode(unsigned char * in,int num,unsigned char * out)789 int uudecode(unsigned char *in, int num, unsigned char *out)
790 {
791 int j, i, k;
792 unsigned int n = 0, space = 0;
793 DES_LONG l;
794 DES_LONG w, x, y, z;
795 unsigned int blank = (unsigned int)'\n' - ' ';
796
797 for (j = 0; j < num;) {
798 n = *(in++) - ' ';
799 if (n == blank) {
800 n = 0;
801 in--;
802 }
803 if (n > 60) {
804 fprintf(stderr, "uuencoded line length too long\n");
805 return (-1);
806 }
807 j++;
808
809 for (i = 0; i < n; j += 4, i += 3) {
810 /*
811 * the following is for cases where spaces are removed from
812 * lines.
813 */
814 if (space) {
815 w = x = y = z = 0;
816 } else {
817 w = *(in++) - ' ';
818 x = *(in++) - ' ';
819 y = *(in++) - ' ';
820 z = *(in++) - ' ';
821 }
822 if ((w > 63) || (x > 63) || (y > 63) || (z > 63)) {
823 k = 0;
824 if (w == blank)
825 k = 1;
826 if (x == blank)
827 k = 2;
828 if (y == blank)
829 k = 3;
830 if (z == blank)
831 k = 4;
832 space = 1;
833 switch (k) {
834 case 1:
835 w = 0;
836 in--;
837 case 2:
838 x = 0;
839 in--;
840 case 3:
841 y = 0;
842 in--;
843 case 4:
844 z = 0;
845 in--;
846 break;
847 case 0:
848 space = 0;
849 fprintf(stderr, "bad uuencoded data values\n");
850 w = x = y = z = 0;
851 return (-1);
852 break;
853 }
854 }
855 l = (w << 18) | (x << 12) | (y << 6) | (z);
856 l2ccc(l, out);
857 }
858 if (*(in++) != '\n') {
859 fprintf(stderr, "missing nl in uuencoded line\n");
860 w = x = y = z = 0;
861 return (-1);
862 }
863 j++;
864 }
865 *out = '\0';
866 w = x = y = z = 0;
867 return (n);
868 }
869