📄 auth.c
字号:
/* * @(#) auth.c RCS: $Revision: 1.4 $ $Date: 95/03/02 12:53:56 $ * * This file contains all the routines needed to interface to routines to * perform digital signatures, and stream data encryption. Currently it * uses the des. If another method is used, this module should be the only * one changed. */#define _POSIX_SOURCE#include <sys/types.h> /* pid_t */#include <unistd.h> /* write getpid */#include <stdio.h>#include <string.h> /* memset memcmp */#include <ctype.h> /* isspace */#include <stdlib.h> /* exit free (after ctype.h for BSDI BSD/386) */#include <time.h>#include "auth.h"#include "txfr.h"#include "log.h"#include "deslogin.h"extern int verbose;typedef struct { char iv[DES_BLOCKSIZE]; unsigned ivlen; keyType key; int mode;} cipherState;cipherKey mkCipherKey(key, mode) keyType key; int mode;{ cipherState *cs =(cipherState *)malloc(sizeof (cipherState)); if (cs != (cipherState *) 0) { memset(cs->iv, '\0', DES_BLOCKSIZE); cs->ivlen = DES_BLOCKSIZE; cs->key = key; cs->mode = mode; } return (cipherKey) cs;}void destroyCipherKey(c) cipherKey *c;{ register cipherState *cs = * (cipherState **) c; if (cs != (cipherState *) 0) { memset(cs->iv, '\0', DES_BLOCKSIZE); cs->ivlen = 0; cs->key = (keyType) 0; cs->mode = 0; free(cs); *c = (cipherKey) 0; }}void cipherData(dst, src, size, c) char *dst, *src; unsigned size; cipherKey c;{ register cipherState *cs = (cipherState *) c; if (cs->key != (keyType) 0) { cs->ivlen = desCFB(dst, src, size, cs->iv, cs->ivlen, cs->key, cs->mode); } else { memcpy(dst, src, size); }}/* * Convert a string of bytes to their hex representation */char *hexData(dst, src, size) register char *dst, *src; register unsigned size;{ register char *chp = dst; if (size != 0) do { sprintf(chp, "%.2x", * (unsigned char *) src++); chp += 2; } while (--size != 0); return dst;}/* * Create a key from a keyString * * Mode: 0 = encrypt, 1 = decrypt */keyType mkKey(keyString) char *keyString;{ char keybits[DES_BLOCKSIZE]; keyType key = (keyType) 0; desKey(keybits, keyString, ' '); /* hash string into 64-bits */ desMakeKey(&key, keybits, DES_BLOCKSIZE, 0); /* always encrypt for CFB */ memset(keybits, '\0', DES_BLOCKSIZE); return key;}/* * Perform one DES encryption(decryption if mode nonzero) (ECB mode) * * Dst and src must be exactly DES_BLOCKSIZE bytes long. */void cipherKeyString(dst, src, keyString, mode) char *dst, *src, *keyString; int mode; /* 0 = encipher, 1 = decipher */{ char keybits[DES_BLOCKSIZE]; keyType key = (keyType) 0; desKey(keybits, keyString, ' '); /* hash string into 64-bits */ desMakeKey(&key, keybits, DES_BLOCKSIZE, mode); memset(keybits, '\0', DES_BLOCKSIZE); des(dst, src, key); desDestroyKey(&key);}/* * Generate a unique session key from the challenge. The idea here is to allow * the program on both the client and server side to destroy the user's * private key from memory ASAP. If a user on the local machine tries to * scan the process memory, they can only compromise the session key and not * the user's long-term login key. */keyType sessionKey(challenge, keyString, mode) char *challenge, *keyString; int mode;{ char keybits[DES_BLOCKSIZE]; keyType res = (keyType) 0; cipherKeyString(keybits, challenge, keyString, 0); /* encrypt */ desMakeKey(&res, keybits, DES_BLOCKSIZE, mode); memset(keybits, '\0', DES_BLOCKSIZE); return res;}/** Issue and validate a crypto challenge * * Returns: session key if success, 0 if failure */keyType challenge(fd, keyString, timeout) int fd; char *keyString; unsigned timeout;{ char plainText[DES_BLOCKSIZE], cipherText[DES_BLOCKSIZE]; char buf[DES_BLOCKSIZE], buf2[DES_BLOCKSIZE*2+1]; int wcount, rcount, res; keyType result = (keyType) 0; /* * The challenge message must be unpredictable and ideally, never reused * to prevent playback, or anticipating the next challenge response * * To make it unpredictable, take the current time + current pid , and * encipher it once with the user's key. This is then used as the * plaintext of the challenge. */ memset(cipherText, '\0', DES_BLOCKSIZE); time((time_t *) &cipherText[0]); * (unsigned *) &cipherText[4] = (unsigned) getpid(); cipherKeyString(plainText, cipherText, keyString, 0); cipherKeyString(cipherText, plainText, keyString, 0); /* encrypt */ if (debug) { log("%s: challenge(%s)\n", progName, hexData(buf2, cipherText, DES_BLOCKSIZE)); } wcount = write(fd, cipherText, DES_BLOCKSIZE); if (wcount != DES_BLOCKSIZE) { log("%s: challenge--write failed; %s\n", progName, ERRMSG); exit(1); } cipherKeyString(buf, cipherText, keyString, 1); /* decrypt */ rcount = getBlock(fd, buf, DES_BLOCKSIZE, timeout); /* decrypt */ if (debug) { if (rcount > 0) { log("%s: response(%s)\n", progName, hexData(buf2, buf, DES_BLOCKSIZE)); } } /* * The remote user deciphers the challenge and it'd better be the same * as the one we originally enciphered to be a valid signature */ if (rcount == DES_BLOCKSIZE) { res = memcmp(buf, plainText, DES_BLOCKSIZE); if (res == 0) { result = sessionKey(cipherText, keyString, 0); } } return result;}/* * Wait for and respond to a crypto challenge return the session key. */keyType signature(fd, keyString, timeout) int fd; char *keyString; unsigned timeout;{ keyType res = (keyType) 0; char plainText[DES_BLOCKSIZE], cipherText[DES_BLOCKSIZE]; register int wcount = -1, rcount; rcount = getBlock(fd, cipherText, DES_BLOCKSIZE, timeout); if (rcount == DES_BLOCKSIZE) { cipherKeyString(plainText, cipherText, keyString, 1); /* decrypt */ wcount = write(fd, plainText, rcount); res = sessionKey(cipherText, keyString, 0); } return res;}/* * Find the corresponding passphrase for the given user name. * * The user file is a sequence of lines with username passphrase pairs * Lines beginning with '#' are comments, empty lines are permitted. * * Returns: -2 if key incorrect, -1 if open failed, 0 no such user, 1 success */int getUserPhrase(fname, phrase, size, uname, key) char *fname; register char *phrase; register unsigned size; char *uname; keyType key;{ register int i; char cipherChar, ch; register int res = -2, state = 0; register char *chp = 0; FILE *f = fopen(fname, "r"); cipherKey ck = (cipherKey) 0; ck = mkCipherKey(key, 1); /* decrypt */ if (f == NULL) return -1; do { i = getc(f); if (i == EOF) { res = 0; break; } cipherChar = (char) i; cipherData(&ch, &cipherChar, 1, ck); if (ch & 0x80) break; /* non-printable character: stop! */ switch (state) { case 0: if (ch == '#') { state = 1; break; } chp = uname; state = 2; /* fall through */ case 2: /* user field leading whitespace */ if (ch == '\n') state = 0; if (ch == '#') { state = 1; break; } if (isspace(ch)) break; /* newline is also whitespace */ state = 3; /* fall through */ case 3: /* user field */ if (!isspace(ch)) { if (*chp++ != ch) state = 1; } else { if (*chp == '\0') { /* match? */ if (ch == '\n') state = 6; else state = 4; if (verbose) log("founduser\n"); } else { state = 0; } } break; case 1: /* skip remainder of line */ if (ch == '\n') state = 0; break; case 4: /* passphrase leading whitespace */ if (ch == '\n') state = 6; if (isspace(ch)) break; state = 5; /* fall through */ chp = phrase; case 5: /* passphrase */ if (ch == '\n') { if (size != 0) *chp = '\0'; state = 6; res = 1; } else { if (size != 0) { *chp++ = ch; --size; } } break; } } while (state != 6); destroyCipherKey(&ck); fclose(f); return res;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -