0

我收到 XML 请求,包含 MsgBody 标记和签名(在.net中完成的签名过程),

我必须验证他们发送的 msg 正文、签名和请求者公钥,但我不能。

我的代码是:

$msg_body = "<MsgBody><Transactions>....</Transactions></MsgBody>";
$signature = "nkI/Z/ySJSxarh..............==";
$verifying_flag = openssl_verify($msg_body, base64_decode($signature), PUBLIC_KEY, OPENSSL_ALGO_SHA256);

我试过这个:

$rsa = new \Crypt_RSA();
$rsa->loadKey(PUBLIC_KEY);
$verifying_flag = $rsa->verify($msg_body, base64_decode($signature));

两种方式的 $verifying_flag 失败,

通过此代码在 .NET 中完成的签名过程:

using System;

public class Program
{
    public static string SignMessage(XElement xmlMessage, Collection<string> xPaths, string certificateSerialNumber)
    {
        string elementsValue = string.Empty;
        foreach (vara xPath in xpaths)
        {
            IEnumerable<XElement> xPathSelectElements = xmlMessage.XPathSelectElements(xPath);
            foreach (XElement xPathSelectElements in xPathSelectElements)
            {
                elementsValue += xPathSelectElements.ToString();
            }
        }

        RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider();
        rsaCryptoServiceProvider.FromXmlString(GetCertificates(certificateSerialNumber).PrivateKey.ToXmlString(true));
        RSACryptoServiceProvider.UseMachineKeyStore = true;
        rsaCryptoServiceProvider.ExportParameters(false);
        rsaCryptoServiceProvider.KeySize = 2048;
        return Convert.ToBase64String(rsaCryptoServiceProvider.SignData(Encoding.Unicode.GetBytes(elementsValue), CryptoConfig.MapNameToOID("SHA256")));
    }

如何验证他们的要求?!

4

1 回答 1

1

首先,您使用 对其进行签名SHA-256,因此您必须在 PHP 端进行设置:

$rsa->setHash('sha256');

其次,您必须将签名模式设置为默认使用 PKCS#1 方案:

$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);

最后,由于您Encoding.Unicode.GetBytes在 C# 上使用,您需要UTF-16LE在验证之前将 php 上的消息正文转换为:

$msg_body = mb_convert_encoding($msg_body, 'UTF-16LE');

最后,代码应该是这样的:

$rsa = new \Crypt_RSA();
$rsa->loadKey(PUBLIC_KEY);

$rsa->setHash('sha256');
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$msg_body = mb_convert_encoding($msg_body, 'UTF-16LE');

$verifying_flag = $rsa->verify($msg_body, base64_decode($signature));

更新

如果你想在 PHP 上生成消息签名,你可以很容易地做到这一点:

$rsa = new \Crypt_RSA();
$rsa->loadKey(PRIVATE_KEY);

$rsa->setHash('sha256');
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$msg_body = mb_convert_encoding($msg_body, 'UTF-16LE');

$signature = base64_encode($rsa->sign($msg_body));

mb_convert_encoding顺便说一句,您可以通过删除双向线路来避免转换消息编码(验证和签名)

于 2020-12-28T08:32:39.643 回答