Mailing List Archive

[PATCH] PKCS#5 PBKDF2
Not sure if this is suitable for libgcrypt, but it seems that even a
complete PKCS#5 implementation would be so small it doesn't make sense
to create a libpkcs5. Only tested on alphaev68-dec-osf5.1 and
i686-pc-linux-gnu.

On a similar topic, what do you think about adding a CRC32 "message
digest"? It might be useful to have, even though it is not the most
secure message digest, and the libgcrypt framework fits rather nicely.

2002-12-03 Simon Josefsson <jas@extundo.com>

* Makefile.am (libcipher_la_SOURCES): Add pkcs5.c

* pkcs5.c: New file.

2002-12-03 Simon Josefsson <jas@extundo.com>

* gcrypt.h (gcry_pbkdf2): Add.

2002-12-03 Simon Josefsson <jas@extundo.com>

* Makefile.am (TESTS): Add pkcs5.c.

* pkcs5.c: Add.

Index: cipher/Makefile.am
===================================================================
RCS file: /cvs/gnupg/libgcrypt/cipher/Makefile.am,v
retrieving revision 1.67
diff -u -p -r1.67 Makefile.am
--- cipher/Makefile.am 10 Nov 2002 18:03:28 -0000 1.67
+++ cipher/Makefile.am 3 Dec 2002 01:47:48 -0000
@@ -45,6 +45,7 @@ libcipher_la_LDFLAGS =
libcipher_la_SOURCES = cipher.c \
pubkey.c \
md.c \
+ pkcs5.c \
dynload.c \
dynload.h \
bithelp.h \
Index: cipher/pkcs5.c
===================================================================
RCS file: cipher/pkcs5.c
diff -N cipher/pkcs5.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ cipher/pkcs5.c 3 Dec 2002 01:47:48 -0000
@@ -0,0 +1,201 @@
+/* pkcs5.c Partial Password-Based Cryptography (PKCS#5) implementation
+ * Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+#include "g10lib.h"
+
+/*
+ * 5.2 PBKDF2
+ *
+ * PBKDF2 applies a pseudorandom function (see Appendix B.1 for an
+ * example) to derive keys. The length of the derived key is essentially
+ * unbounded. (However, the maximum effective search space for the
+ * derived key may be limited by the structure of the underlying
+ * pseudorandom function. See Appendix B.1 for further discussion.)
+ * PBKDF2 is recommended for new applications.
+ *
+ * PBKDF2 (P, S, c, dkLen)
+ *
+ * Options: PRF underlying pseudorandom function (hLen
+ * denotes the length in octets of the
+ * pseudorandom function output)
+ *
+ * Input: P password, an octet string
+ * S salt, an octet string
+ * c iteration count, a positive integer
+ * dkLen intended length in octets of the derived
+ * key, a positive integer, at most
+ * (2^32 - 1) * hLen
+ *
+ * Output: DK derived key, a dkLen-octet string
+ */
+
+int
+gcry_pbkdf2 (int PRF, const char *P, size_t Plen, const char *S,
+ size_t Slen, unsigned int c, unsigned int dkLen, char *DK)
+{
+ GCRY_MD_HD prf;
+ char *U;
+ unsigned int u;
+ unsigned int hLen;
+ unsigned int l;
+ unsigned int r;
+ unsigned int t;
+ int rc;
+ unsigned char *p;
+ int i;
+ int k;
+
+ hLen = gcry_md_get_algo_dlen (PRF);
+ if (hLen == 0)
+ return GCRYERR_INV_MD_ALGO;
+
+ if (c == 0)
+ return GCRYERR_INV_ARG;
+
+ if (dkLen == 0)
+ return GCRYERR_INV_ARG;
+
+ /*
+ *
+ * Steps:
+ *
+ * 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and
+ * stop.
+ */
+
+ if (dkLen > 4294967295U)
+ return GCRYERR_INV_ARG;
+
+ /*
+ * 2. Let l be the number of hLen-octet blocks in the derived key,
+ * rounding up, and let r be the number of octets in the last
+ * block:
+ *
+ * l = CEIL (dkLen / hLen) ,
+ * r = dkLen - (l - 1) * hLen .
+ *
+ * Here, CEIL (x) is the "ceiling" function, i.e. the smallest
+ * integer greater than, or equal to, x.
+ */
+
+ l = dkLen / hLen;
+ if (dkLen % hLen)
+ l++;
+ r = dkLen - (l - 1) * hLen;
+
+ /*
+ * 3. For each block of the derived key apply the function F defined
+ * below to the password P, the salt S, the iteration count c, and
+ * the block index to compute the block:
+ *
+ * T_1 = F (P, S, c, 1) ,
+ * T_2 = F (P, S, c, 2) ,
+ * ...
+ * T_l = F (P, S, c, l) ,
+ *
+ * where the function F is defined as the exclusive-or sum of the
+ * first c iterates of the underlying pseudorandom function PRF
+ * applied to the password P and the concatenation of the salt S
+ * and the block index i:
+ *
+ * F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
+ *
+ * where
+ *
+ * U_1 = PRF (P, S || INT (i)) ,
+ * U_2 = PRF (P, U_1) ,
+ * ...
+ * U_c = PRF (P, U_{c-1}) .
+ *
+ * Here, INT (i) is a four-octet encoding of the integer i, most
+ * significant octet first.
+ *
+ * 4. Concatenate the blocks and extract the first dkLen octets to
+ * produce a derived key DK:
+ *
+ * DK = T_1 || T_2 || ... || T_l<0..r-1>
+ *
+ * 5. Output the derived key DK.
+ *
+ * Note. The construction of the function F follows a "belt-and-
+ * suspenders" approach. The iterates U_i are computed recursively to
+ * remove a degree of parallelism from an opponent; they are exclusive-
+ * ored together to reduce concerns about the recursion degenerating
+ * into a small set of values.
+ *
+ */
+
+ prf = gcry_md_open (PRF, GCRY_MD_FLAG_HMAC);
+ if (prf == NULL)
+ return gcry_errno();
+
+ U = gcry_malloc(hLen);
+ if (!U)
+ {
+ rc = GCRYERR_NO_MEM;
+ goto done;
+ }
+
+ for (i = 1; i <= l; i++)
+ {
+ memset(DK + (i - 1) * hLen, 0, i == l ? r : hLen);
+
+ for (u = 1; u <= c; u++)
+ {
+ gcry_md_reset (prf);
+
+ rc = gcry_md_setkey (prf, P, Plen);
+ if (rc != GCRYERR_SUCCESS)
+ goto done;
+
+ if (u == 1)
+ {
+ char tmp[4];
+ gcry_md_write (prf, S, Slen);
+ tmp[0] = (i & 0xff000000) >> 24;
+ tmp[1] = (i & 0x00ff0000) >> 16;
+ tmp[2] = (i & 0x0000ff00) >> 8;
+ tmp[3] = (i & 0x000000ff) >> 0;
+ gcry_md_write (prf, tmp, 4);
+ }
+ else
+ gcry_md_write (prf, U, hLen);
+
+ p = gcry_md_read (prf, PRF);
+ if (p == NULL)
+ {
+ rc = gcry_errno();
+ goto done;
+ }
+
+ memcpy (U, p, hLen);
+
+ for (k = 0; k < (i == l ? r : hLen); k++)
+ DK[(i - 1) * hLen + k] ^= U[k];
+ }
+ }
+
+ rc = GCRYERR_SUCCESS;
+
+ done:
+ gcry_md_close (prf);
+ gcry_free(U);
+ return rc;
+}
Index: src/gcrypt.h
===================================================================
RCS file: /cvs/gnupg/libgcrypt/src/gcrypt.h,v
retrieving revision 1.64
diff -u -p -r1.64 gcrypt.h
--- src/gcrypt.h 10 Nov 2002 18:02:34 -0000 1.64
+++ src/gcrypt.h 3 Dec 2002 01:47:48 -0000
@@ -916,6 +916,9 @@ void gcry_free (void *a);
/* Return true if A is allocated in "secure" memory. */
int gcry_is_secure (const void *a);

