"Fossies" - the Fresh Open Source Software archive

Member "evolution-brutus-1.2.35/server/brutus_uuid.c" of archive evolution-brutus-1.2.35.tar.gz:


/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
**  OSSP uuid - Universally Unique Identifier
**  Copyright (c) 2004-2007 Ralf S. Engelschall <rse@engelschall.com>
**  Copyright (c) 2004-2007 The OSSP Project <http://www.ossp.org/>
**  Copyright (C) 2007 Jules Colding <colding@42tools.com>
**
**  This file is mainly composed of code which has been pillaged
**  from OSSP uuid, a library for the generation of UUIDs which can
**  be found at http://www.ossp.org/pkg/lib/uuid/
**
**  Permission to use, copy, modify, and distribute this software for
**  any purpose with or without fee is hereby granted, provided that
**  the above copyright notice and this permission notice appear in all
**  copies.
**
**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
**  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
**  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
**  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
**  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
**  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
**  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
**  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
**  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
**  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
**  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
**  SUCH DAMAGE.
**
**  brutus_uuid.c: UUID creation function
*/

#ifdef HAVE_CONFIG_H
#   include <config.h>
#endif

/* system headers */
#include <glib.h>
#include <glib/gprintf.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef HAVE_SYS_TIME_H
#   include <sys/time.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#   include <sys/types.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#   include <sys/param.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#   include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#   include <sys/socket.h>
#endif
#ifdef HAVE_SYS_SOCKIO_H
#   include <sys/sockio.h>
#endif
#ifdef HAVE_NET_IF_H
#   include <net/if.h>
#endif
#ifdef HAVE_NET_IF_DL_H
#   include <net/if_dl.h>
#endif
#ifdef HAVE_NET_IF_ARP_H
#   include <net/if_arp.h>
#endif
#ifdef HAVE_NETINET_IN_H
#   include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#   include <arpa/inet.h>
#endif
#ifdef HAVE_NETDB_H
#   include <netdb.h>
#endif
#ifdef HAVE_IFADDRS_H
#   include <ifaddrs.h>
#endif

#include "brutus_uuid.h"

/*
 *  Bitmask Calculation Macros (up to 32 bit only)
 *  (Notice: bit positions are counted n...0, i.e. lowest bit is position 0)
 */

/* generate a bitmask consisting of 1 bits from (and including)
   bit position `l' (left) to (and including) bit position `r' */
#define BM_MASK(l,r)					\
	((((unsigned int)1<<(((l)-(r))+1))-1)<<(r))

/* extract a value v from a word w at position `l' to `r' and return value */
#define BM_GET(w,l,r)				\
	(((w)>>(r))&BM_MASK((l)-(r),0))

/* insert a value v into a word w at position `l' to `r' and return word */
#define BM_SET(w,l,r,v)				\
	((w)|(((v)&BM_MASK((l)-(r),0))<<(r)))

/* generate a single bit `b' (0 or 1) at bit position `n' */
#define BM_BIT(n,b)				\
	((b)<<(n))

/* generate a quad word octet of bits (a half byte, i.e. bit positions 3 to 0) */
#define BM_QUAD(b3,b2,b1,b0)						\
	(BM_BIT(3,(b3))|BM_BIT(2,(b2))|BM_BIT(1,(b1))|BM_BIT(0,(b0)))

/* generate an octet word of bits (a byte, i.e. bit positions 7 to 0) */
#define BM_OCTET(b7,b6,b5,b4,b3,b2,b1,b0)			\
	((BM_QUAD(b7,b6,b5,b4)<<4)|BM_QUAD(b3,b2,b1,b0))

/* generate the value 2^n */
#define BM_POW2(n)				\
	BM_BIT(n,1)

/* shift word w k bits to the left or to the right */
#define BM_SHL(w,k)				\
	((w)<<(k))
#define BM_SHR(w,k)				\
	((w)>>(k))

/* rotate word w (of bits n..0) k bits to the left or to the right */
#define BM_ROL(w,n,k)							\
	((BM_SHL((w),(k))&BM_MASK(n,0))|BM_SHR(((w)&BM_MASK(n,0)),(n)-(k)))
#define BM_ROR(w,n,k)							\
	((BM_SHR(((w)&BM_MASK(n,0)),(k)))|BM_SHL(((w),(n)-(k))&BM_MASK(n,0)))

/* F, G, H and I are basic MD5 functions. */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))

/* ROTATE_LEFT rotates x left n bits. */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
   Rotation is separate from addition to prevent recomputation. */
#define FF(a, b, c, d, x, s, ac) {				\
		(a) += F ((b), (c), (d)) + (x) + (guint32)(ac);	\
		(a) = ROTATE_LEFT ((a), (s));			\
		(a) += (b);					\
	}
#define GG(a, b, c, d, x, s, ac) {				\
		(a) += G ((b), (c), (d)) + (x) + (guint32)(ac);	\
		(a) = ROTATE_LEFT ((a), (s));			\
		(a) += (b);					\
	}
#define HH(a, b, c, d, x, s, ac) {				\
		(a) += H ((b), (c), (d)) + (x) + (guint32)(ac);	\
		(a) = ROTATE_LEFT ((a), (s));			\
		(a) += (b);					\
	}
#define II(a, b, c, d, x, s, ac) {				\
		(a) += I ((b), (c), (d)) + (x) + (guint32)(ac);	\
		(a) = ROTATE_LEFT ((a), (s));			\
		(a) += (b);					\
	}

#define UI64_BASE   256		/* 2^8 */
#define UI64_DIGITS 8		/* 8*8 = 64 bit */
#define UIXX_T(n) struct { unsigned char x[n]; }

/* fill an ui64_t with a sequence of a particular digit */
#define brutus_ui64_fill(__x, __n)			\
	do {                                            \
		int __i;                                \
		for (__i = 0; __i < UI64_DIGITS; __i++) \
			(__x).x[__i] = (__n);           \
	} while (0)

/* encoding octet stream lengths */
#define UUID_LEN_BIN  (128 /*bit*/ / 8 /*bytes*/)
#define UUID_LEN_STR  (128 /*bit*/ / 4 /*nibbles*/ + 4 /*hyphens*/)

#define MAC_LEN 6
#define SHA1_LEN_BIN 20
#define SHA1_LEN_STR 40
#define SHA1HashSize 20
#define MD5_LEN_BIN 16
#define MD5_LEN_STR 32

/* maximum number of 100ns ticks of the actual resolution of system clock
   (which in our case is 1us (= 1000ns) because we use gettimeofday(2) */
#define UUIDS_PER_TICK 10

/* time offset between UUID and Unix Epoch time according to standards.
   (UUID UTC base time is October 15, 1582
   Unix UTC base time is January  1, 1970) */
