/* The algorithm implemented in this function was created by Poul-Henning * Kamp and released under the following license: * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * <*****@*****.**> wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp * ---------------------------------------------------------------------------- */ static void do_phk_hash( const struct berval *passwd, const struct berval *salt, const struct berval *magic, unsigned char *digest) { lutil_MD5_CTX ctx, ctx1; int n; /* Start hashing */ lutil_MD5Init(&ctx); lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, passwd->bv_len); lutil_MD5Update(&ctx, (const unsigned char *) magic->bv_val, magic->bv_len); lutil_MD5Update(&ctx, (const unsigned char *) salt->bv_val, salt->bv_len); /* Inner hash */ lutil_MD5Init(&ctx1); lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); lutil_MD5Update(&ctx1, (const unsigned char *) salt->bv_val, salt->bv_len); lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); lutil_MD5Final(digest, &ctx1); /* Nom start mixing things up */ for (n = passwd->bv_len; n > 0; n -= LUTIL_MD5_BYTES) lutil_MD5Update(&ctx, digest, (n > LUTIL_MD5_BYTES ? LUTIL_MD5_BYTES : n)); memset(digest, 0, LUTIL_MD5_BYTES); /* Curiouser and curiouser... */ for (n = passwd->bv_len; n; n >>= 1) if (n & 1) lutil_MD5Update(&ctx, digest, 1); else lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, 1); lutil_MD5Final(digest, &ctx); /* * Repeatedly hash things into the final value. This was originally * intended to slow the algorithm down. */ for (n = 0; n < 1000; n++) { lutil_MD5Init(&ctx1); if (n & 1) lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); else lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES); if (n % 3) lutil_MD5Update(&ctx1, (const unsigned char *) salt->bv_val, salt->bv_len); if (n % 7) lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); if (n & 1) lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES); else lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len); lutil_MD5Final(digest, &ctx1); } }
/* * lutil_entropy() provides nbytes of entropy in buf. * Quality offerred is suitable for one-time uses, such as "once" keys. * Values may not be suitable for multi-time uses. * * Note: Callers are encouraged to provide additional bytes of * of entropy in the buf argument. This information is used in * fallback mode to improve the quality of bytes returned. * * This routinue should be extended to support additional sources * of entropy. */ int lutil_entropy( unsigned char *buf, ber_len_t nbytes ) { if( nbytes == 0 ) return 0; #ifdef URANDOM_DEVICE #define URANDOM_NREADS 4 /* Linux and *BSD offer a urandom device */ { int rc, fd, n=0; fd = open( URANDOM_DEVICE, O_RDONLY ); if( fd < 0 ) return -1; do { rc = read( fd, buf, nbytes ); if( rc <= 0 ) break; buf+=rc; nbytes-=rc; if( ++n >= URANDOM_NREADS ) break; } while( nbytes > 0 ); close(fd); return nbytes > 0 ? -1 : 0; } #elif PROV_RSA_FULL { /* Not used since _WIN32_WINNT not set... */ HCRYPTPROV hProv = 0; /* Get handle to user default provider */ if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) { return -1; } /* Generate random initialization vector */ if(!CryptGenRandom(hProv, (DWORD) nbytes, (BYTE *) buf)) { return -1; } /* Release provider handle */ if(hProv != 0) CryptReleaseContext(hProv, 0); return 0; } #else { /* based upon Phil Karn's "practical randomness" idea * but implementation 100% OpenLDAP. So don't blame Phil. * * Worse case is that this is a MD5 hash of a counter, if * MD5 is a strong cryptographic hash, this should be fairly * resistant to attack */ /* * the caller may need to provide external synchronization OR * provide entropy (in buf) to ensure quality results as * access to this counter may not be atomic. */ static int counter = 0; ber_len_t n; struct rdata_s { int counter; unsigned char *buf; struct rdata_s *stack; pid_t pid; #ifdef HAVE_GETTIMEOFDAY struct timeval tv; #else time_t time; #endif unsigned long junk; /* purposely not initialized */ } rdata; /* make sure rdata differs for each process */ rdata.pid = getpid(); /* make sure rdata differs for each program */ rdata.buf = buf; rdata.stack = &rdata; for( n = 0; n < nbytes; n += 16 ) { struct lutil_MD5Context ctx; unsigned char digest[16]; /* poor resolution */ #ifdef HAVE_GETTIMEOFDAY (void) gettimeofday( &rdata.tv, NULL ); #else (void) time( &rdata.time ); #endif /* make sure rdata differs */ rdata.counter = ++counter; rdata.pid++; rdata.junk++; lutil_MD5Init( &ctx ); lutil_MD5Update( &ctx, (unsigned char *) &rdata, sizeof( rdata ) ); /* allow caller to provided additional entropy */ lutil_MD5Update( &ctx, buf, nbytes ); lutil_MD5Final( digest, &ctx ); AC_MEMCPY( &buf[n], digest, nbytes - n >= 16 ? 16 : nbytes - n ); } return 0; } #endif return -1; }