static gpg_error_t compute_master_secret (unsigned char *master, size_t masterlen, const unsigned char *sk_a, size_t sk_a_len, const unsigned char *pk_b, size_t pk_b_len) { gpg_error_t err; gcry_sexp_t s_sk_a = NULL; gcry_sexp_t s_pk_b = NULL; gcry_sexp_t s_shared = NULL; gcry_sexp_t s_tmp; const char *s; size_t n; log_assert (masterlen == 32); err = gcry_sexp_build (&s_sk_a, NULL, "%b", (int)sk_a_len, sk_a); if (!err) err = gcry_sexp_build (&s_pk_b, NULL, "(public-key(ecdh(curve Curve25519)" " (flags djb-tweak)(q%b)))", (int)pk_b_len, pk_b); if (err) { log_error ("error building S-expression: %s\n", gpg_strerror (err)); goto leave; } err = gcry_pk_encrypt (&s_shared, s_sk_a, s_pk_b); if (err) { log_error ("error computing DH: %s\n", gpg_strerror (err)); goto leave; } /* gcry_log_debugsxp ("sk_a", s_sk_a); */ /* gcry_log_debugsxp ("pk_b", s_pk_b); */ /* gcry_log_debugsxp ("shared", s_shared); */ s_tmp = gcry_sexp_find_token (s_shared, "s", 0); if (!s_tmp || !(s = gcry_sexp_nth_data (s_tmp, 1, &n)) || n != 33 || s[0] != 0x40) { err = gpg_error (GPG_ERR_INTERNAL); log_error ("error computing DH: %s\n", gpg_strerror (err)); goto leave; } memcpy (master, s+1, 32); leave: gcry_sexp_release (s_sk_a); gcry_sexp_release (s_pk_b); gcry_sexp_release (s_shared); return err; }