Beispiel #1
0
/*
 * 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;
}
Beispiel #2
0
/* 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);
	}
}