Commit 69b36b2c authored by Niels Möller's avatar Niels Möller
Browse files

* src/publickey_crypto.c: Moved the dsa-ralated code to a separate

file.

Rev: src/publickey_crypto.c:1.33
parent 5e6da035
......@@ -30,7 +30,6 @@
#include "crypto.h"
#include "format.h"
#include "parse.h"
#include "publickey_crypto.h"
#include "sha.h"
#include "ssh.h"
#include "werror.h"
......@@ -44,377 +43,6 @@
#include "publickey_crypto.c.x"
/* DSA signatures */
/* GABA:
(class
(name dsa_signer)
(super signer)
(vars
(random object randomness)
(public struct dsa_public)
(a bignum)))
*/
/* GABA:
(class
(name dsa_signer_kludge)
(super signer)
(vars
(dsa object dsa_signer)))
*/
/* GABA:
(class
(name dsa_verifier)
(super verifier)
(vars
(public struct dsa_public)))
*/
/* GABA:
(class
(name dsa_algorithm)
(super signature_algorithm)
(vars
(random object randomness)))
*/
static void dsa_hash(mpz_t h, UINT32 length, UINT8 *msg)
{
/* Compute hash */
struct hash_instance *hash = MAKE_HASH(&sha_algorithm);
UINT8 *digest = alloca(hash->hash_size);
HASH_UPDATE(hash, length, msg);
HASH_DIGEST(hash, digest);
bignum_parse_u(h, hash->hash_size, digest);
debug("DSA hash: %xn\n", h);
KILL(hash);
}
static void generic_dsa_sign(struct dsa_signer *closure,
UINT32 length, UINT8 *msg,
mpz_t r, mpz_t s)
{
mpz_t k, tmp;
assert(r && s);
/* Select k, 0<k<q, randomly */
mpz_init_set(tmp, closure->public.q);
mpz_sub_ui(tmp, tmp, 1);
mpz_init(k);
bignum_random(k, closure->random, tmp);
mpz_add_ui(k, k, 1);
debug("generic_dsa_sign, k: %xn\n", k);
/* Compute r = (g^k (mod p)) (mod q) */
mpz_powm(r, closure->public.g, k, closure->public.p);
debug("do_dsa_sign, group element: %xn\n", r);
mpz_fdiv_r(r, r, closure->public.q);
debug("do_dsa_sign, r: %xn\n", r);
/* Compute hash */
dsa_hash(tmp, length, msg);
/* Compute k^-1 (mod q) */
if (!mpz_invert(k, k, closure->public.q))
{
fatal("do_dsa_sign: k non-invertible\n");
}
/* Compute signature s = k^-1(h + ar) (mod q) */
mpz_mul(s, r, closure->a);
mpz_fdiv_r(s, s, closure->public.q);
mpz_add(s, s, tmp);
mpz_mul(s, s, k);
mpz_fdiv_r(s, s, closure->public.q);
debug("generic_dsa_sign, s: %xn\n", s);
mpz_clear(k);
mpz_clear(tmp);
}
static struct lsh_string *do_dsa_sign(struct signer *c,
UINT32 length,
UINT8 *msg)
{
CAST(dsa_signer, closure, c);
mpz_t r, s;
struct lsh_string *signature;
mpz_init(r); mpz_init(s);
generic_dsa_sign(closure, length, msg, r, s);
/* Build signature */
/* FIXME: Uses the (better) format from an obsoleted draft */
signature = ssh_format("%a%n%n", ATOM_SSH_DSS, r, s);
mpz_clear(r);
mpz_clear(s);
return signature;
}
#if DATAFELLOWS_SSH2_SSH_DSA_KLUDGE
static struct lsh_string *do_dsa_sign_kludge(struct signer *c,
UINT32 length,
UINT8 *msg)
{
CAST(dsa_signer_kludge, self, c);
mpz_t r, s;
struct lsh_string *signature;
mpz_init(r); mpz_init(s);
generic_dsa_sign(self->dsa, length, msg, r, s);
/* Build signature */
/* FIXME: This generates length fields, and it also doesn't
* guarantee that r and s occupy half of the signature each. */
signature = ssh_format("%un%un", r, s);
mpz_clear(r);
mpz_clear(s);
return signature;
}
#endif /* DATAFELLOWS_SSH2_SSH_DSA_KLUDGE */
#if 0
static struct lsh_string *dsa_public_key(struct signer *dsa)
{
return ssh_format("%a%n%n%n%n",
ATOM_SSH_DSS, dsa->p, dsa->q, dsa->g, dsa->y);
}
#endif
static int do_dsa_verify(struct verifier *c,
UINT32 length,
UINT8 *msg,
UINT32 signature_length,
UINT8 * signature_data)
{
CAST(dsa_verifier, closure, c);
struct simple_buffer buffer;
int res;
int atom;
mpz_t r, s;
mpz_t w, tmp, v;
simple_buffer_init(&buffer, signature_length, signature_data);
if (!parse_atom(&buffer, &atom)
|| (atom != ATOM_SSH_DSS) )
return 0;
mpz_init(r);
mpz_init(s);
if (! (parse_bignum(&buffer, r)
&& parse_bignum(&buffer, s)
&& parse_eod(&buffer)
&& (mpz_sgn(r) == 1)
&& (mpz_sgn(s) == 1)
&& (mpz_cmp(r, closure->public.q) < 0)
&& (mpz_cmp(s, closure->public.q) < 0) ))
{
mpz_clear(r);
mpz_clear(s);
return 0;
}
debug("do_dsa_verify, r: %xn\n"
" s: %xn\n", r, s);
/* Compute w = s^-1 (mod q) */
mpz_init(w);
/* FIXME: mpz_invert generates negative inverses. Is this a problem? */
if (!mpz_invert(w, s, closure->public.q))
{
werror("do_dsa_verify: s non-invertible.\n");
mpz_clear(r);
mpz_clear(s);
mpz_clear(w);
return 0;
}
debug("do_dsa_verify, w: %xn\n", w);
/* Compute hash */
mpz_init(tmp);
dsa_hash(tmp, length, msg);
/* g^{w * h (mod q)} (mod p) */
mpz_init(v);
mpz_mul(tmp, tmp, w);
mpz_fdiv_r(tmp, tmp, closure->public.q);
debug("u1: %xn\n", tmp);
mpz_powm(v, closure->public.g, tmp, closure->public.p);
/* y^{w * r (mod q) } (mod p) */
mpz_mul(tmp, r, w);
mpz_fdiv_r(tmp, tmp, closure->public.q);
debug("u2: %xn\n", tmp);
mpz_powm(tmp, closure->public.y, tmp, closure->public.p);
/* (g^{w * h} * y^{w * r} (mod p) ) (mod q) */
mpz_mul(v, v, tmp);
mpz_fdiv_r(v, v, closure->public.p);
debug("do_dsa_verify, group element: %xn\n", v);
mpz_fdiv_r(v, v, closure->public.q);
debug("do_dsa_verify, v: %xn\n", v);
res = mpz_cmp(v, r);
mpz_clear(r);
mpz_clear(s);
mpz_clear(w);
mpz_clear(tmp);
mpz_clear(v);
return !res;
}
static int parse_dsa_public(struct simple_buffer *buffer,
struct dsa_public *public)
{
return (parse_bignum(buffer, public->p)
&& (mpz_sgn(public->p) == 1)
&& parse_bignum(buffer, public->q)
&& (mpz_sgn(public->q) == 1)
&& (mpz_cmp(public->q, public->p) < 0) /* q < p */
&& parse_bignum(buffer, public->g)
&& (mpz_sgn(public->g) == 1)
&& (mpz_cmp(public->g, public->p) < 0) /* g < p */
&& parse_bignum(buffer, public->y)
&& (mpz_sgn(public->y) == 1)
&& (mpz_cmp(public->y, public->p) < 0) /* y < p */ );
}
/* FIXME: Outside of the protocol transactions, keys should be stored
* in SPKI-style S-expressions. */
static struct signer *make_dsa_signer(struct signature_algorithm *c,
UINT32 public_length,
UINT8 *public,
UINT32 private_length,
UINT8 *private)
{
CAST(dsa_algorithm, closure, c);
NEW(dsa_signer, res);
struct simple_buffer public_buffer;
struct simple_buffer private_buffer;
int atom;
/* FIXME: The allocator could do this kind of initialization
* automatically. */
mpz_init(res->public.p);
mpz_init(res->public.q);
mpz_init(res->public.g);
mpz_init(res->public.y);
mpz_init(res->a);
simple_buffer_init(&public_buffer, public_length, public);
if (!parse_atom(&public_buffer, &atom)
|| (atom != ATOM_SSH_DSS) )
{
KILL(res);
return 0;
}
simple_buffer_init(&private_buffer, private_length, private);
if (! (parse_dsa_public(&public_buffer, &res->public)
&& parse_bignum(&private_buffer, res->a)
/* FIXME: Perhaps do some more sanity checks? */
&& (mpz_sgn(res->a) == 1)
&& parse_eod(&private_buffer) ))
{
KILL(res);
return NULL;
}
res->super.sign = do_dsa_sign;
res->random = closure->random;
return &res->super;
}
#if DATAFELLOWS_SSH2_SSH_DSA_KLUDGE
struct signer *make_dsa_signer_kludge(struct signer *s)
{
NEW(dsa_signer_kludge, self);
CAST(dsa_signer, dsa, s);
self->super.sign = do_dsa_sign_kludge;
self->dsa = dsa;
return &self->super;
}
#endif /* DATAFELLOWS_SSH2_SSH_DSA_KLUDGE */
static struct verifier *
make_dsa_verifier(struct signature_algorithm *closure UNUSED,
UINT32 public_length,
UINT8 *public)
{
NEW(dsa_verifier, res);
struct simple_buffer buffer;
int atom;
/* FIXME: The allocator could do this kind of initialization
* automatically. */
mpz_init(res->public.p);
mpz_init(res->public.q);
mpz_init(res->public.g);
mpz_init(res->public.y);
simple_buffer_init(&buffer, public_length, public);
if (!parse_atom(&buffer, &atom)
|| (atom != ATOM_SSH_DSS) )
{
KILL(res);
return 0;
}
if (!parse_dsa_public(&buffer, &res->public))
/* FIXME: Perhaps do some more sanity checks? */
{
KILL(res);
return NULL;
}
res->super.verify = do_dsa_verify;
return &res->super;
}
struct signature_algorithm *make_dsa_algorithm(struct randomness *random)
{
NEW(dsa_algorithm, dsa);
dsa->super.make_signer = make_dsa_signer;
dsa->super.make_verifier = make_dsa_verifier;
dsa->random = random;
return &dsa->super;
}
/* Groups */
/* GABA:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment