nisse@lysator.liu.se (Niels Möller) writes:
One possibility might be to have all dsa functions take the dsa group parameters and the actual key as separate function arguments.
I've tried this now. I think it looks reasonably good. Excerpts from the new dsa.h:
struct dsa_params { /* Modulo */ mpz_t p;
/* Group order */ mpz_t q;
/* Generator */ mpz_t g; };
So this is the new parameter struct. Is this a good name, or should it be struct dsa_group?
int dsa_sign(const struct dsa_params *params, const mpz_t x, void *random_ctx, nettle_random_func *random, size_t digest_size, const uint8_t *digest, struct dsa_signature *signature);
int dsa_verify(const struct dsa_params *params, const mpz_t y, size_t digest_size, const uint8_t *digest, const struct dsa_signature *signature);
These functions now take the parameters separately. One could get something more in style with the the old interface by defining
#define dsa_sign(pub, key, [...]) dsa_sign(&pub->params, key->x, [...]) #define dsa_verify(pub, [...]) dsa_verify(&pub->params, pub->y, [...])
Almost makes one wish for C++ style overloading...
int dsa_generate_params (struct dsa_params *params, void *random_ctx, nettle_random_func *random, void *progress_ctx, nettle_progress_func *progress, unsigned p_bits, unsigned q_bits);
void dsa_generate_keypair (const struct dsa_params *params, mpz_t pub, mpz_t key,
void *random_ctx, nettle_random_func *random);
It seems reasonable to provide one key generation function which also generates parameters, and one key generation function which takes fixed parameters as argument. Any suggestion for naming? For compatibility, it would be preferable to keep dsa_generate_keypair unchanged, and invent a new name for the function above.
/* Convenience structs, close to the interface used in nettle-2.7.x and earlier. */ struct dsa_public_key { struct dsa_params params; /* Public value */ mpz_t y; };
This is essentially the same struct as in earlier versions, but it wraps the parameters in a struct, so it's an API change. I think this is the sane way to do it, if this is viewed as an interface to be supported in future versions, and not just something retained for backwards compatibility.
In this version of the interface, struct dsa_public_key is not deprecated, but it is made *optional*: all dsa features should be available even if you don't bundle parameters and public key value in this way.
And I think bundling the parameters with the public key do make sense for many common use cases, in particular applications only wanting to verify signatures and certificates.
int dsa_sha1_sign(const struct dsa_public_key *pub, const struct dsa_private_key *key, void *random_ctx, nettle_random_func *random, struct sha1_ctx *hash, struct dsa_signature *signature);
int dsa_sha1_verify(const struct dsa_public_key *key, struct sha1_ctx *hash, const struct dsa_signature *signature);
These and related functions retained, with no change to the prototypes. I think most applications can use these functions, rather than the more general dsa_sign and dsa_verify above. Maybe the _sign functions should be changed to take a struct dsa_params * rather than a struct dsa_public_key *; that would be more logical and consistent, but less compatible with existing code.
int dsa_generate_keypair_old(struct dsa_public_key *pub, struct dsa_private_key *key,
void *random_ctx, nettle_random_func *random, void *progress_ctx, nettle_progress_func *progress, unsigned p_bits, unsigned q_bits);
As said above, there's a naming issue here. I think it would be nice to keep this function with name and prototype unchanged.
/* Generates a public-key expression if PRIV is NULL .*/ int dsa_keypair_to_sexp(struct nettle_buffer *buffer, const char *algorithm_name, /* NULL means "dsa" */ const struct dsa_params *params, const mpz_t pub, const mpz_t priv);
/* If PRIV is NULL, expect a public-key expression. If PUB is NULL, * expect a private key expression and ignore the parts not needed for * the public key. */ /* Keys must be initialized before calling this function, as usual. */ int dsa_sha1_keypair_from_sexp(struct dsa_params *params, mpz_t pub, mpz_t priv, unsigned p_max_bits, size_t length, const uint8_t *expr);
int dsa_params_from_der_iterator(struct dsa_params *params, unsigned max_bits, unsigned q_bits, struct asn1_der_iterator *i); int dsa_public_key_from_der_iterator(const struct dsa_params *params, mpz_t pub, struct asn1_der_iterator *i);
int dsa_openssl_private_key_from_der_iterator(struct dsa_params *params, mpz_t pub, mpz_t priv, unsigned p_max_bits, struct asn1_der_iterator *i);
int dsa_openssl_private_key_from_der(struct dsa_params *params, mpz_t pub, mpz_t priv, unsigned p_max_bits, size_t length, const uint8_t *data);
These conversion functions all take a separate dsa_params argument, and don't use struct dsa_public_key and dsa_private_key.
Regards, /Niels