#define UUID_TIMEOFFSET "01B21DD213814000"

/* IEEE 802 MAC address encoding/decoding bit fields */
#define IEEE_MAC_MCBIT BM_OCTET(0,0,0,0,0,0,0,1)
#define IEEE_MAC_LOBIT BM_OCTET(0,0,0,0,0,0,1,0)

/* IEEE 802 MAC address octet length */
#define IEEE_MAC_OCTETS 6

/* API return codes */
typedef enum {
	UUID_RC_OK = 0,		/* everything ok    */
	UUID_RC_ARG = 1,	/* invalid argument */
	UUID_RC_MEM = 2,	/* out of memory    */
	UUID_RC_SYS = 3,	/* system error     */
	UUID_RC_INT = 4,	/* internal error   */
	UUID_RC_IMP = 5		/* not implemented  */
} uuid_rc_t;

/* UUID import/export formats */
typedef enum {
	UUID_FMT_BIN = 0,	/* binary representation (import/export) */
	UUID_FMT_STR = 1,	/* string representation (import/export) */
} uuid_fmt_t;


typedef struct {
	unsigned char x[8];	/* x_0, ..., x_7 */
} ui64_t;

typedef enum {
	PRNG_RC_OK = 0,
	PRNG_RC_ARG = 1,
	PRNG_RC_MEM = 2,
	PRNG_RC_INT = 3
} prng_rc_t;

typedef enum {
	SHA1_RC_OK = 0,
	SHA1_RC_ARG = 1,
	SHA1_RC_MEM = 2,
	SHA1_RC_INT = 3
} sha1_rc_t;

/* This structure will hold context information for the SHA-1 hashing operation */
typedef struct SHA1Context {
	guint32 Intermediate_Hash[SHA1HashSize / 4]; /* Message Digest */
	guint32 Length_Low;                          /* Message length in bits */
	guint32 Length_High;                         /* Message length in bits */
	gint16 Message_Block_Index;                  /* Index into message block array */
	guint8 Message_Block[64];                    /* 512-bit message blocks */
	int Computed;                                /* Is the digest computed? */
	int Corrupted;                               /* Is the message digest corrupted? */
} SHA1Context;

typedef unsigned char *POINTER;

/* finalization padding */
static unsigned char 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
};

typedef enum {
	MD5_RC_OK = 0,
	MD5_RC_ARG = 1,
	MD5_RC_MEM = 2
} md5_rc_t;

/* MD5 context. */
typedef struct {
	guint32 state[4];	/* state (ABCD) */
	guint32 count[2];	/* number of bits, modulo 2^64 (lsb first) */
	guint8 buffer[64];	/* input buffer */
} MD5_CTX;

typedef struct md5_st {
	MD5_CTX ctx;
} md5_t;

typedef struct sha1_st {
	SHA1Context ctx;
} sha1_t;

typedef struct prng_st {
	int dev;		/* system PRNG device */
	md5_t *md5;		/* local MD5 PRNG engine */
	long cnt;		/* time resolution compensation counter */
} prng_t;

/* UUID binary representation according to UUID standards */
typedef struct {
	guint32 time_low;	/* bits  0-31 of time field */
	guint16 time_mid;	/* bits 32-47 of time field */
	guint16 time_hi_and_version;	/* bits 48-59 of time field plus 4 bit version */
	guint8 clock_seq_hi_and_reserved;	/* bits  8-13 of clock sequence field plus 2 bit variant */
	guint8 clock_seq_low;	/* bits  0-7  of clock sequence field */
	guint8 node[IEEE_MAC_OCTETS];	/* bits  0-47 of node MAC address */
} uuid_obj_t;

/* abstract data type (ADT) of API */
typedef struct uuid_st {
	uuid_obj_t obj;		/* inlined UUID object */
	prng_t *prng;		/* RPNG sub-object */
	md5_t *md5;		/* MD5 sub-object */
	sha1_t *sha1;		/* SHA-1 sub-object */
	guint8 mac[IEEE_MAC_OCTETS];	/* pre-determined MAC address */
	struct timeval time_last;	/* last retrieved timestamp */
	unsigned long time_seq;	/* last timestamp sequence counter */
} uuid_t;

/* INTERNAL: pre-defined UUID values.
   (defined as network byte ordered octet stream) */
#define UUID_MAKE(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16) \
	{ (guint8)(a1),  (guint8)(a2),  (guint8)(a3),  (guint8)(a4),	\
			(guint8)(a5),  (guint8)(a6),  (guint8)(a7),  (guint8)(a8), \
			(guint8)(a9),  (guint8)(a10), (guint8)(a11), (guint8)(a12), \
			(guint8)(a13), (guint8)(a14), (guint8)(a15), (guint8)(a16) }
static struct {
	char *name;
	guint8 uuid[UUID_LEN_BIN];
} uuid_value_table[] = {
	{
		"nil",     /* 00000000-0000-0000-0000-000000000000 ("Nil UUID") */
		UUID_MAKE(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			  0x00, 0x00, 0x00, 0x00, 0x00,
			  0x00, 0x00, 0x00, 0x00)}, {
		"ns:DNS",  /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */
		UUID_MAKE(0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11,
			  0xd1, 0x80, 0xb4, 0x00, 0xc0,
			  0x4f, 0xd4, 0x30, 0xc8)}, {
		"ns:URL",  /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */
		UUID_MAKE(0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11,
			  0xd1, 0x80, 0xb4, 0x00, 0xc0,
			  0x4f, 0xd4, 0x30, 0xc8)}, {
		"ns:OID",  /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */
		UUID_MAKE(0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11,
			  0xd1, 0x80, 0xb4, 0x00, 0xc0,
			  0x4f, 0xd4, 0x30, 0xc8)}, {
		"ns:X500", /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */
		UUID_MAKE(0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11,
			  0xd1, 0x80, 0xb4, 0x00, 0xc0,
			  0x4f, 0xd4, 0x30, 0xc8)}
};

/* Decodes input (unsigned char) into output (guint32).
   Assumes len is a multiple of 4. */
static void
Decode(guint32 * output,
       unsigned char *input,
       unsigned int len)
{
	unsigned int i, j;

	for (i = 0, j = 0; j < len; i++, j += 4)
		output[i] = ((guint32) input[j])
			| (((guint32) input[j + 1]) << 8)
			| (((guint32) input[j + 2]) << 16)
			| (((guint32) input[j + 3]) << 24);
	return;
}

