php - 使用 .NET (VB) 验证 OpenSSL RSA 签名 (PHP)
问题描述
我想实现一些我认为非常简单的事情:
A) 我的 VB.NET 客户端(理想情况下以 Framework 4.0 为目标)通过 HTTPS POST 请求向我的 Apache/PHP 服务器发送一个文本字符串。
B) 我的服务器以该文本字符串的签名响应。服务器使用的私钥始终相同,客户端使用的公钥已经嵌入源代码中。
在调查和阅读了大量文档后,我想出了以下策略,并有两个问题:
- 我的策略有效吗?
- 下面提供的代码不起作用(.VerifyData 返回 FALSE)。我错过了什么?
战略
服务器端
- Apache/PHP:因为这是我熟悉的唯一服务器语言,但如果推荐我可以切换。
- OpenSSL:因为我使用 PHP
- PEM 文件:因为我使用 OpenSSL
- RSA 密钥大小为 2048 位:2019 年推荐的最小值
- 算法是 SHA256:因为每个人似乎都使用那个
- 标题文本/纯文本,UTF8:为什么不呢?
客户端
- VB.Net Framework 4.0 客户端配置文件:因为我想最大化遗留(VSTO 2013)
- System.Security.Cryptography.RSACryptoServiceProvider
- 通过 XML 字符串加载的 PEM 公钥信息
- HTTPS 应该是 TLS1.0 或更高版本:因为我的目标是 .Net Framework 4.0(如果可能,建议使用 TLS1.1)
源代码
服务器端(生成 .pem 密钥文件,仅一次)
<?
// Create new Keys Pair
$new_key_pair = openssl_pkey_new(array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));
//Save Private Key
openssl_pkey_export($new_key_pair, $private_key_pem, "my passphrase to protect my private key; add random characters like $, ?, #, & or ! for improved security");
file_put_contents('private_key.pem', $private_key_pem);
//Save Public Key
$details = openssl_pkey_get_details($new_key_pair);
$public_key_pem = $details['key'];
file_put_contents('public_key.pem', $public_key_pem);
?>
服务器端(POST 请求的目标)
<?
header('Content-Type: text/plain; charset=utf-8');
// Verify connection is secure
if(empty($_SERVER['HTTPS']) || $_SERVER['HTTPS']=="off")
{
echo "Unauthorized Access";
exit;
}
// Data to Sign
$data = base64_decode(file_get_contents('php://input'));
//Load Private Key
$private_key_pem = openssl_pkey_get_private('file:///path/protected/by/dotHtaccess/private_key.pem', "my passphrase to protect my private key; add random characters like $, ?, #, & or ! for improved security");
//Create Signature
openssl_sign($data, $signature, $private_key_pem, OPENSSL_ALGO_SHA256);
echo base64_encode($signature);
?>
客户端
imports System.Diagnostics
Sub mySignatureTest()
Dim oURI As Uri = New Uri("https://www.example.com/targetpage.php")
Dim sData As String = "myStringToSign"
Dim sResponse As String
'# Get POST request Response
Using oWeb As New System.Net.WebClient()
Try
System.Net.ServicePointManager.SecurityProtocol = System.Net.ServicePointManager.SecurityProtocol And Not System.Net.ServicePointManager.SecurityProtocol.Ssl3 'Override defautl Security Protocols: Prohibit SSL3
oWeb.Encoding = Encoding.UTF8
Debug.Print("SSL version is " & System.Net.ServicePointManager.SecurityProtocol.ToString)
Debug.Print("Sending " & sData)
Debug.Print("To " & oURI.ToString)
Debug.Print("Encoding is " & oWeb.Encoding.ToString)
sResponse = oWeb.UploadString(oURI, "POST", Convert.ToBase64String(Encoding.UTF8.GetBytes(sData)))
Debug.Print("Server reponse = " & sResponse)
Catch ex As Exception
MsgBox("Connection with server failed: " & ex.ToString, vbCritical + vbOKOnly, "Add-In")
End Try
End Using
'#Verify RSA SHA256 Signature
Dim sDataToSign As String = sData
Dim sSignatureToVerify As String = sResponse
Using myRSA As New System.Security.Cryptography.RSACryptoServiceProvider
'XML format obtain from PEM file by hand copy/paste here: https://superdry.apphb.com/tools/online-rsa-key-converter
myRSA.FromXmlString("<RSAKeyValue><Modulus>SomeLongBase64StringHere</Modulus><Exponent>SomeShortBase64StringHere</Exponent></RSAKeyValue>")
Debug.Print("Signature verification = " & myRSA.VerifyData(Encoding.UTF8.GetBytes(sDataToSign), _
System.Security.Cryptography.CryptoConfig.MapNameToOID("SHA256"), _
Convert.FromBase64String(sSignatureToVerify)).ToString)
End Using
End Sub
一旦问题 2) 得到解决,我希望我们可以让这段代码发展,以便它提供一个很好但简单的示例,说明如何实现 OpenSSL 服务器签名的 .NET 客户端验证。我无法在 Internet 上找到一个简单明了的示例。
这通常可用于许可目的,其中服务器将提供包含到期日期以及该日期签名的文件,以便客户端应用程序确认此到期日期未被更改,例如客户端所有者计算机。
解决方案
推荐阅读
- java - 如何启用 bean 验证器 - Spring Boot
- java - 使用 JSONPATH 规范化嵌套的 json
- c# - ASP.NET Core API 如何转换 ActionResult
to T in action 方法 - r - 将字符串转换为变量名
- java - 自定义错误控制器中的 @Controller 和 @RequestMapping
- python - 如何在 Python 中正确使用 opencv.imread 的参数“flags”?
- javascript - 如何显示 sweetalert denied 消息?
- sql - 如何计算一个位置的属性并显示所有属性列表
- asp.net-mvc - Web API - 如何发布包含文件的对象
- javascript - 如果一个函数返回一个对象,它就不能在 JS 中充当构造函数。我的假设是否正确