+/* PKCS#5 Key derivation function */
+int gcry_pbkdf2 (int PRF, const char *P, size_t Plen, const char *S,
+ size_t Slen, unsigned int c, unsigned int dkLen, char *DK);

#ifndef GCRYPT_NO_MPI_MACROS
# ifndef DID_MPI_TYPEDEF
Index: tests/Makefile.am
===================================================================
RCS file: /cvs/gnupg/libgcrypt/tests/Makefile.am,v
retrieving revision 1.4
diff -u -p -r1.4 Makefile.am
--- tests/Makefile.am 14 May 2002 13:11:08 -0000 1.4
+++ tests/Makefile.am 3 Dec 2002 01:47:48 -0000
@@ -21,7 +21,7 @@

# TESTS_ENVIRONMENT =

-TESTS = basic tsexp
+TESTS = basic tsexp pkcs5

EXTRA_DIST =

Index: tests/pkcs5.c
===================================================================
RCS file: tests/pkcs5.c
diff -N tests/pkcs5.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/pkcs5.c 3 Dec 2002 01:47:48 -0000
@@ -0,0 +1,179 @@
+/* pkcs5.c - pkcs5 regression tests
+ * Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "../src/gcrypt.h"
+
+static int verbose;
+static int error_count;
+
+static void
+fail ( const char *format, ... )
+{
+ va_list arg_ptr ;
+
+ va_start( arg_ptr, format ) ;
+ vfprintf (stderr, format, arg_ptr );
+ va_end(arg_ptr);
+ error_count++;
+}
+
+static void
+die ( const char *format, ... )
+{
+ va_list arg_ptr ;
+
+ va_start( arg_ptr, format ) ;
+ vfprintf (stderr, format, arg_ptr );
+ va_end(arg_ptr);
+ exit (1);
+}
+
+#define ESZETT "\xC3\x9F"
+#define S_CARON "\xC5\xA1"
+#define C_ACUTE "\xC4\x87"
+#define G_CLEF "\xF0\x9D\x84\x9E"
+
+struct pkcs5
+{
+ int iterations;
+ char *password;
+ char *salt;
+ int algo;
+ int dklen;
+ char *expected;
+}
+ pkcs5[] = {
+ {
+ 1, "password", "ATHENA.MIT.EDUraeburn", GCRY_MD_SHA1, 16,
+ "\xCD\xED\xB5\x28\x1B\xB2\xF8\x01\x56\x5A\x11\x22\xB2\x56\x35\x15"}
+ ,
+ {
+ 2, "password", "ATHENA.MIT.EDUraeburn", GCRY_MD_SHA1, 16,
+ "\x01\xdb\xee\x7f\x4a\x9e\x24\x3e\x98\x8b\x62\xc7\x3c\xda\x93\x5d"}
+ ,
+ {
+ 2, "password", "ATHENA.MIT.EDUraeburn", GCRY_MD_SHA1, 32,
+ "\x01\xdb\xee\x7f\x4a\x9e\x24\x3e\x98\x8b\x62\xc7\x3c\xda\x93\x5d"
+ "\xa0\x53\x78\xb9\x32\x44\xec\x8f\x48\xa9\x9e\x61\xad\x79\x9d\x86"}
+ ,
+ {
+ 1200, "password", "ATHENA.MIT.EDUraeburn", GCRY_MD_SHA1, 16,
+ "\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b"}
+ ,
+ {
+ 1200, "password", "ATHENA.MIT.EDUraeburn", GCRY_MD_SHA1, 32,
+ "\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b"
+ "\xa7\xe5\x2d\xdb\xc5\xe5\x14\x2f\x70\x8a\x31\xe2\xe6\x2b\x1e\x13"}
+ ,
+ {
+ 5, "password", "\x12\x34\x56\x78\x78\x56\x34\x12\x00", GCRY_MD_SHA1, 16,
+ "\xd1\xda\xa7\x86\x15\xf2\x87\xe6\xa1\xc8\xb1\x20\xd7\x06\x2a\x49"}
+ ,
+ {
+ 5, "password", "\x12\x34\x56\x78\x78\x56\x34\x12\x00", GCRY_MD_SHA1, 32,
+ "\xd1\xda\xa7\x86\x15\xf2\x87\xe6\xa1\xc8\xb1\x20\xd7\x06\x2a\x49"
+ "\x3f\x98\xd2\x03\xe6\xbe\x49\xa6\xad\xf4\xfa\x57\x4b\x6e\x64\xee"}
+ ,
+ {
+ 1200, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ "pass phrase equals block size", GCRY_MD_SHA1, 16,
+ "\x13\x9c\x30\xc0\x96\x6b\xc3\x2b\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9"}
+ ,
+ {
+ 1200, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ "pass phrase equals block size", GCRY_MD_SHA1, 32,
+ "\x13\x9c\x30\xc0\x96\x6b\xc3\x2b\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9"
+ "\xc5\xec\x59\xf1\xa4\x52\xf5\xcc\x9a\xd9\x40\xfe\xa0\x59\x8e\xd1"}
+ ,
+ {
+ 1200, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ "pass phrase exceeds block size", GCRY_MD_SHA1, 16,
+ "\x9c\xca\xd6\xd4\x68\x77\x0c\xd5\x1b\x10\xe6\xa6\x87\x21\xbe\x61"}
+ ,
+ {
+ 1200, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+ "pass phrase exceeds block size", GCRY_MD_SHA1, 32,
+ "\x9c\xca\xd6\xd4\x68\x77\x0c\xd5\x1b\x10\xe6\xa6\x87\x21\xbe\x61"
+ "\x1a\x8b\x4d\x28\x26\x01\xdb\x3b\x36\xbe\x92\x46\x91\x5e\xc8\x2a"}
+ ,
+ {
+ 50, G_CLEF "\x00", "EXAMPLE.COMpianist", GCRY_MD_SHA1, 16,
+ "\x6b\x9c\xf2\x6d\x45\x45\x5a\x43\xa5\xb8\xbb\x27\x6a\x40\x3b\x39"}
+ ,
+ {
+ 50, G_CLEF "\x00", "EXAMPLE.COMpianist", GCRY_MD_SHA1, 32,
+ "\x6b\x9c\xf2\x6d\x45\x45\x5a\x43\xa5\xb8\xbb\x27\x6a\x40\x3b\x39"
+ "\xe7\xfe\x37\xa0\xc4\x1e\x02\xc2\x81\xff\x30\x69\xe1\xe9\x4f\x52"}
+ ,
+ {
+ 500, "All n-entities must communicate with other n-entities via n-1 "
+ "entiteeheehees", "\x12\x34\x56\x78\x78\x56\x34\x12\x00",
+ GCRY_MD_SHA1, 16,
+ "\x6A\x89\x70\xBF\x68\xC9\x2C\xAE\xA8\x4A\x8D\xF2\x85\x10\x85\x86"}
+ };
+
+int
+main (int argc, char **argv)
+{
+ unsigned char out[BUFSIZ];
+ int res;
+ int i;
+
+ if (argc > 1 && !strcmp (argv[1], "--verbose"))
+ verbose = 1;
+
+ gcry_control (GCRYCTL_DISABLE_SECMEM, NULL, 0);
+ if (!gcry_check_version (GCRYPT_VERSION))
+ die ("version mismatch\n");
+
+ for (i = 0; i < sizeof (pkcs5) / sizeof (pkcs5[0]); i++)
+ {
+ if (verbose)
+ printf ("PKCS5 entry %d\n", i);
+
+ res = gcry_pbkdf2 (pkcs5[i].algo,
+ pkcs5[i].password,strlen (pkcs5[i].password),
+ pkcs5[i].salt, strlen (pkcs5[i].salt),
+ pkcs5[i].iterations, pkcs5[i].dklen, out);
+ if (res)
+ {
+ fail ("PKCS5 entry %d failed fatally: %d\n", i, res);
+ continue;
+ }
+
+ if (memcmp (pkcs5[i].expected, out, pkcs5[i].dklen) != 0)
+ {
+ fail ("PKCS5 entry %d failed\n", i);
+
+ if (verbose)
+ printf ("ERROR\n");
+ }
+ else if (verbose)
+ printf ("OK\n");
+ }
+
+ return error_count? 1:0;
+}
+
+
Re: [PATCH] PKCS#5 PBKDF2 [ In reply to ]
On Tue, 03 Dec 2002 02:53:07 +0100, Simon Josefsson said:

> Not sure if this is suitable for libgcrypt, but it seems that even a
> complete PKCS#5 implementation would be so small it doesn't make sense
> to create a libpkcs5. Only tested on alphaev68-dec-osf5.1 and
> i686-pc-linux-gnu.

I think that key derive functions make sense in libgcrypt becuase they
are basic crypto building blocks. However we should not add just
pkcs5 but introduce a generic key derive API much like we have it for
the other building blocks. Would you like to work on it?

> On a similar topic, what do you think about adding a CRC32 "message
> digest"? It might be useful to have, even though it is not the most
> secure message digest, and the libgcrypt framework fits rather nicely.

Doing CRC32 is pretty easy to code, so there is no real advantage.
OTOH, I agree that it fits perfectly into the message digest framework
and it is useful for certain applications. I don't know of any OIDs
assigned to CRC algorithms, so I can assign this one from the GNU arc:

/* GNU.crcAlgorithm.crc32 */
"1.3.6.1.4.1.11591.14.1"

Please tell if if you want to use it.


Salam-Shalom,

Werner
Re: [PATCH] PKCS#5 PBKDF2 [ In reply to ]
On Tue Dec 03 2002; 10:19, Werner Koch wrote:

> are basic crypto building blocks. However we should not add just
> pkcs5 but introduce a generic key derive API much like we have it for
> the other building blocks. Would you like to work on it?

I really like the idea and I suggest we should also add the RFC2440 S2K modes.

Then we could use an enumeration of all modes like this:
GCRY_S2K_SIMPLE,
GCRY_S2K_SALTED,
GCRY_S2K_ITERSALTED,
GCRY_S2K_PKCS5,
[..]


Of course it's just an idea...


Timo
Re: [PATCH] PKCS#5 PBKDF2 [ In reply to ]
Werner Koch <wk@gnupg.org> writes:

> On Tue, 03 Dec 2002 02:53:07 +0100, Simon Josefsson said:
>
>> Not sure if this is suitable for libgcrypt, but it seems that even a
>> complete PKCS#5 implementation would be so small it doesn't make sense
>> to create a libpkcs5. Only tested on alphaev68-dec-osf5.1 and
>> i686-pc-linux-gnu.
>
> I think that key derive functions make sense in libgcrypt becuase they
> are basic crypto building blocks. However we should not add just
> pkcs5 but introduce a generic key derive API much like we have it for
> the other building blocks. Would you like to work on it?

