Skip to content

Commit

Permalink
Implement Diffie-Hellman computations in crypto backends. (libssh2#149)
Browse files Browse the repository at this point in the history
Not all backends feature the low level API needed to compute a Diffie-Hellman
secret, but some of them directly implement Diffie-Hellman support with opaque
private data. The later approach is now generalized and backends are
responsible for all Diffie Hellman computations.
As a side effect, procedures/macros _libssh2_bn_rand and _libssh2_bn_mod_exp
are no longer needed outside the backends.
  • Loading branch information
monnerat authored and alamaison committed Nov 27, 2016
1 parent 5abceec commit f7daf31
Show file tree
Hide file tree
Showing 10 changed files with 215 additions and 96 deletions.
24 changes: 0 additions & 24 deletions docs/HACKING.CRYPTO
Original file line number Diff line number Diff line change
Expand Up @@ -338,13 +338,6 @@ TripleDES-CBC algorithm identifier initializer.


5) Diffie-Hellman support.
If the crypto-library supports opaque Diffie-Hellman computations, symbol
`libssh2_dh_key_pair' should be #defined as described below and the rest of
this section applies.
Else, the Diffie-Hellman context MUST be defined as `_libssh2_bn *' and
the computation is emulated via calls to _libssh2_bn_rand() and
_libssh2_bn_mod_exp(): all other symbols in this section are unused in this
case.

5.1) Diffie-Hellman context.
_libssh2_dh_ctx
Expand All @@ -364,7 +357,6 @@ Generates a Diffie-Hellman key pair using base `g', prime `p' and the given
The private key is stored as opaque in the Diffie-Hellman context `*dhctx' and
the public key is returned in `public'.
0 is returned upon success, else -1.
If defined, this procedure MUST be implemented as a #define'd macro.

int libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p, _libssh2_bn_ctx * bnctx)
Expand Down Expand Up @@ -434,22 +426,6 @@ Converts the absolute value of bn into big-endian form and store it at
val. val must point to _libssh2_bn_bytes(bn) bytes of memory.
Returns the length of the big-endian number.

void _libssh2_bn_rand(_libssh2_bn *bn, int bits, int top, int bottom);
Generates a cryptographically strong pseudo-random number of bits in
length and stores it in bn. If top is -1, the most significant bit of the
random number can be zero. If top is 0, it is set to 1, and if top is 1, the
two most significant bits of the number will be set to 1, so that the product
of two such random numbers will always have 2*bits length. If bottom is true,
the number will be odd.
This procedure is only needed if no specific Diffie-Hellman support is provided.

void _libssh2_bn_mod_exp(_libssh2_bn *r, _libssh2_bn *a,
_libssh2_bn *p, _libssh2_bn *m,
_libssh2_bn_ctx *ctx);
Computes a to the p-th power modulo m and stores the result into r (r=a^p % m).
May use the given context.
This procedure is only needed if no specific Diffie-Hellman support is provided.


7) Private key algorithms.
Format of an RSA public key:
Expand Down
38 changes: 0 additions & 38 deletions src/kex.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,44 +98,6 @@
} \
}

/*
* Generic Diffie-Hellman computation support.
*
* DH context should be a _libssh2_bn *.
*/

#ifndef libssh2_dh_key_pair
static void libssh2_dh_init(_libssh2_dh_ctx *dhctx)
{
*dhctx = _libssh2_bn_init(); /* Random from client */
}

static int libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
_libssh2_bn *g, _libssh2_bn *p, int group_order,
_libssh2_bn_ctx *bnctx)
{
/* Generate x and e */
_libssh2_bn_rand(*dhctx, group_order * 8 - 1, 0, -1);
_libssh2_bn_mod_exp(public, g, *dhctx, p, bnctx);
return 0;
}

static int libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p,
_libssh2_bn_ctx * bnctx)
{
/* Compute the shared secret */
_libssh2_bn_mod_exp(secret, f, *dhctx, p, bnctx);
return 0;
}

static void libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
{
_libssh2_bn_free(*dhctx);
*dhctx = NULL;
}
#endif


/*
* diffie_hellman_sha1
Expand Down
33 changes: 33 additions & 0 deletions src/libgcrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,4 +624,37 @@ void _libssh2_init_aes_ctr(void)
{
/* no implementation */
}

void
_libssh2_dh_init(_libssh2_dh_ctx *dhctx)
{
*dhctx = gcry_mpi_new(0); /* Random from client */
}

int
_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
_libssh2_bn *g, _libssh2_bn *p, int group_order)
{
/* Generate x and e */
gcry_mpi_randomize(*dhctx, group_order * 8 - 1, GCRY_WEAK_RANDOM);
gcry_mpi_powm(public, g, *dhctx, p);
return 0;
}

int
_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p)
{
/* Compute the shared secret */
gcry_mpi_powm(secret, f, *dhctx, p);
return 0;
}

void
_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
{
gcry_mpi_release(*dhctx);
*dhctx = NULL;
}

#endif /* LIBSSH2_LIBGCRYPT */
17 changes: 14 additions & 3 deletions src/libgcrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,25 @@
#define _libssh2_bn_ctx_free(bnctx) ((void)0)
#define _libssh2_bn_init() gcry_mpi_new(0)
#define _libssh2_bn_init_from_bin() NULL /* because gcry_mpi_scan() creates a new bignum */
#define _libssh2_bn_rand(bn, bits, top, bottom) gcry_mpi_randomize (bn, bits, GCRY_WEAK_RANDOM)
#define _libssh2_bn_mod_exp(r, a, p, m, ctx) gcry_mpi_powm (r, a, p, m)
#define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val)
#define _libssh2_bn_from_bin(bn, len, val) gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL)
#define _libssh2_bn_to_bin(bn, val) gcry_mpi_print (GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn)
#define _libssh2_bn_bytes(bn) (gcry_mpi_get_nbits (bn) / 8 + ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1))
#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn)
#define _libssh2_bn_free(bn) gcry_mpi_release(bn)

#define _libssh2_dh_ctx _libssh2_bn *
#define _libssh2_dh_ctx struct gcry_mpi *
#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx)
#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \
_libssh2_dh_key_pair(dhctx, public, g, p, group_order)
#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \
_libssh2_dh_secret(dhctx, secret, f, p)
#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx)
extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx);
extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
_libssh2_bn *g, _libssh2_bn *p,
int group_order);
extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p);
extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);

41 changes: 40 additions & 1 deletion src/mbedtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ _libssh2_mbedtls_bignum_init(void)
return bignum;
}

int
static int
_libssh2_mbedtls_bignum_random(_libssh2_bn *bn, int bits, int top, int bottom)
{
size_t len;
Expand Down Expand Up @@ -603,4 +603,43 @@ void _libssh2_init_aes_ctr(void)
{
/* no implementation */
}


/*******************************************************************/
/*
* mbedTLS backend: Diffie-Hellman functions
*/

void
_libssh2_dh_init(_libssh2_dh_ctx *dhctx)
{
*dhctx = _libssh2_mbedtls_bignum_init(); /* Random from client */
}

int
_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
_libssh2_bn *g, _libssh2_bn *p, int group_order)
{
/* Generate x and e */
_libssh2_mbedtls_bignum_random(*dhctx, group_order * 8 - 1, 0, -1);
mbedtls_mpi_exp_mod(public, g, *dhctx, p, NULL);
return 0;
}

int
_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p)
{
/* Compute the shared secret */
mbedtls_mpi_exp_mod(secret, f, *dhctx, p, NULL);
return 0;
}

void
_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
{
mbedtls_mpi_free(*dhctx);
*dhctx = NULL;
}

#endif /* LIBSSH2_MBEDTLS */
26 changes: 18 additions & 8 deletions src/mbedtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,6 @@ mbedtls_ctr_drbg_context _libssh2_mbedtls_ctr_drbg;
_libssh2_mbedtls_bignum_init()
#define _libssh2_bn_init_from_bin() \
_libssh2_mbedtls_bignum_init()
#define _libssh2_bn_rand(bn, bits, top, bottom) \
_libssh2_mbedtls_bignum_random(bn, bits, top, bottom)
#define _libssh2_bn_mod_exp(r, a, p, m, ctx) \
mbedtls_mpi_exp_mod(r, a, p, m, NULL)
#define _libssh2_bn_set_word(bn, word) \
mbedtls_mpi_lset(bn, word)
#define _libssh2_bn_from_bin(bn, len, bin) \
Expand All @@ -262,7 +258,13 @@ mbedtls_ctr_drbg_context _libssh2_mbedtls_ctr_drbg;
* mbedTLS backend: Diffie-Hellman support.
*/

#define _libssh2_dh_ctx _libssh2_bn *
#define _libssh2_dh_ctx mbedtls_mpi *
#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx)
#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \
_libssh2_dh_key_pair(dhctx, public, g, p, group_order)
#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \
_libssh2_dh_secret(dhctx, secret, f, p)
#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx)


/*******************************************************************/
Expand Down Expand Up @@ -310,9 +312,6 @@ _libssh2_mbedtls_bignum_init(void);
void
_libssh2_mbedtls_bignum_free(_libssh2_bn *bn);

int
_libssh2_mbedtls_bignum_random(_libssh2_bn *bn, int bits, int top, int bottom);

int
_libssh2_mbedtls_rsa_new(libssh2_rsa_ctx **rsa,
const unsigned char *edata,
Expand Down Expand Up @@ -377,3 +376,14 @@ _libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
const char *privatekeydata,
size_t privatekeydata_len,
const char *passphrase);

extern void
_libssh2_dh_init(_libssh2_dh_ctx *dhctx);
extern int
_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
_libssh2_bn *g, _libssh2_bn *p, int group_order);
extern int
_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p);
extern void
_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);
34 changes: 34 additions & 0 deletions src/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1189,4 +1189,38 @@ _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
return st;
}

void
_libssh2_dh_init(_libssh2_dh_ctx *dhctx)
{
*dhctx = BN_new(); /* Random from client */
}

int
_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
_libssh2_bn *g, _libssh2_bn *p, int group_order,
_libssh2_bn_ctx *bnctx)
{
/* Generate x and e */
BN_rand(*dhctx, group_order * 8 - 1, 0, -1);
BN_mod_exp(public, g, *dhctx, p, bnctx);
return 0;
}

int
_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p,
_libssh2_bn_ctx *bnctx)
{
/* Compute the shared secret */
BN_mod_exp(secret, f, *dhctx, p, bnctx);
return 0;
}

void
_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
{
BN_clear_free(*dhctx);
*dhctx = NULL;
}

#endif /* LIBSSH2_OPENSSL */
18 changes: 15 additions & 3 deletions src/openssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,16 +278,28 @@ int _libssh2_md5_init(libssh2_md5_ctx *ctx);
#define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx)
#define _libssh2_bn_init() BN_new()
#define _libssh2_bn_init_from_bin() _libssh2_bn_init()
#define _libssh2_bn_rand(bn, bits, top, bottom) BN_rand(bn, bits, top, bottom)
#define _libssh2_bn_mod_exp(r, a, p, m, ctx) BN_mod_exp(r, a, p, m, ctx)
#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val)
#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn)
#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val)
#define _libssh2_bn_bytes(bn) BN_num_bytes(bn)
#define _libssh2_bn_bits(bn) BN_num_bits(bn)
#define _libssh2_bn_free(bn) BN_clear_free(bn)

#define _libssh2_dh_ctx _libssh2_bn *
#define _libssh2_dh_ctx BIGNUM *
#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx)
#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \
_libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx)
#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \
_libssh2_dh_secret(dhctx, secret, f, p, bnctx)
#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx)
extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx);
extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
_libssh2_bn *g, _libssh2_bn *p, int group_order,
_libssh2_bn_ctx *bnctx);
extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p,
_libssh2_bn_ctx *bnctx);
extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);

const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void);
const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void);
Expand Down
Loading

0 comments on commit f7daf31

Please sign in to comment.