<div dir="ltr"><div class="gmail_default" style="font-family:times new roman,serif;font-size:large;color:#073763">thanks for your time. you say you don't see the bug, but did you run my test programs? they show the bug.</div><div class="gmail_default" style="font-family:times new roman,serif;font-size:large;color:#073763"><br></div><div class="gmail_default" style="font-family:times new roman,serif;font-size:large;color:#073763">#include <stdio.h><br>#include <string.h><br>#include <gcrypt.h><br><br>int main(void) {<br>    gcry_error_t err;<br>    gcry_sexp_t keypair = NULL, privkey = NULL, pubkey = NULL;<br>    gcry_sexp_t s_sig = NULL, s_data = NULL;<br><br>    gcry_check_version(NULL);<br>    gcry_control(GCRYCTL_DISABLE_SECMEM, 0);<br>    gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);<br><br>    // Generate Ed25519 keypair<br>    err = gcry_sexp_build(&keypair, NULL, "(genkey (ecc (curve Ed25519)))");<br>    gcry_pk_genkey(&keypair, keypair);<br>    privkey = gcry_sexp_find_token(keypair, "private-key", 0);<br>    pubkey = gcry_sexp_find_token(keypair, "public-key", 0);<br><br>    const char *msg = "Test message";<br>    size_t msg_len = strlen(msg);<br><br>    // TEST 1: GPG agent Format 2 (THE BUG)<br>    printf("Format 2: (data (flags eddsa) (hash-algo sha512) (value %%b))\n");<br>    err = gcry_sexp_build(&s_data, NULL,<br>                         "(data (flags eddsa) (hash-algo sha512) (value %b))",<br>                         msg_len, msg);<br><br>    err = gcry_pk_sign(&s_sig, s_data, privkey);<br>    printf("  Sign: %s\n", err ? "FAILED" : "OK");<br><br>    err = gcry_pk_verify(s_sig, s_data, pubkey);<br>    printf("  Verify: %s\n", err ? "FAILED ❌" : "OK");<br><br>    gcry_sexp_release(s_sig);<br>    gcry_sexp_release(s_data);<br><br>    // TEST 2: Simple Format 3 (CONTROL - should work)<br>    printf("\nFormat 3: (data (value %%b))\n");<br>    err = gcry_sexp_build(&s_data, NULL, "(data (value %b))", msg_len, msg);<br><br>    err = gcry_pk_sign(&s_sig, s_data, privkey);<br>    printf("  Sign: %s\n", err ? "FAILED" : "OK");<br><br>    err = gcry_pk_verify(s_sig, s_data, pubkey);<br>    printf("  Verify: %s\n", err ? "FAILED" : "OK ✓");<br><br>    // Cleanup<br>    gcry_sexp_release(s_sig);<br>    gcry_sexp_release(s_data);<br>    gcry_sexp_release(pubkey);<br>    gcry_sexp_release(privkey);<br>    gcry_sexp_release(keypair);<br><br>    return 0;<br>}</div><div class="gmail_default" style="font-family:times new roman,serif;font-size:large;color:#073763"><br></div><div class="gmail_default" style="font-family:times new roman,serif;font-size:large;color:#073763">the full issue has more example programs and information why integrating with libsodium fails in this way. <a href="https://github.com/zfogg/ascii-chat/issues/92">https://github.com/zfogg/ascii-chat/issues/92</a><br><br>i did however find a work around: have gpg do verification through gpg-agent. so my ascii-chat program works now, but not via the libsodium+gcrypt verification method that i originally planned.</div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Thu, Jan 15, 2026 at 8:41 AM Werner Koch <<a href="mailto:wk@gnupg.org">wk@gnupg.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi!<br>
<br>
Just a short note on your bug report.  You gave a lot of examples and a<br>
nicely formated report at <a href="https://github.com/zfogg/ascii-chat/issues/92" rel="noreferrer" target="_blank">https://github.com/zfogg/ascii-chat/issues/92</a><br>
but I can't read everything of it.<br>
<br>
On Tue, 30 Dec 2025 02:30, Zachary Fogg said:<br>
> **In-Reply-To:** <response from NIIBE Yutaka on Oct 22, 2025><br>
<br>
> Your response mentioned using `(flags eddsa)` during key generation, which<br>
> is good practice. However, I want to clarify that **my bug report concerns<br>
> signature verification, not key generation**.<br>
<br>
If you look at the way GnuPG uses Libgcrypt will find in<br>
gnupg/g10/pkglue.c:pk_verify this:<br>
<br>
          if (openpgp_oid_is_ed25519 (pkey[0]))<br>
            fmt = "(public-key(ecc(curve %s)(flags eddsa)(q%m)))";<br>
          else<br>
            fmt = "(public-key(ecc(curve %s)(q%m)))";<br>
<br>
and this for the data:<br>
<br>
      if (openpgp_oid_is_ed25519 (pkey[0]))<br>
        fmt = "(data(flags eddsa)(hash-algo sha512)(value %m))";<br>
      else<br>
        fmt = "(data(value %m))";<br>
<br>
and more complicated stuff for re-formatting the signature data.  It is<br>
a bit unfortunate that we need to have these special cases but that's<br>
the drawback of a having a stable API and protocol.<br>
<br>
> 1. Can you confirm this is a genuine bug in libgcrypt's verification logic?<br>
<br>
No, at least not as I understand it.  ed25519 signatures are working<br>
well and are in active use since GnuPG 2.1 from 2014.<br>
<br>
> 2. Should I open a formal bug in the <a href="http://dev.gnupg.org" rel="noreferrer" target="_blank">dev.gnupg.org</a> tracker?<br>
<br>
I don't see a bug ;-)<br>
<br>
> 3. Would a patch fixing the PUBKEY_FLAG_PREHASH handling be acceptable?<br>
<br>
I do not understand exactly what you propose.  A more concise<br>
description would be helpful.  But note that API stability is a primary<br>
goal.<br>
<br>
BTW on your website your wrote: <br>
<br>
  I've created a working exploit that demonstrates the severity of this<br>
  bug. The exploit proves that GPG agent creates EdDSA signatures that<br>
  cannot be verified by standard libgcrypt verification code, even with<br>
  the correct keys.<br>
<br>
The term "exploit" is used to describe an attack method which undermines<br>
the security of a system.  What you describe is a claimed inconsistent<br>
API.  That may or may not be the case; I don't see a security bug here,<br>
though.<br>
<br>
<br>
<br>
Salam-Shalom,<br>
<br>
   Werner<br>
<br>
<br>
p.s.<br>
I had a brief look at your project:  In src/main.c I notice<br>
<br>
  // Set global FPS from command-line option if provided<br>
  extern int g_max_fps;<br>
<br>
The declaration of an external variable inside a function is a not a<br>
good coding style.  Put this at the top of the file or into a header.<br>
A few lines above:<br>
<br>
  #ifndef NDEBUG<br>
    // Initialize lock debugging system after logging is fully set up<br>
    log_debug("Initializing lock debug system...");<br>
<br>
Never ever use NDEBUG.  This is an idea of the 70ies.  This also<br>
disables the assert(3) functionality and if you do this you won't get an<br>
assertion failure at all in your production code - either you know the<br>
code is correct or you are not sure.  Never remove an assert from<br>
production code.<br>
<br>
I have noticed a lot of documentation inside the code - that's good.<br>
<br>
-- <br>
The pioneers of a warless world are the youth that<br>
refuse military service.             - A. Einstein<br>
</blockquote></div>