Yes, although it won't be main priority. I guess the most important
thing is to define how the API would look like. I haven't thought
about what properties a generic key derivation algorithm has, so here
is a starting point that can be modified by someone who thought about
it (I might get around to thinking about it too, of course..).

/* Algorithm IDs for the key derivation functions we know about. Not all of them
are implemented. */
enum gcry_kd_algos
{
GCRY_KD_NONE = 0,
GCRY_KD_PKCS5_PBKDF = 1,
GCRY_KD_PKCS5_PBKDF2 = 2,
GCRY_KD_RFC2440_SIMPLE = 3,
GCRY_KD_RFC2440_SALTED = 4,
GCRY_KD_RFC2440_ITERSALTED = 5
};

/* Flags used with the gcry_kd_open function. */
enum gcry_kd_flags
{
GCRY_KD_FLAG_SECURE = 1, /* Allocate all buffers in "secure" memory */
};


/* This object is used to hold a handle to an key derivation object. */
struct gcry_kd_context;
struct gcry_kd_handle
{ ...
};
typedef struct gcry_kd_handle *Gcry_KD_Hd;

/* Create a key derivation object for algorithm ALGO. FLAGS may be
given as an bitwise OR of the gcry_kd_flags values. */
Gcry_KD_Hd gcry_kd_open(int algo, unsigned int flags);

/* Release the message digest object HD. */
void gcry_kd_close (Gcry_KD_Hd hd);

/* Create a new key derivation object as an exact copy of the object HD. */
Gcry_Kd_Hd gcry_kd_copy (Gcry_KD_Hd hd);

/* Reset the key derivation object HD to its initail state. */
void gcry_kd_reset (Gcry_KD_Hd hd);

/* Perform various operations on the key derivation object HD. */
int gcry_kd_ctl (Gcry_KD_Hd hd, int cmd, unsigned char *buffer, size_t buflen);

/* Read out the final key from HD. If algorithm uses a fixed size
output, length can be 0. */
unsigned char *gcry_kd_read (Gcry_KD_Hd hd, size_t length);

/* Retrieve the algorithm used with HD. */
int gcry_kd_get_algo (Gcry_KD_Hd hd);

/* Retrieved the length in bytes of the key yielded by algorithm
ALGO. This is 0 if the output length is decided by user. */
unsigned int gcry_kd_get_algo_dlen (int algo);

/* Map the key derivation algorithm id ALGO to a string representation of the
algorithm name. For unknown algorithms this functions returns an
empty string. */
const char *gcry_kd_algo_name (int algo);

/* Map the algorithm NAME to a key derivation algorithm Id. Return 0 if
the algorithm name is not known. */
int gcry_kd_map_name (const char* name);

