charles@utastro.UUCP (Charles Sandel) (07/25/84)
--------- Below is a "shar" archive file which contains the ingredients to make "randpasswd" - a program which will generate random passwords. With no arguments, the passwords generated may contain lower- or upper-case ASCII alphas, or ASCII numerics, and will be of a random length between MINLENGTH (default=6) and MAXDESLEN (default=10). The program will accept two optional arguments: a numeric argument indicating the desired length of the generated password, and a "-w" indicating that the program should attempt to generate a "real-sounding English word". The program has its uses, particularly for "uucp" administrators who have a separate login and password for each neighboring site, and are faced with the problem of occasionally coming up with a new password for everyone. The attempt at making "real" words is done by using a table lookup to find out what characters are legal to follow the previous character. The advantage of this method is that it is simple; the disadvantage is that it is *too* simple, and doesn't take into account any rules of English grammar. But this can be overcome, by having the program generate passwords until you find one you like. Of course, you can always use the generated password as inspiration and mung it until you like it. Try this from the cshell: while (1) ? randpasswd -w ? sleep 1 ? end ... the "sleep" will give you time to decide if you liked the previous password. "Randpasswd" is written for sites running UN*X 4.2BSD, as it uses both gettimeofday(2) and the suite of routines from random(3). There is no reason why it should prove difficult to adapt to other UN*Xes, though, just making appropriate substitutions of time(2) and rand(3). The archive file contains the Makefile, the source and include files, and a manual page. ------------(cut here)------------------------------------ : This is a shar archive. Extract with sh, not csh. echo x - Makefile cat > Makefile << '!Funky!Stuff!' DEST = . EXTHDRS = /usr/include/sys/time.h HDRS = defs.h LDFLAGS = -s CFLAGS = -O LIBS = LINKER = cc MAKEFILE = Makefile OBJS = randpasswd.o PRINT = pr PROGRAM = randpasswd SRCS = randpasswd.c all: $(PROGRAM) $(PROGRAM): $(OBJS) $(LIBS) @echo -n "Loading $(PROGRAM) ... " @$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM) @echo "done" clean:; @rm -f $(OBJS) depend:; @mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST) index:; @ctags -wx $(HDRS) $(SRCS) install: $(PROGRAM) @echo Installing $(PROGRAM) in $(DEST) @install -s $(PROGRAM) $(DEST) print:; @$(PRINT) $(HDRS) $(SRCS) program: $(PROGRAM) tags: $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS) update: $(DEST)/$(PROGRAM) $(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS) @make -f $(MAKEFILE) DEST=$(DEST) install ### randpasswd.o: /usr/include/sys/time.h defs.h !Funky!Stuff! echo x - defs.h cat > defs.h << '!Funky!Stuff!' #define MAXLENGTH 16 /* maximum length of passwords */ #define MINLENGTH 6 /* minimum length of passwords */ #define MAXDESLEN 10 /* maximum desired length of passwords */ /* defined indexes into the randrange array of structures */ #define ANY -1 /* produce any random value from any range */ #define NUMERIC 0 /* index of the numeric range */ #define LALPHA 1 /* index of the lower alpha range */ #define UALPHA 2 /* index of the upper alpha range */ /* extra ranges to cover the entire 7-bit ASCII range */ /*#define CONTROL 3 /* index of the range NUL through US */ /*#define PUNCT1 4 /* index of the range SP through / */ /*#define PUNCT2 5 /* index of the range : through @ */ /*#define PUNCT3 6 /* index of the range [ through ` */ /*#define PUNCT4 7 /* index of the range { through DEL */ #define STATESZ 256 /* determines randomness of number generation */ #define NRANGE 3 /* number of ranges used */ struct randrange { unsigned seed; char state[STATESZ]; int width; char offset; }; /* define what characters may follow any character */ struct after { char ch; char *follow; }; struct randrange start, range[NRANGE] = /* seed state width offset */ { 0, "", 10, '0', 0, "", 26, 'a', 0, "", 26, 'A' /* other ASCII ranges may be useful; uncomment the ones needed , 0, "", 32, '\0', 0, "", 16, ' ', 0, "", 7, ':', 0, "", 6, '\0134', 0, "", 5, '{' */ }; /* ch follow */ struct after aft[] = { 'a', "abcdefghijklmnopqrstuvwxyz", 'b', "abdeilorstuwy", 'c', "aehikorstuwy", 'd', "adeioruy", 'e', "abcdefghijklmnopqrstuvwxyz", 'f', "aefiloruy", 'g', "aeghilnopruwy", 'h', "aefimnorsy", 'i', "abcdefghijklmnopqrstuvwxyz", 'j', "aeghijklouy", 'k', "acehijklorstuwxy", 'l', "aeiklmnoptuvwy", 'm', "abegiklmnopqrstuwxyz", 'n', "adegiknorstuxyz", 'o', "abcdefghijklmnopqrstuvwxyz", 'p', "aehilopqrstuwyz", 'q', "aeioruy", 'r', "acdefgiklmnopqrstuvxyz", 's', "acehiklmnopstuvwxyz", 't', "aehiortuyz", 'u', "abcdefghijklmnopqrstuvwxyz", 'v', "aeiouvwy", 'w', "aefghiklorsuvwy", 'x', "aeilouxyz", 'y', "acdeiklopqsuvwxyz", 'z', "acehilopqrstuwyz" }; !Funky!Stuff! echo x - randpasswd.c cat > randpasswd.c << '!Funky!Stuff!' /* randpasswd - generate a random password Calling syntax: randpasswd [-w] [length] where "length" is an optional numeric argument specifying the length of the password needed. If "length" is lesser or greater than MINLENGTH or MAXLENGTH, it is rounded up or down to a legal value. Passwords of length between MINLENGTH and MAXLENGTH are therefore possible, but if no argument is provided, a password of random length between MINLENGTH and MAXDESLEN is produced. If the argument "-w" is specified, "randpasswd" will attempt to generate a "real-sounding" English word, in lower-case alpha, sans numerics. Compilation: cc -O -s randpasswd.c -o randpasswd Author: Charles Sandel University of Texas Department of Astronomy Austin, Texas 78712 July 24, 1984 uucp: utastro!charles arpa: charles@utastro.UTEXAS.ARPA */ #include <sys/time.h> #include "defs.h" char passwd[MAXLENGTH+1]; long random(); char *initstate(), *setstate(); main(argc, argv) char *argv[]; { int i, length, word=0; struct timeval tp; struct timezone tzp; /* initialize generic state */ gettimeofday(&tp, &tzp); start.seed = tp.tv_usec; initstate(start.seed, start.state, STATESZ); setstate(start.state); length = -1; for(i=1; i<argc && i<3; i++) { if(strcmp("-w", argv[i]) == 0) word++; else { length = atoi(argv[i]); if(length < MINLENGTH) length = MINLENGTH; if(length > MAXLENGTH) length = MAXLENGTH; } } if(length == -1) length = random()%(MAXDESLEN - MINLENGTH + 1) + MINLENGTH; /* initalize range states & seeds */ for(i=0; i<NRANGE; i++) { gettimeofday(&tp, &tzp); range[i].seed = tp.tv_usec + random()%(NRANGE*STATESZ); initstate(range[i].seed, range[i].state, STATESZ); } /* make a password */ if(word != 0) { passwd[0] = randchar(LALPHA); setstate(range[LALPHA].state); for(i=1; i<length; i++) passwd[i] = wordchar(passwd[i-1]); } else for(i=0; i<length; i++) passwd[i] = randchar(ANY); passwd[++i] = '\0'; printf("%s\n", passwd); } randchar(inx) { long r; char c; if(inx == ANY || inx < 0 || inx > NRANGE-1) { /* set generic state and get a random index into the array */ setstate(start.state); r = random()%NRANGE; } else r = inx; /* set state for that range and get a random character from it */ setstate(range[r].state); c = random() % range[r].width + range[r].offset; return(c); } wordchar(pc) char pc; { register len, i; char c; i = pc - 'a'; len = strlen(aft[i].follow); c = aft[i].follow[random()%len]; return(c); } !Funky!Stuff! echo x - randpasswd.l cat > randpasswd.l << '!Funky!Stuff!' .TH RANDPASSWD 1L "24 July 1984" .UC 4 .SH NAME randpasswd \- generate a random password .SH SYNOPSIS .B randpasswd [ .B \-w ] [ .B length ] .SH DESCRIPTION This command generates a random password which can be used as a login password, or as an encryption key. .PP There are two optional arguments: .TP .B \-w If included, an attempt will be made to generate a password which, though nonsensical, might sound like a "real word". The resulting password will be in all lower-case ASCII characters. If omitted, the resulting password my contain lower- or upper-case ASCII characters, or ASCII numerics. .TP .B length "Length" is a number indicating the desired length of the resulting password. "Length" may be between 6 and 16. Larger or smaller requests are rounded up or down to a legal value. If this argument is omitted, the resulting length will be a random value between 6 and 10. .PP For most uses, you should probably get .B randpasswd to generate passwords until you find one you like. Try the following from csh: .ti +5 while (1) .ti +10 randpasswd -w .ti +5 end or this from sh: .ti +5 while (true) .ti +5 do .ti +10 randpasswd -w .ti +5 done .PP .SH "SEE ALSO" login(1), passwd(5), crypt(3) .br Robert Morris and Ken Thompson, .I UNIX password security .SH BUGS The attempt to generate a "real word" is simplistic, and makes no attempt at simulating the rules of English grammar. It is, however, effective if you try enough times. .SH DIAGNOSTICS None. Silence is Golden. .SH AUTHOR Charles Sandel .br University of Texas .br Department of Astronomy .br Austin, Texas 78712 !Funky!Stuff! -- *>> Charles Sandel <<* uucp: {ut-sally, ut-ngp, noao, charm}!utastro!charles arpa: chaz@ut-ngp or charles@ut-sally at&t: (512) 471-4461 x439
perl@rdin2.UUCP (Robert Perlberg) (07/27/84)
<Isn't it sad what happened to the G'gugvunts and the Vl'hurgs?> >Try this from the cshell: > >while (1) >? randpasswd -w >? sleep 1 >? end > >... the "sleep" will give you time to decide if you liked the >previous password. You've been caught, Charles. I ran the above loop without the sleep and found out why you REALLY put the sleep in. Since the random number generator is seeded by the time of day IN SECONDS, two runs of randpasswd within the same second will generate the same password. Users of randpasswd should keep this in mind if using randpasswd to generate a block of passwords that will not be examined. Robert Perlberg Resource Dynamics Inc. New York philabs!rdin!rdin2!perl