Re: Help with hashing and signatures

TheJackiMonster <[email protected]> Tue, 04 Aug 2020 16:21:27 +0200
Newsgroups gmane.network.gnunet.general
Message-ID <[email protected]>
Hello,

I am currently working on signing messages with ECDSA using GNUnets EGO
keys as well, so maybe I can help you.

On Tue, 2020-08-04 at 15:13 +0200, Alessio Vanni wrote:
> Hello,
> 
> I have a function used to sign some data and embed it in a larger
> structure, defined like so:
> 
>      int
>      sign_data(container, public_key, private_key) { ... }
> 
> (the type of the arguments are not included because they are not
> important; the keys are the GNUnet structs used by egos.)
> 
> The function hashes the data inside the container using GNUnet's
> hashing
> contexts and then signs the hash with the ECDSA signing
> functions.  The
> problem is that when I do the reverse, i.e. verifying the signature,
> I'm
> always getting a bad signature error.
> 
> The verify function is defined as:
> 
>      int
>      verify_signature(container) { ... }
> 
> in which `container' contains the signature and the public key of the
> signing entity.
> 
> Both functions hash the data using the following snippet (`msg' is
> the
> formal name of `container' in the actual function.)
> 
>      #define MAXBYTES 8192
>      struct SignatureData *sd = GNUNET_new(struct SignatureData);
> 
>      size_t segments = (msg->data_size / MAXBYTES) + 1;
>      struct GNUNET_HashContext *hc =
> GNUNET_CRYPTO_hash_context_start();
> 
>      if (1 == segments) {
> 	  GNUNET_CRYPTO_hash_context_read(hc, msg->data, msg-
> >data_size);
>      } else {
> 	  size_t cursor = 0;
> 	  for (size_t i=0; i<segments; ++i) {
> 	       size_t mult = i * MAXBYTES;
> 	       size_t sz = (msg->data_size - mult > MAXBYTES) ?
> 		    MAXBYTES :
> 		    msg->data_size - mult;
> 
> 	       GNUNET_CRYPTO_hash_context_read(hc, msg->data+cursor,
> sz);
> 	       cursor += sz;
> 	  }
>      }
> 
>      GNUNET_CRYPTO_hash_context_finish(hc, &sd->hash);
> 
>      sd->purpose.size = htonl(sizeof(struct SignatureData));
>      sd->purpose.purpose = htonl(SIGN_PURPOSE);
> 
> where `struct SignatureData' is defined as such:
> 
>      struct SignatureData {
>           struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
>           struct GNUNET_HashCode hash;
>      };
> 
> After hashing the data, the signing function does this:
> 
>      struct GNUNET_CRYPTO_EcdsaSignature sig;
>      GNUNET_CRYPTO_ecdsa_sign(private_key, sd, &sig);
>      char *sstr = GNUNET_STRINGS_data_to_string_alloc(&sig,
> sizeof(sig));
> 
> `sstr' is then embedded in the container as explained earlier.
> 
> The verifying function first extracts the public key and the
> signature
> from the container, like so:
> 
>      struct GNUNET_CRYPTO_EcdsaPublicKey pk;
>      char *pkstr = extract_key(msg);
>      size_t pklen = strlen(pkstr);
>      GNUNET_CRYPTO_ecdsa_public_key_from_string(pkstr, pklen, &pk);
> 
>      struct GNUNET_CRYPTO_EcdsaSignature sig;
>      char *sigstr = extract_sig(msg);
>      size_t siglen = strlen(sigstr);
>      GNUNET_STRINGS_string_to_data(sigstr, siglen, &sig,
> sizeof(sig));
> 
> After that it hashes the data with the same code as above and then
> executes these statements:
> 
>      if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(SIGN_PURPOSE,
> 						 sd,
> 						 &sig,
> 						 &pk)) {
> 	  ERRLOG(_("Message not verified!\n"));
> 	  GNUNET_free(sd);
> 	  return GNUNET_NO;
>      }
> 
> The error happens here, as I'm always getting the error message and a
> return value of GNUNET_NO.

Does the `sd` variable contain the the same data in the verify function
as in the sign function? You wrote you would hash again but the
documentation mentions also: 

"The size field in ps->purpose must correctly indicate the number of
bytes of the data structure, including its header."

and

"purpose of the signature, must match 'ps->purpose.purpose' (except in
host byte order)"

So maybe these points are the root of your problem.

> 
> I don't really know what I'm doing wrong here and the documentation
> unfortunately isn't helpful at all, as the comments before the
> `GNUNET_CRYPTO_ecdsa_verify' function isn't even about that function
> (they list arguments that the function doesn't use.)  I'd really
> appreciate some guidance here.
> 
> Thank you,
> A.V.
> 

Also a question: Why do you sign the hash values instead of the actual
data to calculate the hash? Do you have memory limitations?

Happy hacking
Jacki
signature.asc (application/pgp-signature, 313 B)
-----BEGIN PGP SIGNATURE-----

iLUEABMKAB0WIQS38CYx4UdSFRm8EMrYUKX3cuiA+QUCXylu5wAKCRDYUKX3cuiA
+WMjAf9kMdjQ01ICsmR2IPFgv1LbgesW9ZlXaPoKcUVWtaHftgg92giROr8otdHf
SmExmbYYUJLoHNiGLm78e9RFkwmeAf4gfKeMGlpVUbSy4G82P6P9Fc/8a2fpePvZ
OJn/Uvq1bJ8eQQ/+csljcuoju1oisr/ery2JDfY2cLHQxbpaAdlT
=ANYm
-----END PGP SIGNATURE-----