From f7daf3185a4e889fcd5272858db97764a279da1e Mon Sep 17 00:00:00 2001 From: monnerat Date: Sun, 27 Nov 2016 19:39:00 +0100 Subject: [PATCH] Implement Diffie-Hellman computations in crypto backends. (#149) 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. --- docs/HACKING.CRYPTO | 24 ----------------------- src/kex.c | 38 ------------------------------------- src/libgcrypt.c | 33 ++++++++++++++++++++++++++++++++ src/libgcrypt.h | 17 ++++++++++++++--- src/mbedtls.c | 41 +++++++++++++++++++++++++++++++++++++++- src/mbedtls.h | 26 +++++++++++++++++-------- src/openssl.c | 34 +++++++++++++++++++++++++++++++++ src/openssl.h | 18 +++++++++++++++--- src/wincng.c | 46 +++++++++++++++++++++++++++++++++++++++------ src/wincng.h | 34 ++++++++++++++++++++------------- 10 files changed, 215 insertions(+), 96 deletions(-) diff --git a/docs/HACKING.CRYPTO b/docs/HACKING.CRYPTO index 91e91e0c..c4a0c716 100644 --- a/docs/HACKING.CRYPTO +++ b/docs/HACKING.CRYPTO @@ -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 @@ -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) @@ -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: diff --git a/src/kex.c b/src/kex.c index c0f92609..8df34172 100644 --- a/src/kex.c +++ b/src/kex.c @@ -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 diff --git a/src/libgcrypt.c b/src/libgcrypt.c index 366d007a..6ba13a14 100644 --- a/src/libgcrypt.c +++ b/src/libgcrypt.c @@ -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 */ diff --git a/src/libgcrypt.h b/src/libgcrypt.h index 2a3f8d1f..113e5b2b 100644 --- a/src/libgcrypt.h +++ b/src/libgcrypt.h @@ -172,8 +172,6 @@ #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) @@ -181,5 +179,18 @@ #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); diff --git a/src/mbedtls.c b/src/mbedtls.c index 1d181e18..c0ecd18e 100644 --- a/src/mbedtls.c +++ b/src/mbedtls.c @@ -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; @@ -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 */ diff --git a/src/mbedtls.h b/src/mbedtls.h index 2b6ce5f7..9ed787e1 100644 --- a/src/mbedtls.h +++ b/src/mbedtls.h @@ -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) \ @@ -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) /*******************************************************************/ @@ -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, @@ -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); diff --git a/src/openssl.c b/src/openssl.c index 4f63ef92..b7b146cd 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -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 */ diff --git a/src/openssl.h b/src/openssl.h index fba04547..6aa12192 100644 --- a/src/openssl.h +++ b/src/openssl.h @@ -278,8 +278,6 @@ 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) @@ -287,7 +285,21 @@ int _libssh2_md5_init(libssh2_md5_ctx *ctx); #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); diff --git a/src/wincng.c b/src/wincng.c index d3271b3e..6b0a7a90 100755 --- a/src/wincng.c +++ b/src/wincng.c @@ -1840,7 +1840,7 @@ _libssh2_wincng_bignum_resize(_libssh2_bn *bn, unsigned long length) return 0; } -int +static int _libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom) { unsigned char *bignum; @@ -1877,12 +1877,11 @@ _libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom) return 0; } -int +static int _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, _libssh2_bn *a, _libssh2_bn *p, - _libssh2_bn *m, - _libssh2_bn_ctx *bnctx) + _libssh2_bn *m) { BCRYPT_KEY_HANDLE hKey; BCRYPT_RSAKEY_BLOB *rsakey; @@ -1890,8 +1889,6 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, unsigned long keylen, offset, length; int ret; - (void)bnctx; - if (!r || !a || !p || !m) return -1; @@ -2063,6 +2060,43 @@ _libssh2_wincng_bignum_free(_libssh2_bn *bn) } +/* + * Windows CNG backend: Diffie-Hellman support. + */ + +void +_libssh2_dh_init(_libssh2_dh_ctx *dhctx) +{ + *dhctx = _libssh2_wincng_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_wincng_bignum_rand(*dhctx, group_order * 8 - 1, 0, -1); + _libssh2_wincng_bignum_mod_exp(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 */ + _libssh2_wincng_bignum_mod_exp(secret, f, *dhctx, p); + return 0; +} + +void +_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) +{ + _libssh2_wincng_bignum_free(*dhctx); + *dhctx = NULL; +} + + /* * Windows CNG backend: other functions */ diff --git a/src/wincng.h b/src/wincng.h index 1e9c3ba6..de307b8b 100755 --- a/src/wincng.h +++ b/src/wincng.h @@ -358,10 +358,6 @@ _libssh2_bn *_libssh2_wincng_bignum_init(void); _libssh2_wincng_bignum_init() #define _libssh2_bn_init_from_bin() \ _libssh2_bn_init() -#define _libssh2_bn_rand(bn, bits, top, bottom) \ - _libssh2_wincng_bignum_rand(bn, bits, top, bottom) -#define _libssh2_bn_mod_exp(r, a, p, m, ctx) \ - _libssh2_wincng_bignum_mod_exp(r, a, p, m, ctx) #define _libssh2_bn_set_word(bn, word) \ _libssh2_wincng_bignum_set_word(bn, word) #define _libssh2_bn_from_bin(bn, len, bin) \ @@ -374,7 +370,17 @@ _libssh2_bn *_libssh2_wincng_bignum_init(void); #define _libssh2_bn_free(bn) \ _libssh2_wincng_bignum_free(bn) -#define _libssh2_dh_ctx _libssh2_bn * +/* + * Windows CNG backend: Diffie-Hellman support + */ + +#define _libssh2_dh_ctx struct _libssh2_wincng_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) +#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) /*******************************************************************/ /* @@ -533,14 +539,6 @@ _libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx); _libssh2_bn * _libssh2_wincng_bignum_init(void); int -_libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom); -int -_libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, - _libssh2_bn *a, - _libssh2_bn *p, - _libssh2_bn *m, - _libssh2_bn_ctx *bnctx); -int _libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word); unsigned long _libssh2_wincng_bignum_bits(const _libssh2_bn *bn); @@ -551,3 +549,13 @@ void _libssh2_wincng_bignum_to_bin(const _libssh2_bn *bn, unsigned char *bin); void _libssh2_wincng_bignum_free(_libssh2_bn *bn); +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);