|
|
1.1 root 1:
2: /*
3: * Stealth V1.1 by Henry Hastur
4: *
5: * May or may not be covered by US ITAR encryption export regulations, if
6: * in doubt, don't export it. It would be pretty stupid if it was, but
7: * hey, governments have done some pretty stupid things before now....
8: *
9: * This program is copyright Henry Hastur 1994, but may be freely distributed,
10: * modified, incorporated into other programs and used, as long as the
11: * copyright stays attached and you obey any relevant import or export
12: * restrictions on the code. No warranty is offered, and no responsibility
13: * is taken for any damage use of this program may cause. In other words,
14: * do what you want with it, but don't expect me to pay up if anything
15: * unexpected goes wrong - you're using it at your own risk...
16: *
17: */
18:
19: #include <stdio.h>
20: #include <ctype.h>
21: #include <stdlib.h>
22: #ifndef DOS
23: #include <unistd.h>
24: #else
25: #include <fcntl.h>
26: #include <io.h>
27: #endif
28: #include <signal.h>
29:
30: /* Few definitions from PGP for its header/algorithm versions */
31:
32: #define CURRENT_VERSION 0x02
33: #define RSA_VERSION 0x01
34: #define ID_SIZE 8
35:
36: /* define TRUE and FALSE */
37:
38: #define TRUE 1
39: #define FALSE 0
40:
41: /* A byte */
42:
43: typedef unsigned char byte;
44:
45: /* Few global variables */
46:
47: static int verbose = FALSE;
48: static int conventional = FALSE;
49: static int adding = FALSE;
50: static char file_name [1024];
51: static int file_open = FALSE;
52: static FILE *afp;
53:
54: /* int_handler() - tidy up and exit */
55:
56: static void int_handler(unused)
57:
58: int unused;
59:
60: {
61: long fpos;
62:
63: /* If we've still got a file open */
64:
65: if (file_open) {
66:
67: /* If we can still write to it, erase it */
68:
69: if (afp) {
70: fseek (afp, 0l, 2);
71: fpos = ftell (afp);
72: fseek (afp, 0l, 0);
73:
74: while (fpos --)
75: putc (0, afp);
76: }
77:
78: #ifndef UNIX
79: /* Finally unlink it */
80:
81: unlink (file_name);
82: #endif
83: }
84:
85: exit (1);
86: }
87:
88: /* Read a PGP ctb-lengh */
89:
90: static long read_length (c,fp)
91:
92: FILE *fp;
93: int c;
94:
95: {
96: static int bytes [] = { 1, 2, 4, 0 };
97: long len = 0;
98: int n;
99:
100: n = bytes [c & 0x03];
101:
102: if (!n)
103: return 0x7FFFFFFF;
104:
105: for (; n > 0 ; n--) {
106: len *= 256;
107: len += getc(fp);
108: }
109:
110: return len;
111: }
112:
113: /* Write a PGP ctb-length */
114:
115: static void write_length (ctb,length,fp)
116:
117: int ctb;
118: unsigned long length;
119: FILE *fp;
120:
121: {
122: unsigned long mask;
123: int bytes, shift,c;
124:
125: ctb &= 0xFC;
126:
127: if (length < 256) {
128: mask = 0xFF;
129: bytes = 1;
130: shift = 0;
131: }
132: else if (length < 65536) {
133: mask = 0xFF00;
134: bytes = 2;
135: shift = 8;
136: ctb |= 1;
137: }
138: else {
139: mask = 0xFF000000;
140: shift = 24;
141: bytes = 4;
142: ctb |= 2;
143: }
144:
145: putc (ctb, fp);
146:
147: while (bytes-- > 0) {
148: c = ((length & mask) >> shift);
149: mask >>= 8;
150: shift -= 8;
151:
152: putc (c, fp);
153: }
154: }
155:
156: /* Hunt through pubring.pgp for the appropriate secret key */
157:
158: #define ID_FROM_NAME 0
159: #define LENGTH_FROM_ID 1
160:
161: static int find_key_id(id,length,s,type)
162:
163: char *s;
164: byte *id;
165: int *length;
166: int type;
167:
168: {
169: char *path;
170: FILE *pub = NULL;
171: int c1, c2, len, i, klen, c;
172: long hex_id = (-1);
173:
174: /* Following are static only to reduce DOS stack requirements */
175:
176: static char pub_name [1024];
177: static char userid [256];
178:
179: /* Find pubring.pgp */
180:
181: if (path = getenv("PGPPATH")) {
182: sprintf (pub_name, "%s/pubring.pgp", path);
183: pub = fopen(pub_name, "rb");
184: }
185:
186: if (!pub)
187: pub = fopen ("pubring.pgp", "rb");
188:
189: if (!pub) {
190: fprintf (stderr,"Can't find pubring.pgp in $PGPPATH or . : exiting !\n");
191: exit (1);
192: }
193:
194: /* Also allow for use of hex key id */
195:
196: if (type == ID_FROM_NAME && !strncmp(s,"0x",2)) {
197: char *i;
198: int c;
199:
200: hex_id = 0l;
201: i = s + 2;
202:
203: while (*i) {
204: hex_id <<= 4;
205: c = tolower (*i);
206:
207: if (c >= '0' && c <= '9') {
208: hex_id += (c - '0');
209: }
210: else if (c >= 'a' && c <= 'f') {
211: hex_id += (c + 10 - 'a');
212: }
213: else {
214: fprintf (stderr, "Hex key id given with invalid hex digits !\n");
215: exit (1);
216: }
217:
218: i++;
219: }
220: }
221:
222: /* Read the contents till we find what we're looking for */
223:
224: while ((c1 = getc(pub)) != EOF) {
225: c2 = (c1 & 0xBC);
226:
227: switch (c2) {
228:
229: /* Secret key, probably revocation cert. */
230:
231: case 0x94:
232: len = read_length (c1, pub);
233:
234: for (; len > 0; len--)
235: (void) getc (pub);
236:
237: break;
238:
239: /* Public key - grab id and length */
240:
241: case 0x98:
242: len = read_length (c1, pub);
243:
244: for (i = 0; i < 8; i++)
245: (void) getc (pub);
246:
247: len -= 10;
248:
249: /* OK, here we are at the public modulus, get the
250: size from the MPI header */
251:
252: klen = getc(pub) * 256;
253: klen += getc (pub);
254:
255: /* Return the length for the caller to use */
256:
257: *length = klen;
258:
259: /* We only need the last 64 bits */
260:
261: len -= ((klen + 7) / 8);
262: i = (((klen + 7) / 8) - ID_SIZE);
263:
264: /* Skip unneccesary bytes */
265:
266: for (; i > 0; i--) {
267: (void) getc (pub);
268: }
269:
270: if (type == ID_FROM_NAME) {
271: for (i = 0; i < ID_SIZE; i++) {
272: id [i] = getc(pub);
273: }
274: }
275: else {
276:
277: /* Looking for length from ID */
278:
279: int found_id = TRUE;
280:
281: for (i = 0; i < ID_SIZE; i++) {
282: if (id[i] != getc(pub))
283: found_id = FALSE;
284: }
285:
286: if (found_id) {
287: fclose (pub);
288: return TRUE;
289: }
290: }
291:
292: for (; len > 0 ; len--) {
293: (void) getc (pub);
294: }
295:
296: break;
297:
298: /* Keyring trust, comment */
299:
300: case 0xB0:
301: case 0xB8:
302:
303: len = getc (pub);
304:
305: for (; len > 0; len--)
306: (void) getc (pub);
307:
308: break;
309:
310: /* USER ID ! */
311:
312: case 0xB4:
313:
314: len = getc (pub);
315:
316: if (type == ID_FROM_NAME) {
317: for (i = 0; i < len; i++) {
318: c = getc (pub);
319: userid [i] = tolower (c);
320: }
321:
322: userid [i] = 0;
323:
324: if (strstr(userid, s)) {
325: if (verbose)
326: fprintf (stderr, "Found user: %s\n",userid);
327: return TRUE;
328: }
329:
330: /* Ok, check for hex id */
331:
332: if (hex_id >= 0) {
333: long id_read = 0l;
334:
335: for (i = 5; i < 8; i++) {
336: id_read <<= 8;
337: id_read += id[i];
338: }
339:
340: if (hex_id == id_read) {
341: if (verbose)
342: fprintf (stderr, "Found hex id : 0x%06X\n", hex_id);
343: return TRUE;
344: }
345: }
346: }
347: else
348: for (i = 0; i < len; i++)
349: (void) getc (pub);
350: break;
351:
352: /* Anything we don't care about */
353:
354: default:
355: len = read_length (c1, pub);
356:
357: for (; len > 0; len--)
358: (void) getc (pub);
359: break;
360:
361: }
362: }
363:
364: fclose (pub);
365:
366: /* Uh-oh, failed to find it ! */
367:
368: return FALSE;
369: }
370:
371: /* Strip_headers() : Should be obvious what this does, really ! */
372:
373: static void strip_headers(fp)
374:
375: FILE *fp;
376:
377: {
378: int c1,c2;
379: long len;
380: int i;
381: byte id [ID_SIZE];
382: int key_length;
383: byte key_length_found = FALSE;
384: byte rsa_written = FALSE;
385: int mpi_length;
386:
387: /* Run through the whole message checking each packet */
388:
389: while ((c1 = getc(fp)) != EOF) {
390: c2 = (c1 & 0xBC);
391:
392: switch (c2) {
393:
394: /* Public key encoded packet */
395:
396: case 0x84:
397:
398: /* Read length */
399:
400: len = read_length(c1, fp);
401: if (verbose)
402: fprintf (stderr, "Found %d byte RSA packet.\n",
403: len);
404:
405: /*
406: We only support ONE RSA block ! This is because
407: we have no idea of the file format when we start
408: adding headers, so we have to assume that this
409: is the case. Warn the user, then abort...
410: */
411:
412: if (rsa_written) {
413: fprintf (stderr, "WARNING: More than one RSA block found... stripping extra block !\n");
414:
415: /* Throw away the block */
416:
417: ohno_abort_abort:
418: while (len-- > 0)
419: (void) getc (fp);
420:
421: break;
422: }
423:
424: /* Check for conventional encryption specified */
425:
426: if (conventional) {
427: fprintf (stderr, "WARNING: You specified conventional encryption with an RSA-encrypted file !\nI hope you know what you're doing... stripping RSA header....\n");
428:
429: goto ohno_abort_abort;
430: }
431:
432: /* Check public key version byte */
433:
434: c1 = getc (fp);
435:
436: if (c1 != CURRENT_VERSION) {
437: fprintf(stderr, "Hmm, PK version %d not %d, may not decrypt at recipient\n", c1, CURRENT_VERSION);
438: }
439:
440: /* Strip key ID */
441:
442: for (i = 0; i < ID_SIZE; i++)
443: id[i] = getc (fp);
444:
445: if (find_key_id (id,&key_length,NULL,LENGTH_FROM_ID)) {
446: key_length_found = TRUE;
447: }
448:
449: /* Check RSA version byte */
450:
451: c1 = getc(fp);
452:
453: if (c1 != RSA_VERSION) {
454: fprintf (stderr, "Hmm, RSA version %d not %d, may not decrypt at recipient\n", c1, RSA_VERSION);
455: }
456:
457: /* Strip MPI prefix */
458:
459: mpi_length = getc(fp);
460: mpi_length = mpi_length * 256 + getc(fp);
461:
462: /* Now, we have a problem in that PGP may generate
463: an RSA block shorter than your key, in which
464: case decryption is likely to fail. Check for
465: this and warn the user ! */
466:
467: if (!key_length_found) {
468: fprintf (stderr, "Hmm, couldn't get the length of this key, so can't verify that decryption\nwill be successful.\n");
469: }
470: else {
471: if (((mpi_length + 7) / 8) !=
472: ((key_length + 7) / 8)) {
473: fprintf (stderr, "WARNING : Short RSA block output, decryption will probably fail if used !\n");
474: }
475: }
476:
477: /* Copy remaining data from packet */
478:
479: len -= 12;
480: for (; len > 0; len--)
481: putchar (getc(fp));
482:
483: rsa_written = TRUE;
484: break;
485:
486: /* IDEA packet */
487:
488: case 0xA4:
489:
490: /* Read length */
491:
492: len = read_length(c1, fp);
493: if (verbose)
494: fprintf (stderr, "Found %d byte IDEA packet.\n",
495: len);
496:
497: /* Copy data from packet */
498:
499: for (; len > 0; len--)
500: putchar (getc (fp));
501:
502: break;
503:
504: default:
505:
506: /* Oh no ! Don't know what this is - just skip it ! */
507:
508: if (verbose)
509: fprintf (stderr, "Oops ! Unexpected packet type, skipping !\n");
510:
511: len = read_length (c1, fp);
512:
513: for (; len > 0; len --)
514: (void) getc (fp);
515:
516: break;
517: }
518: }
519: }
520:
521: /* Now we put the headers back in again */
522:
523: static void add_headers(id, length)
524:
525: byte *id;
526: int length;
527:
528: {
529: unsigned long len, mask;
530: int shift;
531: int i, c;
532: long fpos;
533: long flen;
534: int s;
535: #ifdef USE_PGPPATH
536: char *pgp_path;
537: #endif
538:
539: /* Foo ! We have to use a temporary file, because we need to be
540: able to output the length after reading it in ! */
541:
542: #ifdef USE_TMP
543: strcpy (file_name, "/tmp/stealth.t");
544: #else
545: #ifdef USE_PGPPATH
546: pgp_path = getenv ("PGPPATH");
547:
548: if (!pgp_path) {
549: fprintf (stderr, "PGPPATH not set !\n");
550: exit (1);
551: }
552:
553: sprintf(file_name,"%s/stealth.t",pgp_path);
554: #else
555: strcpy (file_name, "stealth.t");
556: #endif
557: #endif
558:
559: s = strlen (file_name);
560:
561: i = 0;
562:
563: #ifdef DOS
564: #define F_OK 0
565: #endif
566:
567: while (!access (file_name, F_OK) && i < 100) {
568: sprintf (file_name + s, "%d", i++);
569: }
570:
571: afp = fopen (file_name,"w+b");
572:
573: if (!afp) {
574: fprintf (stderr, "Can't open '%s' !\n", file_name);
575: exit (2);
576: }
577:
578: /* On unix, unlink the file immediately, to improve security */
579:
580: #ifdef UNIX
581: unlink (file_name);
582: #endif
583:
584: file_open = TRUE;
585:
586: if (!conventional) {
587:
588: /* First output the PK header */
589:
590: len = 4 + ID_SIZE + (length + 7)/8;
591:
592: write_length (0x84, len, afp);
593: putc (CURRENT_VERSION, afp);
594:
595: /* Store the key ID */
596:
597: for (i = 0; i < 8; i++) {
598: putc (id [i], afp);
599: }
600:
601: /* RSA version */
602:
603: putc (RSA_VERSION, afp);
604:
605: /* MPI header */
606:
607: c = (length & 0xFF00) >> 8;
608: putc (c, afp);
609: putc (length & 0xFF, afp);
610:
611: /* Copy the MPI over */
612:
613: i = (length + 7) / 8;
614: while (i-- > 0) {
615: c = getchar();
616: putc (c, afp);
617: }
618:
619: }
620:
621: /* Now the IDEA bits */
622:
623: len = 0xFFFFFFFF;
624:
625: fpos = ftell (afp) + 1;
626: write_length (0xA4, len, afp);
627:
628: len = 0;
629:
630: while ((c = getchar ()) != EOF) {
631: len ++;
632: putc (c, afp);
633: }
634:
635: fseek (afp, fpos, 0);
636:
637: /* Set up mask for length writing */
638:
639: mask = 0xFF000000;
640: shift = 24;
641:
642: /* Write the length back */
643:
644: for (i = 0; i < 4; i++) {
645: c = (len & mask) >> shift;
646: shift -= 8;
647: mask >>= 8;
648:
649: putc (c, afp);
650: }
651:
652: /* OK, now let's output the data ! */
653:
654: fseek (afp, 0l, 0);
655:
656: while ((c = getc (afp)) != EOF) {
657: putchar (c);
658: }
659:
660: /* Erase the file */
661:
662: flen = ftell (afp);
663:
664: fseek (afp, 0l,0);
665:
666: while (flen --)
667: putc (0, afp);
668:
669: fclose (afp);
670: afp = NULL;
671:
672: #ifndef UNIX
673: /* Finally, delete the temporary file */
674:
675: unlink (file_name);
676: #endif
677:
678: file_open = FALSE;
679: }
680:
681: static char looking_for [256];
682:
683: /* Do the stuff */
684:
685: main(argc,argv)
686:
687: char *argv[];
688: int argc;
689:
690: {
691: int length;
692: byte id [ID_SIZE];
693: char *s, *d;
694: int arg = 1,i;
695:
696: /* Following needed for binary stdin/stdout on DOS */
697:
698: #ifdef DOS
699: _fmode = O_BINARY;
700: setmode (fileno(stdin), O_BINARY);
701: setmode (fileno(stdout), O_BINARY);
702: #endif
703:
704: /* Set the umask for any files we may create */
705:
706: umask (077);
707:
708: signal (SIGINT, int_handler);
709:
710: /* Check command line parameters */
711:
712: while (arg != argc && argv [arg][0] == '-') {
713:
714: for (i = 1; argv[arg][i]; i++) {
715: switch (argv[arg][i]) {
716:
717: case 'v':
718: verbose = TRUE;
719: break;
720:
721: case 'c':
722: conventional = TRUE;
723: break;
724:
725: case 'a':
726: adding = TRUE;
727: break;
728:
729: }
730: }
731:
732: arg++;
733: }
734:
735: if (!adding)
736: strip_headers (stdin);
737: else {
738: if (!conventional) {
739:
740: if (arg == argc) {
741: fprintf (stderr, "You specified -a, but gave no user id !\n");
742: exit (1);
743: }
744:
745: s = argv[arg];
746: d = looking_for;
747:
748: while (*s) {
749: *d++ = tolower (*s);
750: s++;
751: }
752: *d = 0;
753: }
754:
755: if (conventional ||
756: find_key_id (id,&length,looking_for,ID_FROM_NAME)) {
757: add_headers (id, length);
758: }
759: else {
760: fprintf (stderr, "Can't find key for user %s\n",argv[arg]);
761: }
762: }
763: }
764:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.