如何使用 rsa 正确验证数据?
How to properly verify data with rsa?
我想用私钥签署消息并用 public 密钥验证它,但我无法让它工作..
这是我对数据进行签名的方式(已编辑,但仍然无法正常工作):
public static string SignData(string message, string privateKey) {
byte[] plainText = ASCIIEncoding.Unicode.GetBytes(message);
var rsaWrite = new RSACryptoServiceProvider();
rsaWrite.FromXmlString(privateKey);
byte[] signature = rsaWrite.SignData(plainText, new SHA1CryptoServiceProvider());
return Convert.ToBase64String(signature);
}
以下是我测试数据的方式(已编辑,但仍然无法正常工作):
public static bool VerifyData(string sign, string publicKey, string orig) {
byte[] signature = Convert.FromBase64String(sign);
byte[] original = ASCIIEncoding.Unicode.GetBytes(orig);
var rsaRead = new RSACryptoServiceProvider();
rsaRead.FromXmlString(publicKey);
if (rsaRead.VerifyData(original, new SHA1CryptoServiceProvider(), signature)) {
return true;
} else {
return false;
}
}
我将密钥对作为 xml 字符串存储在我的帐户 class 中。该函数在account.cs:
的构造函数中执行
public void addKeys() {
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(1024);
privateKey = provider.ToXmlString(true);
publicKey = provider.ToXmlString(false);
}
我用这个来测试整体:
string signedHash = Utility.SignData("test" ,account.privateKey);
if (Utility.VerifyData(signedHash, account.publicKey, "test")) {
Console.WriteLine("WORKING!");
} else {
Console.WriteLine("SIGNING NOT WORKING");
}
为什么整体没有效果?我的猜测是由于某些编码问题它不起作用。
return ASCIIEncoding.Unicode.GetString(signature);
签名是任意二进制数据,不一定合法Unicode/UCS-2。您需要使用任意编码 (https://en.wikipedia.org/wiki/Binary-to-text_encoding#Encoding_standards) 来对所有任意数据进行编码。最流行的签名传输方式是 Base64,因此您需要
return Convert.ToBase64String(signature);
当然,在验证方法中使用Convert.FromBase64String
。
如果您使用 .NET 4.6 或更高版本的目标进行编译,您还可以使用更新的 sign/verify API:
rsaRead.VerifyData(original, new SHA1CryptoServiceProvider(), signature)
会是
rsaRead.VerifyData(original, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)
虽然它可能看起来并不简单,但它阻止了另一种方法所做的 SHA1CryptoServiceProvider 的分配和完成,并且当您可能想要从 Pkcs1 签名填充切换到 PSS 签名填充时,它会为 The Future 设置。 (但真正的优势是该方法基于 RSA
基础 class 而不是 RSACryptoServiceProvider
特定类型)。
我想用私钥签署消息并用 public 密钥验证它,但我无法让它工作..
这是我对数据进行签名的方式(已编辑,但仍然无法正常工作):
public static string SignData(string message, string privateKey) {
byte[] plainText = ASCIIEncoding.Unicode.GetBytes(message);
var rsaWrite = new RSACryptoServiceProvider();
rsaWrite.FromXmlString(privateKey);
byte[] signature = rsaWrite.SignData(plainText, new SHA1CryptoServiceProvider());
return Convert.ToBase64String(signature);
}
以下是我测试数据的方式(已编辑,但仍然无法正常工作):
public static bool VerifyData(string sign, string publicKey, string orig) {
byte[] signature = Convert.FromBase64String(sign);
byte[] original = ASCIIEncoding.Unicode.GetBytes(orig);
var rsaRead = new RSACryptoServiceProvider();
rsaRead.FromXmlString(publicKey);
if (rsaRead.VerifyData(original, new SHA1CryptoServiceProvider(), signature)) {
return true;
} else {
return false;
}
}
我将密钥对作为 xml 字符串存储在我的帐户 class 中。该函数在account.cs:
的构造函数中执行public void addKeys() {
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(1024);
privateKey = provider.ToXmlString(true);
publicKey = provider.ToXmlString(false);
}
我用这个来测试整体:
string signedHash = Utility.SignData("test" ,account.privateKey);
if (Utility.VerifyData(signedHash, account.publicKey, "test")) {
Console.WriteLine("WORKING!");
} else {
Console.WriteLine("SIGNING NOT WORKING");
}
为什么整体没有效果?我的猜测是由于某些编码问题它不起作用。
return ASCIIEncoding.Unicode.GetString(signature);
签名是任意二进制数据,不一定合法Unicode/UCS-2。您需要使用任意编码 (https://en.wikipedia.org/wiki/Binary-to-text_encoding#Encoding_standards) 来对所有任意数据进行编码。最流行的签名传输方式是 Base64,因此您需要
return Convert.ToBase64String(signature);
当然,在验证方法中使用Convert.FromBase64String
。
如果您使用 .NET 4.6 或更高版本的目标进行编译,您还可以使用更新的 sign/verify API:
rsaRead.VerifyData(original, new SHA1CryptoServiceProvider(), signature)
会是
rsaRead.VerifyData(original, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)
虽然它可能看起来并不简单,但它阻止了另一种方法所做的 SHA1CryptoServiceProvider 的分配和完成,并且当您可能想要从 Pkcs1 签名填充切换到 PSS 签名填充时,它会为 The Future 设置。 (但真正的优势是该方法基于 RSA
基础 class 而不是 RSACryptoServiceProvider
特定类型)。