/* MD5 basic transformation. Transforms state based on block. */
static void
MD5Transform(guint32 state[],
	     unsigned char block[])
{
	guint32 a = state[0], b = state[1], c = state[2], d = state[3], x[16];

	Decode(x, block, 64);

	/* Round 1 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
	FF(a, b, c, d, x[0], S11, 0xd76aa478);	/* 1 */
	FF(d, a, b, c, x[1], S12, 0xe8c7b756);	/* 2 */
	FF(c, d, a, b, x[2], S13, 0x242070db);	/* 3 */
	FF(b, c, d, a, x[3], S14, 0xc1bdceee);	/* 4 */
	FF(a, b, c, d, x[4], S11, 0xf57c0faf);	/* 5 */
	FF(d, a, b, c, x[5], S12, 0x4787c62a);	/* 6 */
	FF(c, d, a, b, x[6], S13, 0xa8304613);	/* 7 */
	FF(b, c, d, a, x[7], S14, 0xfd469501);	/* 8 */
	FF(a, b, c, d, x[8], S11, 0x698098d8);	/* 9 */
	FF(d, a, b, c, x[9], S12, 0x8b44f7af);	/* 10 */
	FF(c, d, a, b, x[10], S13, 0xffff5bb1);	/* 11 */
	FF(b, c, d, a, x[11], S14, 0x895cd7be);	/* 12 */
	FF(a, b, c, d, x[12], S11, 0x6b901122);	/* 13 */
	FF(d, a, b, c, x[13], S12, 0xfd987193);	/* 14 */
	FF(c, d, a, b, x[14], S13, 0xa679438e);	/* 15 */
	FF(b, c, d, a, x[15], S14, 0x49b40821);	/* 16 */

	/* Round 2 */
#define S21 5
#define S22 9
#define S23 14
#define S24 20
	GG(a, b, c, d, x[1], S21, 0xf61e2562);	/* 17 */
	GG(d, a, b, c, x[6], S22, 0xc040b340);	/* 18 */
	GG(c, d, a, b, x[11], S23, 0x265e5a51);	/* 19 */
	GG(b, c, d, a, x[0], S24, 0xe9b6c7aa);	/* 20 */
	GG(a, b, c, d, x[5], S21, 0xd62f105d);	/* 21 */
	GG(d, a, b, c, x[10], S22, 0x2441453);	/* 22 */
	GG(c, d, a, b, x[15], S23, 0xd8a1e681);	/* 23 */
	GG(b, c, d, a, x[4], S24, 0xe7d3fbc8);	/* 24 */
	GG(a, b, c, d, x[9], S21, 0x21e1cde6);	/* 25 */
	GG(d, a, b, c, x[14], S22, 0xc33707d6);	/* 26 */
	GG(c, d, a, b, x[3], S23, 0xf4d50d87);	/* 27 */
	GG(b, c, d, a, x[8], S24, 0x455a14ed);	/* 28 */
	GG(a, b, c, d, x[13], S21, 0xa9e3e905);	/* 29 */
	GG(d, a, b, c, x[2], S22, 0xfcefa3f8);	/* 30 */
	GG(c, d, a, b, x[7], S23, 0x676f02d9);	/* 31 */
	GG(b, c, d, a, x[12], S24, 0x8d2a4c8a);	/* 32 */

	/* Round 3 */
#define S31 4
#define S32 11
#define S33 16
#define S34 23
	HH(a, b, c, d, x[5], S31, 0xfffa3942);	/* 33 */
	HH(d, a, b, c, x[8], S32, 0x8771f681);	/* 34 */
	HH(c, d, a, b, x[11], S33, 0x6d9d6122);	/* 35 */
	HH(b, c, d, a, x[14], S34, 0xfde5380c);	/* 36 */
	HH(a, b, c, d, x[1], S31, 0xa4beea44);	/* 37 */
	HH(d, a, b, c, x[4], S32, 0x4bdecfa9);	/* 38 */
	HH(c, d, a, b, x[7], S33, 0xf6bb4b60);	/* 39 */
	HH(b, c, d, a, x[10], S34, 0xbebfbc70);	/* 40 */
	HH(a, b, c, d, x[13], S31, 0x289b7ec6);	/* 41 */
	HH(d, a, b, c, x[0], S32, 0xeaa127fa);	/* 42 */
	HH(c, d, a, b, x[3], S33, 0xd4ef3085);	/* 43 */
	HH(b, c, d, a, x[6], S34, 0x4881d05);	/* 44 */
	HH(a, b, c, d, x[9], S31, 0xd9d4d039);	/* 45 */
	HH(d, a, b, c, x[12], S32, 0xe6db99e5);	/* 46 */
	HH(c, d, a, b, x[15], S33, 0x1fa27cf8);	/* 47 */
	HH(b, c, d, a, x[2], S34, 0xc4ac5665);	/* 48 */

	/* Round 4 */
#define S41 6
#define S42 10
#define S43 15
#define S44 21
	II(a, b, c, d, x[0], S41, 0xf4292244);	/* 49 */
	II(d, a, b, c, x[7], S42, 0x432aff97);	/* 50 */
	II(c, d, a, b, x[14], S43, 0xab9423a7);	/* 51 */
	II(b, c, d, a, x[5], S44, 0xfc93a039);	/* 52 */
	II(a, b, c, d, x[12], S41, 0x655b59c3);	/* 53 */
	II(d, a, b, c, x[3], S42, 0x8f0ccc92);	/* 54 */
	II(c, d, a, b, x[10], S43, 0xffeff47d);	/* 55 */
	II(b, c, d, a, x[1], S44, 0x85845dd1);	/* 56 */
	II(a, b, c, d, x[8], S41, 0x6fa87e4f);	/* 57 */
	II(d, a, b, c, x[15], S42, 0xfe2ce6e0);	/* 58 */
	II(c, d, a, b, x[6], S43, 0xa3014314);	/* 59 */
	II(b, c, d, a, x[13], S44, 0x4e0811a1);	/* 60 */
	II(a, b, c, d, x[4], S41, 0xf7537e82);	/* 61 */
	II(d, a, b, c, x[11], S42, 0xbd3af235);	/* 62 */
	II(c, d, a, b, x[2], S43, 0x2ad7d2bb);	/* 63 */
	II(b, c, d, a, x[9], S44, 0xeb86d391);	/* 64 */

	state[0] += a;
	state[1] += b;
	state[2] += c;
	state[3] += d;

	/* Zeroize sensitive information. */
	memset((POINTER) x, 0, sizeof(x));
}

/* Encodes input (guint32) into output (unsigned char).
   Assumes len is a multiple of 4. */
static void
Encode(unsigned char *output,
       guint32 * input,
       unsigned int len)
{
	unsigned int i, j;

	for (i = 0, j = 0; j < len; i++, j += 4) {
		output[j] = (unsigned char) (input[i] & 0xff);
		output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
		output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
		output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
	}
	return;
}

