如何使 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));
我想这里有两件事需要解决:
- 将 MGF1 设置为明确使用 SHA-256;
- 设置盐大小,其中 OpenSSL 使用可能的最大盐大小。
有关详细信息,请参阅旧讨论 here。
我正在开发 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));
我想这里有两件事需要解决:
- 将 MGF1 设置为明确使用 SHA-256;
- 设置盐大小,其中 OpenSSL 使用可能的最大盐大小。
有关详细信息,请参阅旧讨论 here。