如何使 JAVA 验证 OpenSSL RSA/PSS 签名

How to make JAVA verify OpenSSL RSA/PSS signature

我正在开发 C RPC 客户端。我需要使用 OpenSSL 对 MIME 数据进行签名,并将 public 密钥和签名发送到服务器。 Java 将尝试使用 public 密钥验证签名。

问题是,JAVA 无法验证 OpenSSL 生成的签名,但可以验证 JAVA 生成的签名。知道如何修复我的 C 客户端代码吗?

c 客户端代码:

#define LENGTH 256
FILE *fp=fopen("ssl.key");
unsigned int uDigestLen = 32;
EVP_PKEY *privkey;
privkey = EVP_PKEY_new();
PEM_read_PrivateKey( fp, &privkey, NULL, NULL);

pRsaKey = EVP_PKEY_get1_RSA(privkey);

if(RSA_check_key(pRsaKey)) {
    printf("RSA key is valid.\n");
}

EVP_MD_CTX_init(&md_ctx);
EVP_DigestInit(&md_ctx, EVP_sha256());
EVP_DigestUpdate(&md_ctx, (const void*) szMessage, strlen(szMessage));
EVP_DigestFinal(&md_ctx, pDigest, &uDigestLen);
EVP_MD_CTX_cleanup(&md_ctx);

// also tried RSA_padding_add_PKCS1_PSS but no luck
status = RSA_padding_add_PKCS1_PSS_mgf1(pRsaKey, EM, pDigest, EVP_sha256(), EVP_sha256(), 20 /* fixed salt length! (tried -2 w/o success)*/);
if (!status)
{
    printf("RSA_padding_add_PKCS1_PSS failed with error %s\n", ERR_error_string(ERR_get_error(), NULL));
}

status = RSA_private_encrypt(LENGTH, EM, pSignature, pRsaKey, RSA_PKCS1_PADDING);
if (status == -1)
{
    printf("RSA_private_encrypt failed with error %s\n", ERR_error_string(ERR_get_error(), NULL));
}

// I send base64 encoded string as well as public key to server, java failed to verify.
cout << "hashedChars: " << base64_encode(pSignature, LENGTH);  

JAVA代码:

Signature publicSignature = Signature.getInstance("SHA256withRSA/PSS", "BC");
publicSignature.initVerify(publicKey);
publicSignature.update(text.getBytes(StandardCharsets.UTF_8));

// always fail!!
byte[] signatureBytes = Base64.getDecoder().decode("base64 encoded  from c client");
System.out.println("verified result:" + publicSignature.verify(signatureBytes));

我想这里有两件事需要解决:

  1. 将 MGF1 设置为明确使用 SHA-256;
  2. 设置盐大小,其中 OpenSSL 使用可能的最大盐大小。

有关详细信息,请参阅旧讨论 here