/* Set string to derive key from. */
#define gcry_kd_set_password(hd, str, len) \
gcry_kd_ctl( (a), GCRYCTL_SET_PASSWORD, str, len )

/* Set salt to derive key from. */
#define gcry_kd_set_salt(hd, str, len) \
gcry_kd_ctl( (a), GCRYCTL_SET_SALT, str, len )

/* Set iteration count for key derivation (currently only used by PKCS5 KD's. */
#define gcry_kd_set_salt(hd, i) \
gcry_kd_ctl( (a), GCRYCTL_SET_ITERATION, i, NULL )

/* Set hash algorithm for key derivation (currently only used by PKCS5 KD's. */
#define gcry_kd_set_hash(hd, algo) \
gcry_kd_ctl( (a), GCRYCTL_SET_HASH, algo, NULL )

>> On a similar topic, what do you think about adding a CRC32 "message
>> digest"? It might be useful to have, even though it is not the most
>> secure message digest, and the libgcrypt framework fits rather nicely.
>
> Doing CRC32 is pretty easy to code, so there is no real advantage.
> OTOH, I agree that it fits perfectly into the message digest framework
> and it is useful for certain applications. I don't know of any OIDs
> assigned to CRC algorithms, so I can assign this one from the GNU arc:
>
> /* GNU.crcAlgorithm.crc32 */
> "1.3.6.1.4.1.11591.14.1"
>
> Please tell if if you want to use it.

I don't need any OID, but if a CRC-32 MD algo is included I guess it
makes sense to allocate one. Is it possible to map an OID to an algo
and certain flags? If so, and if possible, maybe allocating another
OID for the modified CRC-32 algorithm as defined by RFC 1510bis would
be useful too. I'm thinking of having a CRC-32 gcrypt MD algo, and
the RFC1510 variation as a gcrypt MD flag.