From 5f96a6ea2dea3576c9f41322ef99ad964f53e764 Mon Sep 17 00:00:00 2001 From: tytso Date: Tue, 14 Jun 2005 22:35:55 +0000 Subject: [PATCH] Add -H, --sha1 option, to allow computing reproducible passwords, given a known file, and a known seed. (ie: pwgen -H ~/my_favourite.mp3#olivier@guerrier.com gives me a list of possibles passwords for my pop3 account, and I can ask this list again and again). Feature suggested and implemented by Olivier Guerrier . --- ChangeLog | 9 ++ Makefile.in | 6 +- debian/changelog | 2 + pw_phonemes.c | 14 +- pw_rand.c | 2 +- pwgen.1 | 14 ++ pwgen.c | 17 +- pwgen.h | 13 +- randnum.c | 7 +- sha1.c | 399 +++++++++++++++++++++++++++++++++++++++++++++++ sha1.h | 24 +++ sha1num.c | 77 +++++++++ 12 files changed, 560 insertions(+), 24 deletions(-) create mode 100644 sha1.c create mode 100644 sha1.h create mode 100644 sha1num.c diff --git a/ChangeLog b/ChangeLog index 64f589b..072aaf1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2005-06-14 Theodore Ts'o + + * pwgen.c: Add -H, --sha1 option, to allow computing reproducible + passwords, given a known file, and a known seed. + (ie: pwgen -H ~/my_favourite.mp3#olivier@guerrier.com gives me + a list of possibles passwords for my pop3 account, and I can + ask this list again and again). Feature suggested and + implemented by Olivier Guerrier . + 2005-06-13 Theodore Ts'o * Fix obvious spelling typo in pwgen.1. (Addresses Debian Bug diff --git a/Makefile.in b/Makefile.in index 9dd2a17..436b365 100644 --- a/Makefile.in +++ b/Makefile.in @@ -31,9 +31,9 @@ all:: pwgen .c.o: $(CC) -c $(ALL_CFLAGS) $< -o $@ -OBJS= pwgen.o pw_phonemes.o pw_rand.o randnum.o +OBJS= pwgen.o pw_phonemes.o pw_rand.o randnum.o sha1.o sha1num.o -SRCS= pwgen.c pw_phonemes.c pw_rand.c randnum.c +SRCS= pwgen.c pw_phonemes.c pw_rand.c randnum.c sha1.c sha1num.c pwgen: $(OBJS) @@ -127,3 +127,5 @@ pwgen.o: pwgen.c pwgen.h pw_phonemes.o: pw_phonemes.c pwgen.h pw_rand.o: pw_rand.c pwgen.h randnum.o: randnum.c pwgen.h +sha1.o: sha1.c sha1.h +sha1num.o: sha1num.c sha1.h pwgen.h diff --git a/debian/changelog b/debian/changelog index 0f418e0..f097555 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,8 @@ pwgen (2.03-2) unstable; urgency=low * Adopt maintainership of pwgen. (Closes: #282076) * Fix minor bug in man page. (Closes: #311461) * Convert from debmake to debhelper + * Add the --sha1 option so that pwgen uses the SHA1 hash to generate + (not so) random passwords. -- Theodore Y. Ts'o Tue, 14 Jun 2005 14:59:19 -0400 diff --git a/pw_phonemes.c b/pw_phonemes.c index cb14ff5..2680498 100644 --- a/pw_phonemes.c +++ b/pw_phonemes.c @@ -69,10 +69,10 @@ try_again: should_be = 0; first = 1; - should_be = pw_random_number(2) ? VOWEL : CONSONANT; + should_be = pw_number(2) ? VOWEL : CONSONANT; while (c < size) { - i = pw_random_number(NUM_ELEMENTS); + i = pw_number(NUM_ELEMENTS); str = elements[i].str; len = strlen(str); flags = elements[i].flags; @@ -98,7 +98,7 @@ try_again: /* Handle PW_ONE_CASE */ if (feature_flags & PW_ONE_CASE) { if ((first || flags & CONSONANT) && - (pw_random_number(10) < 3)) { + (pw_number(10) < 3)) { buf[c] = toupper(buf[c]); feature_flags &= ~PW_ONE_CASE; } @@ -114,14 +114,14 @@ try_again: * Handle PW_ONE_NUMBER */ if (feature_flags & PW_ONE_NUMBER) { - if (!first && (pw_random_number(10) < 3)) { - buf[c++] = pw_random_number(10)+'0'; + if (!first && (pw_number(10) < 3)) { + buf[c++] = pw_number(10)+'0'; buf[c] = 0; feature_flags &= ~PW_ONE_NUMBER; first = 1; prev = 0; - should_be = pw_random_number(2) ? + should_be = pw_number(2) ? VOWEL : CONSONANT; continue; } @@ -135,7 +135,7 @@ try_again: } else { /* should_be == VOWEL */ if ((prev & VOWEL) || (flags & DIPTHONG) || - (pw_random_number(10) > 3)) + (pw_number(10) > 3)) should_be = CONSONANT; else should_be = VOWEL; diff --git a/pw_rand.c b/pw_rand.c index 5c9cd4f..5246ca0 100644 --- a/pw_rand.c +++ b/pw_rand.c @@ -20,7 +20,7 @@ void pw_rand(char *buf, int size, int pw_flags) len = strlen(chars); while (i < size) { - ch = chars[pw_random_number(len)]; + ch = chars[pw_number(len)]; buf[i++] = ch; } buf[size] = 0; diff --git a/pwgen.1 b/pwgen.1 index fc01c3f..8160021 100644 --- a/pwgen.1 +++ b/pwgen.1 @@ -71,6 +71,20 @@ only be used for machine passwords, since otherwise it's almost guaranteed that users will simply write the password on a piece of paper taped to the monitor... .TP +.B \-H, --sha1=\fI/path/to/file[#seed] +Will use the sha1's hash of given file and the optional seed to create +password. It will allow you to compute the same password later, +if you remember the file, seed, and pwgen's options used. +ie: pwgen -H ~/your_favourite.mp3#your@email.com gives +a list of possibles passwords for your pop3 account, and you can +ask this list again and again. +.IP +.B WARNING: +The passwords generated using this option are not very random. If you use +this option, make sure the attacker can not obtain a copy of the file. +Also, note that the name of the file may be easily available from the +~/.history or ~/.bash_history file. +.TP .B \-h, --help Print a help message. .TP diff --git a/pwgen.c b/pwgen.c index a563929..9787d0a 100644 --- a/pwgen.c +++ b/pwgen.c @@ -18,11 +18,8 @@ #include "pwgen.h" -struct pwgen_func generators[] = { - { "phonemes", pw_phonemes, 0 }, - { "rand", pw_rand, 0 }, - { 0, 0, 0 } -}; +/* Globals variables */ +int (*pw_number)(int max_num); /* Program parameters set via getopt */ @@ -42,6 +39,7 @@ struct option pwgen_options[] = { { "help", no_argument, 0, 'h'}, { "no-numerals", no_argument, &numeric_flag, 0 }, { "no-capitalize", no_argument, &case_flag, 0 }, + { "sha1", required_argument, 0, 'H' }, { 0, 0, 0, 0} }; #endif @@ -59,6 +57,8 @@ const char *usage_msg = "\tPrint a help message\n" " --no-numerals, --no-capitalize\n" "\tDon't include a number or capital letter in the password\n" +" -H or --sha1=path/to/file[#seed]\n" +"\tUse sha1 hash of given file as a (not so) random generator\n" " -C\n\tPrint the generated passwords in columns\n" " -1\n\tDon't print the generated passwords in columns\n" ; @@ -79,6 +79,7 @@ int main(int argc, char **argv) void (*pwgen)(char *inbuf, int size, int pw_flags); pwgen = pw_phonemes; + pw_number = pw_random_number; if (isatty(1)) { do_columns = 1; case_flag = PW_ONE_CASE; @@ -87,7 +88,7 @@ int main(int argc, char **argv) while (1) { #ifdef HAVE_GETOPT_LONG - c = getopt_long(argc, argv, "1aCcnN:sh", pwgen_options, 0); + c = getopt_long(argc, argv, "1aCcnN:shH:", pwgen_options, 0); #else c = getopt(argc, argv, "1aCcnN:sh"); #endif @@ -120,6 +121,10 @@ int main(int argc, char **argv) case '1': do_columns = 0; break; + case 'H': + pw_sha1_init(optarg); + pw_number = pw_sha1_number; + break; case 'h': case '?': usage(); diff --git a/pwgen.h b/pwgen.h index e28ac95..102c685 100644 --- a/pwgen.h +++ b/pwgen.h @@ -26,14 +26,11 @@ struct pw_element { #define PW_ONE_NUMBER 0x0001 #define PW_ONE_CASE 0x0002 -struct pwgen_func { - const char *name; - void (*func)(char *buf, int size, int pw_flags); - int flags; -}; - /* Function prototypes */ +/* pointer to choose between random or sha1 pseudo random number generator */ +extern int (*pw_number)(int max_num); + /* pw_phonemes.c */ extern void pw_phonemes(char *buf, int size, int pw_flags); @@ -42,3 +39,7 @@ extern void pw_rand(char *buf, int size, int pw_flags); /* randnum.c */ extern int pw_random_number(int max_num); + +/* sha1num.c */ +extern void pw_sha1_init(char *sha1); +extern int pw_sha1_number(int max_num); diff --git a/randnum.c b/randnum.c index 8d88e2d..036e092 100644 --- a/randnum.c +++ b/randnum.c @@ -21,8 +21,10 @@ extern double drand48(void); #endif +static int get_random_fd(void); + /* Borrowed/adapted from e2fsprogs's UUID generation code */ -static int get_random_fd(void) +static int get_random_fd() { struct timeval tv; static int fd = -2; @@ -56,7 +58,8 @@ static int get_random_fd(void) * Generate a random number n, where 0 <= n < max_num, using * /dev/urandom if possible. */ -int pw_random_number(int max_num) +int pw_random_number(max_num) + int max_num; { int i, fd = get_random_fd(); int lose_counter = 0, nbytes=4; diff --git a/sha1.c b/sha1.c new file mode 100644 index 0000000..980b607 --- /dev/null +++ b/sha1.c @@ -0,0 +1,399 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright (C) 2001-2003 Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "sha1.h" + + +void sha1_process(sha1_context *ctx, uint8 data[64]); + + +#define GET_UINT32(n,b,i) \ +{ \ + (n) = ( (uint32) (b)[(i) ] << 24 ) \ + | ( (uint32) (b)[(i) + 1] << 16 ) \ + | ( (uint32) (b)[(i) + 2] << 8 ) \ + | ( (uint32) (b)[(i) + 3] ); \ +} + +#define PUT_UINT32(n,b,i) \ +{ \ + (b)[(i) ] = (uint8) ( (n) >> 24 ); \ + (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \ + (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \ + (b)[(i) + 3] = (uint8) ( (n) ); \ +} + +void sha1_starts(ctx) + sha1_context *ctx; +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +void sha1_process(ctx, data) + sha1_context *ctx; + uint8 data[64]; +{ + uint32 temp, W[16], A, B, C, D, E; + + GET_UINT32( W[0], data, 0 ); + GET_UINT32( W[1], data, 4 ); + GET_UINT32( W[2], data, 8 ); + GET_UINT32( W[3], data, 12 ); + GET_UINT32( W[4], data, 16 ); + GET_UINT32( W[5], data, 20 ); + GET_UINT32( W[6], data, 24 ); + GET_UINT32( W[7], data, 28 ); + GET_UINT32( W[8], data, 32 ); + GET_UINT32( W[9], data, 36 ); + GET_UINT32( W[10], data, 40 ); + GET_UINT32( W[11], data, 44 ); + GET_UINT32( W[12], data, 48 ); + GET_UINT32( W[13], data, 52 ); + GET_UINT32( W[14], data, 56 ); + GET_UINT32( W[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ +( \ + temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \ + W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \ + ( W[t & 0x0F] = S(temp,1) ) \ +) + +#define P(a,b,c,d,e,x) \ +{ \ + e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P( A, B, C, D, E, W[0] ); + P( E, A, B, C, D, W[1] ); + P( D, E, A, B, C, W[2] ); + P( C, D, E, A, B, W[3] ); + P( B, C, D, E, A, W[4] ); + P( A, B, C, D, E, W[5] ); + P( E, A, B, C, D, W[6] ); + P( D, E, A, B, C, W[7] ); + P( C, D, E, A, B, W[8] ); + P( B, C, D, E, A, W[9] ); + P( A, B, C, D, E, W[10] ); + P( E, A, B, C, D, W[11] ); + P( D, E, A, B, C, W[12] ); + P( C, D, E, A, B, W[13] ); + P( B, C, D, E, A, W[14] ); + P( A, B, C, D, E, W[15] ); + P( E, A, B, C, D, R(16) ); + P( D, E, A, B, C, R(17) ); + P( C, D, E, A, B, R(18) ); + P( B, C, D, E, A, R(19) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P( A, B, C, D, E, R(20) ); + P( E, A, B, C, D, R(21) ); + P( D, E, A, B, C, R(22) ); + P( C, D, E, A, B, R(23) ); + P( B, C, D, E, A, R(24) ); + P( A, B, C, D, E, R(25) ); + P( E, A, B, C, D, R(26) ); + P( D, E, A, B, C, R(27) ); + P( C, D, E, A, B, R(28) ); + P( B, C, D, E, A, R(29) ); + P( A, B, C, D, E, R(30) ); + P( E, A, B, C, D, R(31) ); + P( D, E, A, B, C, R(32) ); + P( C, D, E, A, B, R(33) ); + P( B, C, D, E, A, R(34) ); + P( A, B, C, D, E, R(35) ); + P( E, A, B, C, D, R(36) ); + P( D, E, A, B, C, R(37) ); + P( C, D, E, A, B, R(38) ); + P( B, C, D, E, A, R(39) ); + +#undef K +#undef F + +#define F(x,y,z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P( A, B, C, D, E, R(40) ); + P( E, A, B, C, D, R(41) ); + P( D, E, A, B, C, R(42) ); + P( C, D, E, A, B, R(43) ); + P( B, C, D, E, A, R(44) ); + P( A, B, C, D, E, R(45) ); + P( E, A, B, C, D, R(46) ); + P( D, E, A, B, C, R(47) ); + P( C, D, E, A, B, R(48) ); + P( B, C, D, E, A, R(49) ); + P( A, B, C, D, E, R(50) ); + P( E, A, B, C, D, R(51) ); + P( D, E, A, B, C, R(52) ); + P( C, D, E, A, B, R(53) ); + P( B, C, D, E, A, R(54) ); + P( A, B, C, D, E, R(55) ); + P( E, A, B, C, D, R(56) ); + P( D, E, A, B, C, R(57) ); + P( C, D, E, A, B, R(58) ); + P( B, C, D, E, A, R(59) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P( A, B, C, D, E, R(60) ); + P( E, A, B, C, D, R(61) ); + P( D, E, A, B, C, R(62) ); + P( C, D, E, A, B, R(63) ); + P( B, C, D, E, A, R(64) ); + P( A, B, C, D, E, R(65) ); + P( E, A, B, C, D, R(66) ); + P( D, E, A, B, C, R(67) ); + P( C, D, E, A, B, R(68) ); + P( B, C, D, E, A, R(69) ); + P( A, B, C, D, E, R(70) ); + P( E, A, B, C, D, R(71) ); + P( D, E, A, B, C, R(72) ); + P( C, D, E, A, B, R(73) ); + P( B, C, D, E, A, R(74) ); + P( A, B, C, D, E, R(75) ); + P( E, A, B, C, D, R(76) ); + P( D, E, A, B, C, R(77) ); + P( C, D, E, A, B, R(78) ); + P( B, C, D, E, A, R(79) ); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +void sha1_update(ctx, input, length ) + sha1_context *ctx; + uint8 *input; + uint32 length; +{ + uint32 left, fill; + + if( ! length ) return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += length; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < length ) + ctx->total[1]++; + + if( left && length >= fill ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, fill ); + sha1_process( ctx, ctx->buffer ); + length -= fill; + input += fill; + left = 0; + } + + while( length >= 64 ) + { + sha1_process( ctx, input ); + length -= 64; + input += 64; + } + + if( length ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, length ); + } +} + +static uint8 sha1_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +void sha1_finish( ctx, digest ) + sha1_context *ctx; + uint8 digest[20]; +{ + uint32 last, padn; + uint32 high, low; + uint8 msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32( high, msglen, 0 ); + PUT_UINT32( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + sha1_update( ctx, sha1_padding, padn ); + sha1_update( ctx, msglen, 8 ); + + PUT_UINT32( ctx->state[0], digest, 0 ); + PUT_UINT32( ctx->state[1], digest, 4 ); + PUT_UINT32( ctx->state[2], digest, 8 ); + PUT_UINT32( ctx->state[3], digest, 12 ); + PUT_UINT32( ctx->state[4], digest, 16 ); +} + +#ifdef TEST + +#include +#include + +/* + * those are the standard FIPS-180-1 test vectors + */ + +static char *msg[] = +{ + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + NULL +}; + +static char *val[] = +{ + "a9993e364706816aba3e25717850c26c9cd0d89d", + "84983e441c3bd26ebaae4aa1f95129e5e54670f1", + "34aa973cd4c4daa4f61eeb2bdbad27316534016f" +}; + +int main( argc, argv ) + int argc; + char **argv; +{ + FILE *f; + int i, j; + char output[41]; + sha1_context ctx; + unsigned char buf[1000]; + unsigned char sha1sum[20]; + + if( argc < 2 ) + { + printf( "\n SHA-1 Validation Tests:\n\n" ); + + for( i = 0; i < 3; i++ ) + { + printf( " Test %d ", i + 1 ); + + sha1_starts( &ctx ); + + if( i < 2 ) + { + sha1_update( &ctx, (uint8 *) msg[i], + strlen( msg[i] ) ); + } + else + { + memset( buf, 'a', 1000 ); + + for( j = 0; j < 1000; j++ ) + { + sha1_update( &ctx, (uint8 *) buf, 1000 ); + } + } + + sha1_finish( &ctx, sha1sum ); + + for( j = 0; j < 20; j++ ) + { + sprintf( output + j * 2, "%02x", sha1sum[j] ); + } + + if( memcmp( output, val[i], 40 ) ) + { + printf( "failed!\n" ); + return( 1 ); + } + + printf( "passed.\n" ); + } + + printf( "\n" ); + } + else + { + if( ! ( f = fopen( argv[1], "rb" ) ) ) + { + perror( "fopen" ); + return( 1 ); + } + + sha1_starts( &ctx ); + + while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + { + sha1_update( &ctx, buf, i ); + } + + sha1_finish( &ctx, sha1sum ); + + for( j = 0; j < 20; j++ ) + { + printf( "%02x", sha1sum[j] ); + } + + printf( " %s\n", argv[1] ); + } + + return( 0 ); +} + +#endif diff --git a/sha1.h b/sha1.h new file mode 100644 index 0000000..806eba1 --- /dev/null +++ b/sha1.h @@ -0,0 +1,24 @@ +#ifndef _SHA1_H +#define _SHA1_H + +#ifndef uint8 +#define uint8 unsigned char +#endif + +#ifndef uint32 +#define uint32 unsigned long int +#endif + +typedef struct +{ + uint32 total[2]; + uint32 state[5]; + uint8 buffer[64]; +} +sha1_context; + +void sha1_starts( sha1_context *ctx ); +void sha1_update( sha1_context *ctx, uint8 *input, uint32 length ); +void sha1_finish( sha1_context *ctx, uint8 digest[20] ); + +#endif /* sha1.h */ diff --git a/sha1num.c b/sha1num.c new file mode 100644 index 0000000..af138c2 --- /dev/null +++ b/sha1num.c @@ -0,0 +1,77 @@ +/* + * sha1num.c --- generate sha1 hash based, pseudo random numbers + * + * Copyright (C) 2005 by Olivier Guerrier + * + * This file may be distributed under the terms of the GNU Public + * License. + */ + +#include +#include +#include +#include "pwgen.h" +#include "sha1.h" + +sha1_context sha1_ctx; +char *sha1_seed; +const char *sha1_magic="pwgen"; +unsigned char sha1sum[20]; +int sha1sum_idx=20; + +void pw_sha1_init(sha1) + char *sha1; +{ + int i = 0; + char *seed; + FILE *f; + unsigned char buf[1024]; + + if ((seed = strchr(sha1,'#'))) { + *(seed++) = 0; + sha1_seed = malloc(strlen(seed)+1); + if (!sha1_seed) { + fprintf(stderr, "Couldn't malloc sha1_seed buffer.\n"); + exit(1); + } + strcpy(sha1_seed, seed); + } + else { + sha1_seed = malloc(strlen(sha1_magic)+1); + if (!sha1_seed) { + fprintf(stderr, "Couldn't malloc sha1_seed buffer.\n"); + exit(1); + } + strcpy(sha1_seed, sha1_magic); + } + + if( ! ( f = fopen( sha1, "rb" ) ) ) { + fprintf(stderr, "Couldn't open file: %s.\n", sha1); + exit(1); + } + + sha1_starts( &sha1_ctx ); + while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) { + sha1_update( &sha1_ctx, buf, i ); + } + + return; +} + + +int pw_sha1_number(max_num) + int max_num; +{ + int val; + sha1_context ctx; + + if(sha1sum_idx>19) + { + sha1sum_idx = 0; + sha1_update(&sha1_ctx, sha1_seed, strlen(sha1_seed)); + ctx = sha1_ctx; + sha1_finish(&ctx, sha1sum ); + } + val = (int) (sha1sum[sha1sum_idx++] / ((float) 256) * max_num); + return (val); +}