LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-10-2004, 11:55 AM   #1
lepricaun
LQ Newbie
 
Registered: Apr 2004
Location: @ home
Distribution: Red Hat 9.0, slackware 9.1, FC2
Posts: 25

Rep: Reputation: 15
written command line password generator


i've written a password generator in C, works just like i want it, has the GPL license, but i was wondering what you guys think of the way it is coded, what i could have done to improve the coding...

pwgenCL
here's the source:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void very_easy_password(int);
void very_easy2_password(int);
void easy_password(int);
void medium_password(int);
void hard_password(int);
void hard2_password(int);
void very_hard_password(int);
void extreme_password(int);

int main(int argc, char** argv)
{
    int characterset=0;
    int password_length=0;
    if((argc<3)|(argc>3))
    {
	printf("\npwgenCL,commandline password generator, Copyright (C) 2004 Scorpius");
    	printf("\n\npwgenCL is free software; you can redistribute it and/or modify");
    	printf("\nit under the terms of the GNU General Public License as published by");
    	printf("\nthe Free Software Foundation; either version 2 of the License.");
    	printf("\n\npwgenCL is distributed in the hope that it will be useful,");
    	printf("\nbut WITHOUT ANY WARRANTY; without even the implied warranty of");
    	printf("\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the");
    	printf("\nGNU General Public License for more details.");
    	printf("\n\nYou should have received a copy of the GNU General Public License");
    	printf("\nalong with this program; if not, write to the Free Software");
    	printf("\nFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\n");
	printf("\nCharacter sets:");
	printf("\n1: (a-z)\t\t\t\t\tvery easy password");
        printf("\n2: (A-Z)\t\t\t\t\tvery easy password");
        printf("\n3: (a-z,A-Z)\t\t\t\t\teasy password");
        printf("\n4: (a-z,0-9)\t\t\t\t\tmedium password");
        printf("\n5: (A-Z,a-z,0-9)\t\t\t\thard password");
        printf("\n6: (a-z,0-9, \\ ] [ ^ _ )\t\t\thard password");
        printf("\n7: ( ! \" # $ % ' ( * ) + , - . /  ,a-z,0-9)\tvery hard password");
        printf("\n8: full keyboard characters (except space), almost impossible to crack\n\n");
	printf("The maximum password length is 256 characters\n");
	printf("Usage: %s <characterset> <password length>\n",argv[0]);
        return 0;
    }
    if(argc==3)
    {
    	characterset=atoi(argv[1]);
    	password_length=atoi(argv[2]);
	if (password_length<1)
        {
		printf("Password length: %d is too small.\n",password_length);
		return -1;
	}
	if (password_length>256)
	{
		printf("Password length: %d is too large.\n",password_length);
		return -1;
	}
    	switch(characterset)
    	{
                case 1:
                        very_easy_password(password_length);
                        break;
                case 2:
                        very_easy2_password(password_length);
                        break;
                case 3:
                        easy_password(password_length);
                        break;
                case 4:
                        medium_password(password_length);
                        break;
                case 5: 
                        hard_password(password_length);
                        break;
                case 6:
                        hard2_password(password_length);
                        break;
                case 7:
                        very_hard_password(password_length);
                        break;
                case 8:
                        extreme_password(password_length);
                        break;
               default:
			printf("Invalid character set\n");
			return -1;
                        break;
    	}
    	    	return 0;
    }   
    else return -1;  
}

/*(a-z) very easy password*/

void very_easy_password(length)
{
    srand(time(NULL));
    while (length>0)
    {
        int cha;
        cha=rand()%128;
        if((cha>=97 && cha<=122))
        {
           printf("%c",cha);
           length--;
        }
    }
}

/* (A-Z) also very easy password */
void very_easy2_password(length)
{
    srand(time(NULL));
    while (length>0)
    {
        int cha;
        cha=rand()%128;
        if((cha>=65 && cha<=90))
        {
           printf("%c",cha);
           length--;
        }
    }
}

/*(A-Z,a-z), easy password*/

void easy_password(length)
{
    srand(time(NULL));
    while (length>0)
    {
        int cha;
        cha=rand()%128;
        if((cha>=65 && cha<=90) || (cha>=97 && cha<=122))
        {
           printf("%c",cha);
           length--;
        }
    }
}

/*(a-z,0-9) medium password*/

void medium_password(length)
{
    srand(time(NULL));
    while (length>0)
    {
        int cha;
        cha=rand()%128;
        if((cha>=48 && cha<=57) ||(cha>=97 && cha<=122))
        {
           printf("%c",cha);
           length--;
        }
    }
}


/*(A-Z,a-z,0-9) hard password*/

