how to use libgcrypt library

Neil Spring nspring@cs.washington.edu
Sun, 27 Jul 2003 02:40:06 -0700


--Apple-Mail-2--612767107
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCII; format=flowed

Zen,

On Tuesday, Jul 22, 2003, at 20:34 US/Pacific, Neil Spring wrote:
> I wrote the following today; you might find it useful, and it seems to 
> work.

Sigh.  The previous example doesn't work. Although it generated 
something I thought was a signature, and did so without errors from 
gcrypt, it would verify any string as matching the signature.  
gcry_pk_sign and _verify were probably not meant to take a data value 
as a quoted string.

The following is an apparently functioning version, with the same 
caveats as before -- it may not be the proper series of function calls 
to sign a chunk of plaintext, but it seems to work.  The main 
difference lies in make_sign_parameters().

I also can't seem to use as small a key as I'd like -- anything smaller 
than 512 bits causes a GCRYERR_TOO_SHORT.  Suggestions for making 
smaller signatures with smaller keys would be appreciated -- 
performance and compactness are much more important to me than 
preventing forgeries.

-neil

#include <gcrypt.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

/* either seems to work */
// #define HASH_TYPE GCRY_MD_SHA1
// #define HASH_NAME "sha1"
#define HASH_TYPE GCRY_MD_MD5
#define HASH_NAME "md5"

void make_sign_parameters(GcrySexp *sign_parms, const char *plain) {
   size_t errof=0;
   int rc;
   size_t hash_len = gcry_md_get_algo_dlen(HASH_TYPE);
   unsigned char *digest;
   GcryMPI mpival;

   digest = malloc(hash_len);
   gcry_md_hash_buffer(HASH_TYPE, digest, plain, strlen(plain));
   gcry_mpi_scan(&mpival, GCRYMPI_FMT_USG, digest, &hash_len);
   rc = gcry_sexp_build (sign_parms, &errof,
                         "(data (flags pkcs1) (hash %s %m))",
                         HASH_NAME, mpival);
   assert(rc == 0);
   gcry_mpi_release(mpival);
   free(digest);
}

int main (int argc, char **argv) {
   static const char message[] = "hello world";
   GcrySexp gen_parms, sign_parms, keypair, pubkey, skey, sig, other;
   size_t errof=0;
   int rc; /* should be gcry_error_t in gcrypt > 1.1.12 */

   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
   rc = gcry_sexp_build (&gen_parms, &errof, "(genkey (rsa (nbits 
3:512)))");
   assert(rc == 0);
   rc = gcry_pk_genkey(&keypair, gen_parms);
   assert(rc == 0);

   skey = gcry_sexp_find_token(keypair, "private-key", 0);
   pubkey = gcry_sexp_find_token(keypair, "public-key", 0);
   assert(skey != NULL);
   assert(pubkey != NULL);

   make_sign_parameters(&sign_parms, message);

   /* doesn't seem to do what I meant it to:
   rc = gcry_sexp_build (&sign_parms, &errof,
   "(data (flags raw) (value \"%s\"))\n", message);
   */

   rc = gcry_pk_sign (&sig, sign_parms, skey);
   if(rc != 0) {
     printf("sign returns error %d: %s\n", rc, gcry_strerror(rc));
     exit(EXIT_FAILURE);
   }
   fprintf(stderr, " the s-expression containing the signature is:\n");
   gcry_sexp_dump(sig);

   make_sign_parameters(&sign_parms, message);
   rc = gcry_pk_verify (sig, sign_parms, pubkey);
   if(rc != 0) {
     printf("verify returns error %d: %s\n", rc, gcry_strerror(rc));
   }

   /* now make sure it doesn't verify an arbitrary string */
   make_sign_parameters(&other, "eat my shorts, man");
   rc = gcry_pk_verify (sig, other, pubkey);
   if(rc == 0) {
     printf("verify verified the wrong thing.\n");
   }

   exit(EXIT_SUCCESS);
}

--Apple-Mail-2--612767107
content-type: application/pgp-signature; x-mac-type=70674453;
	name=PGP.sig
content-disposition: inline
content-transfer-encoding: 7bit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (Darwin)

iD8DBQE/I538tvhXVvuQ3oQRAvnoAJ9w4ixJqiOmumY6a2tnkdUyR4ZERQCfeO9C
XJ04nBuaLovQpa6x55PWx28=
=1PL9
-----END PGP SIGNATURE-----

--Apple-Mail-2--612767107--