在 PHP 中验证 RSA-SHA256 xml在 .NET 中登录并在 PHP 中验证

问题描述

我收到 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")));
    }

如何验证他们的请求?!

解决方法

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

$rsa->setHash('sha256');

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

$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);

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

$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 行来避免转换消息编码

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...