ED25519在Java中签名的有效载荷在Golang中验证失败。

huangapple go评论87阅读模式
英文:

ED25519 Verification fails in Golang for payload signed in Java

问题

我有两个独立的应用程序,一个是用Java编写的,另一个是用golang编写的。Java应用程序负责生成密钥对,其中公钥与golang应用程序共享。每当需要对任何有效负载进行签名时,golang应用程序会向Java应用程序发送请求,并获得base64编码的签名作为返回结果。需要使用公钥验证此签名。但是,在golang应用程序中验证始终失败。然而,我能够在Java应用程序中成功验证。如果使用golang进行密钥生成和有效负载签名,golang中的验证将起作用。

对于Java,我使用了Bouncy Castle库,对于golang,我使用了https://pkg.go.dev/crypto/ed25519包。

生成密钥

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());

签名有效负载

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验证签名

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)
		}

	}
}
英文:

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)
		}

	}
}

答案1

得分: 2

Java代码不对消息本身进行签名,而是对Base64编码的消息进行签名。

我怀疑你的验证失败是因为签名和验证的消息不同。然而,由于你没有在Go端发布payload的内容,无法确定这一点。

无论如何,如果在Java端签名消息本身(通常情况下),验证将成功:

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

同样,如果使用未修改的Java代码,Go端验证Base64编码的消息也将成功(这可能相对不常见):

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

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)))

huangapple
  • 本文由 发表于 2022年1月25日 19:32:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/70847910.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定