static void
MD5Init(MD5_CTX * context)
{
	context->count[0] = context->count[1] = 0;

	/* Load magic initialization constants. */
	context->state[0] = 0x67452301;
	context->state[1] = 0xefcdab89;
	context->state[2] = 0x98badcfe;
	context->state[3] = 0x10325476;
	return;
}

/* MD5 block update operation. Continues an MD5 message-digest
   operation, processing another message block, and updating the
   context. */
static void
MD5Update(MD5_CTX * context,	/* context */
	  unsigned char *input,	/* input block */
	  unsigned int inputLen)
{				/* length of input block */
	unsigned int i, idx, partLen;

	/* Compute number of bytes mod 64 */
	idx = (unsigned int) ((context->count[0] >> 3) & 0x3F);

	/* Update number of bits */
	if ((context->count[0] += ((guint32) inputLen << 3)) < ((guint32) inputLen << 3))
		context->count[1]++;
	context->count[1] += ((guint32) inputLen >> 29);

	partLen = (unsigned int) 64 - idx;

	/* Transform as many times as possible.  */
	if (inputLen >= partLen) {
		memcpy((POINTER) & context->buffer[idx], (POINTER) input, (size_t) partLen);
		MD5Transform(context->state, context->buffer);
		for (i = partLen; i + 63 < inputLen; i += 64)
			MD5Transform(context->state, &input[i]);
		idx = 0;
	} else
		i = 0;

	/* Buffer remaining input */
	memcpy((POINTER) & context->buffer[idx], (POINTER) & input[i], (size_t) (inputLen - i));
}

/* MD5 finalization. Ends an MD5 message-digest operation, writing the
   the message digest and zeroizing the context. */
static void
MD5Final(unsigned char digest[], /* message digest */
	 MD5_CTX * context)      /* context */
{				
	unsigned char bits[8];
	unsigned int idx, padLen;

	/* Save number of bits */
	Encode(bits, context->count, 8);

	/* Pad out to 56 mod 64. */
	idx = (unsigned int) ((context->count[0] >> 3) & 0x3f);
	padLen = (idx < 56) ? ((unsigned int) 56 - idx) : ((unsigned int) 120 - idx);
	MD5Update(context, PADDING, padLen);

	/* Append length (before padding) */
	MD5Update(context, bits, 8);

	/* Store state in digest */
	Encode(digest, context->state, 16);

	/* Zeroize sensitive information. */
	memset((POINTER) context, 0, sizeof(*context));
}

static md5_rc_t
brutus_md5_create(md5_t ** md5)
{
	if (md5 == NULL)
		return MD5_RC_ARG;
	if ((*md5 = (md5_t *) malloc(sizeof(md5_t))) == NULL)
		return MD5_RC_MEM;
	MD5Init(&((*md5)->ctx));

	return MD5_RC_OK;
}

static md5_rc_t
brutus_md5_update(md5_t * md5,
		  const void *data_ptr,
		  size_t data_len)
{
	if (md5 == NULL)
		return MD5_RC_ARG;
	MD5Update(&(md5->ctx), (unsigned char *) data_ptr,
		  (unsigned int) data_len);
	return MD5_RC_OK;
}

static md5_rc_t
brutus_md5_store(md5_t * md5,
		 void **data_ptr,
		 size_t * data_len)
{
	MD5_CTX ctx;

	if (md5 == NULL || data_ptr == NULL)
		return MD5_RC_ARG;
	if (*data_ptr == NULL) {
		*data_ptr = malloc(MD5_LEN_BIN);

		if (NULL == *data_ptr)
			return MD5_RC_MEM;
		if (data_len != NULL)
			*data_len = MD5_LEN_BIN;
	} else {
		if (data_len != NULL) {
			if (*data_len < MD5_LEN_BIN)
				return MD5_RC_MEM;
			*data_len = MD5_LEN_BIN;
		}
	}
	memcpy((void *) (&ctx), (void *) (&(md5->ctx)), sizeof(MD5_CTX));
	MD5Final((unsigned char *) (*data_ptr), &(ctx));

	return MD5_RC_OK;
}

static md5_rc_t
brutus_md5_destroy(md5_t * md5)
{
	if (md5 == NULL)
		return MD5_RC_ARG;
	free(md5);

	return MD5_RC_OK;
}

/*
 *  This function will initialize the SHA1Context in preparation for
 *  computing a new SHA1 message digest.
 */
static int
brutus_SHA1Reset(SHA1Context * context)
{
	if (context == NULL)
		return 1;

	context->Length_Low = 0;
	context->Length_High = 0;
	context->Message_Block_Index = 0;

	context->Intermediate_Hash[0] = 0x67452301;
	context->Intermediate_Hash[1] = 0xEFCDAB89;
	context->Intermediate_Hash[2] = 0x98BADCFE;
	context->Intermediate_Hash[3] = 0x10325476;
	context->Intermediate_Hash[4] = 0xC3D2E1F0;

	context->Computed = 0;
	context->Corrupted = 0;

	return 0;
}

static sha1_rc_t
brutus_sha1_create(sha1_t ** sha1)
{
	if (sha1 == NULL)
		return SHA1_RC_ARG;
	if ((*sha1 = (sha1_t *) malloc(sizeof(sha1_t))) == NULL)
		return SHA1_RC_MEM;
	if (brutus_SHA1Reset(&((*sha1)->ctx)))
		return SHA1_RC_INT;

	return SHA1_RC_OK;
}

static sha1_rc_t
brutus_sha1_destroy(sha1_t * sha1)
{
	if (sha1 == NULL)
		return SHA1_RC_ARG;
	free(sha1);

	return SHA1_RC_OK;
}


static prng_rc_t
brutus_prng_create(prng_t ** prng)
{
	int fd = -1;
	struct timeval tv;
	pid_t pid;
	unsigned int i;

	/* sanity check argument(s) */
	if (prng == NULL)
		return PRNG_RC_ARG;

	/* allocate object */
	if ((*prng = (prng_t *) malloc(sizeof(prng_t))) == NULL)
		return PRNG_RC_MEM;

	/* try to open the system PRNG device */
	(*prng)->dev = -1;
	if ((fd = open("/dev/urandom", O_RDONLY)) == -1)
		fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
	if (fd != -1) {
		(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
		(*prng)->dev = fd;
	}

	/* initialize MD5 engine */
	if (brutus_md5_create(&((*prng)->md5)) != MD5_RC_OK) {
		free(*prng);
		return PRNG_RC_INT;
	}

	/* initialize time resolution compensation counter */
	(*prng)->cnt = 0;

	/* seed the C library PRNG once */
	(void) gettimeofday(&tv, NULL);
	pid = getpid();
	srand((unsigned int) (((unsigned int) pid << 16)
			      ^ (unsigned int) pid
			      ^ (unsigned int) tv.tv_sec
			      ^ (unsigned int) tv.tv_usec));
	for (i = (unsigned int) ((tv.tv_sec ^ tv.tv_usec) & 0x1F); i > 0; i--)
		(void) rand();

	return PRNG_RC_OK;
}

static prng_rc_t
brutus_prng_data(prng_t * prng,
		 void *data_ptr,
		 size_t data_len)
{
	size_t n;
	unsigned char *p;
	struct {
		struct timeval tv;
		long cnt;
		int rnd;
	} entropy;
	unsigned char md5_buf[MD5_LEN_BIN] = { 0 };
	void *md5_ptr;
	size_t md5_len;
	int retries;
	int i;

	/* sanity check argument(s) */
	if (prng == NULL || data_len == 0)
		return PRNG_RC_ARG;

	/* prepare for generation */
	p = (unsigned char *) data_ptr;
	n = data_len;

	/* approach 1: try to gather data via stronger system PRNG device */
	if (prng->dev != -1) {
		retries = 0;
		while (n > 0) {
			i = (int) read(prng->dev, (void *) p, n);
			if (i <= 0) {
				if (retries++ > 16)
					break;
				continue;
			}
			retries = 0;
			n -= (unsigned int) i;
			p += (unsigned int) i;
		}
	}

	/* approach 2: try to gather data via weaker libc PRNG API. */
	while (n > 0) {
		/* gather new entropy */
		(void) gettimeofday(&(entropy.tv), NULL);	/* source: libc time */
		entropy.rnd = rand();	/* source: libc PRNG */
		entropy.cnt = prng->cnt++;	/* source: local counter */

		/* pass entropy into MD5 engine */
		if (brutus_md5_update(prng->md5, (void *) &entropy, sizeof(entropy)) != MD5_RC_OK)
			return PRNG_RC_INT;

		/* store MD5 engine state as PRN output */
		md5_ptr = (void*)md5_buf;
		md5_len = sizeof(md5_buf);
		if (brutus_md5_store(prng->md5, &md5_ptr, &md5_len) != MD5_RC_OK)
			return PRNG_RC_INT;
		for (i = 0; i < MD5_LEN_BIN && n > 0; i++, n--)
			*p++ ^= md5_buf[i];	/* intentionally no assignment because arbitrary
						   caller buffer content is leveraged, too */
	}

	return PRNG_RC_OK;
}

static prng_rc_t
brutus_prng_destroy(prng_t * prng)
{
	/* sanity check argument(s) */
	if (prng == NULL)
		return PRNG_RC_ARG;

	/* close PRNG device */
	if (prng->dev != -1)
		(void) close(prng->dev);

	/* destroy MD5 engine */
	(void) brutus_md5_destroy(prng->md5);

	/* free object */
	free(prng);

	return PRNG_RC_OK;
}

/* return the Media Access Control (MAC) address of
   the FIRST network interface card (NIC) */
static int
brutus_mac_address(unsigned char *data_ptr,
		   size_t data_len)
{
	/* sanity check arguments */
	if (data_ptr == NULL || data_len < MAC_LEN)
		return FALSE;

#if defined(HAVE_IFADDRS_H) && defined(HAVE_NET_IF_DL_H) && defined(HAVE_GETIFADDRS)
	/* use getifaddrs(3) on BSD class platforms (xxxBSD, MacOS X, etc) */
	{
		struct ifaddrs *ifap;
		struct ifaddrs *ifap_head;
		const struct sockaddr_dl *sdl;
		unsigned char *ucp;
		int i;

		if (getifaddrs(&ifap_head) < 0)
			return FALSE;
		for (ifap = ifap_head; ifap != NULL; ifap = ifap->ifa_next) {
			if (ifap->ifa_addr != NULL && ifap->ifa_addr->sa_family == AF_LINK) {
				sdl = (const struct sockaddr_dl *) (void *) ifap->ifa_addr;
				ucp = (unsigned char *) (sdl->sdl_data + sdl->sdl_nlen);
				if (sdl->sdl_alen > 0) {
					for (i = 0; i < MAC_LEN && i < sdl->sdl_alen; i++, ucp++)
						data_ptr[i] = (unsigned char) (*ucp & 0xff);
					freeifaddrs(ifap_head);

					return TRUE;
				}
			}
		}
		freeifaddrs(ifap_head);
	}
#endif

#if defined(HAVE_NET_IF_H) && defined(SIOCGIFHWADDR)
	/* use SIOCGIFHWADDR ioctl(2) on Linux class platforms */
	{
		struct ifreq ifr;
		struct sockaddr *sa;
		int s;
		int i;

		if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
			return FALSE;
		sprintf(ifr.ifr_name, "eth0");
		if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {
			close(s);
			return FALSE;
		}
		sa = (struct sockaddr *) &ifr.ifr_addr;
		for (i = 0; i < MAC_LEN; i++)
			data_ptr[i] = (unsigned char) (sa->sa_data[i] & 0xff);
		close(s);

		return TRUE;
	}
#endif

#if defined(SIOCGARP)
	/* use SIOCGARP ioctl(2) on SVR4 class platforms (Solaris, etc) */
	{
		char hostname[MAXHOSTNAMELEN];
		struct hostent *he;
		struct arpreq ar;
		struct sockaddr_in *sa;
		int s;
		int i;

		if (gethostname(hostname, sizeof(hostname)) < 0)
			return FALSE;
		if ((he = gethostbyname(hostname)) == NULL)
			return FALSE;
		if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
			return FALSE;
		memset(&ar, 0, sizeof(ar));
		sa = (struct sockaddr_in *) ((void *) &(ar.arp_pa));
		sa->sin_family = AF_INET;
		memcpy(&(sa->sin_addr), *(he->h_addr_list), sizeof(struct in_addr));
		if (ioctl(s, SIOCGARP, &ar) < 0) {
			close(s);
			return FALSE;
		}
		close(s);
		if (!(ar.arp_flags & ATF_COM))
			return FALSE;
		for (i = 0; i < MAC_LEN; i++)
			data_ptr[i] = (unsigned char) (ar.arp_ha.sa_data[i] & 0xff);

		return TRUE;
	}
#endif

	return FALSE;
}

/* convert ISO-C "unsigned long" into internal format */
static ui64_t
brutus_ui64_n2i(unsigned long n)
{
	ui64_t z;
	int i;

	i = 0;
	do {
		z.x[i++] = (n % UI64_BASE);
	} while ((n /= UI64_BASE) > 0 && i < UI64_DIGITS);

	for (; i < UI64_DIGITS; i++)
		z.x[i] = 0;

	return z;
}

/* convert internal format into ISO-C "unsigned long";
   truncates if sizeof(unsigned long) is less than UI64_DIGITS! */
static unsigned long
brutus_ui64_i2n(ui64_t x)
{
	unsigned long n;
	int i;

	n = 0;
	i = (int) sizeof(n);

	if (i > UI64_DIGITS)
		i = UI64_DIGITS;

	while (--i >= 0) {
		n = (n * UI64_BASE) + x.x[i];
	}

	return n;
}

static ui64_t
brutus_ui64_muln(ui64_t x,
		 int y,
		 int *ov)
{
	ui64_t z;
	int carry;
	int i;

	carry = 0;
	for (i = 0; i < UI64_DIGITS; i++) {
		carry += (x.x[i] * y);
		z.x[i] = (carry % UI64_BASE);
		carry /= UI64_BASE;
	}
	if (ov != NULL)
		*ov = carry;
	return z;
}

/* addition of an ui64_t and a single digit */
static ui64_t
brutus_ui64_addn(ui64_t x,
		 int y,
		 int *ov)
{
	ui64_t z;
	int i;

	for (i = 0; i < UI64_DIGITS; i++) {
		y += x.x[i];
		z.x[i] = (y % UI64_BASE);
		y /= UI64_BASE;
	}

	if (ov != NULL)
		*ov = y;

	return z;
}

/* convert string representation of arbitrary base into internal format */
static ui64_t
brutus_ui64_s2i(const char *str,
		char **end,
		int base)
{
	ui64_t z;
	const char *cp;
	int carry;
	static char map[] = {
		0, 1, 2, 3, 4, 5, 6, 7, 8, 9,	/* 0...9 */
		36, 36, 36, 36, 36, 36, 36,	/* illegal chars */
		10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,	/* A...M */
		23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,	/* N...Z */
		36, 36, 36, 36, 36, 36,	/* illegal chars */
		10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,	/* a...m */
		23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35	/* m...z */
	};

	brutus_ui64_fill(z, 0);
	if (str == NULL || (base < 2 || base > 36))
		return z;
	cp = str;
	while (*cp != '\0' && isspace((int) (*cp)))
		cp++;
	while (*cp != '\0' && isalnum((int) (*cp))
	       && map[(int) (*cp) - '0'] < base) {
		z = brutus_ui64_muln(z, base, &carry);
		if (carry)
			break;
		z = brutus_ui64_addn(z, map[(int) (*cp) - '0'], &carry);
		if (carry)
			break;
		cp++;
	}
	if (end != NULL)
		*end = (char *) cp;

	return z;
}

/* addition of two ui64_t */
static ui64_t
brutus_ui64_add(ui64_t x,
		ui64_t y,
		ui64_t * ov)
{
	ui64_t z;
	int carry;
	int i;

	carry = 0;
	for (i = 0; i < UI64_DIGITS; i++) {
		carry += (x.x[i] + y.x[i]);
		z.x[i] = (carry % UI64_BASE);
		carry /= UI64_BASE;
	}

	if (ov != NULL)
		*ov = brutus_ui64_n2i((unsigned long) carry);

	return z;
}

/* the value zero */
static ui64_t
brutus_ui64_zero(void)
{
	ui64_t z;

	brutus_ui64_fill(z, 0);

	return z;
}

static ui64_t
brutus_ui64_rol(ui64_t x,
		int s,
		ui64_t * ov)
{
	UIXX_T(UI64_DIGITS + UI64_DIGITS) zx;
	ui64_t z;
	int i;
	int carry;

	if (s <= 0) {
		/* no shift at all */
		if (ov != NULL)
			*ov = brutus_ui64_zero();
		return x;
	} else if (s > 64) {
		/* too large shift */
		if (ov != NULL)
			*ov = brutus_ui64_zero();
		return brutus_ui64_zero();
	} else if (s == 64) {
		/* maximum shift */
		if (ov != NULL)
			*ov = x;
		return brutus_ui64_zero();
	} else {		/* regular shift */
		/* shift (logically) left by s/8 bytes */
		for (i = 0; i < UI64_DIGITS + UI64_DIGITS; i++)
			zx.x[i] = 0;
		for (i = 0; i < UI64_DIGITS; i++)
			zx.x[i + (s / 8)] = x.x[i];
		/* shift (logically) left by remaining s%8 bits */
		s %= 8;
		if (s > 0) {
			carry = 0;
			for (i = 0; i < UI64_DIGITS + UI64_DIGITS; i++) {
				carry += (zx.x[i] * (1 << s));
				zx.x[i] = (carry % UI64_BASE);
				carry /= UI64_BASE;
			}
		}
		memcpy(z.x, zx.x, UI64_DIGITS);
		if (ov != NULL)
			memcpy((*ov).x, &zx.x[UI64_DIGITS], UI64_DIGITS);
	}

	return z;
}

/* destroy UUID object */
static uuid_rc_t
uuid_destroy(uuid_t * uuid)
{
	/* argument sanity check */
	if (uuid == NULL)
		return UUID_RC_ARG;

	/* destroy PRNG, MD5 and SHA-1 sub-objects */
	(void) brutus_prng_destroy(uuid->prng);
	(void) brutus_md5_destroy(uuid->md5);
	(void) brutus_sha1_destroy(uuid->sha1);

	/* free UUID object */
	free(uuid);

	return UUID_RC_OK;
}

/* INTERNAL: unpack UUID binary presentation into UUID object
   (allows in-place operation for internal efficiency!) */
static uuid_rc_t
uuid_import_bin(uuid_t * uuid,
		const void *data_ptr,
		size_t data_len)
{
	const guint8 *in;
	guint32 tmp32;
	guint16 tmp16;
	unsigned int i;

	/* sanity check argument(s) */
	if (uuid == NULL || data_ptr == NULL || data_len < UUID_LEN_BIN)
		return UUID_RC_ARG;

	/* treat input data buffer as octet stream */
	in = (const guint8 *) data_ptr;

	/* unpack "time_low" field */
	tmp32 = (guint32) (*in++);
	tmp32 = (tmp32 << 8) | (guint32) (*in++);
	tmp32 = (tmp32 << 8) | (guint32) (*in++);
	tmp32 = (tmp32 << 8) | (guint32) (*in++);
	uuid->obj.time_low = tmp32;

	/* unpack "time_mid" field */
	tmp16 = (guint16) (*in++);
	tmp16 = (guint16) (tmp16 << 8) | (guint16) (*in++);
	uuid->obj.time_mid = tmp16;

	/* unpack "time_hi_and_version" field */
	tmp16 = (guint16) * in++;
	tmp16 = (guint16) (tmp16 << 8) | (guint16) (*in++);
	uuid->obj.time_hi_and_version = tmp16;

	/* unpack "clock_seq_hi_and_reserved" field */
	uuid->obj.clock_seq_hi_and_reserved = *in++;

	/* unpack "clock_seq_low" field */
	uuid->obj.clock_seq_low = *in++;

	/* unpack "node" field */
	for (i = 0; i < (unsigned int) sizeof(uuid->obj.node); i++)
		uuid->obj.node[i] = *in++;

	return UUID_RC_OK;
}


/* INTERNAL: check for valid UUID string representation syntax */
static int
uuid_isstr(const char *str,
	   size_t str_len)
{
	int i;
	const char *cp;

	/* example reference:
	   f81d4fae-7dec-11d0-a765-00a0c91e6bf6
	   012345678901234567890123456789012345
	   0         1         2         3       */
	if (str == NULL)
		return FALSE;
	if (str_len == 0)
		str_len = strlen(str);
	if (str_len < UUID_LEN_STR)
		return FALSE;
	for (i = 0, cp = str; i < UUID_LEN_STR; i++, cp++) {
		if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
			if (*cp == '-')
				continue;
			else
				return FALSE;
		}
		if (!isxdigit((int) (*cp)))
			return FALSE;
	}

	return TRUE;
}

/* INTERNAL: import UUID object from string representation */
static uuid_rc_t
uuid_import_str(uuid_t * uuid,
		const void *data_ptr,
		size_t data_len)
{
	guint16 tmp16;
	const char *cp;
	char hexbuf[3];
	const char *str;
	unsigned int i;

	/* sanity check argument(s) */
	if (uuid == NULL || data_ptr == NULL || data_len < UUID_LEN_STR)
		return UUID_RC_ARG;

	/* check for correct UUID string representation syntax */
	str = (const char *) data_ptr;
	if (!uuid_isstr(str, 0))
		return UUID_RC_ARG;

	/* parse hex values of "time" parts */
	uuid->obj.time_low = (guint32) strtoul(str, NULL, 16);
	uuid->obj.time_mid = (guint16) strtoul(str + 9, NULL, 16);
	uuid->obj.time_hi_and_version = (guint16) strtoul(str + 14, NULL, 16);

	/* parse hex values of "clock" parts */
	tmp16 = (guint16) strtoul(str + 19, NULL, 16);
	uuid->obj.clock_seq_low = (guint8) (tmp16 & 0xff);
	tmp16 >>= 8;
	uuid->obj.clock_seq_hi_and_reserved = (guint8) (tmp16 & 0xff);

	/* parse hex values of "node" part */
	cp = str + 24;
	hexbuf[2] = '\0';
	for (i = 0; i < (unsigned int) sizeof(uuid->obj.node); i++) {
		hexbuf[0] = *cp++;
		hexbuf[1] = *cp++;
		uuid->obj.node[i] = (guint8) strtoul(hexbuf, NULL, 16);
	}

	return UUID_RC_OK;
}

/* INTERNAL: export UUID object to string representation */
static uuid_rc_t
uuid_export_str(const uuid_t * uuid,
		uuid_str_t uuid_str)
{
	/* sanity check argument(s) */
	if (uuid == NULL)
		return UUID_RC_ARG;

	/* format UUID into string representation */
	if (g_snprintf(uuid_str,
		       UUID_LEN_STR + 1,
		       "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
		       (unsigned long) uuid->obj.time_low,
		       (unsigned int) uuid->obj.time_mid,
		       (unsigned int) uuid->obj.time_hi_and_version,
		       (unsigned int) uuid->obj.clock_seq_hi_and_reserved,
		       (unsigned int) uuid->obj.clock_seq_low,
		       (unsigned int) uuid->obj.node[0],
		       (unsigned int) uuid->obj.node[1],
		       (unsigned int) uuid->obj.node[2],
		       (unsigned int) uuid->obj.node[3],
		       (unsigned int) uuid->obj.node[4],
		       (unsigned int) uuid->obj.node[5]) != UUID_LEN_STR) {
		return UUID_RC_INT;
	}

	return UUID_RC_OK;
}

/* UUID importing */
static uuid_rc_t
uuid_import(uuid_t * uuid,
	    uuid_fmt_t fmt,
	    const void *data_ptr,
	    size_t data_len)
{
	uuid_rc_t rc;

	/* sanity check argument(s) */
	if (uuid == NULL || data_ptr == NULL)
		return UUID_RC_ARG;

	/* dispatch into format-specific functions */
	switch (fmt) {
	case UUID_FMT_BIN:
		rc = uuid_import_bin(uuid, data_ptr, data_len);
		break;
	case UUID_FMT_STR:
		rc = uuid_import_str(uuid, data_ptr, data_len);
		break;
	default:
		rc = UUID_RC_ARG;
	}

	return rc;
}

/* load UUID object with pre-defined value */
static uuid_rc_t
uuid_load(uuid_t * uuid,
	  const char *name)
{
	guint8 *uuid_octets;
	uuid_rc_t rc;
	unsigned int i;

	/* sanity check argument(s) */
	if (uuid == NULL || name == NULL)
		return UUID_RC_ARG;

	/* search for UUID in table */
	uuid_octets = NULL;
	for (i = 0; i < (unsigned int) sizeof(uuid_value_table) / sizeof(uuid_value_table[0]); i++) {
		if (strcmp(uuid_value_table[i].name, name) == 0) {
			uuid_octets = uuid_value_table[i].uuid;
			break;
		}
	}
	if (uuid_octets == NULL)
		return UUID_RC_ARG;

	/* import value into UUID object */
	if ((rc = uuid_import(uuid, UUID_FMT_BIN, uuid_octets, UUID_LEN_BIN)) != UUID_RC_OK)
		return rc;

	return UUID_RC_OK;
}


/* INTERNAL: brand UUID with version and variant */
static void
uuid_brand(uuid_t * uuid,
	   unsigned int version)
{
	/* set version (as given) */
	uuid->obj.time_hi_and_version &= BM_MASK(11, 0);
	uuid->obj.time_hi_and_version |= (guint16) BM_SHL(version, 12);

	/* set variant (always DCE 1.1 only) */
	uuid->obj.clock_seq_hi_and_reserved &= BM_MASK(5, 0);
	uuid->obj.clock_seq_hi_and_reserved |= BM_SHL(0x02, 6);

	return;
}

