"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;
}