aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2020-01-06 14:02:40 +0100
committerFlorian Dold <florian.dold@gmail.com>2020-01-06 14:02:40 +0100
commit1ad2fb331548adf635e9cff8786b468e54666371 (patch)
tree1eeafe3a8aa5a32ea78ead24fe742110133e0805 /src
parent2111817ee190b99561f067277c3b081da27e2afa (diff)
downloadgnunet-1ad2fb331548adf635e9cff8786b468e54666371.tar.gz
gnunet-1ad2fb331548adf635e9cff8786b468e54666371.zip
Fix ECDSA/ECDH key exchange
Libgcrypt interprets the private key as little endian, while tweetnacl interprets it as big endian. This caused the key exchange to fail.
Diffstat (limited to 'src')
-rw-r--r--src/util/.gitignore1
-rw-r--r--src/util/crypto_ecc.c109
-rw-r--r--src/util/tweetnacl-gnunet.c21
-rw-r--r--src/util/tweetnacl-gnunet.h4
4 files changed, 42 insertions, 93 deletions
diff --git a/src/util/.gitignore b/src/util/.gitignore
index 01ebcc834..0495dcf8f 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -30,6 +30,7 @@ test_container_multihashmap32
30test_container_multipeermap 30test_container_multipeermap
31test_crypto_crc 31test_crypto_crc
32test_crypto_ecc_dlog 32test_crypto_ecc_dlog
33test_crypto_ecdh_ecdsa
33test_crypto_ecdh_eddsa 34test_crypto_ecdh_eddsa
34test_crypto_ecdhe 35test_crypto_ecdhe
35test_crypto_ecdsa 36test_crypto_ecdsa
diff --git a/src/util/crypto_ecc.c b/src/util/crypto_ecc.c
index bd7c425d4..d4cfaa72c 100644
--- a/src/util/crypto_ecc.c
+++ b/src/util/crypto_ecc.c
@@ -173,22 +173,8 @@ GNUNET_CRYPTO_ecdsa_key_get_public (
173 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv, 173 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
174 struct GNUNET_CRYPTO_EcdsaPublicKey *pub) 174 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
175{ 175{
176 gcry_sexp_t sexp;
177 gcry_ctx_t ctx;
178 gcry_mpi_t q;
179
180 BENCHMARK_START (ecdsa_key_get_public); 176 BENCHMARK_START (ecdsa_key_get_public);
181 177 GNUNET_TWEETNACL_scalarmult_le_ed25519_base (pub->q_y, priv->d);
182 sexp = decode_private_ecdsa_key (priv);
183 GNUNET_assert (NULL != sexp);
184 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
185 gcry_sexp_release (sexp);
186 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
187 GNUNET_assert (NULL != q);
188 GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof(pub->q_y), q);
189 gcry_mpi_release (q);
190 gcry_ctx_release (ctx);
191
192 BENCHMARK_END (ecdsa_key_get_public); 178 BENCHMARK_END (ecdsa_key_get_public);
193} 179}
194 180
@@ -1041,45 +1027,6 @@ GNUNET_CRYPTO_ecdsa_public_key_derive (
1041 1027
1042 1028
1043/** 1029/**
1044 * Take point from ECDH and convert it to key material.
1045 *
1046 * @param result point from ECDH
1047 * @param ctx ECC context
1048 * @param key_material[out] set to derived key material
1049 * @return #GNUNET_OK on success
1050 */
1051static int
1052point_to_hash (gcry_mpi_point_t result,
1053 gcry_ctx_t ctx,
1054 struct GNUNET_HashCode *key_material)
1055{
1056 gcry_mpi_t result_x;
1057 unsigned char xbuf[256 / 8];
1058 size_t rsize;
1059
1060 /* finally, convert point to string for hashing */
1061 result_x = gcry_mpi_new (256);
1062 if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1063 {
1064 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1065 return GNUNET_SYSERR;
1066 }
1067
1068 rsize = sizeof(xbuf);
1069 GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1070 /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1071 as that does not include the sign bit; x should be a 255-bit
1072 value, so with the sign it should fit snugly into the 256-bit
1073 xbuf */
1074 GNUNET_assert (
1075 0 == gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize, result_x));
1076 GNUNET_CRYPTO_hash (xbuf, rsize, key_material);
1077 gcry_mpi_release (result_x);
1078 return GNUNET_OK;
1079}
1080
1081
1082/**
1083 * @ingroup crypto 1030 * @ingroup crypto
1084 * Derive key material from a ECDH public key and a private EdDSA key. 1031 * Derive key material from a ECDH public key and a private EdDSA key.
1085 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa. 1032 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
@@ -1125,41 +1072,18 @@ GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1125 const struct GNUNET_CRYPTO_EcdhePublicKey *pub, 1072 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1126 struct GNUNET_HashCode *key_material) 1073 struct GNUNET_HashCode *key_material)
1127{ 1074{
1128 gcry_mpi_point_t result; 1075 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1129 gcry_mpi_point_t q; 1076 uint8_t d_rev[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1130 gcry_mpi_t d;
1131 gcry_ctx_t ctx;
1132 gcry_sexp_t pub_sexpr;
1133 int ret;
1134 1077
1135 BENCHMARK_START (ecdsa_ecdh); 1078 BENCHMARK_START (ecdsa_ecdh);
1136 1079 for (size_t i = 0; i < 32; i++)
1137 /* first, extract the q = dP value from the public key */ 1080 d_rev[i] = priv->d[31 - i];
1138 if (0 != gcry_sexp_build (&pub_sexpr, 1081 GNUNET_TWEETNACL_scalarmult_curve25519 (p, d_rev, pub->q_y);
1139 NULL, 1082 GNUNET_CRYPTO_hash (p,
1140 "(public-key(ecc(curve " CURVE ")(q %b)))", 1083 GNUNET_TWEETNACL_SCALARMULT_BYTES,
1141 (int) sizeof(pub->q_y), 1084 key_material);
1142 pub->q_y))
1143 return GNUNET_SYSERR;
1144 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1145 gcry_sexp_release (pub_sexpr);
1146 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1147
1148 /* second, extract the d value from our private key */
1149 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof(priv->d));
1150
1151 /* then call the 'multiply' function, to compute the product */
1152 result = gcry_mpi_point_new (0);
1153 gcry_mpi_ec_mul (result, d, q, ctx);
1154 gcry_mpi_point_release (q);
1155 gcry_mpi_release (d);
1156
1157 /* finally, convert point to string for hashing */
1158 ret = point_to_hash (result, ctx, key_material);
1159 gcry_mpi_point_release (result);
1160 gcry_ctx_release (ctx);
1161 BENCHMARK_END (ecdsa_ecdh); 1085 BENCHMARK_END (ecdsa_ecdh);
1162 return ret; 1086 return GNUNET_OK;
1163} 1087}
1164 1088
1165 1089
@@ -1191,7 +1115,7 @@ GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1191/** 1115/**
1192 * @ingroup crypto 1116 * @ingroup crypto
1193 * Derive key material from a ECDSA public key and a private ECDH key. 1117 * Derive key material from a ECDSA public key and a private ECDH key.
1194 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh. 1118 * Dual to #GNUNET_CRYPTO_ecdsa_ecdh.
1195 * 1119 *
1196 * @param priv private key to use for the ECDH (y) 1120 * @param priv private key to use for the ECDH (y)
1197 * @param pub public key from ECDSA to use for the ECDH (X=h(x)G) 1121 * @param pub public key from ECDSA to use for the ECDH (X=h(x)G)
@@ -1203,10 +1127,13 @@ GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1203 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub, 1127 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1204 struct GNUNET_HashCode *key_material) 1128 struct GNUNET_HashCode *key_material)
1205{ 1129{
1206 return GNUNET_CRYPTO_ecdh_eddsa (priv, 1130 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1207 (const struct GNUNET_CRYPTO_EddsaPublicKey *) 1131 uint8_t curve25510_pk[GNUNET_TWEETNACL_SIGN_PUBLICBYTES];
1208 pub, 1132
1209 key_material); 1133 GNUNET_TWEETNACL_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y);
1134 GNUNET_TWEETNACL_scalarmult_curve25519 (p, priv->d, curve25510_pk);
1135 GNUNET_CRYPTO_hash (p, GNUNET_TWEETNACL_SCALARMULT_BYTES, key_material);
1136 return GNUNET_OK;
1210} 1137}
1211 1138
1212 1139
diff --git a/src/util/tweetnacl-gnunet.c b/src/util/tweetnacl-gnunet.c
index 1c27730a4..c3471ae66 100644
--- a/src/util/tweetnacl-gnunet.c
+++ b/src/util/tweetnacl-gnunet.c
@@ -424,8 +424,25 @@ GNUNET_TWEETNACL_sign_pk_from_seed (u8 *pk, const u8 *seed)
424 d[31] &= 127; 424 d[31] &= 127;
425 d[31] |= 64; 425 d[31] |= 64;
426 426
427 scalarbase (p,d); 427 scalarbase (p, d);
428 pack (pk,p); 428 pack (pk, p);
429}
430
431void
432GNUNET_TWEETNACL_scalarmult_le_ed25519_base (u8 *pk, const u8 *s)
433{
434 u8 d[64];
435 gf p[4];
436
437 // Treat s as little endian.
438 for (u32 i = 0; i < 32; i++)
439 d[i] = s[31 - i];
440 d[0] &= 248;
441 d[31] &= 127;
442 d[31] |= 64;
443
444 scalarbase (p, d);
445 pack (pk, p);
429} 446}
430 447
431void 448void
diff --git a/src/util/tweetnacl-gnunet.h b/src/util/tweetnacl-gnunet.h
index 239166ffc..2b2dc8e63 100644
--- a/src/util/tweetnacl-gnunet.h
+++ b/src/util/tweetnacl-gnunet.h
@@ -47,4 +47,8 @@ GNUNET_TWEETNACL_sign_detached (uint8_t *sig,
47 const uint8_t *m, 47 const uint8_t *m,
48 uint64_t n, 48 uint64_t n,
49 const uint8_t *sk); 49 const uint8_t *sk);
50
51void
52GNUNET_TWEETNACL_scalarmult_le_ed25519_base (uint8_t *pk, const uint8_t *s);
53
50#endif 54#endif