/* INTERNAL: generate UUID version 1: time, clock and node based */
static uuid_rc_t
uuid_make(uuid_t * uuid)
{
	struct timeval time_now;
#ifdef HAVE_NANOSLEEP
	struct timespec ts;
#else
	struct timeval tv;
#endif
	ui64_t t;
	ui64_t offset;
	ui64_t ov;
	guint16 clck;

	/*
	 *  GENERATE TIME
	 */

	/* determine current system time and sequence counter */
	for (;;) {
		/* determine current system time */
		if (gettimeofday(&time_now, NULL) == -1)
			return UUID_RC_SYS;

		/* check whether system time changed since last retrieve */
		if (!(time_now.tv_sec == uuid->time_last.tv_sec
		      && time_now.tv_usec == uuid->time_last.tv_usec)) {
			/* reset time sequence counter and continue */
			uuid->time_seq = 0;
			break;
		}

		/* until we are out of UUIDs per tick, increment
		   the time/tick sequence counter and continue */
		if (uuid->time_seq < UUIDS_PER_TICK) {
			uuid->time_seq++;
			break;
		}

		/* stall the UUID generation until the system clock (which
		   has a gettimeofday(2) resolution of 1us) catches up */
#ifdef HAVE_NANOSLEEP
		/* sleep for 500ns (1/2us) */
		ts.tv_sec = 0;
		ts.tv_nsec = 500;
		nanosleep(&ts, NULL);
#else
		/* sleep for 1000ns (1us) */
		tv.tv_sec = 0;
		tv.tv_usec = 1;
		select(0, NULL, NULL, NULL, &tv);
#endif
	}

	/* convert from timeval (sec,usec) to OSSP ui64 (100*nsec) format */
	t = brutus_ui64_n2i((unsigned long) time_now.tv_sec);
	t = brutus_ui64_muln(t, 1000000, NULL);
	t = brutus_ui64_addn(t, (int) time_now.tv_usec, NULL);
	t = brutus_ui64_muln(t, 10, NULL);

	/* adjust for offset between UUID and Unix Epoch time */
	offset = brutus_ui64_s2i(UUID_TIMEOFFSET, NULL, 16);
	t = brutus_ui64_add(t, offset, NULL);

	/* compensate for low resolution system clock by adding
	   the time/tick sequence counter */
	if (uuid->time_seq > 0)
		t = brutus_ui64_addn(t, (int) uuid->time_seq, NULL);

	/* store the 60 LSB of the time in the UUID */
	t = brutus_ui64_rol(t, 16, &ov);
	uuid->obj.time_hi_and_version = (guint16) (brutus_ui64_i2n(ov) & 0x00000fff);	/* 12 of 16 bit only! */
	t = brutus_ui64_rol(t, 16, &ov);
	uuid->obj.time_mid = (guint16) (brutus_ui64_i2n(ov) & 0x0000ffff);	/* all 16 bit */
	t = brutus_ui64_rol(t, 32, &ov);
	uuid->obj.time_low = (guint32) (brutus_ui64_i2n(ov) & 0xffffffff);	/* all 32 bit */

	/*
	 *  GENERATE CLOCK
	 */

	/* retrieve current clock sequence */
	clck = ((uuid->obj.clock_seq_hi_and_reserved & BM_MASK(5, 0)) << 8) + uuid->obj.clock_seq_low;

	/* generate new random clock sequence (initially or if the
	   time has stepped backwards) or else just increase it */
	if (!clck
	    || (time_now.tv_sec < uuid->time_last.tv_sec
		|| (time_now.tv_sec == uuid->time_last.tv_sec
		    && time_now.tv_usec < uuid->time_last.tv_usec))) {
		if (brutus_prng_data(uuid->prng, (void *) &clck, sizeof(clck)) != PRNG_RC_OK)
			return UUID_RC_INT;
	} else
		clck++;
	clck %= BM_POW2(14);

	/* store back new clock sequence */
	uuid->obj.clock_seq_hi_and_reserved = (uuid->obj.clock_seq_hi_and_reserved & BM_MASK(7, 6)) | (guint8) ((clck >> 8) & 0xff);
	uuid->obj.clock_seq_low = (guint8) (clck & 0xff);

	/*
	 *  GENERATE NODE
	 */

	memcpy(uuid->obj.node, uuid->mac, sizeof(uuid->mac));

	/*
	 *  FINISH
	 */

	/* remember current system time for next iteration */
	uuid->time_last.tv_sec = time_now.tv_sec;
	uuid->time_last.tv_usec = time_now.tv_usec;

	/* brand with version and variant */
	uuid_brand(uuid, 1);

	return UUID_RC_OK;
}


/* create UUID object */
static uuid_rc_t
uuid_create(uuid_t ** uuid)
{
	uuid_t *obj;

	/* argument sanity check */
	if (uuid == NULL)
		return UUID_RC_ARG;

	/* allocate UUID object */
	if ((obj = (uuid_t *) malloc(sizeof(uuid_t))) == NULL)
		return UUID_RC_MEM;

	/* create PRNG, MD5 and SHA1 sub-objects */
	if (brutus_prng_create(&obj->prng) != PRNG_RC_OK) {
		free(obj);
		return UUID_RC_INT;
	}
	if (brutus_md5_create(&obj->md5) != MD5_RC_OK) {
		(void) brutus_prng_destroy(obj->prng);
		free(obj);
		return UUID_RC_INT;
	}
	if (brutus_sha1_create(&obj->sha1) != SHA1_RC_OK) {
		(void) brutus_md5_destroy(obj->md5);
		(void) brutus_prng_destroy(obj->prng);
		free(obj);
		return UUID_RC_INT;
	}

	/* set UUID object initially to "Nil UUID" */
	if (uuid_load(obj, "nil") != UUID_RC_OK) {
		(void) brutus_sha1_destroy(obj->sha1);
		(void) brutus_md5_destroy(obj->md5);
		(void) brutus_prng_destroy(obj->prng);
		free(obj);
		return UUID_RC_INT;
	}

	/* resolve MAC address for insertion into node field of UUIDs */
	if (!brutus_mac_address((unsigned char *) (obj->mac), sizeof(obj->mac))) {
		memset(obj->mac, 0, sizeof(obj->mac));
		obj->mac[0] = BM_OCTET(1, 0, 0, 0, 0, 0, 0, 0);
	}

	/* initialize time attributes */
	obj->time_last.tv_sec = 0;
	obj->time_last.tv_usec = 0;
	obj->time_seq = 0;

	/* store result object */
	*uuid = obj;

	return UUID_RC_OK;
}

int
brutus_uuid(uuid_str_t uuid_str)
{
	uuid_t *uuid;
	uuid_rc_t rc;

	memset((void*)uuid_str, '\0', sizeof(uuid_str));

	if ((rc = uuid_create(&uuid)) != UUID_RC_OK)
		return 1;
	if ((rc = uuid_make(uuid)) != UUID_RC_OK)
		return 1;
	if ((rc = uuid_export_str(uuid, uuid_str)) != UUID_RC_OK)
		return 1;
	if ((rc = uuid_destroy(uuid)) != UUID_RC_OK)
		return 1;

	return 0;
}