ED25519 Verification fails in Golang for payload signed in Java

Issue

I’ve two separate applications one written in Java and the other in golang. Java application is responsible to generate keypair out of which public key is shared with golang app. Whenever, there’s a need to sign any payload golang app sends a request to Java app and gets the base64 encoded signature in return. This signature needs to be verified using the public key. The verification always fails in golang app. However, I’m able to successfully verify in Java app. Verification in golang works if key generation and signing the payload is also done using golang.

For Java, I’m using Bouncy Castle library and for golang using package https://pkg.go.dev/crypto/ed25519.

Generate Key

Ed25519KeyPairGenerator keyPairGenerator = new Ed25519KeyPairGenerator();
keyPairGenerator.init(new Ed25519KeyGenerationParameters(new SecureRandom()));
AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
Ed25519PrivateKeyParameters privateKey = (Ed25519PrivateKeyParameters) asymmetricCipherKeyPair.getPrivate();
Ed25519PublicKeyParameters publicKey = (Ed25519PublicKeyParameters) asymmetricCipherKeyPair.getPublic();
String privateKey = Base64.getEncoder().encodeToString(privateKey.getEncoded());
String publicKey = Base64.getEncoder().encodeToString(publicKey.getEncoded());

Sign Payload

byte[] privateKeyContent = Base64.getDecoder().decode(privateKeyInfo);
Ed25519PrivateKeyParameters privateKeyParameters = new Ed25519PrivateKeyParameters(privateKeyContent, 0);

byte[] payload = Base64.getEncoder().encode(input.getBytes(StandardCharsets.UTF_8));
Signer signer = new Ed25519Signer();
signer.init(true, privateKeyParameters);
signer.update(payload, 0, payload.length);
byte[] signature = signer.generateSignature();
String encodedSignature = Base64.getEncoder().encodeToString(signature);

Golang Verify Signature

func verifySignature(payload []byte, publicKeyStr string, signatureStr string) {
    publicKey, error := base64.StdEncoding.DecodeString(publicKeyStr)
    if error != nil {
        fmt.Println(error)
    } else {
        signature, error := base64.StdEncoding.DecodeString(signatureStr)
        if error != nil {
            fmt.Println(error)
        } else {
            isVerified := ed25519.Verify(publicKey, payload, signature)
            fmt.Println(isVerified)
        }

    }
}

Solution

The Java code does not sign the message itself, but the Base64 encoded message.

I suspect that verification fails for you because signed and verified message are different. However, this cannot be answered for sure, since you did not post the content of payload on the Go side.

In any case, verification is successful if on the Java side the message itself is signed (which is usually the case):

String input = "...";
byte[] payload = input.getBytes(StandardCharsets.UTF_8);

Similarly, verification is successful if, with unmodified Java code, the Go side verifies the Base64 encoded message (which would be rather unusual):

input := "..."
payload := []byte(base64.StdEncoding.EncodeToString([]byte(input)))

Answered By – Topaco

Answer Checked By – Katrina (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.