summaryrefslogtreecommitdiffstats
path: root/src/lib/crypto/builtin/pbkdf2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/crypto/builtin/pbkdf2.c')
-rw-r--r--src/lib/crypto/builtin/pbkdf2.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/src/lib/crypto/builtin/pbkdf2.c b/src/lib/crypto/builtin/pbkdf2.c
new file mode 100644
index 000000000..d897e9a71
--- /dev/null
+++ b/src/lib/crypto/builtin/pbkdf2.c
@@ -0,0 +1,265 @@
+/*
+ * lib/crypto/pbkdf2.c
+ *
+ * Copyright 2002, 2008 by the Massachusetts Institute of Technology.
+ * 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 M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Implementation of PBKDF2 from RFC 2898.
+ * Not currently used; likely to be used when we get around to AES support.
+ */
+
+#include <ctype.h>
+#include "k5-int.h"
+#include "hash_provider.h"
+
+/* Not exported, for now. */
+static krb5_error_code
+krb5int_pbkdf2 (krb5_error_code (*prf)(krb5_keyblock *, krb5_data *,
+ krb5_data *),
+ size_t hlen, const krb5_data *pass, const krb5_data *salt,
+ unsigned long count, const krb5_data *output);
+
+static int debug_hmac = 0;
+
+static void printd (const char *descr, krb5_data *d) {
+ unsigned int i, j;
+ const int r = 16;
+
+ printf("%s:", descr);
+
+ for (i = 0; i < d->length; i += r) {
+ printf("\n %04x: ", i);
+ for (j = i; j < i + r && j < d->length; j++)
+ printf(" %02x", 0xff & d->data[j]);
+ for (; j < i + r; j++)
+ printf(" ");
+ printf(" ");
+ for (j = i; j < i + r && j < d->length; j++) {
+ int c = 0xff & d->data[j];
+ printf("%c", isprint(c) ? c : '.');
+ }
+ }
+ printf("\n");
+}
+static void printk(const char *descr, krb5_keyblock *k) {
+ krb5_data d;
+ d.data = (char *) k->contents;
+ d.length = k->length;
+ printd(descr, &d);
+}
+
+static krb5_error_code
+F(char *output, char *u_tmp1, char *u_tmp2,
+ krb5_error_code (*prf)(krb5_keyblock *, krb5_data *, krb5_data *),
+ size_t hlen,
+ const krb5_data *pass, const krb5_data *salt,
+ unsigned long count, int i)
+{
+ unsigned char ibytes[4];
+ size_t tlen;
+ unsigned int j, k;
+ krb5_keyblock pdata;
+ krb5_data sdata;
+ krb5_data out;
+ krb5_error_code err;
+
+ pdata.contents = pass->data;
+ pdata.length = pass->length;
+
+#if 0
+ printf("F(i=%d, count=%lu, pass=%d:%s)\n", i, count,
+ pass->length, pass->data);
+ printk("F password", &pdata);
+#endif
+
+ /* Compute U_1. */
+ store_32_be(i, ibytes);
+
+ tlen = salt->length;
+ memcpy(u_tmp2, salt->data, tlen);
+ memcpy(u_tmp2 + tlen, ibytes, 4);
+ tlen += 4;
+ sdata.data = u_tmp2;
+ sdata.length = tlen;
+
+#if 0
+ printd("initial salt", &sdata);
+#endif
+
+ out.data = u_tmp1;
+ out.length = hlen;
+
+#if 0
+ printf("F: computing hmac #1 (U_1) with %s\n", pdata.contents);
+#endif
+ err = (*prf)(&pdata, &sdata, &out);
+ if (err)
+ return err;
+#if 0
+ printd("F: prf return value", &out);
+#endif
+ memcpy(output, u_tmp1, hlen);
+
+ /* Compute U_2, .. U_c. */
+ sdata.length = hlen;
+ for (j = 2; j <= count; j++) {
+#if 0
+ printf("F: computing hmac #%d (U_%d)\n", j, j);
+#endif
+ memcpy(u_tmp2, u_tmp1, hlen);
+ err = (*prf)(&pdata, &sdata, &out);
+ if (err)
+ return err;
+#if 0
+ printd("F: prf return value", &out);
+#endif
+ /* And xor them together. */
+ for (k = 0; k < hlen; k++)
+ output[k] ^= u_tmp1[k];
+#if 0
+ printf("F: xor result:\n");
+ for (k = 0; k < hlen; k++)
+ printf(" %02x", 0xff & output[k]);
+ printf("\n");
+#endif
+ }
+ return 0;
+}
+
+static krb5_error_code
+krb5int_pbkdf2 (krb5_error_code (*prf)(krb5_keyblock *, krb5_data *,
+ krb5_data *),
+ size_t hlen,
+ const krb5_data *pass, const krb5_data *salt,
+ unsigned long count, const krb5_data *output)
+{
+ int l, r, i;
+ char *utmp1, *utmp2;
+ char utmp3[20]; /* XXX length shouldn't be hardcoded! */
+
+ if (output->length == 0 || hlen == 0)
+ abort();
+ /* Step 1 & 2. */
+ if (output->length / hlen > 0xffffffff)
+ abort();
+ /* Step 2. */
+ l = (output->length + hlen - 1) / hlen;
+ r = output->length - (l - 1) * hlen;
+
+ utmp1 = /*output + dklen; */ malloc(hlen);
+ if (utmp1 == NULL)
+ return ENOMEM;
+ utmp2 = /*utmp1 + hlen; */ malloc(salt->length + 4 + hlen);
+ if (utmp2 == NULL) {
+ free(utmp1);
+ return ENOMEM;
+ }
+
+ /* Step 3. */
+ for (i = 1; i <= l; i++) {
+#if 0
+ int j;
+#endif
+ krb5_error_code err;
+ char *out;
+
+ if (i == l)
+ out = utmp3;
+ else
+ out = output->data + (i-1) * hlen;
+ err = F(out, utmp1, utmp2, prf, hlen, pass, salt, count, i);
+ if (err) {
+ free(utmp1);
+ free(utmp2);
+ return err;
+ }
+ if (i == l)
+ memcpy(output->data + (i-1) * hlen, utmp3,
+ output->length - (i-1) * hlen);
+
+#if 0
+ printf("after F(%d), @%p:\n", i, output->data);
+ for (j = (i-1) * hlen; j < i * hlen; j++)
+ printf(" %02x", 0xff & output->data[j]);
+ printf ("\n");
+#endif
+ }
+ free(utmp1);
+ free(utmp2);
+ return 0;
+}
+
+static krb5_error_code hmac1(const struct krb5_hash_provider *h,
+ krb5_keyblock *key, krb5_data *in, krb5_data *out)
+{
+ char tmp[40];
+ size_t blocksize, hashsize;
+ krb5_error_code err;
+ krb5_keyblock k;
+
+ k = *key;
+ key = &k;
+ if (debug_hmac)
+ printk(" test key", key);
+ blocksize = h->blocksize;
+ hashsize = h->hashsize;
+ if (hashsize > sizeof(tmp))
+ abort();
+ if (key->length > blocksize) {
+ krb5_data d, d2;
+ d.data = (char *) key->contents;
+ d.length = key->length;
+ d2.data = tmp;
+ d2.length = hashsize;
+ err = h->hash (1, &d, &d2);
+ if (err)
+ return err;
+ key->length = d2.length;
+ key->contents = (krb5_octet *) d2.data;
+ if (debug_hmac)
+ printk(" pre-hashed key", key);
+ }
+ if (debug_hmac)
+ printd(" hmac input", in);
+ err = krb5_hmac(h, key, 1, in, out);
+ if (err == 0 && debug_hmac)
+ printd(" hmac output", out);
+ return err;
+}
+
+static krb5_error_code
+foo(krb5_keyblock *pass, krb5_data *salt, krb5_data *out)
+{
+ krb5_error_code err;
+
+ memset(out->data, 0, out->length);
+ err = hmac1 (&krb5int_hash_sha1, pass, salt, out);
+ return err;
+}
+
+krb5_error_code
+krb5int_pbkdf2_hmac_sha1 (const krb5_data *out, unsigned long count,
+ const krb5_data *pass, const krb5_data *salt)
+{
+ return krb5int_pbkdf2 (foo, 20, pass, salt, count, out);
+}