Skip to content

Instantly share code, notes, and snippets.

@raidzero
Created March 3, 2014 20:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raidzero/9334503 to your computer and use it in GitHub Desktop.
Save raidzero/9334503 to your computer and use it in GitHub Desktop.
Password generator. Takes password requirements as arguments using getopt()
/*
* USAGE: passgen [-u UPPER] [-l LOWER] [-n NUMBER] -s [SPECIAL] -a LENGTH
* The approach is take the desired length, and set aside positions in the result
* string for the required characters, then fill in the other positions
* with random characters
*/
#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
//#define DEBUG 1
// define the selection of characters to choose from each category
#define UCC "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define LCC "abcdefghijklmnopqrstuvwxyz"
#define NCC "0123456789"
#define SCC "~!@#$%^&*-)(|,.?"
//prototypes
int checkUsedLocs(int, int*, int);
int getRandInt(int, int, int*);
char getRandChar(char*);
void printdbg(char* fmt, ...); // only print stuff if DEBUG is defined
int main(int argc, char* argv[])
{
char* uc_min = NULL;
char* lc_min = NULL;
char* nc_min = NULL;
char* sc_min = NULL;
// these all default to 0, so the default behavior is no requirements
int UC_MIN = 0;
int LC_MIN = 0;
int NC_MIN = 0;
int SC_MIN = 0;
int length = 0;
// these are needed for getopt()
extern char* optarg;
extern int optind;
int o, opterr = 0;
static char usage[] = "usage: passgen [-u UPPER] [-l LOWER] [-n NUMBER] -s [SPECIAL] -a LENGTH\n";
// use getopt to parse args
while ((o = getopt(argc, argv, "u:l:n:s:a:")) != -1)
{
switch(o)
{
case 'u':
UC_MIN = atoi(optarg);
printdbg("UC_MIN: %d\n", UC_MIN);
break;
case 'l':
LC_MIN = atoi(optarg);
printdbg("LC_MIN: %d\n", LC_MIN);
break;
case 'n':
NC_MIN = atoi(optarg);
printdbg("NC_MIN: %d\n", NC_MIN);
break;
case 's':
SC_MIN = atoi(optarg);
printdbg("SC_MIN: %d\n", SC_MIN);
break;
case 'a':
printdbg("length str: %s\n", optarg);
length = atoi(optarg);
break;
default:
printf("%s", usage);
opterr = 1; // set this to 1 to cause getopt() to fail
return 1;
}
}
// only required param is length
if (length == 0)
{
printf("Length required! pass with -a LENGTH.\n");
return 1;
}
// the sum of the number of all required characters
int min_length = UC_MIN + LC_MIN + NC_MIN + SC_MIN;
if (length < min_length)
{
printf("Invalid length. Must be greater than %d.\n", min_length);
return -1;
}
printdbg("Length: %d.\n", length);
// allocate some memory for the result & the location map
char* res = malloc(length * sizeof(char) + 1);
int* usedLocs = malloc(length* sizeof(int));
// fill usedLocs with -1 - so checkUsedLocs() works correctly
memset(usedLocs, -1, sizeof(int) * length);
int i; // good old iterator
int locsCount = 0; // remember how many locations we have reserved
// lets determine the positions of the required characters
if (UC_MIN > 0)
{
// uppercase requirement
int *upperLocs = malloc(UC_MIN * sizeof(int));
for (i=0; i<UC_MIN; i++)
{
upperLocs[i] = getRandInt(0, locsCount, usedLocs);
char c = getRandChar(UCC);
res[upperLocs[i]] = c;
printdbg("UC: %c[%d]\n", c, upperLocs[i]);
usedLocs[locsCount++] = upperLocs[i];
}
free(upperLocs);
}
if (LC_MIN > 0)
{
// lowercase requirement
int *lowerLocs = malloc(LC_MIN * sizeof(int));
for (i=0; i<LC_MIN; i++)
{
lowerLocs[i] = getRandInt(0, locsCount, usedLocs);
char c = getRandChar(LCC);
res[lowerLocs[i]] = c;
printdbg("LC: %c[%d]\n", c, lowerLocs[i]);
usedLocs[locsCount++] = lowerLocs[i];
}
free(lowerLocs);
}
if (NC_MIN > 0)
{
// numeric requirement
int *numberLocs = malloc(NC_MIN * sizeof(int));
for (i=0; i<NC_MIN; i++)
{
numberLocs[i] = getRandInt(0, locsCount, usedLocs);
char c = getRandChar(NCC);
res[numberLocs[i]] = c;
printdbg("NC: %c[%d]\n", c, numberLocs[i]);
usedLocs[locsCount++] = numberLocs[i];
}
free(numberLocs);
}
if (SC_MIN > 0)
{
// special requirement
int *specialLocs = malloc(SC_MIN * sizeof(int));
for (i=0; i<SC_MIN; i++)
{
specialLocs[i] = getRandInt(0, locsCount, usedLocs);
char c = getRandChar(SCC);
res[specialLocs[i]] = c;
printdbg("SC: %c[%d]\n", c, specialLocs[i]);
usedLocs[locsCount++] = specialLocs[i];
}
free(specialLocs);
}
// make pool of all chars from each category
char* allChars = malloc(strlen(UCC) + strlen(LCC) + strlen(NCC) + strlen(SCC) + 1 * sizeof(char));
strcat(allChars, UCC); strcat(allChars, LCC); strcat(allChars, NCC); strcat(allChars, SCC);
printdbg("all chars: %s\n", allChars);
for (i=0; i<length; i++)
{
printdbg("usedLocs[%d]: %d\n", i, usedLocs[i]);
}
// fill in the rest
for (i=0; i<length; i++)
{
if (!checkUsedLocs(i, usedLocs, length))
{
res[i] = getRandChar(allChars);
}
}
printf("%s\n", res);
free(usedLocs);
free(allChars);
free(res);
return 0;
}
int checkUsedLocs(int loc, int* usedLocs, int size)
{
int i;
for (i=0; i<size; i++)
{
if (usedLocs[i] == -1)
{
return 0; // this hasnt been set at all
}
if (usedLocs[i] == loc)
{
return 1;
}
}
return 0;
}
int getRandInt(int min, int max, int* usedLocs)
{
// sleep for 1 usec , to ensure a new random number next time
usleep(1);
// structs for time
struct timezone tz;
struct tm *tm;
struct timeval tv;
gettimeofday (&tv, &tz);
tm = (struct tm*) localtime (&tv.tv_sec);
srand (tv.tv_usec); // seed random number generator with microsenconds
int r = (rand() % (max+1-min))+min;
if (!usedLocs) // we are just pulling what will be a character
{
printdbg("getRandInt(%d, %d) returning %d\n", min, max, r);
return r;
}
// get a valid location to store this soon-to-be character in
while (checkUsedLocs(r, usedLocs, max))
{
r = (rand() % (max+1-min))+min;
}
printdbg(">>getRandInt(%d, %d) returning %d\n", min, max, r);
return r;
}
char getRandChar(char* str)
{
int len = (strlen(str)) - 1; // 0-indexed
int pos = getRandInt(0, len, 0);
char r = str[pos];
return r;
}
void printdbg(char* fmt, ...)
{
#ifdef DEBUG
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment