1. OCAU Merchandise now available! Check out our 20th Anniversary Mugs, Classic Logo Shirts and much more! Discussion here.
    Dismiss Notice

Need help from the C gurus!

Discussion in 'Programming & Software Development' started by deepspring, Jan 3, 2011.

  1. Foliage

    Foliage Member

    Joined:
    Jan 22, 2002
    Messages:
    32,085
    Location:
    Sleepwithyourdadelaide
    he meant the actual dev/random data could be larger than that, eg it could be an entire string of 20 bytes, however my interpretation of random means it doesn't matter which or how many bytes you use it will still be just as random.
     
  2. OP
    OP
    deepspring

    deepspring Member

    Joined:
    Jul 8, 2002
    Messages:
    3,601
    Location:
    Maitland, NSW
    Ah ok then... well running this version of the program returns some interesting results:
    Code:
    #include <time.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    
    int main(int argc, const char *argv[]) {
    	/* Length of the password */
    	unsigned short int length = 0;
    
    	/* Check if we have a command line argument */
    	if(argc > 1) {
    		/* Set our password length */
    		length = atoi(argv[1]);
    	}
    	
    	/* Just in case atoi() returns 0 or the user gives a negative
    	   integer */
    	if(length <= 0) {
    		length = 8;
    	}
    
    	/* Set our char variable to length + 1 for null termination */
    	char chars[length+1];
    
    	/* Try opening /dev/random for a random seed for srand() function */
    	int rdata = open("/dev/random", O_RDONLY);
    	unsigned long int randomInt;
    	
    	if (!rdata) {
    		printf("Failure: /dev/random could not be opened, using time instead!\n");
    		randomInt = (unsigned long int)time(NULL) + getpid();
    	} else {
    		read(rdata, &randomInt, sizeof(randomInt));
    		close(rdata);	
    	}
    
    	/* Seed the rand() function */
    	srand(randomInt);
    	
    	/* For debugging purposes */
    	printf("Random Integer\t=>\t%lu", randomInt);
    	
    	/* ASCII characters 33 to 126 */
    	int count = 0;
    	while(count < length) {
    		chars[count] = (char)(rand() % 94 + 33);
    		srand(rand());
    		count++;
    	}
    
    	/* Terminate the char array with a Null character */
    	chars[length] = '\0';
    	
    	/* Output the generated password */
    	printf("\nRandom Password\t=>\t%s", chars);
    	printf("\n\n");
    
    	/* Return Success */
    	return EXIT_SUCCESS;
    }
    
    //EOF
    
    Here are some of the results:
    Code:
    Scott-Smiths-MacBook-Pro:~ scottsmith$ gcc random.c -o random
    Scott-Smiths-MacBook-Pro:~ scottsmith$ ./random 20
    Random Integer	=>	17068935360523746046
    Random Password	=>	0WUw=^Tv%a,K2Yn}[}kA
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$ ./random 20
    Random Integer	=>	1157636657195386462
    Random Password	=>	\d3sE<`a'gOFN#hd-%QE
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$ ./random 20
    Random Integer	=>	14374914413199177588
    Random Password	=>	,T[}}.ofOg",G)u6tHsc
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$ ./random 20
    Random Integer	=>	4038139871015997161
    Random Password	=>	;/WkE"Y{|_6'$fea`wMf
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$ ./random 20
    Random Integer	=>	11767659052862117959
    Random Password	=>	M~N^j|0h:odr=+:cP~?O
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$ ./random 20
    Random Integer	=>	3331488456374113321
    Random Password	=>	d`8Y21w#qA?/='.y:{>u
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$ ./random 20
    Random Integer	=>	1855746506989820728
    Random Password	=>	El2yk<?RE#P9D>m3'c[F
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$ ./random 20
    Random Integer	=>	6736858495394617765
    Random Password	=>	~|N[*ueI2qBnviBh1n*Z
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$ ./random 20
    Random Integer	=>	1085732971504407423
    Random Password	=>	`{tSfE1yD~cBbk#=)#@^
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$ ./random 20
    Random Integer	=>	1969148855045060752
    Random Password	=>	t,0.Qmjxgr-wJn%c[VVg
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$
    
    Take a close look at the random ("unsigned long int") integers that are generated, some of them are a full 20 digits wide, others are less. It's also stopped generating negative integers now.
     
  3. OP
    OP
    deepspring

    deepspring Member

    Joined:
    Jul 8, 2002
    Messages:
    3,601
    Location:
    Maitland, NSW
    I got curious about the execution time used by this program, especially seeing as how it is making a call to /dev/random, so guess what... I added a timer to track how fast this program is. :D

    Original code courtesy of these guys:
    http://www.physicsforums.com/showthread.php?t=224989

    Code:
    #include <time.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    
    /* Function to calculate the time in milliseconds it took to execute our code */
    double diffclock(clock_t clock1, clock_t clock2) {
    	double diffticks = clock1 - clock2;
    	double diffms = (diffticks * 1000) / CLOCKS_PER_SEC;
    	return diffms;
    }
    
    int main(int argc, const char *argv[]) {
    	/* Length of the password */
    	unsigned short int length = 0;
    	
    	/* Just for performance testing get the cpu cycle ticks at the start */
    	clock_t begin = clock();
    	
    	/* Check if we have a command line argument */
    	if(argc > 1) {
    		/* Set our password length */
    		length = atoi(argv[1]);
    	}
    	
    	/* Just in case atoi() returns 0 or the user gives a negative
    	   integer */
    	if(length <= 0) {
    		length = 8;
    	}
    
    	/* Set our char variable to length + 1 for null termination */
    	char chars[length+1];
    
    	/* Try opening /dev/random for a random seed for srand() function */
    	int rdata = open("/dev/random", O_RDONLY);
    	unsigned long int randomInt;
    	
    	if (!rdata) {
    		printf("Failure: /dev/random could not be opened, using time instead!\n");
    		randomInt = (unsigned long int)time(NULL) + getpid();
    	} else {
    		read(rdata, &randomInt, sizeof(randomInt));
    		close(rdata);	
    	}
    
    	/* Seed the rand() function */
    	srand(randomInt);
    	
    	/* For debugging purposes */
    	printf("Random Integer\t=>\t%lu", randomInt);
    	
    	/* ASCII characters 33 to 126 */
    	int count = 0;
    	while(count < length) {
    		chars[count] = (char)(rand() % 94 + 33);
    		srand(rand());
    		count++;
    	}
    
    	/* Terminate the char array with a Null character */
    	chars[length] = '\0';
    	
    	/* Output the generated password */
    	printf("\nRandom Password\t=>\t%s", chars);
    
    	/* Get our remaining cpu cycle ticks*/
    	clock_t end = clock();
    	
    	/*Compute how long it has taken us to generate 1 random password */
    	printf("\nGenerated In\t=>\t%.4f ms", (double)(diffclock(end, begin)));
    	printf("\n\n");
    	
    	/* Return Success */
    	return EXIT_SUCCESS;
    }
    
    //EOF
    
    And here is the output (from 5 execution hits):
    Code:
    Scott-Smiths-MacBook-Pro:~ scottsmith$ gcc random.c -o random
    Scott-Smiths-MacBook-Pro:~ scottsmith$ for var in 1 2 3 4 5; do ./random 25; done;
    Random Integer	=>	18363435332199311883
    Random Password	=>	&^+bxcsWwtioN?D$]8OE;!f1m
    Generated In	=>	0.0900 ms
    
    Random Integer	=>	8687248893709279902
    Random Password	=>	$96Tc;99p2%;a8GGT1KP*(Qr%
    Generated In	=>	0.0880 ms
    
    Random Integer	=>	14482025061927558484
    Random Password	=>	#m\)PS;^v?\0@[FGn40dzO]k1
    Generated In	=>	0.0860 ms
    
    Random Integer	=>	1739732273610739149
    Random Password	=>	+|;SK0/46O-=D$CqShEX]<b8F
    Generated In	=>	0.0860 ms
    
    Random Integer	=>	11507129718193807434
    Random Password	=>	4kZg[NT&g@Fa8*46nz>ib'>5l
    Generated In	=>	0.0850 ms
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$
    
    I'm still working on the other stuff...
     
    Last edited: Jan 4, 2011
  4. OP
    OP
    deepspring

    deepspring Member

    Joined:
    Jul 8, 2002
    Messages:
    3,601
    Location:
    Maitland, NSW
    After many hours googling, I finally found out how to do an MD5 checksum of the password.

    First here is the output:
    Code:
    Scott-Smiths-MacBook-Pro:~ scottsmith$ gcc random.c -lcrypto -o random
    Scott-Smiths-MacBook-Pro:~ scottsmith$ ./random
    Random Integer	=>	12034640183854385822
    Random Password	=>	;<U\'3F1
    MD5 Digest	=>	f03fd423cbbd6263ced5f27f3c3959de
    Generated In	=>	0.2400 ms
    
    Scott-Smiths-MacBook-Pro:~ scottsmith$ 
    
    
    Here is the source code:
    Code:
    #include <time.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <openssl/evp.h>
    
    /* Function to calculate the time in milliseconds it took to execute our code */
    double diffclock(clock_t clock1, clock_t clock2) {
    	double diffticks = clock1 - clock2;
    	double diffms = (diffticks * 1000) / CLOCKS_PER_SEC;
    	return diffms;
    }
    
    int main(int argc, const char *argv[]) {
    	/* Length of the password */
    	unsigned short int length = 0;
    	
    	/* Just for performance testing get the cpu cycle ticks at the start */
    	clock_t begin = clock();
    	
    	/* Check if we have a command line argument */
    	if(argc > 1) {
    		/* Set our password length */
    		length = atoi(argv[1]);
    	}
    	
    	/* Just in case atoi() returns 0 or the user gives a negative
    	   integer */
    	if(length <= 0) {
    		length = 8;
    	}
    
    	/* Set our char variable to length + 1 for null termination */
    	char chars[length+1];
    
    	/* Try opening /dev/random for a random seed for srand() function */
    	int rdata = open("/dev/random", O_RDONLY);
    	unsigned long int randomInt;
    	
    	if (!rdata) {
    		printf("Failure: /dev/random could not be opened, using time instead!\n");
    		randomInt = (unsigned long int)time(NULL) + getpid();
    	} else {
    		read(rdata, &randomInt, sizeof(randomInt));
    		close(rdata);	
    	}
    
    	/* Seed the rand() function */
    	srand(randomInt);
    	
    	/* For debugging purposes */
    	printf("Random Integer\t=>\t%lu", randomInt);
    	
    	/* ASCII characters 33 to 126 */
    	int count = 0;
    	while(count < length) {
    		chars[count] = (char)(rand() % 94 + 33);
    		srand(rand());
    		count++;
    	}
    
    	/* Terminate the char array with a Null character */
    	chars[length] = '\0';
    	
    	/* Output the generated password */
    	printf("\nRandom Password\t=>\t%s", chars);
    	
    	/* Calculate the MD5 sum of the random password */
    	EVP_MD_CTX mdctx;
    	const EVP_MD *md;
    	unsigned char md_value[EVP_MAX_MD_SIZE];
    	int md_len, i;
    	OpenSSL_add_all_digests();
    	md = EVP_get_digestbyname("md5");
    	
    	EVP_MD_CTX_init(&mdctx);
    	EVP_DigestInit_ex(&mdctx, md, NULL);
    	EVP_DigestUpdate(&mdctx, chars, strlen(chars));
    	EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
    	EVP_MD_CTX_cleanup(&mdctx);
    	printf("\nMD5 Digest\t=>\t");
    	for(i = 0; i < md_len; i++) printf("%02x", md_value[i]);
    		
    	/* Get our remaining cpu cycle ticks*/
    	clock_t end = clock();
    	
    	/*Compute how long it has taken us to generate 1 random password */
    	printf("\nGenerated In\t=>\t%.4f ms", (double)(diffclock(end, begin)));
    	printf("\n\n");
    	
    	/* Return Success */
    	return EXIT_SUCCESS;
    }
    
    //EOF
    
    Now I'm sure there are probably numerous mistakes or code enhancements I can do to speed this up. The trick is finding them.

    Edit: The beauty of using the openssl evp library is we can swap from MD5 to SHA1 hashes with minimal effort.
     
    Last edited: Jan 4, 2011
  5. OP
    OP
    deepspring

    deepspring Member

    Joined:
    Jul 8, 2002
    Messages:
    3,601
    Location:
    Maitland, NSW
    Ok. Here is my final version. In this version:
    • Added code to save the generated password out to a file named "output.txt"
      for later comparison (demonstrated below)

    Code:
    /*
    	To compile this application you must use the following:
    		$ gcc random.c -lcrypto -o random
    */
    
    #include <time.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <openssl/evp.h>
    
    /* Function to calculate the time in milliseconds it took to execute our code */
    double diffclock(clock_t clock1, clock_t clock2) {
    	double diffticks = clock1 - clock2;
    	double diffms = (diffticks * 1000) / CLOCKS_PER_SEC;
    	return diffms;
    }
    
    int main(int argc, const char *argv[]) {
    	/* Length of the password */
    	unsigned short int length = 0;
    	
    	/* Just for performance testing get the cpu cycle ticks at the start */
    	clock_t begin = clock();
    	
    	/* Check if we have a command line argument */
    	if(argc > 1) {
    		/* Set our password length */
    		length = atoi(argv[1]);
    	}
    	
    	/* Just in case atoi() returns 0 or the user gives a negative
    	   integer */
    	if(length <= 0) {
    		length = 8;
    	}
    
    	/* Set our char variable to length + 1 for null termination */
    	char chars[length+1];
    
    	/* Try opening /dev/random for a random seed for srand() function */
    	int rdata = open("/dev/random", O_RDONLY);
    	unsigned long int randomInt;
    	
    	if (!rdata) {
    		printf("Failure: /dev/random could not be opened, using time instead!\n");
    		randomInt = (unsigned long int)time(NULL) + getpid();
    	} else {
    		read(rdata, &randomInt, sizeof(randomInt));
    		close(rdata);	
    	}
    
    	/* Seed the rand() function */
    	srand(randomInt);
    	
    	/* For debugging purposes */
    	printf("Random Integer\t=>\t%lu", randomInt);
    	
    	/* ASCII characters 33 to 126 */
    	int count;
    	for(count = 0; count < length; count++) {
    		chars[count] = (char)(rand() % 94 + 33);
    		srand(rand());
    	}
    
    	/* Terminate the char array with a Null character */
    	chars[length] = '\0';
    	
    	/* Output the generated password */
    	printf("\nRandom Password\t=>\t%s", chars);
    	
    	/* Output our newly generated password to a file for external MD5 testing: 
    				$ cat output.txt | openssl md5
    	*/
    	FILE * pFile;
    	pFile = fopen("output.txt", "w");
    	fprintf(pFile, "%s", chars);
    	fclose(pFile);
    	
    	/* Calculate the MD5 sum of the random password */
    	EVP_MD_CTX mdctx;
    	const EVP_MD *md;
    	unsigned char md_value[EVP_MAX_MD_SIZE];
    	int md_len, i;
    	OpenSSL_add_all_digests();
    	md = EVP_get_digestbyname("md5");
    	EVP_MD_CTX_init(&mdctx);
    	EVP_DigestInit_ex(&mdctx, md, NULL);
    	EVP_DigestUpdate(&mdctx, chars, strlen(chars));
    	EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
    	EVP_MD_CTX_cleanup(&mdctx);
    
    	/*Output the MD5 digest */
    	printf("\nMD5 Digest\t=>\t");
    	for(i = 0; i < md_len; i++) printf("%02x", md_value[i]);
    	
    	/* Get our remaining cpu cycle ticks*/
    	clock_t end = clock();
    	
    	/*Compute how long it has taken us to generate 1 random password */
    	printf("\nGenerated In\t=>\t%.4f ms", (double)(diffclock(end, begin)));
    	printf("\n\n");
    	
    	/* Return Success */
    	return EXIT_SUCCESS;
    }
    
    //EOF
    
    Here is the output:
    Code:
    Scott-Smiths-MacBook-Pro:rand scottsmith$ gcc random.c -lcrypto -o random
    Scott-Smiths-MacBook-Pro:rand scottsmith$ ./random
    Random Integer	=>	13288617834276608257
    Random Password	=>	#R&4B,7W
    MD5 Digest	=>	f75fed1cbdebdb011506a6784877354d
    Generated In	=>	0.4160 ms
    
    Scott-Smiths-MacBook-Pro:rand scottsmith$ cat output.txt | openssl md5
    f75fed1cbdebdb011506a6784877354d
    Scott-Smiths-MacBook-Pro:rand scottsmith$ 
    
    
    You will notice in the output above that I actually use "cat output.txt | openssl md5" to validate the MD5 Digest generated by my application (manually). The digests actually match perfectly.

    You are probably wondering why I didn't use the "md5sum" command... thats because it isn't available under MacOSX, so you have to use openssl instead.
     
  6. Foliage

    Foliage Member

    Joined:
    Jan 22, 2002
    Messages:
    32,085
    Location:
    Sleepwithyourdadelaide
    Looks good, you've picked most of it up pretty quickly, time for a bigger project?
     
  7. OP
    OP
    deepspring

    deepspring Member

    Joined:
    Jul 8, 2002
    Messages:
    3,601
    Location:
    Maitland, NSW
    Thanks for all the help and encouragement Foliage. :D

    To be honest, I'm not overly happy with my "seq" program, I think it needs to be re-written to be as close to the Linux command as possible.

    Having said that, I could just compile the linux one... but that would take the challenge out of it.
     
  8. mikeyyy

    mikeyyy Member

    Joined:
    Apr 7, 2005
    Messages:
    590
    Location:
    Sydney
    Btw I'm wrong about /dev/random being a string, I decided to check. It actually returns a random N bytes so you're doing it right. Just thought I'd clear up my incorrect comments. :)
     
  9. Foliage

    Foliage Member

    Joined:
    Jan 22, 2002
    Messages:
    32,085
    Location:
    Sleepwithyourdadelaide
    Find something you know is well out of your depth and start with that, best way to learn imo. Your first version will probably be a train wreck and poorly designed, but then you can go back and do it again from scratch.

    How I've always taught myself anyway.
     
  10. the-enigma

    the-enigma Member

    Joined:
    Mar 18, 2002
    Messages:
    1,728
    Location:
    BrisVegas
    Being pedantic here, I know, but pedantic is good in these areas I reckon. You've declared "length" as a uint (shorthand for unsigned int), so it'll never be less than zero. But "atoi" returns an int, not a uint. So (unless your C implementation differs from mine), if you do
    Code:
    # ./random -5
    instead of giving a length 8 password, it'll give a .. very long password. Technically your code still runs fine, it just doesn't run the way your comments read.

    Additionally, you might want to use "-Wall" as a compiler option, it basically turns on all warnings, which sometimes can point out where you have comparisons between signed and unsigned variables like this. It doesn't in this case, but I'm not sure why it doesn't.
     
  11. OP
    OP
    deepspring

    deepspring Member

    Joined:
    Jul 8, 2002
    Messages:
    3,601
    Location:
    Maitland, NSW
    Wow. Thanks for spotting this, I just changed it to a regular int, I will keep it in mind for future reference.

    Edit: fixed all the warnings i had. Here is the final code...

    Code:
    /*
    	To compile this application you must use the following:
    		$ gcc random.c -lcrypto -Wall -o random
    */
    
    #include <time.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <openssl/evp.h>
    #include <unistd.h>
    
    /* Function to calculate the time in milliseconds it took to execute our code */
    double diffclock(clock_t clock1, clock_t clock2) {
    	double diffticks = clock1 - clock2;
    	double diffms = (diffticks * 1000) / CLOCKS_PER_SEC;
    	return diffms;
    }
    
    int main(int argc, const char *argv[]) {
    	/* Length of the password */
    	int length = 0;
    	
    	/* Just for performance testing get the cpu cycle ticks at the start */
    	clock_t begin = clock();
    	
    	/* Check if we have a command line argument */
    	if(argc > 1) {
    		/* Set our password length */
    		length = atoi(argv[1]);
    	}
    	
    	/* Just in case atoi() returns 0 or the user gives a negative
    	   integer */
    	if(length <= 0) {
    		length = 8;
    	}
    
    	/* Set our char variable to length + 1 for null termination */
    	char password[length+1];
    
    	/* Try opening /dev/random for a random seed for srand() function */
    	int rdata = open("/dev/random", O_RDONLY);
    	long int randomInt;
    	
    	if (!rdata) {
    		printf("Failure: /dev/random could not be opened, using time instead!\n");
    		randomInt = (long int)time(NULL) + (int)getpid();
    	} else {
    		read(rdata, &randomInt, sizeof(randomInt));
    		close(rdata);	
    	}
    
    	/* Seed the rand() function */
    	srand(randomInt);
    	
    	/* For debugging purposes */
    	printf("Random Integer\t=>\t%lu", randomInt);
    	
    	/* ASCII characters 33 to 126 */
    	int count;
    	for(count = 0; count < length; count++) {
    		password[count] = (char)(rand() % 94 + 33);
    		srand(rand());
    	}
    
    	/* Terminate the char array with a Null character */
    	password[length] = '\0';
    	
    	/* Output the generated password */
    	printf("\nRandom Password\t=>\t%s", password);
    	
    	/* Calculate the MD5 sum of the random password */
    	EVP_MD_CTX mdctx;
    	const EVP_MD *md;
    	unsigned char md_value[EVP_MAX_MD_SIZE];
    	unsigned int md_len; 
    	int i;
    	OpenSSL_add_all_digests();
    	md = EVP_get_digestbyname("md5");
    	EVP_MD_CTX_init(&mdctx);
    	EVP_DigestInit_ex(&mdctx, md, NULL);
    	EVP_DigestUpdate(&mdctx, password, strlen(password));
    	EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
    	EVP_MD_CTX_cleanup(&mdctx);
    
    	/* Convert our digest to a usable string */
    	char digest[EVP_MAX_MD_SIZE];
    	char temp[3];
    	for(i = 0; i < md_len; i++) {
    		sprintf(temp, "%02x", md_value[i]);
    		strcat(digest, temp);
    	}
    
    	/* Output the MD5 digest */
    	printf("\nMD5 Digest\t=>\t%s", digest);
    	
    	/* Get our remaining cpu cycle ticks*/
    	clock_t end = clock();
    	
    	/*Compute how long it has taken us to generate 1 random password */
    	printf("\nGenerated In\t=>\t%.4f ms", (double)(diffclock(end, begin)));
    	printf("\n\n");
    	
    	/* Return Success */
    	return EXIT_SUCCESS;
    }
    
    //EOF
    
    
    Compile and test:
    Code:
    scott:rand scottsmith$ gcc random.c -lcrypto -Wall -o random
    scott:rand scottsmith$ ./random -5
    Random Integer	=>	3593509343860802575
    Random Password	=>	(Ad3vcfl
    MD5 Digest	=>	09f5e6013affb5ccb39a01ddb2bcda81
    Generated In	=>	0.2360 ms
    
    scott:rand scottsmith$
    
     
    Last edited: Jan 10, 2011
  12. Foliage

    Foliage Member

    Joined:
    Jan 22, 2002
    Messages:
    32,085
    Location:
    Sleepwithyourdadelaide
    I can fix the last one, int md_len, is meant to be unsigned int md_len;

    as the header describes it like this
    Code:
    int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md,
           unsigned int *s);
    Surprised when you called atoi with a different type to the return type it didn't give the same error.

    The other ones aren't serious, they obviously are declared or the linker would tell you they were missing, just means it is compiling that function before reading their header files, a bit odd as you have included them, maybe someone else will know.
     
  13. OP
    OP
    deepspring

    deepspring Member

    Joined:
    Jul 8, 2002
    Messages:
    3,601
    Location:
    Maitland, NSW
    Thanks Foliage. I figured that out for myself after a few minutes and updated my previous post reflect the correct code. I guess if I need to fix something like that in future, it's better to read the documentation carefully.

    As for the other warnings, they were fixed by including the unistd.h header.

    I also discovered compiler optimisations "-O3". :D
     
    Last edited: Jan 10, 2011
  14. Foliage

    Foliage Member

    Joined:
    Jan 22, 2002
    Messages:
    32,085
    Location:
    Sleepwithyourdadelaide
    Yeah basically it is a warning to say 'hey you used a function definition that I haven't seen yet!' not knowing that it might see it in the future. I never understood why the hell C compilers can't do a simple check for all functions pass before compiling and then you wouldn't get them.
     
  15. OP
    OP
    deepspring

    deepspring Member

    Joined:
    Jul 8, 2002
    Messages:
    3,601
    Location:
    Maitland, NSW
    I found out that the code used to work out the time taken to generate a password wasn't accurate, so I removed it in favor of using a command line tool called "time" that measures the time taken for a command to execute and exit.

    Sample output:
    Code:
    scott:rand scottsmith$ gcc random.c -lcrypto -Wall -O3 -o random
    scott:rand scottsmith$ time ./random
    Random Integer	=>	10861266106826919572
    Random Password	=>	m[Bn938w
    MD5 Digest	=>	(??_?73e3793be2452760a74f0715e632b84b
    
    
    real	0m0.009s
    user	0m0.001s
    sys	0m0.002s
    scott:rand scottsmith$
    
    I will look at adding back the code when I work out what is wrong in the calculation.
     
  16. OP
    OP
    deepspring

    deepspring Member

    Joined:
    Jul 8, 2002
    Messages:
    3,601
    Location:
    Maitland, NSW
    I just noticed that I'm getting really strange MD5 digests from my code output. At first I thought it was my compiler optimisations, then I found out it was because I updated OpenSSL to latest bleeding edge version available in macports.

    So I've had to scratch the MD5 code in favor of the following code instead (which still assumes you have OpenSSL installed):
    Code:
    /*
    	To compile this application you must use the following:
    		$ gcc random.c -lcrypto -Wall -o random
    */
    
    #include <time.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    int main(int argc, const char *argv[]) {
    	/* Length of the password */
    	int length = 0;
    	
    	/* Check if we have a command line argument */
    	if(argc > 1) {
    		/* Set our password length */
    		length = atoi(argv[1]);
    	}
    	
    	/* Just in case atoi() returns 0 or the user gives a negative
    	   integer */
    	if(length <= 0) {
    		length = 8;
    	}
    
    	/* Set our char variable to length + 1 for null termination */
    	char password[length+1];
    
    	/* Try opening /dev/random for a random seed for srand() function */
    	int rdata = open("/dev/random", O_RDONLY);
    	long int randomInt;
    	
    	if (!rdata) {
    		printf("Failure: /dev/random could not be opened, using time instead!\n");
    		randomInt = (long int)time(NULL) + (int)getpid();
    	} else {
    		read(rdata, &randomInt, sizeof(randomInt));
    		close(rdata);	
    	}
    
    	/* Seed the rand() function */
    	srand(randomInt);
    	
    	/* For debugging purposes */
    	printf("Random Integer\t=>\t%lu", randomInt);
    	
    	/* ASCII characters 33 to 126 */
    	int count;
    	for(count = 0; count < length; count++) {
    		password[count] = (char)(rand() % 94 + 33);
    		srand(rand());
    	}
    
    	/* Terminate the char array with a Null character */
    	password[length] = '\0';
    	
    	/* Output the generated password */
    	printf("\nRandom Password\t=>\t%s", password);
    
    	/* Alternate method of generating an MD5 sum */
    	char digest[256];
    	FILE *fp;
    	FILE *temp;
    	
    	temp = fopen("temp_file", "w");
    	if (temp == NULL) {
    		perror("Failure: failed to open temp_file!");
    		return EXIT_FAILURE;
    	}
    	
    	fwrite(password, strlen(password), 1, temp);
    	fclose(temp);
    
    	fp = popen("openssl md5 temp_file | sed \'s/MD5(temp_file)= //g\'", "r");
    	fgets(digest, sizeof digest, fp);
    	pclose(fp);
    	
    	/* Remove the tmp file */
    	remove("temp_file");
    
    	/* Output the MD5 digest */
    	printf("\nMD5 Digest\t=>\t%s", digest);
    	printf("\n\n");
    	
    	/* Return Success */
    	return EXIT_SUCCESS;
    }
    
    //EOF
    
    I know that opening two file streams to achieve the one task is somewhat over the top, but it works. Next step is to figure out how to do regex in C.

    Edit: Updated the code.

    New Output:
    Code:
    scott:rand scottsmith$ gcc random.c -Wall -O3 -o random
    scott:rand scottsmith$ time ./random 
    Random Integer	=>	3018829041633111956
    Random Password	=>	5J9OX&1u
    MD5 Digest	=>	367ee4cf309b26198a040728deb9d154
    
    
    
    real	0m0.039s
    user	0m0.005s
    sys	0m0.010s
    scott:rand scottsmith$
    
     
    Last edited: Jan 12, 2011
  17. Foliage

    Foliage Member

    Joined:
    Jan 22, 2002
    Messages:
    32,085
    Location:
    Sleepwithyourdadelaide
    Start using a c++ compiler lol.
     
  18. OP
    OP
    deepspring

    deepspring Member

    Joined:
    Jul 8, 2002
    Messages:
    3,601
    Location:
    Maitland, NSW
    C++ is evil. EVIL. Just kidding. :lol:

    I figured out that I could pipe the output of the openssl command straight into sed from my code. No need to regex, although GNU C has a regex library installed by default.
     
  19. OP
    OP
    deepspring

    deepspring Member

    Joined:
    Jul 8, 2002
    Messages:
    3,601
    Location:
    Maitland, NSW
    Added some error handling.

    Code:
    /*
    	To compile this application you must use the following:
    		$ gcc random.c -Wall -O3 -o random
    */
    
    #include <time.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    int main(int argc, const char *argv[]) {
    	/* Length of the password */
    	int length = 0;
    	
    	/* Check if we have a command line argument */
    	if(argc > 1) {
    		/* Set our password length */
    		length = atoi(argv[1]);
    	}
    	
    	/* Just in case atoi() returns 0 or the user gives a negative
    	   integer */
    	if(length <= 0) {
    		length = 8;
    	}
    
    	/* Set our char variable to length + 1 for null termination */
    	char password[length+1];
    
    	/* Try opening /dev/random for a random seed for srand() function */
    	int rdata = open("/dev/random", O_RDONLY);
    	long int randomInt;
    	
    	if (!rdata) {
    		printf("Failure: /dev/random could not be opened, using time instead!\n");
    		randomInt = (long int)time(NULL) + (int)getpid();
    	} else {
    		read(rdata, &randomInt, sizeof(randomInt));
    		close(rdata);	
    	}
    
    	/* Seed the rand() function */
    	srand(randomInt);
    	
    	/* For debugging purposes */
    	printf("Random Integer\t=>\t%lu", randomInt);
    	
    	/* ASCII characters 33 to 126 */
    	int count;
    	for(count = 0; count < length; count++) {
    		password[count] = (char)(rand() % 94 + 33);
    		srand(rand());
    	}
    
    	/* Terminate the char array with a Null character */
    	password[length] = '\0';
    	
    	/* Output the generated password */
    	printf("\nRandom Password\t=>\t%s", password);
    
    	/* Alternate method of generating an MD5 sum */
    	char digest[256];
    	FILE *fp;
    	FILE *temp;
    	
    	temp = fopen("temp_file", "w");
    	if (temp == NULL) {
    		perror("Failure: failed to open temp_file!");
    		return EXIT_FAILURE;
    	} else {
    		fwrite(password, strlen(password), 1, temp);
    		fclose(temp);
    		
    		/* Try opening a process stream */
    		fp = popen("openssl md5 temp_file | sed \'s/MD5(temp_file)= //g\'", "r");
    		if (fp == NULL) {
    			perror("Failure: failed to open process stream!");
    			return EXIT_FAILURE;
    		} else {
    			fgets(digest, sizeof(digest), fp);
    			pclose(fp);
    			
    			/* Output the MD5 digest */
    			printf("\nMD5 Digest\t=>\t%s", digest);
    		}
    		/* Remove the tmp file */
    		remove("temp_file");
    	}
    	
    	printf("\n");
    	/* Return Success */
    	return EXIT_SUCCESS;
    }
    
    //EOF
    
     
  20. mikeyyy

    mikeyyy Member

    Joined:
    Apr 7, 2005
    Messages:
    590
    Location:
    Sydney
    I think your previous md5sum was broken because of this:

    Code:
    char digest[EVP_MAX_MD_SIZE];
    
    I found online:
    Code:
    #define EVP_MAX_MD_SIZE (16+20) /* The SSLv3 md5+sha1 type */
    
    The way strcat works, it starts appending at the location of the null character in the first string. Your array is uninitialised, so if there's no null char at digest[0] you'll get garbage at the beginning.

    Also you can pick the correct size for the char array to be 33 (32 chars for the hexstring, 1 for null). I think the EVP_MAX_MD_SIZE define actually refers to the number of bytes in binary-representation, and so it's usage is wrong. I think you got lucky that it happens to fit what you need, as the ascii hexstring is twice as large as the equivalent binary representation (128-bit digest = 16 bytes, but you need 32 bytes to represent it in ASCII).

    My suggestion is:

    Code:
    #define MD5SUM_NUM_BYTES 16
    char digest[2 * MD5SUM_NUM_BYTES + 1] = {0};
    
    The {0} will initialise the entire array to 0, however, {1} will only initialise the first member. 0 is special. I think. :) Been a while since I've checked that.

    That should fix it hopefully. If the library has a #define just for the size of an MD5 hash and you can use theirs, then go with that. :)
     

Share This Page

Advertisement: