From 8087f2a5e454c42723df8b35f4ad41196e735425 Mon Sep 17 00:00:00 2001 From: "Adel I. Mirzazhanov" Date: Wed, 21 Mar 2001 10:46:44 +0600 Subject: [PATCH] APG v2.0.0a0 --- CHANGES | 7 + INSTALL | 3 + Makefile | 38 +++++- README | 10 +- THANKS | 1 + apg.c | 34 +++-- apgbfm.c | 298 ++++++++++++++++++++++++++++++++++++++++++ bloom.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++ bloom.h | 80 ++++++++++++ doc/APG_TIPS | 46 +++++++ doc/man/apg.1 | 18 ++- doc/man/apgbfm.1 | 113 ++++++++++++++++ doc/man/apgd.8 | 15 ++- md5/md5.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++ md5/md5.h | 41 ++++++ restrict.c | 11 ++ restrict.h | 4 +- 17 files changed, 1352 insertions(+), 29 deletions(-) create mode 100644 apgbfm.c create mode 100644 bloom.c create mode 100644 bloom.h create mode 100644 doc/APG_TIPS create mode 100644 doc/man/apgbfm.1 create mode 100644 md5/md5.c create mode 100644 md5/md5.h diff --git a/CHANGES b/CHANGES index 6f20ae6..273b01a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +apg-2.0.0a0 + Added new algorithm (-b option) to check generated passwords + quality (Bloom filter). + Added utility apgbfm to manage Bloom filter. + Some code style fixes. + Added APG_TIPS file in documentation. + apg-1.2.13 Added support for NetBSD. (Thanks to Tomasz Luchowski ). diff --git a/INSTALL b/INSTALL index f7afd40..f2c6100 100644 --- a/INSTALL +++ b/INSTALL @@ -28,6 +28,9 @@ If you are reading this file, you probably have already done this! % make all +During the make process compiler will generate some warnings +Just ignore this fact. I'm working to fix them. + 4. install the binaries and man pages. You may need to be superuser to do this (depending on where you are installing things): diff --git a/Makefile b/Makefile index 3b9bbb3..5643ff6 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,10 @@ FLAGS = -Wall # libraries LIBS = -lcrypt +LIBM = -lm +# Use lines below for cygwin +# LIBS = +# LIBM = # DO NOT EDIT THE LINE BELOW !!! CRYPTED_PASS = APG_DONOTUSE_CRYPT @@ -41,23 +45,33 @@ FIND_GROUP = `grep '^root:' /etc/passwd | awk -F: '{ print $$4 }'` PROGNAME = apg CS_PROGNAME = apgd -SOURCES = rnd.c ./cast/cast.c pronpass.c randpass.c restrict.c errors.c apg.c +BFM_PROGNAME = apgbfm +BFM_SOURCES = apgbfm.c bloom.c md5/md5.c errors.c +SOURCES = bloom.c md5/md5.c rnd.c ./cast/cast.c pronpass.c randpass.c restrict.c errors.c apg.c HEADERS = owntypes.h pronpass.h randpass.h restrict.h errs.h rnd.h ./cast/cast.h ./cast/cast_sboxes.h OBJECTS = rnd.o ./cast/cast.o pronpass.o randpass.o restrict.o apg.o errors.o all: cliserv standalone +cliserv: apgd apgbfm + +standalone: apg apgbfm + cygwin: standalone -cliserv: ${SOURCES} ${HEADERS} - ${CC} ${FLAGS} ${CS_LIBS} -DCLISERV -o ${CS_PROGNAME} ${SOURCES} +apg: + ${CC} ${FLAGS} ${LIBS} ${LIBM} -D${CRYPTED_PASS} -o ${PROGNAME} ${SOURCES} -standalone: ${SOURCES} ${HEADERS} - ${CC} ${FLAGS} ${LIBS} -D${CRYPTED_PASS} -o ${PROGNAME} ${SOURCES} +apgd: + ${CC} ${FLAGS} ${CS_LIBS} ${LIBM} -DCLISERV -o ${CS_PROGNAME} ${SOURCES} + +apgbfm: + ${CC} ${FLAGS} ${LIBM} -o ${BFM_PROGNAME} ${BFM_SOURCES} strip: strip ${PROGNAME} strip ${CS_PROGNAME} + strip ${BFM_PROGNAME} install: if test -x ./apg; then \ @@ -71,6 +85,12 @@ fi ./mkinstalldirs ${INSTALL_PREFIX}${APGD_MAN_DIR}; \ ./install-sh -c -m 0755 -o root -g ${FIND_GROUP} ./apgd ${INSTALL_PREFIX}${APGD_BIN_DIR}; \ ./install-sh -c -m 0444 ./doc/man/apgd.8 ${INSTALL_PREFIX}${APGD_MAN_DIR}; \ +fi + if test -x ./apgbfm; then \ +./mkinstalldirs ${INSTALL_PREFIX}${APG_BIN_DIR}; \ +./mkinstalldirs ${INSTALL_PREFIX}${APG_MAN_DIR}; \ +./install-sh -c -m 0755 -o root -g ${FIND_GROUP} ./apgbfm ${INSTALL_PREFIX}${APG_BIN_DIR}; \ +./install-sh -c -m 0444 ./doc/man/apgbfm.1 ${INSTALL_PREFIX}${APG_MAN_DIR}; \ fi install-cygwin: @@ -79,7 +99,13 @@ install-cygwin: ./mkinstalldirs ${INSTALL_PREFIX}${APG_MAN_DIR}; \ ./install-sh -c -m 0755 ./apg.exe ${INSTALL_PREFIX}${APG_BIN_DIR}; \ ./install-sh -c -m 0444 ./doc/man/apg.1 ${INSTALL_PREFIX}${APG_MAN_DIR}; \ +fi + if test -x ./apgbfm.exe; then \ +./mkinstalldirs ${INSTALL_PREFIX}${APG_BIN_DIR}; \ +./mkinstalldirs ${INSTALL_PREFIX}${APG_MAN_DIR}; \ +./install-sh -c -m 0755 ./apgbfm.exe ${INSTALL_PREFIX}${APG_BIN_DIR}; \ +./install-sh -c -m 0444 ./doc/man/apgbfm.1 ${INSTALL_PREFIX}${APG_MAN_DIR}; \ fi clean: - rm -f ${CS_PROGNAME} ${PROGNAME} ${OBJECTS} core* + rm -f ${CS_PROGNAME} ${PROGNAME} ${BFM_PROGNAME} ${OBJECTS} core* diff --git a/README b/README index dabea23..a9b0644 100644 --- a/README +++ b/README @@ -1,3 +1,10 @@ +APG v2.0.0a0 was tested and found working on: + + i386 FreeBSD 4.0-RELEASE + i386 Linux-Mandrake 6.0 + Intel Solaris 8 gcc-2.95.2 + Intel Windows 2000+CYGWIN v1.1.4 + APG v1.2.13 was tested and found working on: i386 FreeBSD 4.0-RELEASE @@ -15,10 +22,11 @@ APG v1.2.13 was tested and found working on: AIX 4.3.3+native cc (reported by Philip Le Riche ) AIX 4.3.3+gcc (reported by Philip Le Riche ) -Any compatibility reports are welcom +Any compatibility reports are welcome * For installation instructions see INSTALL * For usage instructions see manpages + * For tips see doc/APG_TIPS * For copying information see COPYING See also APG Homepage at: http://www.adel.nursat.kz/apg/ diff --git a/THANKS b/THANKS index c082f28..a12ccc7 100644 --- a/THANKS +++ b/THANKS @@ -9,3 +9,4 @@ Andrew J. Caird Alexander J Pierce Philip Le Riche Tomasz Luchowski +Barton Hodges diff --git a/apg.c b/apg.c index 3a9b29e..849462a 100644 --- a/apg.c +++ b/apg.c @@ -36,6 +36,8 @@ #include #include +#define APG_VERSION "2.0.0a0" + #ifdef __NetBSD__ #include #endif @@ -67,6 +69,7 @@ #include "pronpass.h" #include "randpass.h" #include "restrict.h" +#include "bloom.h" #include "rnd.h" #include "errs.h" @@ -96,6 +99,7 @@ main (int argc, char *argv[]) int algorithm = 0; /* algorithm for generation */ int restrictions_present = FALSE; /* restrictions flag */ + int bloom_restrict_present = FALSE; /* bloom filter restrictions flag */ char *restrictions_file; /* dictionary file name */ unsigned int pass_mode = 0; /* password generation mode */ unsigned int pass_mode_present = FALSE; /* password generation mode flag */ @@ -144,12 +148,12 @@ main (int argc, char *argv[]) */ #ifndef CLISERV #ifdef APG_USE_CRYPT - while ((option = getopt (argc, argv, "SNCLRM:a:r:sdc:n:m:x:hvy")) != -1) + while ((option = getopt (argc, argv, "SNCLRM:a:r:b:sdc:n:m:x:hvy")) != -1) #else /* APG_USE_CRYPT */ - while ((option = getopt (argc, argv, "SNCLRM:a:r:sdc:n:m:x:hv")) != -1) + while ((option = getopt (argc, argv, "SNCLRM:a:r:b:sdc:n:m:x:hv")) != -1) #endif /* APG_USE_CRYPT */ #else /* CLISERV */ - while ((option = getopt (argc, argv, "SNCLRM:a:r:n:m:x:v")) != -1) + while ((option = getopt (argc, argv, "SNCLRM:a:r:b:n:m:x:v")) != -1) #endif /* CLISERV */ { switch (option) @@ -189,6 +193,11 @@ main (int argc, char *argv[]) restrictions_present = TRUE; restrictions_file = optarg; break; + case 'b': /* bloom restrictions */ + restrictions_present = TRUE; + bloom_restrict_present = TRUE; + restrictions_file = optarg; + break; #ifndef CLISERV case 's': /* user random seed required */ user_defined_seed = get_user_seq (); @@ -227,7 +236,7 @@ main (int argc, char *argv[]) #endif /* CLISERV */ case 'v': /* print version */ printf ("APG (Automated Password Generator)"); - printf ("\nversion 1.2.13"); + printf ("\nversion %s", APG_VERSION); printf ("\nCopyright (c) 1999, 2000, 2001 Adel I. Mirzazhanov\n"); return (0); default: /* print help end exit */ @@ -284,9 +293,12 @@ main (int argc, char *argv[]) (void *)crypt_string, 255); #endif /* APG_USE_CRYPT */ #endif /* CLISERV */ - if (restrictions_present == 1) + if (restrictions_present == TRUE) { - restrict_res = check_pass(pass_string, restrictions_file); + if (bloom_restrict_present == TRUE) + restrict_res = bloom_check_pass(pass_string, restrictions_file); + else + restrict_res = check_pass(pass_string, restrictions_file); switch (restrict_res) { case 0: @@ -351,9 +363,12 @@ main (int argc, char *argv[]) (void *)crypt_string, 255); #endif /* APG_USE_CRYPT */ #endif /* CLISERV */ - if (restrictions_present == 1) + if ( (restrictions_present == TRUE)) { - restrict_res = check_pass(pass_string, restrictions_file); + if (bloom_restrict_present == TRUE) + restrict_res = bloom_check_pass(pass_string, restrictions_file); + else + restrict_res = check_pass(pass_string, restrictions_file); switch (restrict_res) { case 0: @@ -471,6 +486,8 @@ print_help (void) printf ("\n-S -N -C -L -R password modes\n"); printf ("-M mode new style pasword modes\n"); printf ("-r file apply dictionary check against file\n"); + printf ("-b filter_file apply bloom filter check against filter_file\n"); + printf (" (filter_file should be created with apgbfm(1) utility)\n"); printf ("-a algorithm choose algorithm\n"); printf (" 1 - random password generation according to\n"); printf (" password modes\n"); @@ -567,3 +584,4 @@ unsigned int construct_mode(char *s_mode) } return (mode); } + diff --git a/apgbfm.c b/apgbfm.c new file mode 100644 index 0000000..26ca353 --- /dev/null +++ b/apgbfm.c @@ -0,0 +1,298 @@ +/* +** Copyright (c) 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include +#include "bloom.h" +#include "errs.h" + +#ifdef __CYGWIN__ +#include +#endif /* __CYGWIN__ */ + +#define VERSION "1.0.0a0" + +int main (int argc, char *argv[]); +void print_help(void); +void checkopt(char *opt); + +int +main (int argc, char *argv[]) +{ + int option = 0; + + char *dictfile; /* dictionary filename */ + FILE *f_dictfile; /* dictionary file descriptor */ + + char *filter; /* filter file name */ + FILE *f_filter; /* filter file descriptor */ + + char *word; /* word to add or check */ + h_val wc = 0L; /* amount of words to build dictionaty */ + h_val filter_size =0L; /* filter size in bits */ + int dummy_test = 0; /* variable to make dummy test for */ + /* options correctness */ + h_val i = 0L; /* cointer */ + + /* flags */ + flag add_word_flag = FALSE; /* -a */ + flag add_file_flag = FALSE; /* -A */ + flag check_word_flag = FALSE; /* -c */ + flag check_file_flag = FALSE; /* -C */ + flag new_flag = FALSE; /* -n */ + flag new_from_dict_flag = FALSE; /* -d */ + flag filter_flag = FALSE; /* -f */ + /* end of flags section */ + + /* Analize options */ + if (argc < 2) + { + print_help(); + exit(-1); + } + + while ((option = getopt (argc, argv, "a:A:c:C:n:d:f:hv")) != -1) + { + switch(option) + { + case 'a': + word = optarg; + add_word_flag = TRUE; + dummy_test = dummy_test + 2; + break; + case 'A': + dictfile = optarg; + add_file_flag = TRUE; + dummy_test = dummy_test + 2; + break; + case 'c': + word = optarg; + check_word_flag = TRUE; + dummy_test = dummy_test + 2; + break; + case 'C': + dictfile = optarg; + check_file_flag = TRUE; + dummy_test = dummy_test + 2; + break; + case 'n': + checkopt(optarg); + wc = atoi(optarg); + new_flag = TRUE; + dummy_test = dummy_test + 2; + break; + case 'd': + dictfile = optarg; + new_from_dict_flag = TRUE; + dummy_test = dummy_test + 2; + break; + case 'f': + filter = optarg; + filter_flag = TRUE; + dummy_test = dummy_test + 1; + break; + case 'h': + print_help(); + return (0); + case 'v': + printf ("APG Bloom filter management programm"); + printf ("\nversion %s", VERSION); + printf ("\nCopyright (c) 2001 Adel I. Mirzazhanov\n"); + return (0); + default: + print_help(); + exit(-1); + } + } + if (filter_flag != TRUE) err_app_fatal ("apg", "-f option is required"); + if (dummy_test != 3) err_app_fatal ("apg", "too many options"); + /* Main part */ + /* At this point we can be sure that all options a correct */ + if (add_word_flag == TRUE) + { + if ( (f_filter = open_filter(filter)) == NULL) + err_sys_fatal("open_filter"); + filter_size = get_filtersize(f_filter); + if ( insert_word (word, f_filter, filter_size) == -1) + err_sys_fatal("insert_word"); + printf ("Word %s added\n",word); + return (0); + } + if (add_file_flag == TRUE) + { + word = (char *) calloc(1,MAX_DICT_STRLEN); + if ( (f_dictfile = fopen(dictfile,"r")) == NULL) + err_sys_fatal("fopen"); + if( (f_filter = open_filter(filter)) == NULL) + err_sys_fatal("open_filter"); + filter_size = get_filtersize(f_filter); + while ((fgets(word, MAX_DICT_STRLEN, f_dictfile) != NULL)) + { + word = (char *)strtok (word," \t\n\0"); + if ( insert_word (word, f_filter, filter_size) == -1) + err_sys_fatal("insert_word"); + i++; + if ( i % 100 == 0) + { + fprintf (stdout,"."); + fflush (stdout); + } + bzero((void *)word, MAX_DICT_STRLEN); + } + printf ("\n"); + free ( (void *)word); + fclose (f_dictfile); + fclose (f_filter); + return (0); + } + if (check_word_flag == TRUE) + { + if ( (f_filter = open_filter(filter)) == NULL) + err_sys_fatal("open_filter"); + filter_size = get_filtersize(f_filter); + switch(check_word (word, f_filter, filter_size)) + { + case -1: + err_sys_fatal("check_word"); + break; + case 1: + printf ("%s: FOUND \n",word); + break; + case 0: + printf ("%s: NOT FOUND\n",word); + break; + } + return (0); + } + if (check_file_flag == TRUE) + { + word = (char *) calloc(1,MAX_DICT_STRLEN); + if ( (f_dictfile = fopen(dictfile,"r")) == NULL) + err_sys_fatal("fopen"); + wc = count_words (f_dictfile); + if( (f_filter = open_filter(filter)) == NULL) + err_sys_fatal("open_filter"); + filter_size = get_filtersize(f_filter); + while ((fgets(word, MAX_DICT_STRLEN, f_dictfile) != NULL)) + { + word = (char *)strtok (word," \t\n\0"); + switch(check_word (word, f_filter, filter_size)) + { + case -1: + err_sys_fatal("check_word"); + break; + case 1: + printf ("%s: FOUND \n",word); + break; + case 0: + printf ("%s: NOT FOUND\n",word); + break; + } + bzero((void *)word, MAX_DICT_STRLEN); + } + free ( (void *)word); + fclose (f_dictfile); + fclose (f_filter); + return (0); + } + if (new_flag == TRUE) /* -n nwords */ + { + if ((f_filter = create_filter(filter, wc)) == NULL) + err_sys_fatal("create_filter"); + fclose(f_filter); + return (0); + } + if (new_from_dict_flag == TRUE) /* -d dictfile */ + { + word = (char *) calloc(1,MAX_DICT_STRLEN); + if ( (f_dictfile = fopen(dictfile,"r")) == NULL) + err_sys_fatal("fopen"); + fprintf (stdout,"Counting words in dictionary. Please wait...\n"); + fflush (stdout); + wc = count_words (f_dictfile); + if( (f_filter = create_filter(filter, wc)) == NULL) + err_sys_fatal("create_filter"); + filter_size = get_filtersize(f_filter); + while ((fgets(word, MAX_DICT_STRLEN, f_dictfile) != NULL)) + { + word = (char *)strtok (word," \t\n\0"); + if ( insert_word (word, f_filter, filter_size) == -1) + err_sys_fatal("insert_word"); + i++; + if ( i % 100 == 0) + { + fprintf (stdout, "."); + fflush (stdout); + } + bzero((void *)word, MAX_DICT_STRLEN); + } + printf ("\n"); + free ( (void *)word); + fclose (f_dictfile); + fclose (f_filter); + return (0); + } +return (0); +} +/* +** print_help - prints short help info +** INPUT: NOTHING +** RETURN: NOTHING +*/ +void +print_help(void) +{ + printf ("\napgbfm APG Bloom filter management\n"); + printf (" Copyright (c) 2001 Adel I. Mirzazhanov\n"); + printf ("\napgbfm -f filter < [-a word] | [-A dictfile] | [-n numofwords] |\n"); + printf (" [-c word] | [-C dictfile] | [-d dictfile] >\n"); + printf ("apgbfm [-v] [-h]\n\n"); + printf ("-a word add word to filter\n"); + printf ("-A dictfile add words from dictfile to filter\n"); + printf ("-c word check word against filter\n"); + printf ("-C dictfile check dictfile against filter\n"); + printf ("-n numofwords create new empty filter\n"); + printf ("-d dictfile create new filter and add all words from dictfile\n"); + printf ("-f filtername use filtername as the name for filter\n"); + printf ("-v print version information\n"); + printf ("-h print help (this screen)\n"); +} + +void +checkopt(char *opt) +{ + int i; + + for(i=0; i < strlen(opt);i++) + if(opt[i] != '0' && opt[i] != '1' && opt[i] != '2' && opt[i] != '3' && + opt[i] != '4' && opt[i] != '5' && opt[i] != '6' && opt[i] != '7' && + opt[i] != '8' && opt[i] != '9') + err_app_fatal ("checkopt", "wrong option format"); +} diff --git a/bloom.c b/bloom.c new file mode 100644 index 0000000..29ee619 --- /dev/null +++ b/bloom.c @@ -0,0 +1,330 @@ +/* +** Copyright (c) 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/* +** C module for APG (Automated Password Generator) +** Bloom filter implementation. +** Functions: +** insert_word - insert word in the filter file +** check_word - check word +** create_filter - create initial(empty) filter file +** open_filter - open APG Bloom filter file +** get_filtersize - get APG Bloom filter size +** count_words - count words in plain dictionary file +*************************************************************************** +** hash2bit - generates 4 values (should be 4 values of independent +** hash functions) from input string. +** getbit - get the bit value from file. +** putbit - put the bit in the file. +*/ + +#include "bloom.h" + +h_val * hash2bit(char * word, h_val *b); +int getbit(FILE * f, h_val bitnum); +int putbit(FILE * f, h_val bitnum); + +/* +** insert_word - insert word in the filter file +** INPUT: +** char *word - word to incert in the filter +** FILE *file - filter file descriptor +** h_val filter_size - filter size in bits +** RETURN: +** int +** 0 - everything OK +** -1 - something wrong +*/ +int +insert_word(char *word, FILE *file, h_val filter_size) +{ +h_val h[4]; +int i = 0; + +hash2bit (word, &h[0]); +for(i = 0; i < 4; i++) + if (putbit (file, h[i] % filter_size)== -1) + return (-1); +return(0); +} + +/* +** check_word - check word +** INPUT: +** char *word - word to check +** FILE *file - filter file descriptor +** h_val filter_size - filter size in bits +** RETURN: +** int +** 0 - word is not in dictionary +** 1 - word is in dictionary +** -1 - something wrong +*/ +int +check_word(char *word, FILE *file, h_val filter_size) +{ + h_val h[4]; + int i = 0; + + hash2bit (word, &h[0]); + for(i = 0; i < 4; i++) + { + switch(getbit(file, h[i] % filter_size)) + { + case 0: + return(0); + break; + case -1: + return(-1); + break; + default: + break; + } + } + return (1); +} + +/* +** open_filter - open APG Bloom filter file +** open filter file and check is this the real bloom filter file +** INPUT: +** char * f_name - filter filename +** RETURN: +** FILE * - file pointer +** NULL - something wrong. +*/ +FILE * +open_filter(char * f_name) +{ + FILE *f; + struct apg_bf_hdr bf_hdr; + if ((f = fopen (f_name, "r+")) == NULL) + return(NULL); + if(fread ( (void *)&bf_hdr, APGBFHDRSIZE, 1, f) < APGBFHDRSIZE) + if (ferror (f) != 0) + return(NULL); + if( (bf_hdr.id[0] != 'A') || (bf_hdr.id[1] != 'P') || + (bf_hdr.id[2] != 'G') || (bf_hdr.id[3] != 'B') || + (bf_hdr.id[4] != 'F') || (bf_hdr.id[5] != '1') || + (bf_hdr.id[6] != '0') || (bf_hdr.id[7] != '0') ) return (NULL); + else + { + if (fseek (f, 0, SEEK_SET) == -1) + return(NULL); + return(f); + } +} + + +/* +** get_filtersize - get APG Bloom filter size +** INPUT: +** FILE *f - filter file descriptor +** RETURN: +** h_val - size of APG Bloom filter. +*/ +h_val +get_filtersize(FILE * f) +{ + struct apg_bf_hdr bf_hdr; + fread ( (void *)&bf_hdr, APGBFHDRSIZE, 1, f); + fseek (f, 0, SEEK_SET); + return( (h_val)bf_hdr.fs); +} + +/* +** create_filter - create initial(empty) filter file +** 4 - number of hash functions +** 0.0001 (0.01%) - probability of false positives +** INPUT: +** char * f_name - filter filename +** unsigned long int n_words - number of words in filter +** RETURN: +** FILE * - filter file descriptor +** NULL - something wrong +*********************************************************** +** n - number of words in the filter +** N - size of filter(?) +** +** a=(1-(4/N))^n +** 0.0001=(1-a)^4 ==> 1-a=0.1 ==> a=0.9 ==> +** 0.9=(1-(4/N))^n ==> 0.9^(1/n)=1-(4/N) ==> +** +** N=4/(1-[0.9^(1/n)]) +** +** 4 +** N = ---------- +** 1/n +** 1 - 0.9 +*/ +FILE * +create_filter(char * f_name, unsigned long int n_words) +{ + FILE *f; + char zero = 0x00; + long int i = 0L; + struct apg_bf_hdr bf_hdr; + + bf_hdr.id[0] = 'A'; + bf_hdr.id[1] = 'P'; + bf_hdr.id[2] = 'G'; + bf_hdr.id[3] = 'B'; + bf_hdr.id[4] = 'F'; + bf_hdr.id[5] = '1'; + bf_hdr.id[6] = '0'; + bf_hdr.id[7] = '0'; + bf_hdr.fs = FSIZE_BIT(n_words); + + if ((f = fopen (f_name, "w+")) == NULL) + return(NULL); + + if (fwrite ( (void *)&bf_hdr, APGBFHDRSIZE, 1, f) < APGBFHDRSIZE) + if (ferror (f) != 0) + return(NULL); + + for (i = 0; i < FSIZE_BYTE(n_words); i++) + if ( fwrite ( (void *)&zero, 1, 1, f) < 1) + if (ferror (f) != 0) + return(NULL); + if (fseek (f, 0, SEEK_SET) == -1) + return (NULL); + + return (f); +} + +/* +** count_words - count words in plain dictionary file +** INPUT: +** FILE *dict_file -plain dicionary file descriptor +** RETURN: +** h_val - amount of words in dictionary file +*/ +h_val +count_words(FILE *dict_file) +{ + h_val i = 0L; /* word counter */ + char *string; /* temp string holder */ + string = (char *) calloc(1,MAX_DICT_STRLEN); + while ((fgets(string, MAX_DICT_STRLEN, dict_file) != NULL)) + i++; + fseek (dict_file, 0, SEEK_SET); + free ((void *) string); + return (i); +} + +/* +** hash2bit - generates 4 values (should be 4 values of independent +** hash functions) from input string. +** INPUT: +** char *word - word to hash +** h_val *b - pointer to bitnumber array +** RETURN +** h_val * - pointer to bitnumber array +*/ +h_val * +hash2bit(char * word, h_val *b) +{ + struct apg_MD5Context context; + unsigned char cs[16]; + + apg_MD5Init (&context); + apg_MD5Update (&context, word, strlen(word)); + apg_MD5Final (cs, &context); + return ( (h_val *)memcpy( (void *)b, (void *)&cs[0], 16)); +} + +/* +** getbit - get the bit value from file. +** INPUT: +** FILE *f - file descriptor +** h_val bitnum - bit number +** RETURN: +** int +** 0,1 - bit value +** -1 - something wrong +*/ +int +getbit(FILE * f, h_val bitnum) +{ + long int bytenum = 0L; + short int bit_in_byte = 0; + unsigned char read_byte = 0x00; + unsigned char test_byte = 0x01; + int i = 0; + + bit_in_byte = bitnum % 8; + bytenum = APGBFHDRSIZE + (bitnum/8); + if (fseek (f, bytenum, SEEK_SET) == -1) + return(-1); + if (fread ((void*)&read_byte,1,1,f) < 1) + if (ferror(f) != 0) + return (-1); + for (i=0;i < bit_in_byte;i++) + test_byte = test_byte*2; + if ((read_byte & test_byte) > 0) return (1); + else return (0); +} + +/* +** putbit - put the bit in the file. +** INPUT: +** FILE *f - file descriptor +** h_val bitnum - bit number +** RETURN: +** int +** 0 - everything OK +** -1 - something wrong +*/ +int +putbit(FILE * f, h_val bitnum) +{ + long int bytenum = 0L; + short int bit_in_byte = 0; + unsigned char read_byte = 0x00; + unsigned char test_byte = 0x01; + int i = 0; + bit_in_byte = bitnum % 8; + bytenum = APGBFHDRSIZE + (bitnum/8); + if (fseek (f, bytenum, SEEK_SET) == -1) + return(-1); + if (fread ((void*)&read_byte,1,1,f) < 1) + if (ferror(f) != 0) + return (-1); + for (i=0;i < bit_in_byte;i++) + test_byte = test_byte*2; + read_byte = read_byte | test_byte; + if (fseek (f, bytenum, SEEK_SET) == -1) + return(-1); + if (fwrite ((void*)&read_byte,1,1,f) < 1) + if (ferror(f) != 0) + return (-1); + return (0); +} +/* END OF bloom.c file */ \ No newline at end of file diff --git a/bloom.h b/bloom.h new file mode 100644 index 0000000..c18c1da --- /dev/null +++ b/bloom.h @@ -0,0 +1,80 @@ +/* +** Copyright (c) 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + + +/* +** Header file for bloom filter algorithm implementation +*/ +#ifndef APG_BLOOM_H +#define APG_BLOOM_H 1 + +#include +#include +#include +#include +#include + +/* Add prototype support. */ +#ifndef PROTO +#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) +#define PROTO(ARGS) ARGS +#else +#define PROTO(ARGS) () +#endif +#endif + +#include "md5/md5.h" + +#define FSIZE_BIT(word_count) ((unsigned long int)(4.0/(1.0-pow( 0.9,1.0/((double)word_count))))) +#define FSIZE_BYTE(word_count) ((((unsigned long int)(4.0/(1.0-pow( 0.9,1.0/((double)word_count)))))/8)+1) + +#define APGBFHDRSIZE 12 + +#define TRUE 1 +#define FALSE 0 + +#define MAX_DICT_STRLEN 255 + +typedef unsigned long int h_val; /* should be 32-bit */ +typedef unsigned short int flag; + +struct apg_bf_hdr { + char id[8]; + unsigned long int fs; +}; + +extern int insert_word(char *word, FILE *file, h_val filter_size); +extern int check_word(char *word, FILE *file, h_val filter_size); +extern FILE * create_filter(char * f_name, unsigned long int n_words); +extern FILE * open_filter(char * f_name); +extern h_val get_filtersize(FILE *f); +extern h_val count_words(FILE *dict_file); + +#endif /* APG_BLOOM_H */ \ No newline at end of file diff --git a/doc/APG_TIPS b/doc/APG_TIPS new file mode 100644 index 0000000..2a4b91c --- /dev/null +++ b/doc/APG_TIPS @@ -0,0 +1,46 @@ +============================================================ += TIPS FOR APG = +============================================================ += This file contains some tips for APG. = += = += 1. If You wish to submit a tip please send an email to = += and if i find it useful i'll put = += Your tip in the APG_TIPS file of the next release. = += I will also put Your tip on the APG website as soon = += as it posible. = += 2. If you wish to remove or update Your tip please send = += en email to . I will remove/update = += Your tip in the APG_TIPS file of the next release. = += I'll remove/update Your tip on the APG website as = += soon as it posible. = += = += Adel I Mirzazhanov = += a-del@iname.com = +============================================================ + +###################################################### +# 1. Elimination of certain characters from the output +# by Barton Hodges +###################################################### +I don't like to use "o"'s or "l"'s in my passwords +because they looke like zeros and ones instead of O's +and L's. + +I hacked together a little shell script to accomplish +the elimination of certain characters from the output. + +----------[cut here] +#!/bin/sh + +genpw () { + PW=$(/usr/local/bin/apg -L -m 10 -x 10 -n 1 | egrep -v [owl]) + if [ "$PW" != "" ]; then + echo $PW + return 0; + else + return 1; + fi +} + +until genpw; do : ; done +----------[cut here] diff --git a/doc/man/apg.1 b/doc/man/apg.1 index 133f71a..52a1891 100644 --- a/doc/man/apg.1 +++ b/doc/man/apg.1 @@ -2,14 +2,14 @@ .\" Licensed under BSD-like License. .\" Created by Adel I. Mirzazhanov .\" -.TH APG 1 "2001 Feb 13" "Automated Password Generator" "User Manual" +.TH APG 1 "2001 Mar 18" "Automated Password Generator" "User Manual" .SH NAME apg \- generates several random passwords .SH SYNOPSIS .B apg -[\fB-r\fP \fIdictfile\fP] +[\fB-r\fP \fIdictfile\fP] [\fB-b\fP \fIfilter_file\fP] [\fB-a algorithm\fP] [\fB-C\fP] [\fB-L\fP] [\fB-S\fP] [\fB-N\fP] [\fB-R\fP] [\fB-M mode\fP] [\fB-m min_pass_len\fP] [\fB-x max_pass_len\fP] [\fB-n num_of_pass\fP] [\fB-s\fP] [\fB-c cl_seed\fP] [\fB-d\fP] [\fB-y\fP] [\fB-h\fP] [\fB-v\fP] @@ -95,7 +95,7 @@ generation algorithm is used). .TP .B R[r] the same as \fBS[s]\fP but it does not generate symbols \fB`\fP, \fB'\fP, -\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Usefull for password generation in +\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Useful for password generation in a shell script. (For random character password generation algorithm only). .RE .RS @@ -117,7 +117,7 @@ use special symbol set. For random character password generation algorithm only. .TP .B -R the same as \fB-S\fP but it does not generate symbols \fB`\fP, \fB'\fP, -\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Usefull for password generation in +\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Useful for password generation in a shell script. For random character password generation algorithm only. (old style - use \fB-M mode\fP instead). .TP @@ -148,7 +148,12 @@ for password generation. .TP .B -r \fIdictfile\fP check generated passwords for their appearance in -.B dictfile +.I dictfile +.TP +.B -b \fIfilter_file\fP +check generated passwords for their appearance in +\fIfilter_file\fP. \fIfilter_file\fP should be created with \fBapgbfm\fP(1) +utility. .TP .B -s ask user for random sequence for password generation @@ -219,8 +224,7 @@ message about it. .B None. If you've found one, please send bug description to the author. .SH "SEE ALSO" -.B apgd -(8) +\fBapgd\fP(8), \fBapgbfm\fP(1) .SH "AUTHOR" Adel I. Mirzazhanov, .br diff --git a/doc/man/apgbfm.1 b/doc/man/apgbfm.1 new file mode 100644 index 0000000..38a685f --- /dev/null +++ b/doc/man/apgbfm.1 @@ -0,0 +1,113 @@ +.\" Man page for apgbfm. +.\" Licensed under BSD-like License. +.\" Created by Adel I. Mirzazhanov +.\" +.TH APGBFM 1 "2001 Mar 18" "Automated Password Generator" "User Manual" +.SH NAME +apg +\- APG Bloom filter management program + +.SH SYNOPSIS +.B apgbfm +\fB-f\fP \fIfilter\fP \fB-n\fP \fBnumofwords\fP +.br +.B apgbfm +\fB-f\fP \fIfilter\fP \fB-d\fP \fIdictfile\fP +.br +.B apgbfm +\fB-f\fP \fIfilter\fP \fB-a\fP \fBword\fP +.br +.B apgbfm +\fB-f\fP \fIfilter\fP \fB-A\fP \fIdictfile\fP +.br +.B apgbfm +\fB-f\fP \fIfilter\fP \fB-c\fP \fBword\fP +.br +.B apgbfm +\fB-f\fP \fIfilter\fP \fB-C\fP \fIdictfile\fP +.br +.B apgbfm +[\fB-v\fP] [\fB-h\fP] +.PP +.SH DESCRIPTION +.B apgbfm +is used to manage Bloom filter that is used to restrict password generation +in \fBAPG\fP pasword generation software. Usage of the Bloom filter allows to speed +up password check for large dictionaries and has some other benefits. +.PP +The idea to use Bloom filter for that purpose is came from the description of +the \fBOPUS\fP project \fBOPUS: Preventing Weak Password Choices\fP +\fIPurdue Technical Report CSD-TR 92-028\fP writen by \fIEugene H. Spafford\fP. +.PP +You can obtain this article from: +.br +\fIhttp://www.cerias.purdue.edu/homes/spaf/tech-reps/9128.ps\fP +.br +It has very nice description of Bloom filter and it's advantages for password +checking systems. +.PP +In simple words, \fBapgbfm\fP generates \fIn\fP hash values for every word and +sets corresponding bits in filter file to 1. To check the word \fBapgbfm\fP +generates the same hash functions for that word and if all \fIn\fP corresponding +bits in filter file are set to 1 then it suppose that word exists in dicionary. +\fBapgbfm\fP uses \fBmd5\fP as a hash function. +.PP +\fBapgbfm\fP can be used as standalone utility, not only with \fBapg\fP, or +\fBapgd\fP. +.PP +.TP +.B WARNING !!! +This is the first release of \fBapgbfm\fP and filter file format can be changed +in the future. I'll try to make file formats compatible but i can not guaranty this. +.TP +.B WARNING !!! +\fBapgbfm\fP may slow down your computer during filter creation. +.SH "OPTIONS" +.TP +.B -f \fIfilter\fP +use \fIfilter\fP as the name for Bloom filter filename. +.TP +.B -n numofwords +create new empty filter for \fBnumofwords\fP number of words. Useful when you +want to fill filter dynamicaly. +.TP +.B -d \fIdictfile\fP +create new filter from \fIdictfile\fP. It may take a lot of time to +generate filter from a big dictionary. To indicate that program is working +\fBapgbfm\fP prints dot for every 100 words added in dictionary. +.TP +.B -a word +add \fBword\fP to the filter. +.TP +.B -A \fIdictfile\fP +add all words from \fIdictfile\fP to the filter. +.TP +.B -c word +check \fBword\fP for appearance in the filter. +.TP +.B -C \fIdictfile\fP +check every word from \fIdictfile\fP for appearance in the filter. +.TP +.B -v +print version information. +.TP +.B -h +print help information. +.SH "EXIT CODE" +On successful completion of its task, +.B apgbfm +will complete with exit code 0. An exit code of -1 indicates an error +occurred. Textual errors are written to the standard error stream. +.SH "FILES" +.B None. +.SH "BUGS" +.B None. +If you've found one, please send bug description to the author. +.PP +This man page is Alpha too. +.SH "SEE ALSO" +\fBapgd\fP(8), \fBapg\fP(1) +.SH "AUTHOR" +Adel I. Mirzazhanov, +.br +Project home page: http://www.adel.nursat.kz/apg/ diff --git a/doc/man/apgd.8 b/doc/man/apgd.8 index 1b9710a..4dfd7fd 100644 --- a/doc/man/apgd.8 +++ b/doc/man/apgd.8 @@ -2,14 +2,14 @@ .\" Licensed under BSD-like License. .\" Created by Adel I. Mirzazhanov .\" -.TH APGD 8 "2001 Jan 8" "Automated Password Generator" "User Manual" +.TH APGD 8 "2001 Mar 18" "Automated Password Generator" "User Manual" .SH NAME apgd \- server that generates several random passwords .SH SYNOPSIS .B apgd -[\fB-r\fP \fIdictfile\fP] +[\fB-r\fP \fIdictfile\fP] [\fB-b\fP \fIfilter_file\fP] [\fB-a algorithm\fP] [\fB-C\fP] [\fB-L\fP] [\fB-S\fP] [\fB-N\fP] [\fB-m min_pass_len\fP] [\fB-x max_pass_len\fP] [\fB-n num_of_pass\fP] .PP @@ -131,7 +131,7 @@ generation algorithm is used). .TP .B R[r] the same as \fBS[s]\fP but it does not generate symbols \fB`\fP, \fB'\fP, -\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Usefull for password generation in +\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Useful for password generation in a shell script. (For random character password generation algorithm only). .RE .RS @@ -153,7 +153,7 @@ use special symbol set. For random character password generation algorithm only. .TP .B -R the same as \fB-S\fP but it does not generate symbols \fB`\fP, \fB'\fP, -\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Usefull for password generation in +\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Useful for password generation in a shell script. For random character password generation algorithm only. (old style - use \fB-M mode\fP instead). .TP @@ -186,6 +186,11 @@ for password generation. check generated passwords for their appearance in .B dictfile .TP +.B -b \fIfilter_file\fP +check generated passwords for their appearance in +\fIfilter_file\fP. \fIfilter_file\fP should be created with \fBapgbfm\fP(1) +utility. +.TP .B -n num_of_pass generate .B num_of_pass @@ -222,7 +227,7 @@ All textual info is written to the .B None. If you've found one, please send bug description to the author. .SH "SEE ALSO" -\fBapg\fP(1) +\fBapg\fP(1), \fBapgbfm\fP(1) .SH "AUTHOR" Adel I. Mirzazhanov, .br diff --git a/md5/md5.c b/md5/md5.c new file mode 100644 index 0000000..855b0be --- /dev/null +++ b/md5/md5.c @@ -0,0 +1,332 @@ +/* +** This code implements the MD5 message-digest algorithm. +** The algorithm is due to Ron Rivest. This code was +** written by Colin Plumb in 1993, no copyright is claimed. +** This code is in the public domain; do with it what you wish. +** +** Equivalent code is available from RSA Data Security, Inc. +** This code has been tested against that, and is equivalent, +** except that you don't need to include two pages of legalese +** with every copy. +** +** To compute the message digest of a chunk of bytes, declare an +** MD5Context structure, pass it to MD5Init, call MD5Update as +** needed on buffers full of bytes, and then call MD5Final, which +** will fill a supplied 16-byte array with the digest. +*/ + +/* +** This code was modified in 1997 by Jim Kingdon of Cyclic Software to +** not require an integer type which is exactly 32 bits. This work +** draws on the changes for the same purpose by Tatu Ylonen +** as part of SSH, but since I didn't actually use +** that code, there is no copyright issue. I hereby disclaim +** copyright in any changes I have made; this code remains in the +** public domain. +*/ + +/* +** Note regarding apg_* namespace: this avoids potential conflicts +** with libraries such as some versions of Kerberos. No particular +** need to worry about whether the system supplies an MD5 library, as +** this file is only about 3k of object code. +*/ + +#include /* for memcpy() and memset() */ + +/* Add prototype support. */ +#ifndef PROTO +#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) +#define PROTO(ARGS) ARGS +#else +#define PROTO(ARGS) () +#endif +#endif + +#include "md5.h" + +/* Little-endian byte-swapping routines. Note that these do not + depend on the size of datatypes such as apg_uint32, nor do they require + us to detect the endianness of the machine we are running on. It + is possible they should be macros for speed, but I would be + surprised if they were a performance bottleneck for MD5. */ + +static apg_uint32 +getu32 (addr) + const unsigned char *addr; +{ + return (((((unsigned long)addr[3] << 8) | addr[2]) << 8) + | addr[1]) << 8 | addr[0]; +} + +static void +putu32 (data, addr) + apg_uint32 data; + unsigned char *addr; +{ + addr[0] = (unsigned char)data; + addr[1] = (unsigned char)(data >> 8); + addr[2] = (unsigned char)(data >> 16); + addr[3] = (unsigned char)(data >> 24); +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +apg_MD5Init (ctx) + struct apg_MD5Context *ctx; +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +apg_MD5Update (ctx, buf, len) + struct apg_MD5Context *ctx; + unsigned char const *buf; + unsigned len; +{ + apg_uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = (t + ((apg_uint32)len << 3)) & 0xffffffff) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if ( t ) { + unsigned char *p = ctx->in + t; + + t = 64-t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + apg_MD5Transform (ctx->buf, ctx->in); + buf += t; + len -= t; + } + + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + apg_MD5Transform (ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +apg_MD5Final (digest, ctx) + unsigned char digest[16]; + struct apg_MD5Context *ctx; +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + apg_MD5Transform (ctx->buf, ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count-8); + } + + /* Append length in bits and transform */ + putu32(ctx->bits[0], ctx->in + 56); + putu32(ctx->bits[1], ctx->in + 60); + + apg_MD5Transform (ctx->buf, ctx->in); + putu32(ctx->buf[0], digest); + putu32(ctx->buf[1], digest + 4); + putu32(ctx->buf[2], digest + 8); + putu32(ctx->buf[3], digest + 12); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +apg_MD5Transform (buf, inraw) + apg_uint32 buf[4]; + const unsigned char inraw[64]; +{ + register apg_uint32 a, b, c, d; + apg_uint32 in[16]; + int i; + + for (i = 0; i < 16; ++i) + in[i] = getu32 (inraw + 4 * i); + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} +#endif + +#ifdef TEST +/* Simple test program. Can use it to manually run the tests from + RFC1321 for example. */ +#include + +int +main (int argc, char **argv) +{ + struct apg_MD5Context context; + unsigned char checksum[16]; + int i; + int j; + + if (argc < 2) + { + fprintf (stderr, "usage: %s string-to-hash\n", argv[0]); + exit (1); + } + for (j = 1; j < argc; ++j) + { + printf ("MD5 (\"%s\") = ", argv[j]); + apg_MD5Init (&context); + apg_MD5Update (&context, argv[j], strlen (argv[j])); + apg_MD5Final (checksum, &context); + for (i = 0; i < 16; i++) + { + printf ("%02x", (unsigned int) checksum[i]); + } + printf ("\n"); + } + return 0; +} +#endif /* TEST */ diff --git a/md5/md5.h b/md5/md5.h new file mode 100644 index 0000000..a8506ec --- /dev/null +++ b/md5/md5.h @@ -0,0 +1,41 @@ +/* See md5.c for explanation and copyright information. */ + +/* + * $FreeBSD: src/contrib/cvs/lib/md5.h,v 1.2 1999/12/11 15:10:02 peter Exp $ + */ + +#ifndef MD5_H +#define MD5_H +/* +#ifdef __FreeBSD__ +#define apg_MD5Context MD5Context +#define apg_MD5Init MD5Init +#define apg_MD5Update MD5Update +#define apg_MD5Final MD5Final +#define apg_MD5Transform MD5Transform +#include +#else +*/ +/* Unlike previous versions of this code, uint32 need not be exactly + 32 bits, merely 32 bits or more. Choosing a data type which is 32 + bits instead of 64 is not important; speed is considerably more + important. ANSI guarantees that "unsigned long" will be big enough, + and always using it seems to have few disadvantages. */ +typedef unsigned long apg_uint32; + +struct apg_MD5Context { + apg_uint32 buf[4]; + apg_uint32 bits[2]; + unsigned char in[64]; +}; + +void apg_MD5Init PROTO ((struct apg_MD5Context *context)); +void apg_MD5Update PROTO ((struct apg_MD5Context *context, + unsigned char const *buf, unsigned len)); +void apg_MD5Final PROTO ((unsigned char digest[16], + struct apg_MD5Context *context)); +void apg_MD5Transform PROTO ((apg_uint32 buf[4], const unsigned char in[64])); + +/*#endif*/ + +#endif /* !MD5_H */ diff --git a/restrict.c b/restrict.c index a24fba7..64f7dbb 100644 --- a/restrict.c +++ b/restrict.c @@ -64,3 +64,14 @@ check_pass(char *pass, char *dict) fclose (dct); return (0); } + +int +bloom_check_pass (char *word, char *filter) +{ + FILE *f_filter; + h_val filter_size = 0L; + if ( (f_filter = open_filter(filter)) == NULL) + return(-1); + filter_size = get_filtersize(f_filter); + return(check_word (word, f_filter, filter_size)); +} diff --git a/restrict.h b/restrict.h index 621821e..39227da 100644 --- a/restrict.h +++ b/restrict.h @@ -33,9 +33,9 @@ #ifndef RESTRICT_H #define RESTRICT_H 1 +#include "bloom.h" #define MAX_DICT_STRING_SIZE 255 extern int check_pass(char * pass, char *dict); -extern int make_db_dict(char *dict, char *bddict); -extern int construct_db_name(char *plain_filename, char * dbname); +extern int bloom_check_pass (char *word, char *filter); #endif /* RESTRICT_H */