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

Implemented DH key exchange.

Rev: src/publickey_crypto.c:1.3
Rev: src/publickey_crypto.h:1.2
parent 876c2b47
......@@ -5,13 +5,16 @@
#include "bignum.h"
#include "sha.h"
#include "atoms.h"
#include "publickey_crypto.h"
/* DSS signatures */
struct dss_public
{
bignum p;
bignum q;
bignum g;
bignum y;
mpz_t p;
mpz_t q;
mpz_t g;
mpz_t y;
};
struct dss_signer
......@@ -19,7 +22,7 @@ struct dss_signer
struct signer super;
struct randomness *random;
struct dss_public public;
bignum a;
mpz_t a;
};
struct dss_verifier
......@@ -34,7 +37,7 @@ struct dss_algorithm
struct randomness *random;
};
static void dss_hash(bignum h, UINT32 length, UINT8 *msg)
static void dss_hash(mpz_t h, UINT32 length, UINT8 *msg)
{
/* Compute hash */
hash = MAKE_HASH(&sha_algorithm);
......@@ -52,7 +55,7 @@ static struct lsh_string *do_dss_sign(struct signer *s,
UINT8 *msg)
{
struct dss_signer *closure = (struct dss_signer *) s;
bignum k, r, s, tmp;
mpz_t k, r, s, tmp;
struct hash_instance *hash;
UINT8 *digest;
struct lsh_string *signature;
......@@ -114,9 +117,9 @@ ind do_dss_verify(struct verifier *closure,
int res;
int atom;
bignum r, s;
mpz_t r, s;
bignum w, tmp, u, v;
mpz_t w, tmp, u, v;
simple_buffer_init(&buffer, signature_length, signature_data);
if (!parse_atom(&buffer, &atom)
......@@ -301,3 +304,207 @@ struct make_dss_algorithm(struct randomness *random)
return &dss->super;
}
/* Groups */
struct group_zn /* Z_n^* */
{
struct group super;
mpz_t modulo;
};
static int zn_member(struct group *c, mpz_t x)
{
struct group_zn *closure = (struct group_zn *) c;
return ( (mpz_sgn(x) == 1) && (mpz_cmp(x, closure->modulo) < 0) );
}
static void zn_invert(struct group *c, mpz_t res, mpz_t x)
{
struct group_zn *closure = (struct group_zn *) c;
if (!mpz_invert(res, x, closure->modulo))
fatal("zn_invert: element is non-invertible\n");
}
static void zn_combine(struct group *c, mpz_t res, mpz_t a, mpz_t b)
{
struct group_zn *closure = (struct group_zn *) c;
mpz_mul(res, a, b);
mpz_tdiv_r(res, res, closure->modulo);
}
static void zn_power(struct group *c, mpz_t res, mpz_t g, mpz_t e)
{
struct group_zn *closure = (struct group_zn *) c;
mpz_powm(res, g, e, closure->modulo);
}
/* Assumes p is a prime number */
struct group *make_zn(mpz_t p)
{
struct group_zn *res = xalloc(sizeof(struct group_zn));
res->super.member = zn_member;
res->super.invert = zn_invert;
res->super.combine = zn_combine;
res->super.power = zn_power; /* Pretty Mutation! Magical Recall! */
mpz_init_set(res->modulo, n);
mpz_init_set(res->super.order, n);
return &res->super;
}
/* diffie-hellman */
struct diffie_hellman_instance *
make_diffie_hellman_instance(struct diffie_hellman_method *m,
struct connection *c)
{
struct diffie_hellman_instance *res
= xalloc(sizeof(struct diffie_hellman_instance));
mpz_init(res->e);
mpz_init(res->f);
mpz_init(res->secret);
res->method = m;
res->hash = make_hash(m->H);
HASH_UPDATE(res->hash,
c->client_version->length,
c->client_version->data);
HASH_UPDATE(res->hash,
c->server_version->length,
c->server_version->data);
return res;
}
struct group *make_dh1(struct randomness *r)
{
struct diffie_hellman_method *res
= xalloc(sizeof(struct diffie_hellman_method));
mpz_t p;
mpz_init_set_str(p,
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
"FFFFFFFFFFFFFFFF", 16);
res->G = make_zn(p);
mpz_clear(p);
mpz_init_set_ui(res->generator, 2);
res->hash_algorithm = &sha_algorithm;
res->random = r;
return res;
}
void dh_generate_secret(struct diffie_hellman_instance *self,
mpz_t r)
{
mpz_t tmp;
/* Generate a random number, 1 < x < O(G) */
mpz_init_set(tmp, self->method->G->order);
mpz_sub_ui(tmp, tmp, 2);
bignum_random(self->secret, tmp);
mpz_add_ui(self->secret, self->secret, 2);
mpz_clear(tmp);
GROUP_POWER(self->methog->G, r, self->method->generator, self->secret);
}
struct lsh_string *dh_make_client_msg(struct diffie_hellman_instance *self)
{
dh_generate_secret(self, self->e);
return ssh_format("%c%n", SSH_MSG_KEXDH_INIT, self->e);
}
int dh_process_client_msg(struct diffie_hellman_instance *self,
struct lsh_string *packet)
{
struct simple_buffer buffer;
UINT8 msg_number;
simple_buffer_init(&buffer, packet->length, packet->data);
return (parse_uint8(&buffer, &msg_number)
&& (msg_number == SSH_MSG_KEXDH_INIT)
&& parse_bignum(&buffer, self->e)
&& (mpz_cmp_ui(self->e, 1) > 0)
&& (mpz_cmp(self->e, self->method->G->order) < 0)
&& parse_eod(&buffer) );
}
void dh_hash_update(struct diffie_hellman_instance *self,
struct lsh_string *packet)
{
HASH_UPDATE(self->hash, packet->length, packet->data);
}
/* Hashes server key, e and f */
void dh_hash_digest(struct diffie_hellman_instance *self, UINT8 *digest)
{
struct lsh_string s = ssh_format("%S%n%n",
self->server_key,
self->e, self->f);
HASH_UPDATE(self->hash, s->length, s->data);
lsh_string_free(s);
HASH_DIGEST(hash, digest);
}
struct lsh_string *dh_make_server_msg(struct diffie_hellman_instance *self,
struct signer *s)
{
UINT8 *digest;
dh_generate_secret(self, self->f);
digest = alloca(self->hash->hash_size);
dh_digest(self, digest);
return ssh_format("%c%S%n%fS",
SSH_MSG_KEXDH_REPLY,
self->server_key,
self->f, SIGN(s, self->hash->hash_size, digest));
}
int dh_process_server_msg(struct diffie_hellman_instance *self,
struct lsh_string *packet)
{
struct simple_buffer buffer;
UINT8 msg_number;
simple_buffer_init(&buffer, packet->length, packet->data);
return (parse_uint8(&buffer, &msg_number)
&& (msg_number == SSH_MSG_KEXDH_REPLY)
&& (res->server_key = parse_string_copy(&buffer))
&& (parse_bignum(&buffer, res->f))
&& (mpz_cmp_ui(self->f, 1) > 0)
&& (mpz_cmp(self->f, self->method->G->order) < 0)
&& (res->signature = parse_string_copy(&buffer))
&& parse_eod(&buffer));
}
int dh_verify_server_msg(struct diffie_hellman_instance *self,
struct verifier *v)
{
UINT8 *digest;
digest = alloca(self->hash->hash_size);
dh_digest(self, digest);
return VERIFY(v, self->hash->hash_size, digest,
self->signature->length, self->signature->data);
}
......@@ -9,5 +9,80 @@
struct make_dss_algorithm(struct randomness *random);
/* Groups. For now, assume that all group elements are represented by
* bignums. */
struct group
{
/* Returns 1 if x is an element of the group, and is in the
* canonical representation */
int (*member)(struct group *closure, mpz_t x);
void (*invert)(struct group *closure, mpz_t res, mpz_t x);
void (*combine)(struct group *closure, mpz_t res, mpz_t a, mpz_t b);
/* FIXME: Doesn't handle negative exponents */
void (*power)(struct group *closure, mpz_t res, mpz_t g, mpz_t e);
mpz_t order;
};
#define GROUP_MEMBER(group, x) ((group)->member((group), (x)))
#define GROUP_INVERT(group, res, x) ((group)->invert((group), (res), (x)))
#define GROUP_COMBINE(group, res, a, b) \
((group)->combine((group), (res), (a), (b)))
#define GROUP_POWER(group, res, g, e) \
((group)->POWER((group), (res), (g), (e)))
/* DH key exchange, with authentication */
struct diffie_hellman_method
{
struct group *G;
mpz_t generator;
struct hash_algorithm *H;
struct randomness *random;
};
struct diffie_hellman_instance
{
struct diffie_hellman_method *method;
mpz_t e; /* client value */
mpz_t f; /* server value */
struct lsh_string *server_key;
struct lsh_string *signature;
mpz_t secret; /* This side's secret exponent */
struct lsh_string *K;
struct hash_instance *hash;
};
/* Creates client message */
struct lsh_string *dh_make_client_msg(struct diffie_hellman_instance *self);
/* Recieves client message */
int dh_process_client_msg(struct diffie_hellman_instance *self,
struct lsh_string *packet);
/* Should be called with the kex_init messages, client's first */
void dh_hash_update(struct diffie_hellman_instance *self,
struct lsh_string *packet);
/* Creates server message */
struct lsh_string *dh_make_server_msg(struct diffie_hellman_instance *self,
struct signer s);
/* Decodes server message, but does not verify its signature */
int dh_process_server_msg(struct diffie_hellman_instance *self,
struct lsh_string *packet);
/* Verifies server's signature */
int dh_verify_server_msg(struct diffie_hellman_instance *self,
struct verifier *v);
#if 0
struct diffie_hellman_method *
make_diffie_hellman_method(struct group *group,
struct hash_algorithm *h,
struct randomness *r);
#endif
struct diffie_hellman_instance *
make_diffie_hellman_instance(struct diffie_hellman_method *m,
struct connection *c);
#endif /* LSH_PUBLICKEY_CRYPTO_H_INCLUDED */
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