📄 cipher.c
字号:
/* * cipher - a more secure replacement for UNIX crypt program * * Generic block encipherment/decipherment program * modified specifically for the Data Encryption Standard using * Cipher Block Feedback (CFB) mode as described in FIPS pub 81. * * See also FIPS PUB 74. * * Permission is given copy and use this program provided it is not sold * for profit. * * Written by David A. Barrett (barrett%asgard@boulder.Colorado.EDU) */#define _POSIX_SOURCE/* * Include files don't declare read(2), write(2), and getopt(3) consistantly. * Specifically, getopt is not part of POSIX so the location of its * declaration and how to make it visable with _POSIX_SOURCE is non-portable. * Secondly, whether "const" is used in the prototypes or not causes some * compilers to issue a fatal error and abort compilation. I use read * and write rather than fread and fwrite to avoid an extra copying step * and having yet another copy of the plaintext lying around in memory. * Getopt is, of course, used for parsing command-line options. */#include <unistd.h> /* POSIX: read write */#include <stdlib.h> /* AES: getopt ANSII C: exit */#include <stdio.h>#include <string.h>#if defined(__msdos) || defined(__MSDOS__)#include <fcntl.h> /* for setmode O_BINARY */#endif#include "cipher.h"extern int errno;extern char *sys_errlist[];extern int sys_nerr;extern int optind;extern char *optarg;#if defined(__STDC__) || defined(__cplusplus)extern int getkey(char *, char *, unsigned);#elseextern int getkey();#endif#if defined(__msdos) || defined(__MSDOS__)#define PATHCHAR '\\'#else#define PATHCHAR '/'#endifstatic char ident[] =" @(#) cipher.c version 3.00 04-Apr-94. Copyright 1994 by Dave Barrett\n";static char rcsIdent[] = " @(#) cipher.c $Revision: 1.8 $ $Date: 94/04/04 13:32:18 $\n";#define IO_BUFSIZE 1024 /* small for data cache speed */#define MAXCIPHER 10 /* maximum multiple encipherments */#define KEYBUFLEN 129 /* allow long keys */typedef struct { char iv[DES_BLOCKSIZE]; keyType key; int ivlen; int decr;} KeyItem;KeyItem keys[MAXCIPHER];char bufs[2][IO_BUFSIZE];char *progName;typedef unsigned char block[DES_BLOCKSIZE];/* * Keys which could accidently reproduce the plaintext with multiple-encryption */block badKeys[16] = { { 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00 }, { 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0 }, { 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e }, { 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe }, { 0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e }, { 0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0 }, { 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe }, { 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00 }, { 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e }, { 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00 }, { 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe }, { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* self-dual */ { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }, /* self-dual */ { 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0 }, /* self-dual */ { 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e }, /* self-dual */};/* * Return nonzero if the key is one of the well-known "weak" keys (FIPS Pub 74) */int weakKey(keybits) char *keybits;{ register block *keyp = &(badKeys[0]); /* common compiler bug here */ register unsigned count = sizeof(badKeys) / sizeof(badKeys[0]); register unsigned i; do { for (i = 0; i < DES_BLOCKSIZE; i++) { if ((((*keyp)[i] ^ keybits[i]) & 0xfe) != 0) goto notfound; } break;notfound: keyp++; } while (--count != 0); return count;}int hexdigit(ch) register char ch;{ if (ch >= '0' && ch <= '9') return ch - '0'; if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; return -1;}/* * Convert an ASCII hexadecimal number to it's corresponding string of bytes */unsigned hex(d, s, size) register char *d, *s; register unsigned size;{ register unsigned count = 0; register int lo, hi; if (size > 0) do { hi = hexdigit(*s++); if (hi < 0) break; lo = hexdigit(*s++); if (lo < 0) break; *d++ = (hi << 4) | lo; count++; } while (count < size); return count;}/* * Because we are using CFB, we always encrypt. Since we'd like to be * able to run the chips in either mode, perhaps CBC would be better. * If CBC is used though, the last block must be handled in OFB mode. Sigh. * * Returns: * -1 - out of memory (program exits, and error reported) * 0 - success * 1 - key is a weak key */int setKey(kp, keybits, keystr, mode) register keyType *kp; char *keybits, *keystr; int mode;{ register int res; if (keystr != (char *) 0) { desKey(keybits, keystr, ' '); /* space padded */ memset(keystr, '\0', strlen(keystr)); /* blank out key asap */ } res = weakKey(keybits); makeKey(kp, keybits, DES_BLOCKSIZE, mode); /* 0 means encrypt mode */ memset(keybits, '\0', DES_BLOCKSIZE); /* zero out bits asap */ if (*kp == (keyType) 0) { fprintf(stderr, "%s: couldn't allocate memory for encryption key\n", progName); exit(1); } return res;}int main(argc, argv) int argc; char *argv[];{ int i, ch, rcount, wcount = -1; int ivcount = 0, keycount = 0, decrcount = 0, ciphercount = 1; int checkkey = 1, keystrlen = 0, keylen = 0; char *chp, *ibuf = bufs[1], *obuf = bufs[0]; char keybits[DES_BLOCKSIZE], ivbits[DES_BLOCKSIZE]; char keybuf[KEYBUFLEN], chkbuf[KEYBUFLEN], ivbuf[DES_BLOCKSIZE]; KeyItem *kip; progName = *argv; if ((chp = strrchr(progName, PATHCHAR)) != (char *) 0) progName = chp+1; if (strcmp(progName, "decipher")==0 || strcmp(progName, "decrypt")==0) { keys[decrcount].decr = 1; } else { keys[decrcount].decr = 0; } while ((ch = getopt(argc, argv, "devni:k:x:")) != EOF) switch (ch) { case 'd': if (decrcount == MAXCIPHER) goto cipherError; keys[decrcount++].decr = 1; /* decrypt */ break; case 'e': if (decrcount == MAXCIPHER) goto cipherError; keys[decrcount++].decr = 0; /* encrypt */ break; case 'i': /* initialization vector */ if (ivcount == MAXCIPHER) goto cipherError; memset(ivbits, '\0', DES_BLOCKSIZE); /* pad iv with '\0' */ /* default IV is zero */ i = hex(ivbuf, optarg, DES_BLOCKSIZE); /* right-justified */ memcpy(ivbits + DES_BLOCKSIZE - i, ivbuf, i); memcpy(keys[ivcount++].iv, ivbits, DES_BLOCKSIZE); break; case 'x': /* key in hexadecimal */ if (keycount == MAXCIPHER) goto cipherError; memset(keybits, '\0', DES_BLOCKSIZE); /* pad key with '\0' */ keylen = hex(keybits, optarg,DES_BLOCKSIZE); /* left-justified */ i = setKey(&keys[keycount++].key, keybits, (char *) 0, 0); goto chkKey; case 'k': /* key as a string */ if (keycount == MAXCIPHER) goto cipherError; i = setKey(&keys[keycount++].key, keybits, optarg, 0);chkKey: if (i) { fprintf(stderr, "%s: warning -- weak key selected\n", progName); } break; case 'v': checkkey++; break; case 'n': --checkkey; break; case '?': default:usage: fprintf(stderr, "usage: %s [ -v|n ] {-de} {-i hex_initvec } {-x hex_key } {-k keystring }\n", progName); return 1;cipherError: fprintf(stderr, "%s: can't exceed %d multiple-encipherments\n", progName, MAXCIPHER); return 1; } argc -= optind; argv += optind; if (argc != 0) goto usage; if (decrcount == 0) decrcount++;#if defined(__msdos) || defined(__MSDOS__)/* * Microsoft C munges '\r', '\n', and ^Z on EOF * This stops that behavior (ciphertext is definitely binary) * * I cannot find a machine independent way to re-open stdin in binary mode */ ch = setmode(0, O_BINARY); ch = setmode(1, O_BINARY);#endif if (decrcount > ciphercount) ciphercount = decrcount; if (ivcount > ciphercount) ciphercount = ivcount; if (keycount > ciphercount) ciphercount = keycount; while (decrcount < ciphercount) keys[decrcount++].decr = keys[0].decr; while (ivcount < ciphercount) { /* default IV = 0 */ keys[ivcount].ivlen = DES_BLOCKSIZE; memset(keys[ivcount++].iv, '\0', DES_BLOCKSIZE); } while (keycount < ciphercount) { /* must input all keys */ keystrlen = getkey("Input Key:", keybuf, KEYBUFLEN-1);keyRetry: if (keystrlen == 0) return 0; /* empty key means give up */ if (keystrlen < 0) { fprintf(stderr, "%s: couldn't get key\n", progName); return 1; } if (checkkey) { i = getkey("Verify Key:", chkbuf, KEYBUFLEN-1); if (i != keystrlen || memcmp(chkbuf, keybuf, i) != 0) { keystrlen = getkey("Keys didn't match; try again\r\nInput Key:", keybuf, KEYBUFLEN-1); goto keyRetry; } memset(chkbuf, '\0', i); } keybuf[keystrlen] = '\0'; i = setKey(&keys[keycount].key, keybits, keybuf, 0); if (i) { keystrlen = getkey("Weak key generated; use another one\r\nInput Key:", keybuf, KEYBUFLEN-1); goto keyRetry; } keycount++; } do { rcount = read(0, obuf, IO_BUFSIZE); if (rcount <= 0) break; i = ciphercount; kip = keys; do { chp = obuf; obuf = ibuf; ibuf = chp; kip->ivlen = desCFB( obuf, ibuf, rcount, kip->iv, kip->ivlen, kip->key, kip->decr); kip++; } while (--i != 0); wcount = write(1, obuf, rcount); } while (wcount == rcount); /* * Actually, we should register this code with atexit and catch all * interrupt signals. This still won't protect us against a system crash * leaving the bit image on the virtual memory disc. Sigh. */ i = ciphercount; kip = keys; do { desDestroyKey(&(kip->key)); /* erase the key schedules */ kip++; } while (--i != 0); if (rcount < 0) { fprintf(stderr, "%s: read failed: %s\n", progName, sys_errlist[errno]); return 3; } if (rcount != 0 && rcount != wcount) { fprintf(stderr, "%s: write failed: %s\n", progName, sys_errlist[errno]); return 2; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -