From: marc@tanda.isis.org (Marc Thibault)
Reply-To: marc@tanda.isis.org
Newsgroups: sci.crypt
Subject: Re: Secure password generation
Date: Mon, 14 Sep 92 10:19:15 EDT
Distribution: na
Organization: Thibault & Friends

In article <1992Sep12.020756.17214@morwyn.uucp> 
(Forrie Aldrich) writes: 
> 
> I'm seeking a program/method which will generate pronounceable passwords,
> securely.  Meaning the process by which the actual password is generated
> should be genuinely random enough so an attack at the algorithm (by
> whatever means) would be infeasable.

        The C program listed below may be what Forrie is looking for,
        but it needs a cryptographically strong RNG to replace
        qrand().  Maybe one of our experts can post one??

----------------- START CODE -------------------------------------------
/* babble.c
    A program to generate random pronounceable words to be
    used as passwords.
    
Author:     Marc Thibault
Created:    17 January 1988
    
Synopsis:
	BABBLE [text]

Description:
	BABBLE, sends 64 random words to STDOUT, each 8 followed by 
	a newline. If the optional [text] argument is provided, the
	argument is used to initialize the random seed. The same argument
	will result in the same words on successive calls.
	
	The word generation is done through a set of arrays which 
	implement a strategy for pronounceability. This improves the 
	mnemonic value of the words without sacrificing randomness
	to any significant degree.

Subroutines:
	putns(c)				add character to word
    qrand(a)                random integer between 0 and (a-1)
	putSel(a,b)				add element to word
	selectStrategy ()		random row from strategy matrix
	doSel(n)				add element from set to word
	makeWord()				create random word
	int utime()				return unsigned int function of time

/*------------------------------------------------------------------*/


#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

/*------------------------------------------------------------------*/
/* Global Data Items
/*------------------------------------------------------------------*/

char word[16];          /* Babble words will be assembled here      */
int wordCount;          /* Count of characters in word              */

						
/*------------------------------------------------------------------*/
/*            Word Elements                                         */
/*------------------------------------------------------------------*/

/* Introductory consonant */
char incon1[] = "bcdfghjklmnpqrstvwzsbbffpptdcst";
char incon2[] = "            u      tlrlrlrrrhhh";

/* Middle Consonants      */
char midcon1[] = "bbcdffghjkllmmnpqrrrsssttvnz";
char midcon2[] = " s   f     l m  u mr st t w ";


/* Ending Consonants      */
char endcon1[] = "bcddfgklmnrssttvz";
char endcon2[] = " k ef       t e y";

/* Vowels                 */
char vowels1[] = "aeiouaeieo";
char vowels2[] = "     iaaeo";



/*------------------------------------------------------------------*/
/* put character if not space and wordCount<8                       */
/* Returns 1 if character put, 0 if not                             */
/*------------------------------------------------------------------*/
char blank=32;

void putns(c)
char c;
    {
    if ((c != blank)&&(wordCount<8))
	word[wordCount++] = c;
    }

/*------------------------------------------------------------------*/
/* Return random number between 0 and argument
/*  This needs a stronger RNG.
/*------------------------------------------------------------------*/

int qrand(a)
int a;
	{
	int r;
	r=rand() % a;
	return (r);
	}


/*------------------------------------------------------------------*/
/* Put from selected array */
/*------------------------------------------------------------------*/


void putSel(a,b)
char a[], b[];
    {
    int i;
    i=qrand(strlen(a));
    putns(a[i]);
    putns(b[i]);
    }


/*------------------------------------------------------------------*/
/* Strategy Options
/* Each row is a sequence of choices representing constants
/* or vowels. See doSel for interpretation. The resulting
/* sequence is the template for a babble word. Greater security
/* can be obtained by increasing the size of the template.
/* If number of rows is changed, fix selectStrategy.
/* If number of cols is changed, fix makeWord.
/*------------------------------------------------------------------*/

int options[5][5]=
    {
	{1,2,1,4,0},			/* vowel, incon, vowel, endcon */
	{1,3,1,4,0},
	{2,1,3,1,0},
	{2,1,4,1,0},
	{2,1,3,1,4}
    };

/*------------------------------------------------------------------*/
/* Return a random row number into options							*/
/*------------------------------------------------------------------*/

int selectStrategy ()
    {
    int i;
    i = qrand(5);
    return (i);
    }


/*------------------------------------------------------------------*/
/* Handle one selection from a strategy
/*------------------------------------------------------------------*/
doSel(n)
int n;
    {
    switch(n)
		{
		case 0:
		    break;
		case 1:
		    putSel(vowels1,vowels2);
		    break;
		case 2:
		    putSel(incon1,incon2);
		    break;
		case 3:
		    putSel(midcon1,midcon2);	
		    break;
		case 4:
		    putSel(endcon1,endcon2);
		    break;
		}
    }

/*------------------------------------------------------------------*/
/* Make a word
/* Fill word buffer with 5 option elements from one strategy
/*------------------------------------------------------------------*/

void makeWord()
    {
    int s;              		/* strategy selection */
    int i;              		/* strategy element */
    
    s=selectStrategy();			/* get a random strategy */
    wordCount = 0;				/* reset word buffer */
    
    /* get 5 elements from selected strategy */
    for (i=0; i<5; i++)  doSel(options[s][i]);
    
    word[wordCount]=0;			/* terminate with nul */
    }

/*------------------------------------------------------------------*/
/* Return daytime function as unsigned int
/*------------------------------------------------------------------*/

unsigned int utime()
	{
	return ( (unsigned)(time(NULL)%32768) );
	}

/*------------------------------------------------------------------*/
/*                    MAIN PROGRAM									*/
/*------------------------------------------------------------------*/

main(argc,argv)
int argc;
char *argv[];
    {
    unsigned int i;
    int j;
    char *a;				/* arg string for random seed           */
    unsigned int t0;			/* initial time reading
    
	/*--------------------------------------------------------------*/
    /* Initialize Random Seed
	/*  If no argument is provided: use daytime, otherwise
	/*  add up bytes of argument
	/*--------------------------------------------------------------*/

	if( argc<2 ) 
		{	
		/* Wait for time to change */
		for (i=utime(); i==utime(););
		
		/* set seed */
		srand(utime());
		}
		
	else
		{
		i=0;
		a=argv[1];
		
		/* add up bytes in argument */
		for (i=0; *a != 0; i += *a++);
		srand(i);
		}	
	

	/*--------------------------------------------------------------*/
	/* Send 64 babble words to stdout */
	/*--------------------------------------------------------------*/
	
    for (i=0;i < 8; i++)
		{
		for (j=0; j<8; j++)
			{
			makeWord();
			printf("%s ",word);
			}
		/* CRLF */
		printf("\n");
		}
	
	/*---------------- That's All She Wrote ------------------------*/
    }

---

 Marc Thibault        |                              |  Any Warming,
 marc@tanda.isis.org  |  Oxford Mills, Ontario       |  Global or otherwise,
 CIS:71441,2226       |     Canada                   |   appreciated.