void hard_password(length)
{
    srand(time(NULL));
    while (length>0)
    {
        int cha;
        cha=rand()%128;
        if((cha>=48 && cha<=57) || (cha>=65 && cha<=90) || (cha>=97 && cha<=122))
        {
           printf("%c",cha);
           length--;
        }
    }
}

/*(a-z,0-9, \ ] [ ^ _ ) hard password*/

void hard2_password(length)
{
    srand(time(NULL));
    while (length>0)
    {
        int cha;
        cha=rand()%128;
        if((cha>=48 && cha<=57) || (cha>=91 && cha<=95) || (cha>=97 && cha<=122))
        {
           printf("%c",cha);
           length--;
        }
    }
}

/*( ! " # $ % ' ( * ) + , - . /  ,a-z,0-9) very hard password*/

void very_hard_password(length)
{
    srand(time(NULL));
    while (length>0)
    {
        int cha;
        cha=rand()%128;
        if((cha>=33 && cha<=57)|| (cha>=97 && cha<=122))
        {
           printf("%c",cha);
           length--;
        }
    }
}

/*full keyboard characters (except space), almost impossible to crack */

void extreme_password(length)
{
    srand(time(NULL));
    while (length>0)
    {
        int cha;
        cha=rand()%128;
        if((cha>=33 && cha<=126))
        {
           printf("%c",cha);
           length--;
        }
    }
}
(if you like the program, feel free to use it, it is opensource software)
 
Old 08-10-2004, 12:15 PM   #2
itsme86
Senior Member
 
Registered: Jan 2004
Location: Oregon, USA
Distribution: Slackware
Posts: 1,246

Rep: Reputation: 59
Code:
void very_easy_password(length)
{
    srand(time(NULL));
    while (length>0)
    {
        int cha;
        cha=rand()%128;
        if((cha>=97 && cha<=122))
        {
           printf("%c",cha);
           length--;
        }
    }
}
This looks horribly inefficient. I think it would be better to create the ability to always grab a valid character with rand(). You might want to consider setting up a character array that contains valid characters for each charset and then grabs a random character from that array. does that make sense?

Like, say for instance that one of your charsets creates a password consisting of lowercase characters, uppercase characters, and underscores.

You could set up an array like this:
Code:
char arr[] =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
Then when you grab a random character you can just do:
Code:
array_len = strlen(arr);
while(length--)
  cha = arr[rand()%array_len];
This way you always end up with a valid character and you don't end up having any "misses".

It also seems (to me at least) to be a little clearer as to which characters each charset contains.

Last edited by itsme86; 08-10-2004 at 12:32 PM.
 
Old 08-10-2004, 12:19 PM   #3
Mohsen
Member
 
Registered: Feb 2003
Location: Iran
Distribution: Solaris 10
Posts: 201

Rep: Reputation: 30
Quote:
if((argc<3)|(argc>3))
How about using if (argc != 3) and then an else statement instead .

Quote:
(if you like the program, feel free to use it, it is opensource software)
Wow, it's a very kindly offer! Thanks.
 
Old 08-10-2004, 12:47 PM   #4
itsme86
Senior Member
 
Registered: Jan 2004
Location: Oregon, USA
Distribution: Slackware
Posts: 1,246

Rep: Reputation: 59
Code:
itsme@dreams:~/C$ cat pwd.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define MAX_PWD_LEN 255

void create_pwd(char *set, int setlen, int pwdlen, char *buffer)
{
  srand(time(NULL));

  while(pwdlen--)
    *buffer++ = set[rand()%setlen];
  *buffer = '\0';
}

int main(int argc, char **argv)
{
  int set, length;
  char *sets[] = { "ABCabc",
                   "ABCabc_",
                   "ABCabc_!@#$%^&*()"
                 };
  int nsets = 3;
  char pwd[MAX_PWD_LEN+1];

  if(argc != 3)
  {
    puts("Usage: pwd <characterset> <password length>");
    exit(EXIT_FAILURE);
  }

  set = atoi(argv[1]);
  if(set < 1 || set > nsets)
  {
    puts("Invalid character set");
    exit(EXIT_FAILURE);
  }
  set--; // So we can use 'set' as array index

  length = atoi(argv[2]);
  if(length < 1 || length > MAX_PWD_LEN)
  {
    printf("Password length must be between 1 and %d\n", MAX_PWD_LEN);
    exit(EXIT_FAILURE);
  }

  create_pwd(sets[set], strlen(sets[set]), length, pwd);
  printf("The password is: %s\n", pwd);

  return 0;
}
That's the way I would write it personally. To add another character set you only have to add another line for the sets array and increment nsets.

Last edited by itsme86; 08-10-2004 at 12:54 PM.
 
