.Net RSA验证OpenSSL签署的数据(.Net RSA verification of data signed by OpenSSL)

编程入门 行业动态 更新时间:2024-10-12 03:24:28
.Net RSA验证OpenSSL签署的数据(.Net RSA verification of data signed by OpenSSL)

我有一种情况,我生成一个2048位RSA公钥/私钥对。 公钥被复制到客户端计算机(Windows),而私钥保存在服务器(Linux)上。 我希望服务器能够使用私钥在数据块上生成签名,然后将签名和数据块发送到客户端,以便客户端可以使用公钥验证签名。

这是密钥的生成方式:

openssl genrsa -out private.key 2048 openssl req -subj "/C=GB/ST=ST/L=L/O=Org/OU=Unit/CN=cert name/emailAddress=nothing@nowhere" -new -x509 -key private.key -out publickey.cer -days 3650 openssl pkcs12 -passout pass:mypassword -export -nokeys -out public.key -in publickey.cer -inkey private.key

这将创建两个密钥文件,private.key(组合的公钥和私钥)和public.key(公钥)。

客户端应用程序在C#中。 在那里,我加载这样的公钥:

X509Certificate2 cert = new X509Certificate2(@"D:\public.key", "mypassword"); RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;

这适用于加密,因为如果我加密数据块并将其发送到套接字连接上的服务器,则服务器可以解密它并正确显示数据内容。 所以我确信密钥正确加载。

当服务器获取加密的数据块并正确解密时,它会签署响应并将其发送回客户端:

// Send a signed reply unsigned char *signature = (unsigned char *) malloc(RSA_size(privateKey)); if (signature != NULL) { char *reply ="Top of the morning to you"; unsigned int siglen; if (RSA_sign(NID_sha1, (unsigned char *)reply, strlen(reply), signature, &siglen, privateKey)) { printf("SigLen = %d\n", siglen); unsigned char *msg = (unsigned char *)malloc(siglen + strlen(reply)); if (msg != NULL) { memcpy(msg, signature, siglen); memcpy(msg+siglen, reply, strlen(reply)); send(sock, msg, siglen + strlen(reply), 0); free(msg); } } free(signature); }

客户端接收数据并从签名的数据中分离出签名,然后尝试验证签名,但这总是失败。 以下是客户端部分的完整代码:

static void Main(string[] args) { X509Certificate2 cert = new X509Certificate2(@"D:\public.key", "mypassword"); RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key; string payload = "Hello world!!"; byte[] encrypted = rsa.Encrypt(Encoding.ASCII.GetBytes(payload), false); TcpClient client = new TcpClient(); client.Connect("192.168.1.57", 2002); NetworkStream ns = client.GetStream(); ns.Write(encrypted, 0, encrypted.Length); ns.ReadTimeout = 2000; byte[] rx = new byte[5000]; int bytesRead = ns.Read(rx, 0, rx.Length); if (bytesRead > 0) { int keySizeBytes = rsa.KeySize >> 3; if (bytesRead > keySizeBytes) { byte[] signedMessage = new byte[bytesRead - keySizeBytes]; Array.Copy(rx, keySizeBytes, signedMessage, 0, signedMessage.Length); Array.Resize<byte>(ref rx, keySizeBytes); if (rsa.VerifyData(signedMessage, CryptoConfig.MapNameToOID("SHA1"), rx)) { Console.WriteLine("Verified OK"); } else { Console.WriteLine("Not verified"); } } } client.Close(); Console.ReadLine(); }

我需要做些什么才能在客户端验证数据?

I have a situation where I generate a 2048 bit RSA public / private key pair. The public key is copied to a client computer (Windows) while the private key is kept on a server (Linux). I want the server to be able to generate a signature on a block of data using the private key then send the signature, and the block of data, to the client so that the client can verify the signature using the public key.

This is how the key is being generated:

openssl genrsa -out private.key 2048 openssl req -subj "/C=GB/ST=ST/L=L/O=Org/OU=Unit/CN=cert name/emailAddress=nothing@nowhere" -new -x509 -key private.key -out publickey.cer -days 3650 openssl pkcs12 -passout pass:mypassword -export -nokeys -out public.key -in publickey.cer -inkey private.key

This creates two key files, private.key (the combined public and private keys) and public.key (the public key).

The client application is in C#. There, I load the public key like this:

X509Certificate2 cert = new X509Certificate2(@"D:\public.key", "mypassword"); RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;

This works fine for encryption because if I encrypt a block of data and send it to the server on a socket connection then the server can decrypt it and correctly display the data contents. So I am confident that the key is being loaded correctly.

When the server gets the encrypted block of data, and correctly decrypts it, it then signs a response and sends it back to the client:

// Send a signed reply unsigned char *signature = (unsigned char *) malloc(RSA_size(privateKey)); if (signature != NULL) { char *reply ="Top of the morning to you"; unsigned int siglen; if (RSA_sign(NID_sha1, (unsigned char *)reply, strlen(reply), signature, &siglen, privateKey)) { printf("SigLen = %d\n", siglen); unsigned char *msg = (unsigned char *)malloc(siglen + strlen(reply)); if (msg != NULL) { memcpy(msg, signature, siglen); memcpy(msg+siglen, reply, strlen(reply)); send(sock, msg, siglen + strlen(reply), 0); free(msg); } } free(signature); }

The client receives the data and separates out the signature from the data being signed and then tries to verify the signature but this always fails. Here is the complete code of the client part:

static void Main(string[] args) { X509Certificate2 cert = new X509Certificate2(@"D:\public.key", "mypassword"); RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PublicKey.Key; string payload = "Hello world!!"; byte[] encrypted = rsa.Encrypt(Encoding.ASCII.GetBytes(payload), false); TcpClient client = new TcpClient(); client.Connect("192.168.1.57", 2002); NetworkStream ns = client.GetStream(); ns.Write(encrypted, 0, encrypted.Length); ns.ReadTimeout = 2000; byte[] rx = new byte[5000]; int bytesRead = ns.Read(rx, 0, rx.Length); if (bytesRead > 0) { int keySizeBytes = rsa.KeySize >> 3; if (bytesRead > keySizeBytes) { byte[] signedMessage = new byte[bytesRead - keySizeBytes]; Array.Copy(rx, keySizeBytes, signedMessage, 0, signedMessage.Length); Array.Resize<byte>(ref rx, keySizeBytes); if (rsa.VerifyData(signedMessage, CryptoConfig.MapNameToOID("SHA1"), rx)) { Console.WriteLine("Verified OK"); } else { Console.WriteLine("Not verified"); } } } client.Close(); Console.ReadLine(); }

Is there something I am missing that I need to do to be able to verify the data on the client side?

最满意答案

您正在使用RSA_sign错误 - 根据文档 (强调我的):

RSA_sign()使用PKCS#1 v2.0中指定的私钥rsa签署大小为m_len的消息摘要 m

换句话说,您必须首先散列您的消息,然后将消息散列传递给RSA_sign 。 然后它应该在.NET中可验证。

以下更改应该有效:

unsigned char* hash = SHA1((unsigned char *)reply, strlen(reply), NULL); if (RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, signature, &siglen, privateKey)) { ...

You are using RSA_sign incorrectly - per the documentation (emphasis mine):

RSA_sign() signs the message digest m of size m_len using the private key rsa as specified in PKCS #1 v2.0

In other words, you must hash your message first, and then pass the message hash to RSA_sign. It should then be verifiable in .NET.

The following change should work:

unsigned char* hash = SHA1((unsigned char *)reply, strlen(reply), NULL); if (RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, signature, &siglen, privateKey)) { ...

更多推荐

本文发布于:2023-08-04 03:41:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1407709.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:数据   OpenSSL   RSA   Net   data

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!