[net.sources] Changes to 4.2bsd Mail to handle encrypted messages.

glenn@sdcrdcf.UUCP (Glenn C. Scott) (01/11/85)

echo x - README
sed 's/^X//' > README << 'EOF'
X  This shell archive contains diffs, (suitable for use with `patch') and a few
Xprograms to make your 4.2bsd Mail handle encrypted mail.  I've tried to make
Xit conform to the RFC822 standard and make it useful.  If you want to improve
Xon it please be my guest.  Note that there is no guarantee that no one can read
Xyour mail.  However, it does slow them down.
X
XOnce you have the diffs installed in your big-M mailer you can send encrypted
Xmail like this:
X
X	% Mail -e 'encryptor,keycode' username
X
XThis will put the field "Encrypted: encryptor,keycode" in the header. For the
Xdetails of the header see RFC822.  NOTE that Mail doesn't do the encryption so
Xyou must do the encryption before you send the message.  A way to do this is to
Xprepare the message before mailing it and put Mail in a pipeline like this.
X
X	% cat > msg
X	hello this is a test
X	^D
X	% crypt msg | Mail -e 'crypt' glenn
X	Key:
X	%
X
XOr you can do this.
X
X	% Mail -e 'vernam' glenn
X	Subject:  Only testing.
X	Hello this is a test
X	~|vernam -e -k toulouse -c 0123456789ABCDEF
X	(continue)
X	.
X	%
X
XSee the "vernam" program below.
X
X  Please remember that if you send encrypted mail to your friends they must
Xhave a way to decypher it.
X
XNow that you can send encrypted mail you should learn how to read it in case
Xyou receive some encrypted mail.  The changes to Mail will make mail messages
Xwith the "Encrypted:" field in the header show up in the header listing.
X
X% Mail
X...
X>N  1 boss     Fri Jan 11 08:37  12/234 "Get back to work!"
X N  2 secret   Fri Jan 11 08:37  vernam "A little message."
X
XNotice the line/characters field no long has lines/characters.
XI type:
X	& p 2
X
X	From secret  Fri Jan 11 08:37:59 1985
X	Received: by sdcrdcf.UUCP (4.12/4.7)
X		id AA10145; Fri, 11 Jan 85 08:35:29 pst
X	Date: Fri, 11 Jan 85 08:35:29 pst
X	From: secret (You'll never know)
X	Message-Id: <8501111635.AA10145@sdcrdcf.UUCP>
X	To: eglenn
X	Subject: A little message.
X	Encrypted: vernam
X
X	3C0A0C 4C2655 191007 1B5518 071A06 021C1B 552548 115311 110319 4C161A
X	064559 425515 000001 45170E 074B1C 551C0B 54091C 1E0A55 1A0B54 1B1D09
X	4F0512 171F06 1B0B4F 191C11 5A657F 65667C 7A6C7D 281909 011B79 274C5E
X
X
XVery nice !  To read it I type:
X
X	& decrypt vernam -d -k toulouse -c 0123456789ABCDEF
X
Xand I get something like:
X
X	From secret  Fri Jan 11 08:37:59 1985
X	Received: by sdcrdcf.UUCP (4.12/4.7)
X		id AA10145; Fri, 11 Jan 85 08:35:29 pst
X	Date: Fri, 11 Jan 85 08:35:29 pst
X	From: secret (You'll never know)
X	Message-Id: <8501111635.AA10145@sdcrdcf.UUCP>
X	To: eglenn
X	Subject: A little message.
X	Encrypted: vernam
X
X	      I just tought I'd tell you - you car's on fire in the parking lot.
X
XBeware !  Currently the 'decrypt' command works only on the current message.
Xie: you cannot type "decrypt 2 vernam -d -k toulouse -c 0123456789ABCDEF".
XThat's why I had to 'p'rint it first.
X
X  The enclosed programs are a encryptor/decryptor based on the encypherment
Xby (probably) Gilbert Vernam.  The second program may be used is an alias in
X/usr/lib/aliases to encrypt, via the vernam cypher, your incoming mail that is
Xplaced in your system mailbox.  Use a line like this in /usr/lib/aliases:
X
X	glenn:"|/b/glenn/bin/mailencrypt /usr/spool/mail/glenn"
X
X
X  The `vernam' program works some thing like this:
X
X  Given a key and a 16 character code the plaintext is exclusive or'ed with
Xsuccesive characters of the key.  The resulting 8-bit character value is split
Xinto 2 4-bit peices.  These peices are used as an index into the code
Xcharacters to be printed.  Therefore each character in the plaintext is
Xtranslated into 2 encrypted characters.  Send short messages.  Experiment with
Xthe enclosed programs and develop your own.  Amaze your friends, baffle your
Xenemies !!
EOF
echo x - cmd1.diff
sed 's/^X//' > cmd1.diff << 'EOF'
X*** /tmp/,RCSt1024747	Thu Jan 10 13:06:07 1985
X--- cmd1.c	Tue Jan  8 12:30:53 1985
X***************
X*** 193,198
X  	if (subjline == NOSTR)
X  		subjline = hfield("subj", mp);
X  
X  	/*
X  	 * Bletch!
X  	 */
X
X--- 193,200 -----
X  	if (subjline == NOSTR)
X  		subjline = hfield("subj", mp);
X  
X+ 	Encrypted = hfield("encrypted", mp);
X+ 
X  	/*
X  	 * Bletch!
X  	 */
X***************
X*** 212,218
X  	if (mp->m_flag & MBOX)
X  		dispc = 'M';
X  	parse(headline, &hl, pbuf);
X! 	sprintf(wcount, " %d/%ld", mp->m_lines, mp->m_size);
X  	s = strlen(wcount);
X  	cp = wcount + s;
X  	while (s < 7)
X
X--- 214,223 -----
X  	if (mp->m_flag & MBOX)
X  		dispc = 'M';
X  	parse(headline, &hl, pbuf);
X! 	if (Encrypted == NOSTR)
X! 		sprintf(wcount, " %d/%ld", mp->m_lines, mp->m_size);
X! 	else
X! 		sprintf(wcount, " %s", Encrypted);
X  	s = strlen(wcount);
X  	cp = wcount + s;
X  	while (s < 7)
EOF
echo x - cmd2.diff
sed 's/^X//' > cmd2.diff << 'EOF'
X*** /tmp/,RCSt1024686	Thu Jan 10 13:04:02 1985
X--- cmd2.c	Thu Jan 10 11:42:56 1985
X***************
X*** 512,514
X  
X  	return(strcmp(*l, *r));
X  }
X
X--- 512,570 -----
X  
X  	return(strcmp(*l, *r));
X  }
X+ 
X+ /*
X+  * Push the indicated messages at the end of the passed
X+  * file name, minus header and trailing blank line.
X+  */
X+ 
X+ scommand(command)
X+ char command[];
X+ {
X+ 	register int	*ip, mesg;
X+ 	register struct message *mp;
X+ 	register char	*disp;
X+ 	char linebuf[BUFSIZ];
X+ 	int	f, *msgvec, t;
X+ 	FILE	*obuf, *mesf;
X+ 
X+ 	printf("scommand(%s)\n", command);
X+ 
X+ 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
X+ 
X+ 	if ((*msgvec = first(0, MMNORM)) == NULL) {
X+ 		printf("No message to process.\n");
X+ 		return(1);
X+ 	}
X+ 	msgvec[1] = NULL;
X+ 
X+ 	if ((obuf = popen(command, "w")) == NULL) {
X+ 		perror(command);
X+ 		return(1);
X+ 	}
X+ 
X+ 	flush();
X+ 
X+ 		ip = msgvec;
X+ 		mesg = *ip;
X+ 		touch(mesg);
X+ 		mp = &message[mesg-1];
X+ 		mesf = setinput(mp);
X+ 		t = mp->m_lines - 1;
X+ 
X+ 		while (t-- > 0 && strlen(fgets(linebuf, BUFSIZ, mesf)) > 1) {
X+ 			fputs(linebuf, stdout);
X+ 		}
X+ 		putchar('\n');
X+ 		flush();
X+ 
X+ 		while (t-- > 0) {
X+ 			fgets(linebuf, BUFSIZ, mesf);
X+ 			fputs(linebuf, obuf);
X+ 		}
X+ 	fflush(obuf);
X+ 	if (ferror(obuf))
X+ 		perror(command);
X+ 	pclose(obuf);
X+ 	return(0);
X+ }
EOF
echo x - cmdtab.diff
sed 's/^X//' > cmdtab.diff << 'EOF'
X*** /tmp/,RCSt1024680	Thu Jan 10 13:03:44 1985
X--- cmdtab.c	Thu Jan 10 08:12:44 1985
X***************
X*** 18,23
X  extern int swrite(), dosh(), file(), echo(), Respond(), scroll(), ifcmd();
X  extern int elsecmd(), endifcmd(), mboxit(), clobber(), alternates();
X  extern int local(), folders(), igfield(), Type();
X  
X  struct cmd cmdtab[] = {
X  	"next",		next,		NDMLIST,	0,	MMNDEL,
X
X--- 18,24 -----
X  extern int swrite(), dosh(), file(), echo(), Respond(), scroll(), ifcmd();
X  extern int elsecmd(), endifcmd(), mboxit(), clobber(), alternates();
X  extern int local(), folders(), igfield(), Type();
X+ extern int scommand();
X  
X  struct cmd cmdtab[] = {
X  	"next",		next,		NDMLIST,	0,	MMNDEL,
X***************
X*** 79,83
X  	"core",		core,		M|NOLIST,	0,	0,
X  	"#",		null,		M|NOLIST,	0,	0,
X  	"clobber",	clobber,	M|RAWLIST,	0,	1,
X  	0,		0,		0,		0,	0
X  };
X
X--- 80,85 -----
X  	"core",		core,		M|NOLIST,	0,	0,
X  	"#",		null,		M|NOLIST,	0,	0,
X  	"clobber",	clobber,	M|RAWLIST,	0,	1,
X+ 	"decrypt",	scommand,	STRLIST,	0,	0,
X  	0,		0,		0,		0,	0
X  };
EOF
echo x - glob.diff
sed 's/^X//' > glob.diff << 'EOF'
X*** /tmp/,RCSt1027807	Thu Jan 10 15:07:57 1985
X--- glob.h	Thu Jan 10 15:07:36 1985
X***************
X*** 56,61
X  char	**localnames;			/* List of aliases for our local host */
X  int	debug;				/* Debug flag set */
X  int	rmail;				/* Being called as rmail */
X  
X  #include <setjmp.h>
X  
X
X--- 56,62 -----
X  char	**localnames;			/* List of aliases for our local host */
X  int	debug;				/* Debug flag set */
X  int	rmail;				/* Being called as rmail */
X+ char	*Encrypted;			/* Encrypted mail */
X  
X  #include <setjmp.h>
X  
EOF
echo x - mailencrypt.c
sed 's/^X//' > mailencrypt.c << 'EOF'
X#include <stdio.h>
X
Xchar	*Key, *Code;
X
Xmain(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
X	char	line[1024];
X	FILE	*fp;
X
X	if (freopen(argv[1], "a", stdout) == NULL)
X		exit(1);
X
X	/*
X	 * Copy the header untouched.
X	 */
X	while (fgets(line, sizeof(line), stdin) != NULL) {
X		if (strlen(line) < 2)
X			break;
X		fputs(line, stdout);
X	}
X
X	fputs("Encrypted: vernam\n\n", stdout);
X	fflush(stdout);
X	SetKey();
X	SetCode();
X	Encrypt();
X	Finish();
X	putchar('\n');
X	exit(0);
X}
X
X/*
X * This is pretty lame against someone
X * who is serious about breaking your mail
X * and has access to the binary of this program.
X * Set your Key and Code in these two routines.
X */
XSetKey()
X{
X	Key = (char *)malloc(8);
X
X	Key[0] = 't';
X	Key[1] = 'o';
X	Key[2] = 'u';
X	Key[3] = 'l';
X	Key[4] = 'o';
X	Key[5] = 'u';
X	Key[6] = 's';
X	Key[7] = 'e';
X	Key[8] = '\0';
X}
X
XSetCode()
X{
X	Code = (char *)malloc(17);
X
X	Code[0] = '0';
X	Code[1] = '1';
X	Code[2] = '2';
X	Code[3] = '3';
X	Code[4] = '4';
X	Code[5] = '5';
X	Code[6] = '6';
X	Code[7] = '7';
X	Code[8] = '8';
X	Code[9] = '9';
X	Code[10] = 'A';
X	Code[11] = 'B';
X	Code[12] = 'C';
X	Code[13] = 'D';
X	Code[14] = 'E';
X	Code[15] = 'F';
X	Code[16] = '\0';
X}
X
X
Xchar	*Keyp;
Xint	Bcount, Ccount;
X
XEncrypt()
X{
X	register char	c;
X
X	while ((c = getchar()) != EOF && !(ferror(stdin) || feof(stdin)))
X		EnCode(Cypher(c));
X}
X
X/* Vernam Cypher */
XCypher(c)
Xchar	c;
X{
X	if (Keyp == 0 || *Keyp == '\0')
X		Keyp = Key;
X
X	return (c ^ *Keyp++);
X}
X
XEnCode(c)
Xchar	c;
X{
X	Output(Code[(unsigned int)(c & 0xf0) >> 4]);
X	Output(Code[(unsigned int)(c & 0x0f)]);
X}
X
XOutput(c, fp)
Xchar	c;
XFILE	*fp;
X{
X	putchar(c);
X
X	if (++Ccount >= 6) {
X		Ccount = 0;
X		if (++Bcount >= 10) {
X			Bcount = 0;
X			putchar('\n');
X		} else
X			putchar(' ');
X	}
X}
X
XFinish()
X{
X	long	t;
X
X	time(&t);
X	srand(t);
X
X	while (Bcount)
X		EnCode(Cypher(Code[rand() & 0xf]));
X}
EOF
echo x - main.diff
sed 's/^X//' > main.diff << 'EOF'
X*** /tmp/,RCSt1024740	Thu Jan 10 13:05:56 1985
X--- main.c	Tue Jan  8 12:21:32 1985
X***************
X*** 214,219
X  			assign("verbose", "");
X  			break;
X  
X  		default:
X  			fprintf(stderr, "Unknown flag: %s\n", argv[i]);
X  			exit(1);
X
X--- 214,226 -----
X  			assign("verbose", "");
X  			break;
X  
X+ 		case 'e':
X+ 			/*
X+ 			 * Encrypted body.
X+ 			 */
X+ 			Encrypted = argv[i + 1];
X+ 			i++;
X+ 			break;
X  		default:
X  			fprintf(stderr, "Unknown flag: %s\n", argv[i]);
X  			exit(1);
EOF
echo x - vernam.c
sed 's/^X//' > vernam.c << 'EOF'
X#include <stdio.h>
Xchar	*Key;
Xchar	*Keyp;
Xchar	*Code;
Xint	Bcount, Ccount;
X
Xmain(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
X	FILE	*fpin, *fpout;
X	register len;
X	register decrypt = 0;
X
X	argc--, argv++;
X	while (argc > 0 && **argv == '-') {
X		register char *cp = *argv++;
X		argc--;
X		while (*++cp) switch (*cp) {
X			case 'k': 
X				len = strlen(*argv);
X				Key = (char *)strcpy(malloc(len + 1), *argv);
X				bzero(*argv, len);
X				argc--, argv++;
X				break;
X			case 'c':
X				len = strlen(*argv);
X				Code = (char *)strcpy(malloc(len + 1), *argv);
X				bzero(*argv, len);
X				argc--, argv++;
X				break;
X			case 'e':
X				decrypt = 0;
X				break;
X			case 'd':
X				decrypt++;
X				break;
X			default:
X				fprintf(stderr, "Unknown option: %c\n", *cp);
X				exit(1);
X		}
X	}
X
X
X	if (Key == (char *)0)
X		SetupKey();
X	if (Code == (char *)0)
X		SetupCode();
X
X	if (*argv) {
X		if ((fpin = freopen(*argv, "r", stdin)) == NULL) {
X			perror(*argv);
X			exit(1);
X		}
X		argv++;
X	}
X
X	if (*argv) {
X		if ((fpout = freopen(*argv, "w", stdout)) == NULL) {
X			perror(*argv);
X			exit(1);
X		}
X		argv++;
X	}
X
X	if (decrypt) {
X		Decrypt();
X	} else {
X		Encrypt();
X		Finish();
X	}
X
X	exit(0);
X}
X
XSetupKey()
X{
X	static char	line[1024];
X	char	*ptr;
X
X	fprintf(stderr, "Key: ");
X	fflush(stderr);
X	Getline(line, sizeof(line));
X
X	Key = line;
X}
X
XSetupCode()
X{
X	register	len;
X	static char	line[20];
X
X	do {
X		fprintf(stderr, "Code: ");
X		fflush(stderr);
X		Getline(line, sizeof(line));
X		len = strlen(line);
X	} while (len < 16);
X	line[16] = 0;
X	Code = line;
X}
X
XGetline(line, length)
Xchar	*line;
X{
X	char	*ptr;
X	FILE	*fp;
X
X	if ((fp = fopen("/dev/tty", "r")) == NULL) {
X		perror("/dev/tty");
X		exit(1);
X	}
X	if (fgets(line, length, fp) == NULL) {
X		fclose(fp);
X		return (1);
X	}
X	if ((ptr = (char *)index(line, '\n')) != NULL)
X		*ptr = 0;
X	fclose(fp);
X	return (0);
X}
X
XEncrypt()
X{
X	register char	c;
X
X	while ((c = getchar()) != EOF && !(ferror(stdin) || feof(stdin)))
X		EnCode(Cypher(c));
X}
X
X/* Vernam Cypher */
XCypher(c)
Xchar	c;
X{
X	if (Keyp == 0 || *Keyp == '\0')
X		Keyp = Key;
X
X	return (c ^ *Keyp++);
X}
X
XEnCode(c)
Xchar	c;
X{
X	Output(Code[(unsigned int)(c & 0xf0) >> 4]);
X	Output(Code[(unsigned int)(c & 0x0f)]);
X}
X
XOutput(c, fp)
Xchar	c;
XFILE	*fp;
X{
X	putchar(c);
X
X	if (++Ccount >= 6) {
X		Ccount = 0;
X		if (++Bcount >= 10) {
X			Bcount = 0;
X			putchar('\n');
X		} else
X			putchar(' ');
X	}
X}
X
XFinish()
X{
X	long	t;
X
X	time(&t);
X	srand(t);
X
X	while (Bcount)
X		EnCode(Cypher(Code[rand() & 0xf]));
X}
X
XDecrypt()
X{
X	register char	c;
X
X	while ((c = DeCode()) != -1)
X		putchar(Cypher(c));
X
X	putchar('\n');
X}
X
XDeCode()
X{
X	unsigned char	hi, lo, c;
X	char	*phi, *plo;
X
X	if ((hi = Input()) == -1)
X		return (-1);
X	if ((phi = (char *)index(Code, hi)) == NULL)
X		return (-1);
X
X	if ((lo = Input()) == -1 || (plo = (char *)index(Code, lo)) == NULL)
X		return (-1);
X
X	hi = phi - Code;
X	lo = plo - Code;
X
X	return (hi << 4 | lo);
X}
X
XInput()
X{
X	register char	c;
X
X	if ((c = getchar()) == EOF && (ferror(stdin) || feof(stdin)))
X		return(-1);
X
X	if (c == ' ' || c == '\n')
X		return (Input());
X
X	return (c);
X}
EOF