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

如何解决在 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 行来避免转换消息编码

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?