* pbkdf2.c, t_hmac.c, t_pkcs5.c: New files
authorKen Raeburn <raeburn@mit.edu>
Thu, 10 Oct 2002 02:41:52 +0000 (02:41 +0000)
committerKen Raeburn <raeburn@mit.edu>
Thu, 10 Oct 2002 02:41:52 +0000 (02:41 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@14916 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/crypto/ChangeLog
src/lib/crypto/pbkdf2.c [new file with mode: 0644]
src/lib/crypto/t_hmac.c [new file with mode: 0644]
src/lib/crypto/t_pkcs5.c [new file with mode: 0644]

index 2fc031488f9313fe4ef270070767f3b1251ecb1e..15efc059d5178d761d1fd7d63a674b5cd2c645f4 100644 (file)
@@ -1,3 +1,7 @@
+2002-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+       * pbkdf2.c, t_hmac.c, t_pkcs5.c: New files.
+
 2002-08-29  Ken Raeburn  <raeburn@mit.edu>
 
        * Makefile.in: Revert $(S)=>/ change, for Windows support.
diff --git a/src/lib/crypto/pbkdf2.c b/src/lib/crypto/pbkdf2.c
new file mode 100644 (file)
index 0000000..b5d0bfc
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * lib/crypto/pbkdf2.c
+ *
+ * Copyright 2002 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"
+
+/* for k5-int.h */
+extern krb5_error_code
+krb5int_pbkdf2 (krb5_error_code (*prf)(krb5_keyblock *, krb5_data *,
+                                      krb5_data *),
+               size_t hlen, const char *pass, const char *salt,
+               unsigned long count, size_t dklen, char *output);
+extern krb5_error_code
+krb5int_pbkdf2_hmac_sha1 (char *out, size_t len, unsigned long count,
+                         const char *pass, const char *salt);
+extern krb5_error_code
+krb5int_pbkdf2_hmac_sha1_128 (char *out, unsigned long count,
+                             const char *pass, const char *salt);
+extern krb5_error_code
+krb5int_pbkdf2_hmac_sha1_256 (char *out, unsigned long count,
+                             const char *pass, const char *salt);
+
+
+
+
+static int debug_hmac = 0;
+
+static void printd (const char *descr, krb5_data *d) {
+    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 = 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 char *pass, const char *salt,
+  unsigned long count, int i)
+{
+    unsigned char ibytes[4];
+    size_t tlen;
+    int j, k;
+    krb5_keyblock pdata;
+    krb5_data sdata;
+    krb5_data out;
+    krb5_error_code err;
+
+    pdata.contents = pass;
+    pdata.length = strlen(pass);
+
+#if 0
+    printf("F(i=%d, count=%lu, pass=%s)\n", i, count, pass);
+    printk("F password", &pdata);
+#endif
+
+    /* Compute U_1.  */
+    ibytes[3] = i & 0xff;
+    ibytes[2] = (i >> 8) & 0xff;
+    ibytes[1] = (i >> 16) & 0xff;
+    ibytes[0] = (i >> 24) & 0xff;
+
+    tlen = strlen(salt);
+    memcpy(u_tmp2, salt, 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;
+}
+
+krb5_error_code
+krb5int_pbkdf2 (krb5_error_code (*prf)(krb5_keyblock *, krb5_data *,
+                                      krb5_data *),
+               size_t hlen,
+               const char *pass, const char *salt,
+               unsigned long count, size_t dklen,
+               char *output)
+{
+    int l, r, i;
+    char *utmp1, *utmp2;
+
+    if (dklen == 0 || hlen == 0)
+       abort();
+    /* Step 1 & 2.  */
+    if (dklen / hlen > 0xffffffff)
+       abort();
+    /* Step 2.  */
+    l = (dklen + hlen - 1) / hlen;
+    r = dklen - (l - 1) * hlen;
+
+#if 0
+    output = malloc(dklen + hlen + strlen(salt) + 4 + hlen);
+    if (output == NULL) {
+       abort();
+    }
+#endif
+    utmp1 = /*output + dklen; */ malloc(hlen);
+    utmp2 = /*utmp1 + hlen; */ malloc(strlen(salt) + 4 + hlen);
+
+    /* Step 3.  */
+    for (i = 1; i <= l; i++) {
+#if 0
+       int j;
+#endif
+       krb5_error_code err;
+
+       err = F(output + (i-1) * hlen, utmp1, utmp2, prf, hlen,
+               pass, salt, count, i);
+       if (err)
+           return err;
+
+#if 0
+       printf("after F(%d), @%p:\n", i, output);
+       for (j = (i-1) * hlen; j < i * hlen; j++)
+           printf(" %02x", 0xff & output[j]);
+       printf ("\n");
+#endif
+    }
+    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;
+
+    if (debug_hmac)
+       printk(" test key", key);
+    h->block_size(&blocksize);
+    h->hash_size(&hashsize);
+    if (hashsize > sizeof(tmp))
+       abort();
+    if (key->length > blocksize) {
+       krb5_data d, d2;
+       d.data = 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 = 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);
+    if (err)
+       com_err("foo", err, "computing hmac");
+    return err;
+}
+
+krb5_error_code
+krb5int_pbkdf2_hmac_sha1 (char *out, size_t len, unsigned long count,
+                         const char *pass, const char *salt)
+{
+    return krb5int_pbkdf2 (foo, 20, pass, salt, count, len, out);
+}
+
+krb5_error_code
+krb5int_pbkdf2_hmac_sha1_128 (char *out, unsigned long count,
+                             const char *pass, const char *salt)
+{
+    return krb5int_pbkdf2 (foo, 20, pass, salt, count, 16, out);
+}
+
+krb5_error_code
+krb5int_pbkdf2_hmac_sha1_256 (char *out, unsigned long count,
+                             const char *pass, const char *salt)
+{
+    return krb5int_pbkdf2 (foo, 20, pass, salt, count, 32, out);
+}
diff --git a/src/lib/crypto/t_hmac.c b/src/lib/crypto/t_hmac.c
new file mode 100644 (file)
index 0000000..69ca42a
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * lib/crypto/t_hmac.c
+ *
+ * Copyright 2001,2002 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.
+ * 
+ *
+ * Test vectors for HMAC-MD5 and HMAC-SHA1 (placeholder only).
+ * Tests taken from RFC 2202.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <krb5.h>
+#include "hash_provider.h"
+
+#define ASIZE(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
+
+const char *whoami;
+
+static void printhex (size_t len, const char *p) {
+    while (len--)
+       printf ("%02x", 0xff & *p++);
+}
+
+static void printstringhex (const char *p) { printhex (strlen (p), p); }
+
+static void printdata (krb5_data *d) { printhex (d->length, d->data); }
+
+static void printkey (krb5_keyblock *k) { printhex (k->length, k->contents); }
+
+static void keyToData (krb5_keyblock *k, krb5_data *d) {
+    d->length = k->length;
+    d->data = k->contents;
+}
+
+static void check_error (int r, int line) {
+    if (r != 0) {
+       fprintf (stderr, "%s:%d: %s\n", __FILE__, line,
+                error_message (r));
+       exit (1);
+    }
+}
+#define CHECK check_error(r, __LINE__)
+
+static void printd (const char *descr, krb5_data *d) {
+    int i, j;
+    const int r = 16;
+
+    printf("%s (%d bytes):", descr, d->length);
+
+    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;
+    keyToData(k,&d);
+    printd(descr, &d);
+}
+
+
+
+struct hmac_test {
+    int key_len;
+    unsigned char key[180];
+    int data_len;
+    unsigned char data[80];
+    const char *hexdigest;
+};
+
+static krb5_error_code hmac1(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;
+
+    printk(" test key", key);
+    h->block_size(&blocksize);
+    h->hash_size(&hashsize);
+    if (hashsize > sizeof(tmp))
+       abort();
+    if (key->length > blocksize) {
+       krb5_data d, d2;
+       d.data = key->contents;
+       d.length = key->length;
+       d2.data = tmp;
+       d2.length = hashsize;
+       err = h->hash (1, &d, &d2);
+       if (err) {
+           com_err(whoami, err, "hashing key before calling hmac");
+           exit(1);
+       }
+       key->length = d2.length;
+       key->contents = d2.data;
+       printk(" pre-hashed key", key);
+    }
+    printd(" hmac input", in);
+    err = krb5_hmac(h, key, 1, in, out);
+    if (err == 0)
+       printd(" hmac output", out);
+    return err;
+}
+
+static void test_hmac()
+{
+    krb5_keyblock key;
+    krb5_data in, out;
+    char outbuf[20];
+    char stroutbuf[80];
+    krb5_error_code err;
+    int i, j;
+    int lose = 0;
+
+    /* RFC 2202 test vector.  */
+    static const struct hmac_test md5tests[] = {
+       {
+           16, {
+               0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb,
+               0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb,
+           },
+           8, "Hi There",
+           "0x9294727a3638bb1c13f48ef8158bfc9d"
+       },
+
+       {
+           4, "Jefe",
+           28, "what do ya want for nothing?",
+           "0x750c783e6ab0b503eaa86e310a5db738"
+       },
+
+       {
+           16, {
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+           },
+           50, {
+               0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+               0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+               0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+               0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+               0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+           },
+           "0x56be34521d144c88dbb8c733f0e8b3f6"
+       },
+
+       {
+           25, {
+               0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+               0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+               0x15, 0x16, 0x17, 0x18, 0x19
+           },
+           50, {
+               0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+               0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+               0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+               0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+               0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+           },
+           "0x697eaf0aca3a3aea3a75164746ffaa79"
+       },
+
+       {
+           16, {
+               0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+               0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
+           },
+           20, "Test With Truncation",
+           "0x56461ef2342edc00f9bab995690efd4c"
+       },
+
+       {
+           80, {
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+           },
+           54, "Test Using Larger Than Block-Size Key - Hash Key First",
+           "0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"
+       },
+
+       {
+           80, {
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+               0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+           },
+           73, ("Test Using Larger Than Block-Size Key and Larger "
+                "Than One Block-Size Data"),
+           "0x6f630fad67cda0ee1fb1f562db3aa53e"
+       },
+    }, sha1tests[] = {
+       {
+/*
+test_case =     1
+key =           0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+key_len =       20
+data =          "Hi There"
+data_len =      8
+digest =        0xb617318655057264e28bc0b6fb378c8ef146be00
+
+test_case =     2
+key =           "Jefe"
+key_len =       4
+data =          "what do ya want for nothing?"
+data_len =      28
+digest =        0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
+
+test_case =     3
+key =           0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+key_len =       20
+data =          0xdd repeated 50 times
+data_len =      50
+digest =        0x125d7342b9ac11cd91a39af48aa17b4f63f175d3
+
+test_case =     4
+key =           0x0102030405060708090a0b0c0d0e0f10111213141516171819
+key_len =       25
+data =          0xcd repeated 50 times
+data_len =      50
+digest =        0x4c9007f4026250c6bc8414f9bf50c86c2d7235da
+
+test_case =     5
+key =           0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+key_len =       20
+data =          "Test With Truncation"
+data_len =      20
+digest =        0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04
+
+test_case =     6
+key =           0xaa repeated 80 times
+key_len =       80
+data =          "Test Using Larger Than Block-Size Key - Hash Key First"
+data_len =      54
+digest =        0xaa4ae5e15272d00e95705637ce8a3b55ed402112
+
+test_case =     7
+key =           0xaa repeated 80 times
+key_len =       80
+data =          "Test Using Larger Than Block-Size Key and Larger
+                Than One Block-Size Data"
+data_len =      73
+digest =        0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91
+data_len =      20
+digest =        0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04
+
+test_case =     6
+key =           0xaa repeated 80 times
+key_len =       80
+data =          "Test Using Larger Than Block-Size Key - Hash Key First"
+data_len =      54
+digest =        0xaa4ae5e15272d00e95705637ce8a3b55ed402112
+
+test_case =     7
+key =           0xaa repeated 80 times
+key_len =       80
+data =          "Test Using Larger Than Block-Size Key and Larger "
+                "Than One Block-Size Data"
+data_len =      73
+digest =        0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91
+*/
+       0 },
+    };
+
+    for (i = 0; i < sizeof(md5tests)/sizeof(md5tests[0]); i++) {
+       key.contents = md5tests[i].key;
+       key.length = md5tests[i].key_len;
+       in.data = md5tests[i].data;
+       in.length = md5tests[i].data_len;
+
+       out.data = outbuf;
+       out.length = 20;
+       printf("\nTest #%d:\n", i+1);
+       err = hmac1(&krb5int_hash_md5, &key, &in, &out);
+       if (err) {
+           com_err(whoami, err, "computing hmac");
+           exit(1);
+       }
+
+       if (sizeof(stroutbuf) - 3 < 2 * out.length)
+           abort();
+       strcpy(stroutbuf, "0x");
+       for (j = 0; j < out.length; j++)
+           sprintf(stroutbuf + strlen(stroutbuf), "%02x", 0xff & outbuf[j]);
+       if (strcmp(stroutbuf, md5tests[i].hexdigest)) {
+           printf("*** CHECK FAILED!\n"
+                  "\tReturned: %s.\n"
+                  "\tExpected: %s.\n", stroutbuf, md5tests[i].hexdigest);
+           lose++;
+       } else
+           printf("Matches expected result.\n");
+    }
+
+    /* Do again with SHA-1 tests....  */
+
+    if (lose) {
+       printf("%d failures; exiting.\n", lose);
+       exit(1);
+    }
+}
+
+
+int main (int argc, char **argv)
+{
+    whoami = argv[0];
+    test_hmac();
+    return 0;
+}
diff --git a/src/lib/crypto/t_pkcs5.c b/src/lib/crypto/t_pkcs5.c
new file mode 100644 (file)
index 0000000..30e8574
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * lib/crypto/t_pkcs5.c
+ *
+ * Copyright 2002 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.
+ * 
+ *
+ * Test vectors for PBKDF2 (from PKCS #5v2), based on RFC 3211.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <krb5.h>
+
+#include "k5-int.h"
+
+static void printhex (size_t len, const char *p)
+{
+    while (len--)
+       printf (" %02X", 0xff & *p++);
+}
+
+static void printdata (krb5_data *d) {
+    printhex (d->length, d->data);
+}
+
+static void test_pbkdf2_rfc3211()
+{
+    char x[100];
+    krb5_error_code err;
+    krb5_data d;
+    int i;
+
+    /* RFC 3211 test cases.  */
+    static const struct {
+       const char *pass;
+       const char *salt;
+       unsigned int count;
+       size_t len;
+       const unsigned char expected[24];
+    } t[] = {
+       { "password", "\x12\x34\x56\x78\x78\x56\x34\x12", 5, 8,
+         { 0xD1, 0xDA, 0xA7, 0x86, 0x15, 0xF2, 0x87, 0xE6 } },
+       { "All n-entities must communicate with other "
+         "n-entities via n-1 entiteeheehees",
+         "\x12\x34\x56\x78\x78\x56\x34\x12", 500, 24,
+         { 0x6A, 0x89, 0x70, 0xBF, 0x68, 0xC9, 0x2C, 0xAE,
+           0xA8, 0x4A, 0x8D, 0xF2, 0x85, 0x10, 0x85, 0x86,
+           0x07, 0x12, 0x63, 0x80, 0xCC, 0x47, 0xAB, 0x2D } },
+    };
+
+    d.data = x;
+    printf("RFC 3211 test of PBKDF#2\n");
+
+    for (i = 0; i < sizeof(t)/sizeof(t[0]); i++) {
+
+       printf("pkbdf2(iter_count=%d, dklen=%d (%d bytes), salt=12 34 56 78 78 56 34 12,\n"
+              "       pass=%s):\n  ->",
+              t[i].count, t[i].len * 8, t[i].len, t[i].pass);
+
+       d.length = t[i].len;
+       err = krb5int_pbkdf2_hmac_sha1 (x, d.length, t[i].count,
+                                       t[i].pass, t[i].salt);
+       if (err) {
+           printf("error in computing pbkdf2: %s\n", error_message(err));
+           exit(1);
+       }
+       printdata(&d);
+       if (!memcmp(x, t[i].expected, t[i].len))
+           printf("\nTest passed.\n\n");
+       else {
+           printf("\n*** CHECK FAILED!\n");
+           exit(1);
+       }
+    }
+}
+
+int main ()
+{
+    test_pbkdf2_rfc3211();
+    return 0;
+}