0

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

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

生成密钥

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

    }
}
4

1 回答 1

2

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

我怀疑您的验证失败,因为签名和验证的消息不同。但是,这不能肯定地回答,因为您没有payload在 Go 端发布 的内容。

在任何情况下,如果在 Java 端对消息本身进行签名(通常是这种情况),则验证成功:

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

同样,如果 Go 端使用未修改的 Java 代码验证 Base64 编码的消息,则验证成功(这将是相当不寻常的):

input := "..."
payload := []byte(base64.StdEncoding.EncodeToString([]byte(input)))
于 2022-01-25T12:38:24.467 回答