summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2016-10-27 05:59:49 +0200
committerNIIBE Yutaka <gniibe@fsij.org>2016-10-27 06:04:45 +0200
commitca0ee4e381d0b6a57e4ddc8f4bb2390eb97a2540 (patch)
tree87cc7058681acb65748ba4fdcc7d3463a527e804
parentscd: Add 0x41 prefix for x-coordinate only result. (diff)
downloadgnupg2-ca0ee4e381d0b6a57e4ddc8f4bb2390eb97a2540.tar.xz
gnupg2-ca0ee4e381d0b6a57e4ddc8f4bb2390eb97a2540.zip
g10: Fix ECDH, clarifying the format.
* g10/ecdh.c (pk_ecdh_encrypt_with_shared_point): Returns error when it's short. Clarify the format. Handle other prefixes correctly. -- With the scdaemon's change, there is no case NBYTES < SECRET_X_SIZE. This fixes the break of ECDH with X25519. Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
-rw-r--r--g10/ecdh.c38
1 files changed, 20 insertions, 18 deletions
diff --git a/g10/ecdh.c b/g10/ecdh.c
index 886427bce..dd47544e6 100644
--- a/g10/ecdh.c
+++ b/g10/ecdh.c
@@ -135,27 +135,29 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
/* Expected size of the x component */
secret_x_size = (nbits+7)/8;
- if (nbytes > secret_x_size)
+ /* Extract X from the result. It must be in the format of:
+ 04 || X || Y
+ 40 || X
+ 41 || X
+
+ Since it always comes with the prefix, it's larger than X. In
+ old experimental version of libgcrypt, there is a case where it
+ returns X with no prefix of 40, so, nbytes == secret_x_size
+ is allowed. */
+ if (nbytes < secret_x_size)
{
- /* Uncompressed format expected, so it must start with 04 */
- if (secret_x[0] != (byte)0x04)
- {
- return gpg_error (GPG_ERR_BAD_DATA);
- }
+ xfree (secret_x);
+ return gpg_error (GPG_ERR_BAD_DATA);
+ }
- /* Remove the "04" prefix of non-compressed format. */
- memmove (secret_x, secret_x+1, secret_x_size);
+ /* Remove the prefix. */
+ if ((nbytes & 1))
+ memmove (secret_x, secret_x+1, secret_x_size);
+
+ /* Clear the rest of data. */
+ if (nbytes - secret_x_size)
+ memset (secret_x+secret_x_size, 0, nbytes-secret_x_size);
- /* Zeroize the y component following */
- if (nbytes > secret_x_size)
- memset (secret_x+secret_x_size, 0, nbytes-secret_x_size);
- }
- else if (nbytes < secret_x_size)
- {
- /* Raw share secret (x coordinate), without leading zeros */
- memmove (secret_x+(secret_x_size - nbytes), secret_x, nbytes);
- memset (secret_x, 0, secret_x_size - nbytes);
- }
if (DBG_CRYPTO)
log_printhex ("ECDH shared secret X is:", secret_x, secret_x_size );
}