views:

570

answers:

4

I want to feed OpenSSL specific data for use as random seed during the signing of data with an EC key. I'm doing this to compare my application with another reference one (closed source). That utility takes the file with private key, file with data to sign and file with random data as parameters.

I've got the generation of EC keys, and signing of data down, but can't compare the two applications since I have no common ground. OpenSSL generates random data used in signing the data (probably from /dev/random) and thus gives me a different signature every run.

I've tried RAND_clear() in combination with RAND_add(), but keep getting changing signatures. Either I don't understand the whole ECDSA concept, or I'm doing something wrong.

My second option for comparing the applications is to import the public key and verify the signature generated by the reference program. This is the better option, but I'm unable to import the given example public key (83 character hex string). EC_POINT_oct2point() keeps giving me null results.

Any help/pointers/references would be greatly appreciated.

char * key_as_binary_data;  //369368AF243193D001E39CE76BB1D5DA08A9BC0A63307AB352338E5EA5C0E05A0C2531866F3E3C2702
int data_size;  //Size of the key buffer
EC_POINT * ecpoint = NULL;
EC_GROUP * ecgroup = NULL;
EC_KEY * eckey = NULL;
point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED;
int asn1_flag = OPENSSL_EC_NAMED_CURVE;

eckey = EC_KEY_new();
ecpoint = EC_POINT_new(ecgroup);
ecgroup = EC_GROUP_new_by_curve_name(OBJ_sn2nid("sect163k1"));
EC_GROUP_set_asn1_flag(ecgroup, asn1_flag);
EC_GROUP_set_point_conversion_form(ecgroup, form);
EC_KEY_set_group(eckey,ecgroup);
EC_KEY_generate_key(eckey);

//This gives me a null ecpoint
EC_POINT_oct2point(ecgroup,ecpoint,key_as_binary_data,data_size-1,ctx); 
EC_KEY_set_public_key(eckey,ecpoint);
A: 

The signing procedure is purely to allow someone else to confirm that you signed it ie. it was your private key that was used to sign the message (or any data) without actually having your private key.

The algorithm is outlined on wikipedia Elliptic_Curve_DSA Reading "Signature generation algorithm" it appears the random data is used to assist in the strength of the signature and to make it harder to attack to figure out the private key.

Therefore you should expect the signature to be different each time since this is not just simply a hash.

See the section "Signature verification algorithm" to see that the verification steps are the ones you wish to use to confirm that your openssl version is outputing valid signatures w.r.t. the ECDSA method and the closed source program.

Rudi Bierach
The reference program claim to support FIPS 186-2, and is given as a utility to sign data for use on a microprocessor. I was hoping I could use the same private key, random data and data with both my program and the reference program and get the same signature.Without the ability to insure both apps use the same random data I'll have to fall back to the complete verification of the signature. Thanks for the input.
Belrog
A: 

I can't find the docs for RAND_clear, so can't comment why it's not resulting in reproducible random numbers.

But even if you get that done, what you want may not be possible. ECDSA signature generation requires choosing a random integer in a particular range. Two different implementations of the algorithm might have completely different ideas about how to generate such an integer from their entropy source. AFAIK the means of transforming bits of entropy into the required number is not part of the ECDSA algorithm.

So for example (very bad examples of course), one implementation might do this:

int random_number = rand() % n;

and another might do this:

int random_number = (rand() * n) / RAND_MAX;

So even if you give them the same seed data, you might still get different signatures from different implementations. All you can do is validate whether you have generated a valid signature.

Steve Jessop
Yes, the lack of docs is a major hurdle for me. I'm slogging through the code trying to find ways of doing what I need. Thanks for the clarification. It seems I'm back to trying to figure out how to import that public key. I was hoping to provide the random data, and not just the seed. That would to my mind have solved the random data component, but I'm not yet desperate enough to have a go at the random engine.
Belrog
A: 

This is how you should go about loading that public key:

  EC_KEY    *key = NULL;
  EC_POINT *pub_key;
  const EC_GROUP *group;

  SSL_library_init();
  SSL_load_error_strings();

  key = EC_KEY_new_by_curve_name(NID_sect163k1);
  group = EC_KEY_get0_group(key);
  pub_key = EC_POINT_new(group);

  EC_POINT_hex2point(group,
    "369368AF243193D001E39CE76BB1D5DA08A9BC0A63307AB352338E5EA5C0E05A0C2531866F3E3C2702", pub_key, NULL);

  EC_KEY_set_public_key(key, pub_key);

  if (!EC_KEY_check_key(key)) {
    printf("EC_KEY_check_key failed:\n");
    printf("%s\n",ERR_error_string(ERR_get_error(),NULL));
  } else {
    printf("Public key verified OK\n");
  }

It seems to verify OK, so it should work for checking a signature.

I think your bug might have just been passing a NULL (in ecgroup) to EC_POINT_new().

caf
+2  A: 

The reason you get different results despite the fact that you are clearing the pool and resetting it is that by default OpenSSL's RAND implementation will hash the pid into the output block (precisely to ensure that even applications that use the same seed do not get the same PRNG output, since 99.9% of the time that happening is a Bad Thing).

In addition, even if this was not the case, it is unlikely that your reference application uses the same PRNG that OpenSSL uses to turn the seed file into a series of random bytes. (Unless your reference application actually uses OpenSSL as well, of course). What you would have to do is first figure out what kind of PRNG the reference app uses - this might be a standard PRNG design like the ones from X9.31 or FIPS-186, or might be something totally custom. Then reimplement that design for OpenSSL and plug it in via RAND_set_rand_method.

As to verification: it looks like you need to transpose the lines:

   ecpoint = EC_POINT_new(ecgroup);
   ecgroup = EC_GROUP_new_by_curve_name(OBJ_sn2nid("sect163k1"));

Otherwise ecpoint is set to NULL right from the start, and this causes EC_KEY_generate_key to fail, because the group is set to NULL. Quoting from openssl-0.9.8k's crypto/ec/ec_key.c:

if (!eckey || !eckey->group)
   {
   ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER);
   return 0;
   }
Jack Lloyd
This makes a lot of sense. The reference app uses a given file as a source of random data. Naturally they might be doing anything with the randomness, but comparing consecutive runs' signatures they are equal. I believe this to show that the given random source is actually used as such, without modification.The OpenSSL seeding of their internal RAND engine is clearly a better way to go for randomness - unless you don't want randomness :)Swapping the lines is an obvious mistake, no wonder I missed it. Thank you for the help.
Belrog