diff options
author | Florian Dold <florian.dold@gmail.com> | 2020-01-06 14:02:40 +0100 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2020-01-06 14:02:40 +0100 |
commit | 1ad2fb331548adf635e9cff8786b468e54666371 (patch) | |
tree | 1eeafe3a8aa5a32ea78ead24fe742110133e0805 /src/util | |
parent | 2111817ee190b99561f067277c3b081da27e2afa (diff) | |
download | gnunet-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/util')
-rw-r--r-- | src/util/.gitignore | 1 | ||||
-rw-r--r-- | src/util/crypto_ecc.c | 109 | ||||
-rw-r--r-- | src/util/tweetnacl-gnunet.c | 21 | ||||
-rw-r--r-- | src/util/tweetnacl-gnunet.h | 4 |
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 | |||
30 | test_container_multipeermap | 30 | test_container_multipeermap |
31 | test_crypto_crc | 31 | test_crypto_crc |
32 | test_crypto_ecc_dlog | 32 | test_crypto_ecc_dlog |
33 | test_crypto_ecdh_ecdsa | ||
33 | test_crypto_ecdh_eddsa | 34 | test_crypto_ecdh_eddsa |
34 | test_crypto_ecdhe | 35 | test_crypto_ecdhe |
35 | test_crypto_ecdsa | 36 | test_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 | */ | ||
1051 | static int | ||
1052 | point_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 | |||
431 | void | ||
432 | GNUNET_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 | ||
431 | void | 448 | void |
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 | |||
51 | void | ||
52 | GNUNET_TWEETNACL_scalarmult_le_ed25519_base (uint8_t *pk, const uint8_t *s); | ||
53 | |||
50 | #endif | 54 | #endif |