📄 cdes.c
字号:
/*
* CDES -- DES encryption package
* options:
* -a key is in ASCII
* -b use key in old style (ie, don't reset parity bit)
* -- default unless key is in ASCII
* -c use CBC (cipher block chaining) mode
* -e use ECB (electronic code book) mode
* -f b use b-bit CFB (cipher feedback) mode
* -F b use b-bit CFB (cipher feedback) alternative mode
* -i invert (decrypt) input
* -m b generate a MAC of length b
* -o b use b-bit OFB (output feedback) mode
* -v v use v as the initialization vector (ignored for ECB)
* note: the last character of the last block is the ASCII digit indicating
* how many characters of that block are to be output.
*/
#include <ctype.h>
#include <stdio.h>
#define C_NULL ((char *) NULL)
/*
* BSD and System V systems offer special library calls that do
* block moves and fills, so if possible we take advantage of them
*/
#ifdef BSD4
# define MEMCPY(dest,src,len) bcopy((src),(dest),(len))
# define MEMZERO(dest,len) bzero((dest),(len))
#else
#ifdef SYSV
# include <memory.h>
# define MEMCPY(dest,src,len) (void) memcpy((dest),(src),(len))
# define MEMZERO(dest,len) (void) memset((dest),'\0',(len))
#else
# define MEMCPY(dest,src,len) \
{ \
register int i1; \
for(i1 = 0; i1 < (len); i1++) \
(dest)[i1] = (src)[i1]; \
}
# define MEMZERO(dest,len) \
{ \
register int i1; \
for(i1 = 0; i1 < (len); i1++) \
(dest)[i1] = '\0'; \
}
#endif
#endif
/*
* these "hide" the calls to the primitive encryption routines
*/
#define DES_KEY(buf) { \
char bits1[64]; /* bits of key */ \
expand(buf, bits1); \
setkey(bits1); \
}
#define DES_XFORM(buf) { \
char bits1[64]; /* bits of message */ \
expand(buf, bits1); \
encrypt(bits1, inverse); \
compress(bits1, buf); \
}
/*
* this does an error-checking write
*/
#define READ(buf, n) fread(buf, sizeof(char), n, stdin)
#define WRITE(buf,n) \
if (fwrite(buf, sizeof(char), n, stdout) != n) \
err(1, bn, C_NULL);
/*
* some things to make references easier
*/
typedef char Desbuf[8];
#define CHAR(x,i) (x[i])
#define UCHAR(x,i) (x[i])
#define BUFFER(x) (x)
#define UBUFFER(x) (x)
/*
* global variables and related macros
*/
#define KEY_DEFAULT 0 /* interpret radix of key from key */
#define KEY_ASCII 1 /* key is in ASCII characters */
int keybase = KEY_DEFAULT; /* how to interpret the key */
#define MODE_ENCRYPT 0x01 /* encrypt */
#define MODE_DECRYPT 0x02 /* decrypt */
#define MODE_AUTHENTICATE 0x04 /* authenticate */
#define GET_DIRECTION ((mode)&0xf)
#define ISSET_MODE_DIRECTION (GET_DIRECTION != 0)
#define MODE_ECB 0x10 /* ECB mode */
#define MODE_CBC 0x20 /* CBC mode */
#define MODE_CFB 0x30 /* cipher feedback mode */
#define MODE_OFB 0x40 /* output feedback mode */
#define MODE_CFBA 0x50 /* alternative cipher feedback mode */
#define GET_ALGORITHM ((mode)&0xf0)
#define ISSET_MODE_ALGORITHM (GET_ALGORITHM != 0)
int mode = 0; /* how to run */
char *keyrep = "*********"; /* replaces command-line key */
Desbuf ivec; /* initialization vector */
char bits[] = { '\200', '\100', /* used to extract bits from a char */
'\040', '\020', '\010', '\004', '\002', '\001' };
int inverse = 0; /* 0 ti encrypt, 1 to decrypt */
char *progname = "des program"; /* program name */
int parity = 1; /* 0 to reset key parity bits */
int macbits = -1; /* number of bits in authentication */
int fbbits = -1; /* number of feedback bits */
char *dummyargs[] = { "*****", NULL }; /* argument list to be printed */
/*
* library hooks
*/
/* see getopt(3) */
extern int optind; /* option (argument) number */
extern char *optarg; /* argument to option if any */
/*
* library functions
*/
char *sprintf(); /* in core formatted print */
char *getpass(); /* get a password from a terminal */
main(argc, argv)
int argc;
char **argv;
{
register int i; /* counter in a for loop */
register char *p; /* used to obtain the key */
int n; /* number of command-line errors */
Desbuf msgbuf; /* I/O buffer */
int nargs; /* internal number of arguments */
char **arglist; /* internal argument list */
/*
* hide the arguments
*/
nargs = argc;
argc = 1;
arglist = argv;
argv = dummyargs;
/*
* initialize the initialization vctor
*/
for(i = 0; i < 8; i++)
UCHAR(ivec, i) = 0x00;
/*
* process the argument list
*/
progname = arglist[0];
n = 0;
while ((i = getopt(nargs, arglist, "abceF:f:im:o:v:")) != EOF)
switch(i){
case 'a': /* key is ASCII */
keybase = KEY_ASCII;
break;
case 'b': /* don't reset parity bit */
parity = 0;
break;
case 'c': /* use CBC mode */
if (ISSET_MODE_ALGORITHM)
err(1, -1, "two modes of operation specified");
mode |= MODE_CBC;
break;
case 'e': /* use ECB mode */
if (ISSET_MODE_ALGORITHM)
err(1, -1, "two modes of operation specified");
mode |= MODE_ECB;
break;
case 'F': /* use alternative CFB mode */
if (ISSET_MODE_ALGORITHM)
err(1, -1, "two modes of operation specified");
mode |= MODE_CFBA;
if ((fbbits = setbits(optarg, 7)) > 56 || fbbits == 0)
err(1, -1, "-F: number must be 1-56 inclusive");
else if (fbbits == -1)
err(1, -1, "-F: number must be a multiple of 7");
break;
case 'f': /* use CFB mode */
if (ISSET_MODE_ALGORITHM)
err(1, -1, "two modes of operation specified");
mode |= MODE_CFB;
if ((fbbits = setbits(optarg, 8)) > 64 || fbbits == 0)
err(1, -1, "-f: number must be 1-64 inclusive");
else if (fbbits == -1)
err(1, -1, "-f: number must be a multiple of 8");
break;
case 'i': /* decrypt */
if (ISSET_MODE_DIRECTION)
err(1, -1, "only one of -i and -m allowed");
mode |= MODE_DECRYPT;
break;
case 'm': /* number of bits for MACing */
if (ISSET_MODE_DIRECTION)
err(1, -1, "only one of -i and -m allowed");
mode |= MODE_AUTHENTICATE;
if ((macbits = setbits(optarg, 1)) > 64)
err(1, -1, "-m: number must be 0-64 inclusive");
break;
case 'o': /* use OFB mode */
if (ISSET_MODE_ALGORITHM)
err(1, -1, "two modes of operation specified");
mode |= MODE_OFB;
if ((fbbits = setbits(optarg, 8)) > 64 || fbbits == 0)
err(1, -1, "-o: number must be 1-64 inclusive");
else if (fbbits == -1)
err(1, -1, "-o: number must be a multiple of 8");
break;
case 'v': /* set initialization vector */
cvtkey(BUFFER(ivec), optarg);
break;
default: /* error */
n++;
break;
}
/*
* on error, quit
*/
if (n > 0)
exit(1);
/*
* if no direction set, default to encryption
*/
if (!ISSET_MODE_DIRECTION)
mode |= MODE_ENCRYPT;
if (!ISSET_MODE_ALGORITHM)
mode |= MODE_ECB;
/*
* pick up the key
* -- if there are no more arguments, prompt for it
* -- if there is 1 more argument, use it as the key
* -- if there are 2 or more arguments, error
*/
if (optind == nargs){
/*
* if the key's not ASCII, can't do this since
* only the first 8 chars are significant
*/
if (keybase != KEY_ASCII)
err(1, -1,
"you must enter non-ASCII keys on the command line");
/*
* get the key
*/
if ((p = getpass("Enter key: ")) == NULL)
err(1, -1, "no key given");
/*
* copy it, nul-padded, into the key area
*/
strncpy(BUFFER(msgbuf), p, 8);
}
else if (optind + 1 == nargs){
/*
* obtain the bit form of the key
* and hide it from a "ps"
*/
cvtkey(BUFFER(msgbuf), arglist[optind]);
arglist[optind] = keyrep;
}
else{
/*
* extra arguments -- bomb
*/
err(1, -1, "extraneous arguments");
}
/*
* main loop
*/
switch(mode){
case MODE_ECB|MODE_ENCRYPT: /* encrypt using ECB mode */
inverse = 0;
makekey(msgbuf);
ecbenc();
break;
case MODE_ECB|MODE_DECRYPT: /* decrypt using ECB mode */
inverse = 1;
makekey(msgbuf);
ecbdec();
break;
case MODE_ECB|MODE_AUTHENTICATE: /* authenticate using ECB */
err(1, -1, "can't authenticate with ECB mode");
break;
case MODE_CBC|MODE_ENCRYPT: /* encrypt using CBC mode */
inverse = 0;
makekey(msgbuf);
cbcenc();
break;
case MODE_CBC|MODE_DECRYPT: /* decrypt using CBC mode */
inverse = 1;
makekey(msgbuf);
cbcdec();
break;
case MODE_CBC|MODE_AUTHENTICATE: /* authenticate using CBC */
inverse = 0;
makekey(msgbuf);
cbcauth();
break;
case MODE_CFB|MODE_ENCRYPT: /* encrypt using CFB mode */
inverse = 0;
makekey(msgbuf);
cfbenc();
break;
case MODE_CFB|MODE_DECRYPT: /* decrypt using CFB mode */
inverse = 0;
makekey(msgbuf);
cfbdec();
break;
case MODE_CFB|MODE_AUTHENTICATE: /* authenticate using CFB */
inverse = 0;
makekey(msgbuf);
cfbauth();
break;
case MODE_CFBA|MODE_ENCRYPT: /* alternative CFB mode */
inverse = 0;
makekey(msgbuf);
cfbaenc();
break;
case MODE_CFBA|MODE_DECRYPT: /* alternative CFB mode */
inverse = 0;
makekey(msgbuf);
cfbadec();
break;
case MODE_OFB|MODE_ENCRYPT: /* encrypt using OFB mode */
inverse = 0;
makekey(msgbuf);
ofbenc();
break;
case MODE_OFB|MODE_DECRYPT: /* decrypt using OFB mode */
inverse = 0;
makekey(msgbuf);
ofbdec();
break;
default: /* unimplemented */
err(1, -1, "can't handle that yet");
break;
}
exit(0);
}
/*
* print a warning message and, possibly, terminate
*/
err(f, n, s)
int f; /* >0 if fatal (status code), 0 if not */
int n; /* offending block number */
char *s; /* the message */
{
char tbuf[BUFSIZ];
if (n > 0)
(void) sprintf(tbuf, "%s (block %d)", progname, n);
else
(void) sprintf(tbuf, "%s", progname);
if (s == C_NULL)
perror(tbuf);
else
fprintf(stderr, "%s: %s\n", tbuf, s);
if (f > 0)
exit(f);
}
/*
* map a hex character to an integer
*/
int tohex(c)
char c;
{
switch(c){
case '0': return(0x0);
case '1': return(0x1);
case '2': return(0x2);
case '3': return(0x3);
case '4': return(0x4);
case '5': return(0x5);
case '6': return(0x6);
case '7': return(0x7);
case '8': return(0x8);
case '9': return(0x9);
case 'A': case 'a': return(0xa);
case 'B': case 'b': return(0xb);
case 'C': case 'c': return(0xc);
case 'D': case 'd': return(0xd);
case 'E': case 'e': return(0xe);
case 'F': case 'f': return(0xf);
}
/*
* invalid character
*/
return(-1);
}
/*
* convert the key to a bit pattern
*/
cvtkey(obuf, ibuf)
char *obuf;
char *ibuf;
{
register int i; /* counter in a for loop */
int nbuf[16]; /* used for hes/key translation */
/*
* just switch on the key base
*/
switch(keybase){
case KEY_ASCII: /* ascii to integer */
(void) strncpy(obuf, ibuf, 8);
return;
case KEY_DEFAULT: /* tell from context */
/*
* leading '0x' or '0X' == hex key
*/
if (ibuf[0] == '0' && (ibuf[1] == 'x' || ibuf[1] == 'x')){
ibuf = &ibuf[2];
/*
* now translate it,m bombing on any illegal hex digit
*/
for(i = 0; ibuf[i] && i < 16; i++)
if ((nbuf[i] = tohex(ibuf[i])) == -1)
err(1, -1, "bad hex digit in key");
while(i < 16)
nbuf[i++] = 0;
for(i = 0; i < 8; i++)
obuf[i] = ((nbuf[2*i]&0xf)<<4)|
(nbuf[2*i+1]&0xf);
parity = 0;
return;
}
/*
* no special leader -- ASCII
*/
(void) strncpy(obuf, ibuf, 8);
}
}
/*
* convert an ASCII string into a decimal number:
* 1. must be between 0 and 64 inclusive
* 2. must be a valid decimal number
* 3. must be a multiple of mult
*/
setbits(s, mult)
char *s;
{
register char *p;
register int n = 0;
/*
* skip white space
*/
while (isspace(*s))
s++;
/*
* get the integer
*/
for(p = s; *p; p++){
if (isdigit(*p))
n = n * 10 + *p - '0';
else{
err(1, -1, "bad decimal digit in MAC length");
}
}
/*
* be sure it's a multiple of mult
*/
return((n % mult != 0) ? -1 : n);
}
/*****************
* DES FUNCTIONS *
*****************/
/*
* This sets the DES key and (if you're using the deszip version)
* the direction of the transformation. Note there are two ways
* to map the 64-bit key onto the 56 bits that the key schedule
* generation routines use: the old way, which just uses the user-
* supplied 64 bits as is, and the new way, which resets the parity
* bit to be the same as the low-order bit in each character. The
* new way generates a greater variety of key schedules, since many
* systems set the parity (high) bit of each character to 0, and the
* DES ignores the low order bit of each character.
*/
makekey(buf)
Desbuf buf; /* key block */
{
register int i; /* counter in a for loop */
/*
* if using new key arrangement, reset the parity bit
* to be the same as the low-order bit
*/
if (parity){
for(i = 0; i < 8; i++)
UCHAR(buf, i) = (UCHAR(buf, i)&0177)|
((UCHAR(buf, i)&01)<<7);
}
/*
* Make the key schedule
*/
DES_KEY(UBUFFER(buf));
}
/*
* This encrypts using the Electronic Code Book mode of DES
*/
ecbenc()
{
register int n; /* number of bytes actually read */
register int bn; /* block number */
Desbuf msgbuf; /* I/O buffer */
for(bn = 0; (n = READ(BUFFER(msgbuf), 8)) == 8; bn++){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -