如何正确使用rsa验证数据?

Loa*_*ing 2 c# encoding rsa digital-signature

我想用私钥签署消息并用公钥验证它,但我无法让它工作。

这是我对数据进行签名的方式(已编辑,但仍然不起作用):

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);
    }
Run Code Online (Sandbox Code Playgroud)

这是我测试数据的方法(已编辑,仍然不起作用):

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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

我将密钥对作为 xml 字符串存储在我的帐户类中。该函数在account.cs的构造函数中执行:

public void addKeys() {

    RSACryptoServiceProvider provider = new RSACryptoServiceProvider(1024);

    privateKey = provider.ToXmlString(true);
    publicKey = provider.ToXmlString(false);
}
Run Code Online (Sandbox Code Playgroud)

我用这个测试总体情况:

string signedHash = Utility.SignData("test" ,account.privateKey);

if (Utility.VerifyData(signedHash, account.publicKey, "test")) {          
    Console.WriteLine("WORKING!");
} else {
    Console.WriteLine("SIGNING NOT WORKING");
}
Run Code Online (Sandbox Code Playgroud)

为什么整体工作不顺利?我的猜测是,由于某些编码问题,它不起作用。

bar*_*njs 5

return ASCIIEncoding.Unicode.GetString(signature);
Run Code Online (Sandbox Code Playgroud)

签名是任意二进制数据,它不一定是合法的 Unicode/UCS-2。您需要使用任意编码(https://en.wikipedia.org/wiki/Binary-to-text_encoding#Encoding_standards)来对所有任意数据进行编码。最流行的签名传输方式是 Base64,因此您需要

return Convert.ToBase64String(signature);
Run Code Online (Sandbox Code Playgroud)

当然,还要Convert.FromBase64String在 verify 方法中使用。


如果您使用 .NET 4.6 或更高版本的目标进行编译,您还可以使用更新的签名/验证 API:

rsaRead.VerifyData(original, new SHA1CryptoServiceProvider(), signature)
Run Code Online (Sandbox Code Playgroud)

将会

rsaRead.VerifyData(original, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1)
Run Code Online (Sandbox Code Playgroud)

虽然它看起来可能并不简单,但它会阻止其他方法所做的 SHA1CryptoServiceProvider 的分配和最终确定,并且当您可能想要从 Pkcs1 签名填充切换到 PSS 签名填充时,它会为未来做好准备。(但真正的优点是方法是在RSA基类上而不是在RSACryptoServiceProvider特定类型上)。