diff options
author | Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 2019-11-08 23:03:16 +0000 |
---|---|---|
committer | Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 2019-11-08 23:03:16 +0000 |
commit | 3d4928e4268bea40a37e796795e42353d4415a6d (patch) | |
tree | 09c47bc9a321b97e42be721cf95951fb909b4227 /lib/nettle | |
parent | b5029c0a57ba881e1db4a8c7d5c680f0f2df8dc4 (diff) | |
parent | 6eadc827ea6323cf7d752cba1b41cf9b93aae9b9 (diff) | |
download | gnutls-3d4928e4268bea40a37e796795e42353d4415a6d.tar.gz |
Merge branch 'gost-split-2' into 'master'
GOST key exchange support
See merge request gnutls/gnutls!1097
Diffstat (limited to 'lib/nettle')
-rw-r--r-- | lib/nettle/Makefile.am | 6 | ||||
-rw-r--r-- | lib/nettle/gost/gost-wrap.c | 132 | ||||
-rw-r--r-- | lib/nettle/gost/gost28147.h | 25 | ||||
-rw-r--r-- | lib/nettle/gost/gostdsa-vko.c | 78 | ||||
-rw-r--r-- | lib/nettle/gost/gostdsa.h | 7 | ||||
-rw-r--r-- | lib/nettle/gost_keywrap.c | 121 | ||||
-rw-r--r-- | lib/nettle/pk.c | 61 |
7 files changed, 428 insertions, 2 deletions
diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am index 035102f127..c1ac2b2125 100644 --- a/lib/nettle/Makefile.am +++ b/lib/nettle/Makefile.am @@ -74,7 +74,7 @@ endif if ENABLE_GOST libcrypto_la_SOURCES += \ gost/nettle-write.h \ - gost/gost28147.c gost/gost28147.h \ + gost/gost28147.c gost/gost28147.h gost/gost-wrap.c \ gost/gosthash94.c gost/gosthash94.h gost/gosthash94-meta.c \ gost/streebog.c gost/streebog.h gost/streebog-meta.c \ gost/hmac-gosthash94.c gost/hmac-streebog.c gost/hmac-gost.h @@ -92,6 +92,8 @@ libcrypto_la_SOURCES += \ gost/ecc-gost512a.c gost/ecc-gost512a-32.h gost/ecc-gost512a-64.h \ gost/ecc-internal.h gost/gmp-glue.h \ gost/ecc-gostdsa-sign.c gost/ecc-gostdsa-verify.c \ - gost/gostdsa-mask.c gost/gostdsa-sign.c gost/gostdsa-verify.c \ + gost/gostdsa-mask.c gost/gostdsa-sign.c gost/gostdsa-verify.c gost/gostdsa-vko.c \ gost/gostdsa.h gost/ecc-gost-curve.h gost/ecc-gost-hash.c + +libcrypto_la_SOURCES += gost_keywrap.c endif diff --git a/lib/nettle/gost/gost-wrap.c b/lib/nettle/gost/gost-wrap.c new file mode 100644 index 0000000000..63e1c321e2 --- /dev/null +++ b/lib/nettle/gost/gost-wrap.c @@ -0,0 +1,132 @@ +/* GOST 28147-89 (Magma) implementation + * + * Copyright: 2015, 2016 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> + * Copyright: 2009-2012 Aleksey Kravchenko <rhash.admin@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnutls_int.h> + +#include <string.h> + +#include <nettle/macros.h> +#include "gost28147.h" +#include <nettle/cfb.h> +#include <nettle/memops.h> + +void +gost28147_kdf_cryptopro(const struct gost28147_param *param, + const uint8_t *in, + const uint8_t *ukm, + uint8_t *out) +{ + struct gost28147_ctx ctx; + int i; + + memcpy(out, in, GOST28147_KEY_SIZE); + for (i = 0; i < 8; i++) { + uint8_t mask; + uint8_t *p; + uint8_t iv[GOST28147_BLOCK_SIZE]; + uint32_t block[2] = {0, 0}; + uint32_t t; + + for (p = out, mask = 1; mask; mask <<= 1) { + t = LE_READ_UINT32(p); + p += 4; + if (mask & ukm[i]) + block[0] += t; + else + block[1] += t; + } + + LE_WRITE_UINT32(iv + 0, block[0]); + LE_WRITE_UINT32(iv + 4, block[1]); + + gost28147_set_key(&ctx, out); + gost28147_set_param(&ctx, param); + cfb_encrypt(&ctx, + (nettle_cipher_func*)gost28147_encrypt_for_cfb, + GOST28147_BLOCK_SIZE, iv, + GOST28147_KEY_SIZE, out, out); + } +} + +void +gost28147_key_wrap_cryptopro(const struct gost28147_param *param, + const uint8_t *kek, + const uint8_t *ukm, size_t ukm_size, + const uint8_t *cek, + uint8_t *enc, + uint8_t *imit) +{ + uint8_t kd[GOST28147_KEY_SIZE]; + struct gost28147_ctx ctx; + struct gost28147_imit_ctx ictx; + + assert(ukm_size >= GOST28147_IMIT_BLOCK_SIZE); + + gost28147_kdf_cryptopro(param, kek, ukm, kd); + gost28147_set_key(&ctx, kd); + gost28147_set_param(&ctx, param); + gost28147_encrypt(&ctx, GOST28147_KEY_SIZE, enc, cek); + + gost28147_imit_init(&ictx); + gost28147_imit_set_key(&ictx, GOST28147_KEY_SIZE, kd); + gost28147_imit_set_param(&ictx, param); + gost28147_imit_set_nonce(&ictx, ukm); + gost28147_imit_update(&ictx, GOST28147_KEY_SIZE, cek); + gost28147_imit_digest(&ictx, GOST28147_IMIT_DIGEST_SIZE, imit); +} + +int +gost28147_key_unwrap_cryptopro(const struct gost28147_param *param, + const uint8_t *kek, + const uint8_t *ukm, size_t ukm_size, + const uint8_t *enc, + const uint8_t *imit, + uint8_t *cek) +{ + uint8_t kd[GOST28147_KEY_SIZE]; + uint8_t mac[GOST28147_IMIT_DIGEST_SIZE]; + struct gost28147_ctx ctx; + struct gost28147_imit_ctx ictx; + + assert(ukm_size >= GOST28147_IMIT_BLOCK_SIZE); + + gost28147_kdf_cryptopro(param, kek, ukm, kd); + gost28147_set_key(&ctx, kd); + gost28147_set_param(&ctx, param); + gost28147_decrypt(&ctx, GOST28147_KEY_SIZE, cek, enc); + + gost28147_imit_init(&ictx); + gost28147_imit_set_key(&ictx, GOST28147_KEY_SIZE, kd); + gost28147_imit_set_param(&ictx, param); + gost28147_imit_set_nonce(&ictx, ukm); + gost28147_imit_update(&ictx, GOST28147_KEY_SIZE, cek); + gost28147_imit_digest(&ictx, GOST28147_IMIT_DIGEST_SIZE, mac); + + return memeql_sec(mac, imit, GOST28147_IMIT_DIGEST_SIZE); +} diff --git a/lib/nettle/gost/gost28147.h b/lib/nettle/gost/gost28147.h index 5fbab90ef1..ae4a385589 100644 --- a/lib/nettle/gost/gost28147.h +++ b/lib/nettle/gost/gost28147.h @@ -69,6 +69,10 @@ extern "C" { #define gost28147_cnt_set_iv _gnutls_gost28147_cnt_set_iv #define gost28147_cnt_crypt _gnutls_gost28147_cnt_crypt +#define gost28147_kdf_cryptopro _gnutls_gost28147_kdf_cryptopro +#define gost28147_key_wrap_cryptopro _gnutls_gost28147_key_wrap_cryptopro +#define gost28147_key_unwrap_cryptopro _gnutls_gost28147_key_unwrap_cryptopro + #define gost28147_imit_init _gnutls_gost28147_imit_init #define gost28147_imit_set_key _gnutls_gost28147_imit_set_key #define gost28147_imit_set_nonce _gnutls_gost28147_imit_set_nonce @@ -147,6 +151,27 @@ gost28147_cnt_crypt(struct gost28147_cnt_ctx *ctx, size_t length, uint8_t *dst, const uint8_t *src); +void +gost28147_kdf_cryptopro(const struct gost28147_param *param, + const uint8_t *in, + const uint8_t *ukm, + uint8_t *out); +void +gost28147_key_wrap_cryptopro(const struct gost28147_param *param, + const uint8_t *kek, + const uint8_t *ukm, size_t ukm_size, + const uint8_t *cek, + uint8_t *enc, + uint8_t *imit); + +int +gost28147_key_unwrap_cryptopro(const struct gost28147_param *param, + const uint8_t *kek, + const uint8_t *ukm, size_t ukm_size, + const uint8_t *enc, + const uint8_t *imit, + uint8_t *cek); + #define GOST28147_IMIT_DIGEST_SIZE 4 #define GOST28147_IMIT_BLOCK_SIZE GOST28147_BLOCK_SIZE #define GOST28147_IMIT_KEY_SIZE GOST28147_KEY_SIZE diff --git a/lib/nettle/gost/gostdsa-vko.c b/lib/nettle/gost/gostdsa-vko.c new file mode 100644 index 0000000000..89dff1cc45 --- /dev/null +++ b/lib/nettle/gost/gostdsa-vko.c @@ -0,0 +1,78 @@ +/* gostdsa-vko.c + + Copyright (C) 2016 Dmitry Eremin-Solenikov + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gnutls_int.h> + +#include <stdlib.h> + +#include "ecc-internal.h" +#include "gostdsa.h" + +int +gostdsa_vko(const struct ecc_scalar *key, + const struct ecc_point *pub, + size_t ukm_length, const uint8_t *ukm, + size_t out_length, uint8_t *out) +{ + const struct ecc_curve *ecc = key->ecc; + unsigned bsize = (ecc_bit_size(ecc) + 7) / 8; + mp_size_t size = ecc->p.size; + mp_size_t itch = 4*size + ecc->mul_itch; + mp_limb_t *scratch; + + if (itch < 5*size + ecc->h_to_a_itch) + itch = 5*size + ecc->h_to_a_itch; + + if (pub->ecc != ecc) + return 0; + + if (out_length < 2 * bsize) { + return 0; + } + + scratch = gmp_alloc_limbs (itch); + + mpn_set_base256_le (scratch, size, ukm, ukm_length); + if (mpn_zero_p (scratch, size)) + mpn_add_1 (scratch, scratch, size, 1); + ecc_modq_mul (ecc, scratch + 3*size, key->p, scratch); + ecc->mul (ecc, scratch, scratch + 3*size, pub->p, scratch + 4*size); + ecc->h_to_a (ecc, 0, scratch + 3*size, scratch, scratch + 5*size); + mpn_get_base256_le (out, bsize, scratch + 3*size, size); + mpn_get_base256_le (out+bsize, bsize, scratch + 4*size, size); + gmp_free_limbs (scratch, itch); + + return 2 * bsize; +} diff --git a/lib/nettle/gost/gostdsa.h b/lib/nettle/gost/gostdsa.h index 9b0f517529..9e0375f2ce 100644 --- a/lib/nettle/gost/gostdsa.h +++ b/lib/nettle/gost/gostdsa.h @@ -47,6 +47,7 @@ extern "C" { #define gostdsa_sign _gnutls_gostdsa_sign #define gostdsa_verify _gnutls_gostdsa_verify #define gostdsa_unmask_key _gnutls_gostdsa_unmask_key +#define gostdsa_vko _gnutls_gostdsa_vko #define ecc_gostdsa_sign _gnutls_ecc_gostdsa_sign #define ecc_gostdsa_sign_itch _gnutls_ecc_gostdsa_sign_itch #define ecc_gostdsa_verify _gnutls_ecc_gostdsa_verify @@ -75,6 +76,12 @@ int gostdsa_unmask_key (const struct ecc_curve *ecc, mpz_t key); +int +gostdsa_vko(const struct ecc_scalar *key, + const struct ecc_point *pub, + size_t ukm_length, const uint8_t *ukm, + size_t out_length, uint8_t *out); + /* Low-level GOSTDSA functions. */ mp_size_t ecc_gostdsa_sign_itch (const struct ecc_curve *ecc); diff --git a/lib/nettle/gost_keywrap.c b/lib/nettle/gost_keywrap.c new file mode 100644 index 0000000000..ca186702df --- /dev/null +++ b/lib/nettle/gost_keywrap.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2011-2012 Free Software Foundation, Inc. + * Copyright (C) 2016 Dmitry Eremin-Solenikov + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + */ + +#include "gnutls_int.h" +#include "gost/gost28147.h" + +static const struct gost28147_param * +_gnutls_gost_get_param(gnutls_gost_paramset_t param) +{ + if (param == GNUTLS_GOST_PARAMSET_TC26_Z) + return &gost28147_param_TC26_Z; + else if (param == GNUTLS_GOST_PARAMSET_CP_A) + return &gost28147_param_CryptoPro_A; + else if (param == GNUTLS_GOST_PARAMSET_CP_B) + return &gost28147_param_CryptoPro_B; + else if (param == GNUTLS_GOST_PARAMSET_CP_C) + return &gost28147_param_CryptoPro_C; + else if (param == GNUTLS_GOST_PARAMSET_CP_D) + return &gost28147_param_CryptoPro_D; + + gnutls_assert(); + + return NULL; +} + +int _gnutls_gost_key_wrap(gnutls_gost_paramset_t gost_params, + const gnutls_datum_t *kek, + const gnutls_datum_t *ukm, + const gnutls_datum_t *cek, + gnutls_datum_t *enc, + gnutls_datum_t *imit) +{ + const struct gost28147_param *gp; + + gp = _gnutls_gost_get_param(gost_params); + if (gp == NULL) { + return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + } + + if (kek->size != GOST28147_KEY_SIZE || + cek->size != GOST28147_KEY_SIZE || + ukm->size < GOST28147_IMIT_BLOCK_SIZE) { + return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + } + + enc->size = GOST28147_KEY_SIZE; + enc->data = gnutls_malloc(enc->size); + if (enc->data == NULL) { + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + } + + imit->size = GOST28147_IMIT_DIGEST_SIZE; + imit->data = gnutls_malloc(imit->size); + if (imit->data == NULL) { + _gnutls_free_datum(enc); + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + } + + gost28147_key_wrap_cryptopro(gp, kek->data, ukm->data, ukm->size, + cek->data, enc->data, imit->data); + + return 0; +} + +int _gnutls_gost_key_unwrap(gnutls_gost_paramset_t gost_params, + const gnutls_datum_t *kek, + const gnutls_datum_t *ukm, + const gnutls_datum_t *enc, + const gnutls_datum_t *imit, + gnutls_datum_t *cek) +{ + const struct gost28147_param *gp; + int ret; + + gp = _gnutls_gost_get_param(gost_params); + if (gp == NULL) { + return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + } + + if (kek->size != GOST28147_KEY_SIZE || + enc->size != GOST28147_KEY_SIZE || + imit->size != GOST28147_IMIT_DIGEST_SIZE || + ukm->size < GOST28147_IMIT_BLOCK_SIZE) { + return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); + } + + cek->size = GOST28147_KEY_SIZE; + cek->data = gnutls_malloc(cek->size); + if (cek->data == NULL) { + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + } + + ret = gost28147_key_unwrap_cryptopro(gp, kek->data, + ukm->data, ukm->size, + enc->data, imit->data, + cek->data); + if (ret == 0) { + gnutls_assert(); + _gnutls_free_temp_key_datum(cek); + return GNUTLS_E_DECRYPTION_FAILED; + } + + return 0; +} diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c index b6bb735566..42d540cb46 100644 --- a/lib/nettle/pk.c +++ b/lib/nettle/pk.c @@ -242,6 +242,7 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo, gnutls_datum_t * out, const gnutls_pk_params_st * priv, const gnutls_pk_params_st * pub, + const gnutls_datum_t * nonce, unsigned int flags) { int ret; @@ -252,6 +253,9 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo, bigint_t k = NULL, ff = NULL, r = NULL; unsigned int bits; + if (nonce != NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + f = pub->params[DH_Y]; x = priv->params[DH_X]; q = priv->params[DH_Q]; @@ -343,6 +347,9 @@ dh_cleanup: out->data = NULL; + if (nonce != NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + curve = get_supported_nist_curve(priv->curve); if (curve == NULL) return @@ -384,6 +391,9 @@ dh_cleanup: { unsigned size = gnutls_ecc_curve_get_size(priv->curve); + if (nonce != NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + /* The point is in pub, while the private part (scalar) in priv. */ if (size == 0 || priv->raw_priv.size != size) @@ -407,6 +417,57 @@ dh_cleanup: } break; } +#if ENABLE_GOST + case GNUTLS_PK_GOST_01: + case GNUTLS_PK_GOST_12_256: + case GNUTLS_PK_GOST_12_512: + { + struct ecc_scalar ecc_priv; + struct ecc_point ecc_pub; + const struct ecc_curve *curve; + + out->data = NULL; + + curve = get_supported_gost_curve(priv->curve); + if (curve == NULL) + return + gnutls_assert_val + (GNUTLS_E_ECC_UNSUPPORTED_CURVE); + + if (nonce == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + ret = _gost_params_to_pubkey(pub, &ecc_pub, curve); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gost_params_to_privkey(priv, &ecc_priv, curve); + if (ret < 0) { + ecc_point_clear(&ecc_pub); + return gnutls_assert_val(ret); + } + + out->size = 2 * gnutls_ecc_curve_get_size(priv->curve); + out->data = gnutls_malloc(out->size); + if (out->data == NULL) { + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto gost_cleanup; + } + + out->size = gostdsa_vko(&ecc_priv, &ecc_pub, + nonce->size, nonce->data, + out->size, out->data); + if (out->size == 0) + ret = GNUTLS_E_INVALID_REQUEST; + + gost_cleanup: + ecc_point_clear(&ecc_pub); + ecc_scalar_zclear(&ecc_priv); + if (ret < 0) + goto cleanup; + break; + } +#endif default: gnutls_assert(); ret = GNUTLS_E_INTERNAL_ERROR; |