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 (
You can control the random data that OpenSSL produces during signing by using the method:
ECDSA_SIG* ECDSA_do_sign_ex(const unsigned char *dgst, int dgstlen, const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey);
where kinv
is the random number that is used during signing.
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().
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.
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.
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;
}