I'm currently developing a CLI password generator and I've been trying to come up with ways of randomizing characters between a defined set of chars. I know the srand(time(NULL))
method but as far as I know, it's a bit incosistent and not so safe to generate random passwords.
I also know there is a way of randomizing numbers using the libsodium library for C (according to this topic), but I'm not sure how to use it. Should I install all the dependencies in my project? Is a relative small project to have such a huge library. Although I plan expanding it as time goes by, I don't know if it's worth having a huge library and not use most of its functions.
On top of that, are there specific algorithms to generate passwords other than just randomizing characters? Should I also randomize the array within itself following another algorithm for better consistency like the Fisher Yates Shuffle?
Thanks in advance!
There are lots of issues to resolve, including:
extern void gen_random_password(size_t length, char buffer[length]);
rand()
and srand()
will be available 'everywhere'nrand48()
- no hidden seedarc4random()
— no seed permitted (BSD, macOS)random()
and srandom()
(BSD, macOS)I like using nrand48()
because it allows the random password generator to run a series of random numbers independently of any other sequence because it takes the seed — an array of 3 unsigned short
integers — as arguments.
Generating a good random seed is tricky. I have code which can be configured to use any of these mechanisms:
The first two are preferable — there may or may not be a significant difference between /dev/random
and /dev/urandom
.
Once you've got these important but tedious issues out of the way, the core algorithm for generating a random password is very simple:
grpwd43.h
#ifndef JLSS_ID_GRPWD43_H
#define JLSS_ID_GRPWD43_H
#include <stddef.h>
extern void gen_random_passwd(size_t length, char buffer[length]);
#endif /* JLSS_ID_GRPWD43_H */
grpwd43.c
#include "grpwd43.h" /* SSC: Self-sufficiency check */
#include <assert.h>
#include "randseed.h"
#include "prng48.h"
/*
** Tweak this list of alphanumerics plus punctuation to suit.
** For example, list the alphabet twice (or more) to make letters more
** likely than numbers or punctuation.
*/
static const char password[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
;
enum { NUM_PASSWORD = sizeof(password) - 1 };
static int initialized = 0;
void gen_random_passwd(size_t length, char buffer[length])
{
assert(buffer != NULL && length != 0);
if (buffer == NULL || length == 0)
return;
if (initialized == 0)
{
unsigned short seed[3];
random_seed_bytes(sizeof(seed), seed);
prng48_seed(seed);
initialized = 1;
}
for (size_t i = 0; i < length - 1; i++)
{
buffer[i] = password[prng48_rand(0, NUM_PASSWORD - 1)];
}
buffer[length - 1] = '\0';
}
#ifdef TEST
#include <stdio.h>
int main(int argc, char **argv)
{
for (int i = 11; i < 31; i++)
{
char passwd[i];
gen_random_passwd(i, passwd);
printf("%d: %s\n", i - 1, passwd);
}
return 0;
}
#endif /* TEST */
The other source files needed can be found in my SOQ (Stack Overflow Questions) repository on GitHub in the src/so-7594-6155 sub-directory or in the src/libsoq sub-directory.