我遇到了生成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();
}
我需要做些什么才能在客户端验证数据?
答案 0 :(得分:0)
您错误地使用RSA_sign
- 按documentation(强调我的):
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))
{
...