Old 08-10-2004, 01:14 PM   #5
max_sipos
Member
 
Registered: Jul 2004
Posts: 96

Rep: Reputation: 15
It's also a good idea to use getopt_long for parsing arguments, it makes it easier to write GNU-style apps (with short and long arguments etc)

--
Maksim Sipos
 
Old 08-10-2004, 07:50 PM   #6
kev82
Senior Member
 
Registered: Apr 2003
Location: Lancaster, England
Distribution: Debian Etch, OS X 10.4
Posts: 1,263

Rep: Reputation: 51
wow, 2 random number posts in 1 night.

ok, rand() is a bad idea because most stdlib's implementation of it is a first order lcg, ie a sequence of the form X_{n+1}=(a*X_n + c) mod m, which for this kind of thing is NOT good because

a) if some characters are known it is quite simple(cpu power wise) to narrow down possibilities of others, ie the generator has very low entropy.

b) some libc's (dont think glibc does) for speed take m to be a power of two because the modulus can be done with a bitwise and. this is DISASTEROUS when you do rand()%128 because its relativly simple to prove that given two sequences

X_n+1=a*X_n +c mod p*q
Y_n = X_n mod p

Y_n has a maximim period of p rather than p*q

so if you link with a libc like this passwords of more than 128 characters will repeat and most likely passwords of less will also repeat but thats dependant on a and c.

so you really shouldnt use rand() especially when there are cryptography libraries with far superior random number generators or the very well written (one of the best i think) entropy collectors that is /dev/random

your choice to disregard numbers although perhaps inefficient as stated by itsme86 is a good way of removing the structure of an lcg, especially in your context where the number of disregarded numbers is dependant only on the seed and the users choice of character set, this makes it much harder for a cracker to analyse passwords. and since today we have lots of cpu power and very large periods(in the region of 2^32) i would definatly stick with this if you inted to use rand() (obviously its a waste if you use /dev/random). if your interested it was first proposed by a guy called Todd in the mid 50s i think.

you do seem to have rather a lot of code repitition here, you need to do something like itsme86 was saying some kind of array, if your familiar with a bitmap i suggest you use something like that.

Code:
char x[128];
memset(x, 0, 128);

switch(charset) {
    case 1:
    memset(x+97, 1, 26);
    break;
    case 2:
    memset(x+64, 1, 26);
    break;
    //... 
    //...
}

//then when generating
int i=rand()%128;
if(x[i]) printf("%c", x[i]);
as a final thought it might be a good idea to test your passwords before you pass them to the user by running them through something like cracklib.

<edit>
i dont know very much about seed choice other than you'll want it to be as unguessable as possible, which is why time(NULL) isnt the best, if the cracker knows the day the password is generated he only has 60*60*24 seeds to try which is a hell of a lot less than 2^32. as stated above sources of entropy are your best bet like /dev/random but you can make things difficult with badly behaved numerical systems such as chaotic dynamical systems or ill conditioned matrix equations
</edit>

Last edited by kev82; 08-10-2004 at 08:46 PM.
 
Old 08-11-2004, 12:36 AM   #7
lepricaun
LQ Newbie
 
Registered: Apr 2004
Location: @ home
Distribution: Red Hat 9.0, slackware 9.1, FC2
Posts: 25

Original Poster
Rep: Reputation: 15
wew, what a response

well first of all, i've just started programming in C 2 months ago (i've started with C++ 1,5 years ago, but never gave it much thought), so most of the things you guys talk about i just haven't thought about or just don't know

but i'm surely gonna check all these points out, and perhaps in a couple of weeks, i can rewrite it with a much more effecient code

thanks a lot for the response

[edit]
ok, here's what i've come up with so far, i've also create an extra parameter to the code to create more randomness.


pwgenCL_2

Code:
/*
pwgenCL version 2 (pwgenCL_2)Copyright (C) 2004 Scorpius, password generator, 
written as a command line scripting utility.
this program is freesource, which means you may use and/or modify it under the GPL license.
if you'd like to contact me with comments/bugs/suggestions or just to say hello,
my email address is: scorpius_unknown@yahoo.com.
  
i hope you enjoy using my program and that you find it usefull :)         
  
to compile it under windows, get a copy of Dev-C++ (it's free), or another C/C++ compiler.
to compile it under linux, just type "gcc -o pwgenCL_2 pwgenCL_2.c" (without the " quotes)
*/

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

char *generated_password(char*, int,int);

