cbc.c revision 16
116Salm/* cbc.c: This file contains the encryption routines for the ed line editor */ 216Salm/*- 316Salm * Copyright (c) 1991 The Regents of the University of California. 416Salm * All rights reserved. 516Salm * 616Salm * This code is derived from software contributed to Berkeley by 716Salm * Matt Bishop of Dartmouth College. 816Salm * 916Salm * The United States Government has rights in this work pursuant 1016Salm * to contract no. NAG 2-680 between the National Aeronautics and 1116Salm * Space Administration and Dartmouth College. 1216Salm * 1316Salm * Redistribution and use in source and binary forms, with or without 1416Salm * modification, are permitted provided that the following conditions 1516Salm * are met: 1616Salm * 1. Redistributions of source code must retain the above copyright 1716Salm * notice, this list of conditions and the following disclaimer. 1816Salm * 2. Redistributions in binary form must reproduce the above copyright 1916Salm * notice, this list of conditions and the following disclaimer in the 2016Salm * documentation and/or other materials provided with the distribution. 2116Salm * 3. All advertising materials mentioning features or use of this software 2216Salm * must display the following acknowledgement: 2316Salm * This product includes software developed by the University of 2416Salm * California, Berkeley and its contributors. 2516Salm * 4. Neither the name of the University nor the names of its contributors 2616Salm * may be used to endorse or promote products derived from this software 2716Salm * without specific prior written permission. 2816Salm * 2916Salm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 3016Salm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3116Salm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3216Salm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3316Salm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3416Salm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3516Salm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3616Salm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3716Salm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3816Salm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3916Salm * SUCH DAMAGE. 4016Salm */ 4116Salm 4216Salm#ifndef lint 4316Salmstatic char sccsid[] = "@(#)cbc.c 5.5 (Berkeley) 6/27/91"; 4416Salm#endif /* not lint */ 4516Salm 4616Salm/* Author: Matt Bishop 4716Salm * Department of Mathematics and Computer Science 4816Salm * Dartmouth College 4916Salm * Hanover, NH 03755 5016Salm * Email: Matt.Bishop@dartmouth.edu 5116Salm * ...!decvax!dartvax!Matt.Bishop 5216Salm * 5316Salm * See Technical Report PCS-TR91-158, Department of Mathematics and Computer 5416Salm * Science, Dartmouth College, for a detailed description of the implemen- 5516Salm * tation and differences between it and Sun's. The DES is described in 5616Salm * FIPS PUB 46, and the modes in FIPS PUB 81 (see either the manual page 5716Salm * or the technical report for a complete reference). 5816Salm */ 5916Salm 6016Salm#include <errno.h> 6116Salm#include <pwd.h> 6216Salm#include <unistd.h> 6316Salm#include <stdio.h> 6416Salm#include <ctype.h> 6516Salm#include <stdlib.h> 6616Salm#include <string.h> 6716Salm#include <sys/types.h> 6816Salm 6916Salm#include "ed.h" 7016Salm 7116Salm/* 7216Salm * Define a divisor for rand() that yields a uniform distribution in the 7316Salm * range 0-255. 7416Salm */ 7516Salm#define RAND_DIV (((unsigned) RAND_MAX + 1) >> 8) 7616Salm 7716Salm/* 7816Salm * BSD and System V systems offer special library calls that do 7916Salm * block moves and fills, so if possible we take advantage of them 8016Salm */ 8116Salm#define MEMCPY(dest,src,len) memcpy((dest),(src),(len)) 8216Salm#define MEMZERO(dest,len) memset((dest), 0, (len)) 8316Salm 8416Salm/* Hide the calls to the primitive encryption routines. */ 8516Salm#define DES_KEY(buf) \ 8616Salm if (des_setkey(buf)) \ 8716Salm err("des_setkey"); 8816Salm#define DES_XFORM(buf) \ 8916Salm if (des_cipher(buf, buf, 0L, (inverse ? -1 : 1))) \ 9016Salm err("des_cipher"); 9116Salm 9216Salm/* 9316Salm * read/write - no error checking 9416Salm */ 9516Salm#define READ(buf, n, fp) fread(buf, sizeof(char), n, fp) 9616Salm#define WRITE(buf, n, fp) fwrite(buf, sizeof(char), n, fp) 9716Salm 9816Salm/* 9916Salm * some things to make references easier 10016Salm */ 10116Salmtypedef char Desbuf[8]; 10216Salm#define CHAR(x,i) (x[i]) 10316Salm#define UCHAR(x,i) (x[i]) 10416Salm#define BUFFER(x) (x) 10516Salm#define UBUFFER(x) (x) 10616Salm 10716Salm/* 10816Salm * global variables and related macros 10916Salm */ 11016Salm 11116Salmenum { /* encrypt, decrypt, authenticate */ 11216Salm MODE_ENCRYPT, MODE_DECRYPT, MODE_AUTHENTICATE 11316Salm} mode = MODE_ENCRYPT; 11416Salm 11516SalmDesbuf ivec; /* initialization vector */ 11616SalmDesbuf pvec; /* padding vector */ 11716Salmchar bits[] = { /* used to extract bits from a char */ 11816Salm '\200', '\100', '\040', '\020', '\010', '\004', '\002', '\001' 11916Salm}; 12016Salmint pflag; /* 1 to preserve parity bits */ 12116Salm 12216Salmchar des_buf[8]; /* shared buffer for desgetc/desputc */ 12316Salmint des_ct = 0; /* count for desgetc/desputc */ 12416Salmint des_n = 0; /* index for desputc/desgetc */ 12516Salm 12616Salm 12716Salm/* desinit: initialize DES */ 12816Salmvoid 12916Salmdesinit() 13016Salm{ 13116Salm#ifdef DES 13216Salm int i; 13316Salm 13416Salm des_ct = des_n = 0; 13516Salm 13616Salm /* initialize the initialization vctor */ 13716Salm MEMZERO(ivec, 8); 13816Salm 13916Salm /* intialize the padding vector */ 14016Salm srand((unsigned) time((time_t *) 0)); 14116Salm for (i = 0; i < 8; i++) 14216Salm CHAR(pvec, i) = (char) (rand()/RAND_DIV); 14316Salm#endif 14416Salm} 14516Salm 14616Salm 14716Salm/* desgetc: return next char in an encrypted file */ 14816Salmdesgetc(fp) 14916Salm FILE *fp; 15016Salm{ 15116Salm#ifdef DES 15216Salm if (des_n >= des_ct) { 15316Salm des_n = 0; 15416Salm des_ct = cbcdec(des_buf, fp); 15516Salm } 15616Salm return (des_ct > 0) ? des_buf[des_n++] : EOF; 15716Salm#endif 15816Salm} 15916Salm 16016Salm 16116Salm/* desputc: write a char to an encrypted file; return char written */ 16216Salmdesputc(c, fp) 16316Salm int c; 16416Salm FILE *fp; 16516Salm{ 16616Salm#ifdef DES 16716Salm if (des_n == sizeof des_buf) { 16816Salm des_ct = cbcenc(des_buf, des_n, fp); 16916Salm des_n = 0; 17016Salm } 17116Salm return (des_ct >= 0) ? (des_buf[des_n++] = c) : EOF; 17216Salm#endif 17316Salm} 17416Salm 17516Salm 17616Salm/* desflush: flush an encrypted file's output; return status */ 17716Salmdesflush(fp) 17816Salm FILE *fp; 17916Salm{ 18016Salm#ifdef DES 18116Salm if (des_n == sizeof des_buf) { 18216Salm des_ct = cbcenc(des_buf, des_n, fp); 18316Salm des_n = 0; 18416Salm } 18516Salm return (des_ct >= 0 && cbcenc(des_buf, des_n, fp) >= 0) ? 0 : EOF; 18616Salm#endif 18716Salm} 18816Salm 18916Salm#ifdef DES 19016Salm/* 19116Salm * get keyword from tty or stdin 19216Salm */ 19316Salmgetkey() 19416Salm{ 19516Salm register char *p; /* used to obtain the key */ 19616Salm Desbuf msgbuf; /* I/O buffer */ 19716Salm 19816Salm /* 19916Salm * get the key 20016Salm */ 20116Salm if (*(p = getpass("Enter key: "))) { 20216Salm 20316Salm /* 20416Salm * copy it, nul-padded, into the key area 20516Salm */ 20616Salm cvtkey(BUFFER(msgbuf), p); 20716Salm MEMZERO(p, _PASSWORD_LEN); 20816Salm makekey(msgbuf); 20916Salm MEMZERO(msgbuf, sizeof msgbuf); 21016Salm return 1; 21116Salm } 21216Salm return 0; 21316Salm} 21416Salm 21516Salm 21616Salmextern char errmsg[]; 21716Salm 21816Salm/* 21916Salm * print a warning message and, possibly, terminate 22016Salm */ 22116Salmvoid 22216Salmerr(s) 22316Salm char *s; /* the message */ 22416Salm{ 22516Salm (void)sprintf(errmsg, "%s", s ? s : strerror(errno)); 22616Salm} 22716Salm 22816Salm/* 22916Salm * map a hex character to an integer 23016Salm */ 23116Salmtobinhex(c, radix) 23216Salm int c; /* char to be converted */ 23316Salm int radix; /* base (2 to 16) */ 23416Salm{ 23516Salm switch(c) { 23616Salm case '0': return(0x0); 23716Salm case '1': return(0x1); 23816Salm case '2': return(radix > 2 ? 0x2 : -1); 23916Salm case '3': return(radix > 3 ? 0x3 : -1); 24016Salm case '4': return(radix > 4 ? 0x4 : -1); 24116Salm case '5': return(radix > 5 ? 0x5 : -1); 24216Salm case '6': return(radix > 6 ? 0x6 : -1); 24316Salm case '7': return(radix > 7 ? 0x7 : -1); 24416Salm case '8': return(radix > 8 ? 0x8 : -1); 24516Salm case '9': return(radix > 9 ? 0x9 : -1); 24616Salm case 'A': case 'a': return(radix > 10 ? 0xa : -1); 24716Salm case 'B': case 'b': return(radix > 11 ? 0xb : -1); 24816Salm case 'C': case 'c': return(radix > 12 ? 0xc : -1); 24916Salm case 'D': case 'd': return(radix > 13 ? 0xd : -1); 25016Salm case 'E': case 'e': return(radix > 14 ? 0xe : -1); 25116Salm case 'F': case 'f': return(radix > 15 ? 0xf : -1); 25216Salm } 25316Salm /* 25416Salm * invalid character 25516Salm */ 25616Salm return(-1); 25716Salm} 25816Salm 25916Salm/* 26016Salm * convert the key to a bit pattern 26116Salm */ 26216Salmvoid 26316Salmcvtkey(obuf, ibuf) 26416Salm char *obuf; /* bit pattern */ 26516Salm char *ibuf; /* the key itself */ 26616Salm{ 26716Salm register int i, j; /* counter in a for loop */ 26816Salm int nbuf[64]; /* used for hex/key translation */ 26916Salm 27016Salm /* 27116Salm * leading '0x' or '0X' == hex key 27216Salm */ 27316Salm if (ibuf[0] == '0' && (ibuf[1] == 'x' || ibuf[1] == 'X')) { 27416Salm ibuf = &ibuf[2]; 27516Salm /* 27616Salm * now translate it, bombing on any illegal hex digit 27716Salm */ 27816Salm for (i = 0; ibuf[i] && i < 16; i++) 27916Salm if ((nbuf[i] = tobinhex((int) ibuf[i], 16)) == -1) 28016Salm err("bad hex digit in key"); 28116Salm while (i < 16) 28216Salm nbuf[i++] = 0; 28316Salm for (i = 0; i < 8; i++) 28416Salm obuf[i] = 28516Salm ((nbuf[2*i]&0xf)<<4) | (nbuf[2*i+1]&0xf); 28616Salm /* preserve parity bits */ 28716Salm pflag = 1; 28816Salm return; 28916Salm } 29016Salm /* 29116Salm * leading '0b' or '0B' == binary key 29216Salm */ 29316Salm if (ibuf[0] == '0' && (ibuf[1] == 'b' || ibuf[1] == 'B')) { 29416Salm ibuf = &ibuf[2]; 29516Salm /* 29616Salm * now translate it, bombing on any illegal binary digit 29716Salm */ 29816Salm for (i = 0; ibuf[i] && i < 16; i++) 29916Salm if ((nbuf[i] = tobinhex((int) ibuf[i], 2)) == -1) 30016Salm err("bad binary digit in key"); 30116Salm while (i < 64) 30216Salm nbuf[i++] = 0; 30316Salm for (i = 0; i < 8; i++) 30416Salm for (j = 0; j < 8; j++) 30516Salm obuf[i] = (obuf[i]<<1)|nbuf[8*i+j]; 30616Salm /* preserve parity bits */ 30716Salm pflag = 1; 30816Salm return; 30916Salm } 31016Salm /* 31116Salm * no special leader -- ASCII 31216Salm */ 31316Salm (void)strncpy(obuf, ibuf, 8); 31416Salm} 31516Salm 31616Salm/***************** 31716Salm * DES FUNCTIONS * 31816Salm *****************/ 31916Salm/* 32016Salm * This sets the DES key and (if you're using the deszip version) 32116Salm * the direction of the transformation. This uses the Sun 32216Salm * to map the 64-bit key onto the 56 bits that the key schedule 32316Salm * generation routines use: the old way, which just uses the user- 32416Salm * supplied 64 bits as is, and the new way, which resets the parity 32516Salm * bit to be the same as the low-order bit in each character. The 32616Salm * new way generates a greater variety of key schedules, since many 32716Salm * systems set the parity (high) bit of each character to 0, and the 32816Salm * DES ignores the low order bit of each character. 32916Salm */ 33016Salmvoid 33116Salmmakekey(buf) 33216Salm Desbuf buf; /* key block */ 33316Salm{ 33416Salm register int i, j; /* counter in a for loop */ 33516Salm register int par; /* parity counter */ 33616Salm 33716Salm /* 33816Salm * if the parity is not preserved, flip it 33916Salm */ 34016Salm if (!pflag) { 34116Salm for (i = 0; i < 8; i++) { 34216Salm par = 0; 34316Salm for (j = 1; j < 8; j++) 34416Salm if ((bits[j]&UCHAR(buf, i)) != 0) 34516Salm par++; 34616Salm if ((par&01) == 01) 34716Salm UCHAR(buf, i) = UCHAR(buf, i)&0177; 34816Salm else 34916Salm UCHAR(buf, i) = (UCHAR(buf, i)&0177)|0200; 35016Salm } 35116Salm } 35216Salm 35316Salm DES_KEY(UBUFFER(buf)); 35416Salm} 35516Salm 35616Salm 35716Salm/* 35816Salm * This encrypts using the Cipher Block Chaining mode of DES 35916Salm */ 36016Salmcbcenc(msgbuf, n, fp) 36116Salm char *msgbuf; 36216Salm int n; 36316Salm FILE *fp; 36416Salm{ 36516Salm int inverse = 0; /* 0 to encrypt, 1 to decrypt */ 36616Salm 36716Salm /* 36816Salm * do the transformation 36916Salm */ 37016Salm if (n == 8) { 37116Salm for (n = 0; n < 8; n++) 37216Salm CHAR(msgbuf, n) ^= CHAR(ivec, n); 37316Salm DES_XFORM(UBUFFER(msgbuf)); 37416Salm MEMCPY(BUFFER(ivec), BUFFER(msgbuf), 8); 37516Salm return WRITE(BUFFER(msgbuf), 8, fp); 37616Salm } 37716Salm /* 37816Salm * at EOF or last block -- in either case, the last byte contains 37916Salm * the character representation of the number of bytes in it 38016Salm */ 38116Salm/* 38216Salm MEMZERO(msgbuf + n, 8 - n); 38316Salm*/ 38416Salm /* 38516Salm * Pad the last block randomly 38616Salm */ 38716Salm (void)MEMCPY(BUFFER(msgbuf + n), BUFFER(pvec), 8 - n); 38816Salm CHAR(msgbuf, 7) = n; 38916Salm for (n = 0; n < 8; n++) 39016Salm CHAR(msgbuf, n) ^= CHAR(ivec, n); 39116Salm DES_XFORM(UBUFFER(msgbuf)); 39216Salm return WRITE(BUFFER(msgbuf), 8, fp); 39316Salm} 39416Salm 39516Salm/* 39616Salm * This decrypts using the Cipher Block Chaining mode of DES 39716Salm */ 39816Salmcbcdec(msgbuf, fp) 39916Salm char *msgbuf; /* I/O buffer */ 40016Salm FILE *fp; /* input file descriptor */ 40116Salm{ 40216Salm Desbuf ibuf; /* temp buffer for initialization vector */ 40316Salm register int n; /* number of bytes actually read */ 40416Salm register int c; /* used to test for EOF */ 40516Salm int inverse = 1; /* 0 to encrypt, 1 to decrypt */ 40616Salm 40716Salm if ((n = READ(BUFFER(msgbuf), 8, fp)) == 8) { 40816Salm /* 40916Salm * do the transformation 41016Salm */ 41116Salm MEMCPY(BUFFER(ibuf), BUFFER(msgbuf), 8); 41216Salm DES_XFORM(UBUFFER(msgbuf)); 41316Salm for (c = 0; c < 8; c++) 41416Salm UCHAR(msgbuf, c) ^= UCHAR(ivec, c); 41516Salm MEMCPY(BUFFER(ivec), BUFFER(ibuf), 8); 41616Salm /* 41716Salm * if the last one, handle it specially 41816Salm */ 41916Salm if ((c = fgetc(fp)) == EOF) { 42016Salm n = CHAR(msgbuf, 7); 42116Salm if (n < 0 || n > 7) { 42216Salm err("decryption failed (block corrupted)"); 42316Salm return EOF; 42416Salm } 42516Salm } else 42616Salm (void)ungetc(c, fp); 42716Salm return n; 42816Salm } 42916Salm if (n > 0) 43016Salm err("decryption failed (incomplete block)"); 43116Salm else if (n < 0) 43216Salm err("cannot read file"); 43316Salm return EOF; 43416Salm} 43516Salm#endif /* DES */ 436