summaryrefslogtreecommitdiffstats
path: root/src/lib/crypto/prng.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/crypto/prng.c')
-rw-r--r--src/lib/crypto/prng.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/src/lib/crypto/prng.c b/src/lib/crypto/prng.c
new file mode 100644
index 0000000000..2d4f6647d4
--- /dev/null
+++ b/src/lib/crypto/prng.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "k5-int.h"
+#include "enc_provider.h"
+
+/* This random number generator is a feedback generator based on a
+ block cipher. It uses DES by default, since it guaranteed to be
+ present in the system, but can be changed. As new seed data comes
+ in, the old state is folded with the new seed into new state. Each
+ time random bytes are requested, the seed is used as a key and
+ cblock, and the encryption is used as the output. The output is
+ fed back as new seed data, as described above. */
+
+/* this can be replaced with another encryption provider, since
+ everything below uses it abstractly */
+
+struct krb5_enc_provider *enc = &krb5_enc_des;
+
+/* XXX state. Should it be in krb5_context? */
+
+static int inited = 0;
+static size_t blocksize, keybytes, keylength;
+static int random_count;
+/* keybytes | state-block | encblock | key | new-keybytes | new-state-block */
+static unsigned char *random_state;
+#define STATE (random_state)
+#define STATEKEY (STATE)
+#define STATEBLOCK (STATEKEY+keybytes)
+#define STATESIZE (keybytes+blocksize)
+#define OUTPUT (STATE)
+#define OUTPUTSIZE (STATESIZE+blocksize)
+#define RANDBLOCK (STATEBLOCK+blocksize)
+#define KEYCONTENTS (RANDBLOCK+blocksize)
+#define NEWSTATE (KEYCONTENTS+keylength)
+#define ALLSTATESIZE (keybytes+blocksize*2+keylength+keybytes+blocksize)
+
+krb5_error_code
+krb5_c_random_seed(krb5_context context, krb5_data *data)
+{
+ unsigned char *fold_input;
+
+ if (inited == 0) {
+ /* this does a bunch of malloc'ing up front, so that
+ generating random keys doesn't have to malloc, so it can't
+ fail. seeding still malloc's, but that's less common. */
+
+ enc->block_size(&blocksize);
+ enc->keysize(&keybytes, &keylength);
+ if ((random_state = (unsigned char *) malloc(ALLSTATESIZE)) == NULL)
+ return(ENOMEM);
+ random_count = 0;
+ inited = 1;
+
+ krb5_nfold(data->length*8, data->data, STATESIZE*8, STATE);
+
+ return(0);
+ }
+
+ if ((fold_input =
+ (unsigned char *) malloc(data->length+STATESIZE)) == NULL)
+ return(ENOMEM);
+
+ memcpy(fold_input, data->data, data->length);
+ memcpy(fold_input+data->length, STATE, STATESIZE);
+
+ krb5_nfold((data->length+STATESIZE)*8, fold_input,
+ STATESIZE*8, STATE);
+ free(fold_input);
+ return(0);
+}
+
+krb5_error_code
+krb5_c_random_make_octets(krb5_context context, krb5_data *data)
+{
+ krb5_error_code ret;
+ krb5_data data1, data2;
+ krb5_keyblock key;
+ int bytes;
+
+ if (inited == 0) {
+ /* i need some entropy. I'd use the current time and pid, but
+ that could cause portability problems. */
+ abort();
+ }
+
+ bytes = 0;
+
+ while (bytes < data->length) {
+ if (random_count == 0) {
+ /* set up random krb5_data, and key to be filled in */
+ data1.length = keybytes;
+ data1.data = STATEKEY;
+ key.length = keylength;
+ key.contents = KEYCONTENTS;
+
+ /* fill it in */
+ if (ret = ((*(enc->make_key))(&data1, &key)))
+ return(ret);
+
+ /* encrypt the block */
+ data1.length = blocksize;
+ data1.data = STATEBLOCK;
+ data2.length = blocksize;
+ data2.data = RANDBLOCK;
+ if (ret = ((*(enc->encrypt))(&key, NULL, &data1, &data2)))
+ return(ret);
+
+ /* fold the new output back into the state */
+
+ krb5_nfold(OUTPUTSIZE*8, OUTPUT, STATESIZE*8, NEWSTATE);
+ memcpy(STATE, NEWSTATE, STATESIZE);
+
+ random_count = blocksize;
+ }
+
+ if ((data->length - bytes) <= random_count) {
+ memcpy(data->data + bytes, RANDBLOCK+(blocksize-random_count),
+ data->length - bytes);
+ random_count -= (data->length - bytes);
+ break;
+ }
+
+ memcpy(data->data + bytes, RANDBLOCK+(blocksize - random_count),
+ random_count);
+
+ bytes += random_count;
+ random_count = 0;
+ }
+
+ return(0);
+}