int main(int argc, char** argv)
{   /*the character sets*/
    char *very_easy_set = "abcdefghijklmnopqrstuvwxyz";
    char *very_easy2_set = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char *easy_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char *medium_set = "abcdefghijklmnopqrstuvwxyz0123456789";
    char *hard_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    char *hard2_set = "\\][^_abcdefghijklmnopqrstuvwxyz0123456789";
    char *very_hard_set = "!\"#$%'(*)+,-./abcdefghijklmnopqrstuvwxyz0123456789";
    char *extreme_set = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
    
    int characterset=0;
    int password_length=0;
    int user_supplied=0;
    if(argc!=4)
    {
	    printf("\npwgenCL_2,commandline password generator, Copyright (C) 2004 Scorpius");
    	printf("\n\npwgenCL_2 is free software; you can redistribute it and/or modify");
    	printf("\nit under the terms of the GNU General Public License as published by");
    	printf("\nthe Free Software Foundation; either version 2 of the License.");
    	printf("\n\npwgenCL_2 is distributed in the hope that it will be useful,");
    	printf("\nbut WITHOUT ANY WARRANTY; without even the implied warranty of");
    	printf("\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the");
    	printf("\nGNU General Public License for more details.");
    	printf("\n\nYou should have received a copy of the GNU General Public License");
    	printf("\nalong with this program; if not, write to the Free Software");
    	printf("\nFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n");
    	printf("\n\t   ***Contact Scorpius: scorpius_unknown@yahoo.com***");
    	printf("\n\nCharacter sets:");
    	printf("\n1: (a-z)\t\t\t\t\tvery easy password");
        printf("\n2: (A-Z)\t\t\t\t\tvery easy password");
        printf("\n3: (a-z,A-Z)\t\t\t\t\teasy password");
        printf("\n4: (a-z,0-9)\t\t\t\t\tmedium password");
        printf("\n5: (A-Z,a-z,0-9)\t\t\t\thard password");
        printf("\n6: (a-z,0-9, \\ ] [ ^ _ )\t\t\thard password");
        printf("\n7: ( ! \" # $ % ' ( * ) + , - . /  ,a-z,0-9)\tvery hard password");
        printf("\n8: full keyboard characters (except space), almost impossible to crack\n\n");
        printf("The maximum password length is 256 characters\n");
        printf("Usage: %s <characterset> <password length> <user supplied number>\n",argv[0]);
        printf("\n*The <user supplied number> is inserted to create extra randomness*\n");
        printf("\nExample: %s 8 15 5454303\n",argv[0]);
        return 0;
    }
    if(argc==4)/*if all parameters, (characterset,passwordlength,randomization number) run the program*/
    {
    	characterset=atoi(argv[1]);/*create integer from the argument*/
    	password_length=atoi(argv[2]);/*create integer from the argument*/
    	user_supplied=atoi(argv[3]);/*create integer from the argument*/
    	if (password_length<1)
        {
		printf("Password length: %d is too small.\n",password_length);
		return -1;
		}
		if (password_length>256)
		{
		printf("Password length: %d is too large.\n",password_length);
		return -1;
		}
    	switch(characterset)
    	{
                case 1:
                        generated_password(very_easy_set,password_length,user_supplied);
                        break;
                case 2:
                        generated_password(very_easy2_set,password_length,user_supplied);
                        break;
                case 3:
                        generated_password(easy_set,password_length,user_supplied);
                        break;
                case 4:
                        generated_password(medium_set,password_length,user_supplied);
                        break;
                case 5: 
                        generated_password(hard_set,password_length,user_supplied);
                        break;
                case 6:
                        generated_password(hard2_set,password_length,user_supplied);
                        break;
                case 7:
                        generated_password(very_hard_set,password_length,user_supplied);
                        break;
                case 8:
                        generated_password(extreme_set,password_length,user_supplied);
                        break;
               default:
                        printf("Invalid character set\n");
			            return -1;
                        break;
    	}
	    return 0;
    }   
    else return -1;  
}

/*the password generator function*/

char *generated_password(char* char_set, int length,int user_number)
{
        
        srand(user_number*time(NULL));
        int loop;
        int set_length=strlen(char_set);
    
        for(loop=0;loop<length;loop++)
        {
             putchar(char_set[rand()%set_length]);
        }
        printf("\n");
}
let me know what you guys think of it

grtz


Scorpius

Last edited by lepricaun; 08-11-2004 at 01:41 PM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
GUI generator for command line programs? pandasuit Linux - Software 5 01-16-2011 04:55 PM
Command Line Password Check jedediah Linux - Security 4 12-09-2004 03:01 PM
Command-line 'adduser': password not hashing Talesin Fedora 0 10-08-2004 08:19 PM
written a password generator in C, get it here lepricaun General 1 08-09-2004 07:12 AM
going to root without password thru command line amanjsingh Linux - Newbie 6 03-29-2004 11:38 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:21 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration