summaryrefslogtreecommitdiff
path: root/source4/heimdal/lib/hcrypto/rnd_keys.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/heimdal/lib/hcrypto/rnd_keys.c')
-rw-r--r--source4/heimdal/lib/hcrypto/rnd_keys.c509
1 files changed, 509 insertions, 0 deletions
diff --git a/source4/heimdal/lib/hcrypto/rnd_keys.c b/source4/heimdal/lib/hcrypto/rnd_keys.c
new file mode 100644
index 0000000000..a035b890b8
--- /dev/null
+++ b/source4/heimdal/lib/hcrypto/rnd_keys.c
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 1995, 1996, 1997, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS 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 INSTITUTE OR 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+
+RCSID("$Id: rnd_keys.c 17445 2006-05-05 10:37:46Z lha $");
+#endif
+
+#ifdef KRB5
+#include <krb5-types.h>
+#endif
+#include <des.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#elif defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+/*
+ * Generate "random" data by checksumming a file.
+ *
+ * Returns -1 if there were any problems with permissions or I/O
+ * errors.
+ */
+static
+int
+sumFile (const char *name, int len, void *res)
+{
+ uint32_t sum[2] = { 0, 0 };
+ uint32_t buf[1024*2];
+ int fd, i;
+
+ fd = open (name, 0);
+ if (fd < 0)
+ return -1;
+
+ while (len > 0)
+ {
+ int n = read(fd, buf, sizeof(buf));
+ if (n < 0)
+ {
+ close(fd);
+ return n;
+ }
+ for (i = 0; i < (n/sizeof(buf[0])); i++)
+ {
+ sum[0] += buf[i];
+ i++;
+ sum[1] += buf[i];
+ }
+ len -= n;
+ }
+ close (fd);
+ memcpy (res, &sum, sizeof(sum));
+ return 0;
+}
+
+#if 0
+static
+int
+md5sumFile (const char *name, int len, int32_t sum[4])
+{
+ int32_t buf[1024*2];
+ int fd, cnt;
+ struct md5 md5;
+
+ fd = open (name, 0);
+ if (fd < 0)
+ return -1;
+
+ md5_init(&md5);
+ while (len > 0)
+ {
+ int n = read(fd, buf, sizeof(buf));
+ if (n < 0)
+ {
+ close(fd);
+ return n;
+ }
+ md5_update(&md5, buf, n);
+ len -= n;
+ }
+ md5_finito(&md5, (unsigned char *)sum);
+ close (fd);
+ return 0;
+}
+#endif
+
+/*
+ * Create a sequence of random 64 bit blocks.
+ * The sequence is indexed with a long long and
+ * based on an initial des key used as a seed.
+ */
+static DES_key_schedule sequence_seed;
+static uint32_t sequence_index[2];
+
+/*
+ * Random number generator based on ideas from truerand in cryptolib
+ * as described on page 424 in Applied Cryptography 2 ed. by Bruce
+ * Schneier.
+ */
+
+static volatile int counter;
+static volatile unsigned char *gdata; /* Global data */
+static volatile int igdata; /* Index into global data */
+static int gsize;
+
+#if !defined(WIN32) && !defined(__EMX__) && !defined(__OS2__) && !defined(__CYGWIN32__)
+/* Visual C++ 4.0 (Windows95/NT) */
+
+static
+RETSIGTYPE
+sigALRM(int sig)
+{
+ if (igdata < gsize)
+ gdata[igdata++] ^= counter & 0xff;
+
+#ifndef HAVE_SIGACTION
+ signal(SIGALRM, sigALRM); /* Reinstall SysV signal handler */
+#endif
+ SIGRETURN(0);
+}
+
+#endif
+
+#if !defined(HAVE_RANDOM) && defined(HAVE_RAND)
+#ifndef srandom
+#define srandom srand
+#endif
+#ifndef random
+#define random rand
+#endif
+#endif
+
+#if !defined(HAVE_SETITIMER) || defined(WIN32) || defined(__EMX__) || defined(__OS2__) || defined(__CYGWIN32__)
+static void
+des_not_rand_data(unsigned char *data, int size)
+{
+ int i;
+
+ srandom (time (NULL));
+
+ for(i = 0; i < size; ++i)
+ data[i] ^= random() % 0x100;
+}
+#endif
+
+#if !defined(WIN32) && !defined(__EMX__) && !defined(__OS2__) && !defined(__CYGWIN32__)
+
+#ifndef HAVE_SETITIMER
+static void
+pacemaker(struct timeval *tv)
+{
+ fd_set fds;
+ pid_t pid;
+ pid = getppid();
+ while(1){
+ FD_ZERO(&fds);
+ FD_SET(0, &fds);
+ select(1, &fds, NULL, NULL, tv);
+ kill(pid, SIGALRM);
+ }
+}
+#endif
+
+#ifdef HAVE_SIGACTION
+/* XXX ugly hack, should perhaps use function from roken */
+static RETSIGTYPE
+(*fake_signal(int sig, RETSIGTYPE (*f)(int)))(int)
+{
+ struct sigaction sa, osa;
+ sa.sa_handler = f;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(sig, &sa, &osa);
+ return osa.sa_handler;
+}
+#define signal(S, F) fake_signal((S), (F))
+#endif
+
+/*
+ * Generate size bytes of "random" data using timed interrupts.
+ * It takes about 40ms/byte random data.
+ * It's not neccessary to be root to run it.
+ */
+void
+DES_rand_data(void *outdata, int size)
+{
+ unsigned char *data = outdata;
+ struct itimerval tv, otv;
+ RETSIGTYPE (*osa)(int);
+ int i, j;
+#ifndef HAVE_SETITIMER
+ RETSIGTYPE (*ochld)(int);
+ pid_t pid;
+#endif
+ const char *rnd_devices[] = {"/dev/random",
+ "/dev/srandom",
+ "/dev/urandom",
+ "/dev/arandom",
+ NULL};
+ const char **p;
+
+ for(p = rnd_devices; *p; p++) {
+ int fd = open(*p, O_RDONLY | O_NDELAY);
+
+ if(fd >= 0 && read(fd, data, size) == size) {
+ close(fd);
+ return;
+ }
+ close(fd);
+ }
+
+ /* Paranoia? Initialize data from /dev/mem if we can read it. */
+ if (size >= 8)
+ sumFile("/dev/mem", (1024*1024*2), data);
+
+ gdata = data;
+ gsize = size;
+ igdata = 0;
+
+ osa = signal(SIGALRM, sigALRM);
+
+ /* Start timer */
+ tv.it_value.tv_sec = 0;
+ tv.it_value.tv_usec = 10 * 1000; /* 10 ms */
+ tv.it_interval = tv.it_value;
+#ifdef HAVE_SETITIMER
+ setitimer(ITIMER_REAL, &tv, &otv);
+#else
+ ochld = signal(SIGCHLD, SIG_IGN);
+ pid = fork();
+ if(pid == -1){
+ signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL);
+ des_not_rand_data(data, size);
+ return;
+ }
+ if(pid == 0)
+ pacemaker(&tv.it_interval);
+#endif
+
+ for(i = 0; i < 4; i++) {
+ for (igdata = 0; igdata < size;) /* igdata++ in sigALRM */
+ counter++;
+ for (j = 0; j < size; j++) /* Only use 2 bits each lap */
+ gdata[j] = (gdata[j]>>2) | (gdata[j]<<6);
+ }
+#ifdef HAVE_SETITIMER
+ setitimer(ITIMER_REAL, &otv, 0);
+#else
+ kill(pid, SIGKILL);
+ while(waitpid(pid, NULL, 0) != pid);
+ signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL);
+#endif
+ signal(SIGALRM, osa != SIG_ERR ? osa : SIG_DFL);
+}
+#else
+void
+DES_rand_data(unsigned char *p, int s)
+{
+ des_not_rand_data (p, s);
+}
+#endif
+
+void
+DES_generate_random_block(DES_cblock *block)
+{
+ DES_rand_data((unsigned char *)block, sizeof(*block));
+}
+
+#define DES_rand_data_key hc_DES_rand_data_key
+
+void
+DES_rand_data_key(DES_cblock *key);
+
+/*
+ * Generate a "random" DES key.
+ */
+void
+DES_rand_data_key(DES_cblock *key)
+{
+ unsigned char data[8];
+ DES_key_schedule sched;
+ do {
+ DES_rand_data(data, sizeof(data));
+ DES_rand_data((unsigned char*)key, sizeof(DES_cblock));
+ DES_set_odd_parity(key);
+ DES_set_key(key, &sched);
+ DES_ecb_encrypt(&data, key, &sched, DES_ENCRYPT);
+ memset(&data, 0, sizeof(data));
+ memset(&sched, 0, sizeof(sched));
+ DES_set_odd_parity(key);
+ } while(DES_is_weak_key(key));
+}
+
+/*
+ * Generate "random" data by checksumming /dev/mem
+ *
+ * It's neccessary to be root to run it. Returns -1 if there were any
+ * problems with permissions.
+ */
+
+#define DES_mem_rand8 hc_DES_mem_rand8
+
+int
+DES_mem_rand8(unsigned char *data);
+
+int
+DES_mem_rand8(unsigned char *data)
+{
+ return 1;
+}
+
+/*
+ * In case the generator does not get initialized use this as fallback.
+ */
+static int initialized;
+
+static void
+do_initialize(void)
+{
+ DES_cblock default_seed;
+ do {
+ DES_generate_random_block(&default_seed);
+ DES_set_odd_parity(&default_seed);
+ } while (DES_is_weak_key(&default_seed));
+ DES_init_random_number_generator(&default_seed);
+}
+
+#define zero_long_long(ll) do { ll[0] = ll[1] = 0; } while (0)
+
+#define incr_long_long(ll) do { if (++ll[0] == 0) ++ll[1]; } while (0)
+
+#define set_sequence_number(ll) \
+memcpy((char *)sequence_index, (ll), sizeof(sequence_index));
+
+/*
+ * Set the sequnce number to this value (a long long).
+ */
+void
+DES_set_sequence_number(void *ll)
+{
+ set_sequence_number(ll);
+}
+
+/*
+ * Set the generator seed and reset the sequence number to 0.
+ */
+void
+DES_set_random_generator_seed(DES_cblock *seed)
+{
+ DES_set_key(seed, &sequence_seed);
+ zero_long_long(sequence_index);
+ initialized = 1;
+}
+
+/*
+ * Generate a sequence of random des keys
+ * using the random block sequence, fixup
+ * parity and skip weak keys.
+ */
+int
+DES_new_random_key(DES_cblock *key)
+{
+ if (!initialized)
+ do_initialize();
+
+ do {
+ DES_ecb_encrypt((DES_cblock *) sequence_index,
+ key,
+ &sequence_seed,
+ DES_ENCRYPT);
+ incr_long_long(sequence_index);
+ /* random key must have odd parity and not be weak */
+ DES_set_odd_parity(key);
+ } while (DES_is_weak_key(key));
+ return(0);
+}
+
+/*
+ * des_init_random_number_generator:
+ *
+ * Initialize the sequence of random 64 bit blocks. The input seed
+ * can be a secret key since it should be well hidden and is also not
+ * kept.
+ *
+ */
+void
+DES_init_random_number_generator(DES_cblock *seed)
+{
+ struct timeval now;
+ DES_cblock uniq;
+ DES_cblock new_key;
+
+ gettimeofday(&now, (struct timezone *)0);
+ DES_generate_random_block(&uniq);
+
+ /* Pick a unique random key from the shared sequence. */
+ DES_set_random_generator_seed(seed);
+ set_sequence_number((unsigned char *)&uniq);
+ DES_new_random_key(&new_key);
+
+ /* Select a new nonshared sequence, */
+ DES_set_random_generator_seed(&new_key);
+
+ /* and use the current time to pick a key for the new sequence. */
+ set_sequence_number((unsigned char *)&now);
+ DES_new_random_key(&new_key);
+ DES_set_random_generator_seed(&new_key);
+}
+
+/* This is for backwards compatibility. */
+void
+DES_random_key(DES_cblock *ret)
+{
+ DES_new_random_key(ret);
+}
+
+#ifdef TESTRUN
+int
+main()
+{
+ unsigned char data[8];
+ int i;
+
+ while (1)
+ {
+ if (sumFile("/dev/mem", (1024*1024*8), data) != 0)
+ { perror("sumFile"); exit(1); }
+ for (i = 0; i < 8; i++)
+ printf("%02x", data[i]);
+ printf("\n");
+ }
+}
+#endif
+
+#ifdef TESTRUN2
+int
+main()
+{
+ DES_cblock data;
+ int i;
+
+ while (1)
+ {
+ do_initialize();
+ DES_random_key(data);
+ for (i = 0; i < 8; i++)
+ printf("%02x", data[i]);
+ printf("\n");
+ }
+}
+#endif