think I discovered a libgcrypt EdDSA Verification Bug -- Ed25519 skips verification + can't verify
Zachary Fogg
zach.fogg at gmail.com
Wed Oct 8 15:04:13 CEST 2025
Hi friends.
I'm working on a project and I implemented crypto for it with libsodium,
with support for ssh and gpg keys. My project is ascii-chat
<https://github.com/zfogg/ascii-chat>: a couple of C programs
(client+server) that let you make video-rendered-to-text video calls from
your terminal over tcp/ip. It's pretty cool and has audio support and
supports multiple clients like Google Hangouts and Zoom. I'm still working
on it a bunch and barely just got it compiling on Windows so be nice if you
check the code.
Anyway, I discovered gpg and libsodium are incompatible in my code.
Verification fails in my crypto process when using libgcrypt and gpg-agent
to authenticate in my protocol. It seems gpg-agent and libgcrypt both
cannot seem to do Ed25519 verifications. I tried a few simple test programs
that look like they should work, but fail. Here's a basic one:
```
#include <stdio.h>
#include <string.h>
#include <gcrypt.h>
int main(void) {
gcry_error_t err;
gcry_sexp_t keypair = NULL, privkey = NULL, pubkey = NULL;
gcry_sexp_t s_sig = NULL, s_data = NULL;
gcry_check_version(NULL);
gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
// Generate Ed25519 keypair
err = gcry_sexp_build(&keypair, NULL, "(genkey (ecc (curve Ed25519)))");
gcry_pk_genkey(&keypair, keypair);
privkey = gcry_sexp_find_token(keypair, "private-key", 0);
pubkey = gcry_sexp_find_token(keypair, "public-key", 0);
const char *msg = "Test message";
size_t msg_len = strlen(msg);
// TEST 1: GPG agent Format 2 (THE BUG)
printf("Format 2: (data (flags eddsa) (hash-algo sha512) (value
%%b))\n");
err = gcry_sexp_build(&s_data, NULL,
"(data (flags eddsa) (hash-algo sha512) (value
%b))",
msg_len, msg);
err = gcry_pk_sign(&s_sig, s_data, privkey);
printf(" Sign: %s\n", err ? "FAILED" : "OK");
err = gcry_pk_verify(s_sig, s_data, pubkey);
printf(" Verify: %s\n", err ? "FAILED ❌" : "OK");
gcry_sexp_release(s_sig);
gcry_sexp_release(s_data);
// TEST 2: Simple Format 3 (CONTROL - should work)
printf("\nFormat 3: (data (value %%b))\n");
err = gcry_sexp_build(&s_data, NULL, "(data (value %b))", msg_len, msg);
err = gcry_pk_sign(&s_sig, s_data, privkey);
printf(" Sign: %s\n", err ? "FAILED" : "OK");
err = gcry_pk_verify(s_sig, s_data, pubkey);
printf(" Verify: %s\n", err ? "FAILED" : "OK ✓");
// Cleanup
gcry_sexp_release(s_sig);
gcry_sexp_release(s_data);
gcry_sexp_release(pubkey);
gcry_sexp_release(privkey);
gcry_sexp_release(keypair);
return 0;
}
```
```
gcc -o test_bug test_bug.c $(pkg-config --cflags --libs libgcrypt)
./test
Format 2: (data (flags eddsa) (hash-algo sha512) (value %b))
Sign: OK
Verify: FAILED ❌
Format 3: (data (value %b))
Sign: OK
Verify: OK ✓
```
In other tests I ran, I FAILED to get format three working in my ascii-chat
crypto code with libsodium + gpg-agent. But this code works. Important to
check this when fixing this bug I guess. So it fails when using "(data
(flags eddsa) (hash-algo sha512) (value %b))" format.
Now, why exactly does this bug exist? I am wondering this, because I was
doubting that it was a bug because this is official gpg code, and I was
banging my head against the wall wondering why my crypto was failing when
the code looks perfect and gpg-agent itself works with itself
cryptographically. My ssh key and password crypto code was working
perfectly too. This was curious to me. Very curious. Is this really a bug?
Well I don't actually usually write crypto code, and to be honest C code is
not my forte.. I'm a JavaScript web developer by nature! So I didn't
investigate as thoroughly as should be done because I don't have the
ability. I'll leave that to you all. What I did do is make this GitHub
issue that has proof of this bug with links to your code that causes it and
test programs to prove it: https://github.com/zfogg/ascii-chat/issues/92 .
The programs are simple and compile easily and print errors when they
shouldn't, but alas this seems to be a real bug.
One more reason this bug exists: you all don't test verification of format
2! I checked gpg test code. That should be tested. Verification is explicit
for RSA in the code but a similar check for Ed25519 verification is missing
from the code and has been since Ed25519 was introduced according to my
research.
What I would like to see come of this: I want to use gpg in ascii-chat to
let users verify with their gpg keys in the crypto process. It will be
cool, the other party (client or server) can load the first party's gpg
keys from github/gitlab automatically with the user's username via https
with my code with --server-key github:username.gpg because everyone's
github gpg public keys are at github.com/yourusername.gpg (your ssh keys
are at .keys! ascii-chat supports that and it works!! proving my code
actually works and this is a gpg bug.). verifying public keys gotten over
https in the crypto protocol, neat huh? useful! i think so anyway. Right
now, my code errors and exits with "crypto verification failed" when using
gpg keys from github or anywhere else. I want to fix this. So I'm
submitting this bug report and I'll follow along until someone tells me
either how to fix my code and that it's not a bug, or fixes it and lets me
compile ascii-chat against working gpg code.
I left a lot of info out.. definitely check the GitHub issue
<https://github.com/zfogg/ascii-chat/issues/92> if you want to see more
(there's a program that shows how it fails with libsodium). But the example
program in this email should be enough in my opinion.. Here's maybe some
info you might need.. here's a simplified view of my crypto protocol. you
can see exactly where it fails when using gpg for verification:
Client Server
| |
|------ Challenge Request ----->|
| |
|<----- Random Challenge -------|
| |
| |
| Sign challenge: |
| - libsodium: ✓ WORKS |
| - SSH keys: ✓ WORKS |
| - GPG keys: ✗ FAILS |
| |
|------ Signed Response ------->|
| |
| | Verify with gcry_pk_verify()
| | Result: "Bad signature"
|<----- Auth Rejected ----------|
see that? my ssh key code works properly there at that point in the
protocol. I can't get gpg-agent program or libgcrypt code to work there
with libsodium. verification fails so the protocol can't proceed.
I hope this is enough information and an actual bug lol. If it's not a bug
please let me know how to get libsodium and gpg working together properly.
Feel free to ask me any questions about this. Thank you.
-Zachary Fogg
--
--
🐨 ẔƑ 👾
zfo.gg/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.gnupg.org/pipermail/gcrypt-devel/attachments/20251008/f5b8c0bb/attachment-0001.html>
More information about the Gcrypt-devel
mailing list