RSA 在 C# 中签名以进行许可

Posted

技术标签:

【中文标题】RSA 在 C# 中签名以进行许可【英文标题】:RSA signing in C# for licensing 【发布时间】:2015-01-22 21:39:48 【问题描述】:

(方法 #2) 我需要做一个软件激活机制。所以我最终采用了这个方案:应用程序根据计算机的硬件创建一个唯一的 id。买家通过电子邮件将此 ID 发送给我。我用我的私钥对其进行签名,然后将签名的字符串发回。应用验证字符串(使用包含的公钥对其进行解码并与硬件 id 进行比较)。

到目前为止,我已经完成了硬件 ID,并且我已经使用 openssl 创建了密钥(1024 位),这是两个文件 private.pem 和 public.pem。

我尝试应用http://www.christian-etter.de/?p=771 中描述的解决方案 但验证总是失败。

代码:

    private void Generate_Click(object sender, EventArgs e)
    
        byte[] SignedData;
        byte[] UnsignedData = Encoding.UTF8.GetBytes(CompID.Text);

        using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
        
            rsa.PersistKeyInCsp = false;
            rsa.LoadPrivateKeyPEM(PrivateKey.Text);
            using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
                SignedData = rsa.SignData(UnsignedData, sha1);
            ActCode.Text = Encoding.UTF8.GetString(SignedData, 0, SignedData.Length);
        
    

    //--------------------------------------------------------------------

    private void Verify_Click(object sender, EventArgs e)
    
        byte[] UnsignedData = Encoding.UTF8.GetBytes(CompID.Text);
        byte[] SignedData = Encoding.UTF8.GetBytes(ActCode.Text);
        bool VerifOK;

        using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
        
            rsa.PersistKeyInCsp = false;
            rsa.LoadPublicKeyPEM(PublicKey.Text);
            using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
                VerifOK = rsa.VerifyData(UnsignedData, sha1, SignedData);
        
        if (VerifOK) verif.Text = "verification ok";
        else verif.Text = "verification error";
    

【问题讨论】:

没有深入研究这一点,但是您的代码在切换到 UTF-8 或存储在文本框中似乎比较随意,这意味着您可能在不知不觉中更改了字节。除非您非常小心,否则从字符串到 byte[] 来回切换是危险的。如果可能,请尝试将数据保留为byte[] 并非所有字节序列都是有效的 UTF-8 编码。通过Convert.To/FromBase64String使用Base64编码处理SignedData @mikez 非常感谢!我错过了。成功了! @LynnCrumbling 感谢您指出正确的方向。 我会将其添加为答案,您可以将其标记为已接受。 【参考方案1】:

您将一些任意字节视为 UTF-8 编码字符串 (SignedData) 这是不正确的,因为并非所有字节序列都是有效的。我怀疑编码器丢弃了无效字节,导致验证失败。您应该使用 Base64 编码以字符串格式保存二进制数据而不会丢失任何内容。所以这个:

using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
    SignedData = rsa.SignData(UnsignedData, sha1);
ActCode.Text = Encoding.UTF8.GetString(SignedData, 0, SignedData.Length);

变成

using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
    SignedData = rsa.SignData(UnsignedData, sha1);
ActCode.Text = Convert.ToBase64String(SignedData);

同样,在验证过程中,您需要使用Convert.FromBase64String 来获取SignedData。 CompID 可以使用 UTF-8,因为它是字符串数据,您需要将其转换为二进制形式进行签名。

【讨论】:

以上是关于RSA 在 C# 中签名以进行许可的主要内容,如果未能解决你的问题,请参考以下文章

使用 rsa 在 c# 中验证来自节点的签名数据

使用 RSA C# 签名和验证签名

使用 mbedtls 生成的 RSA 签名,无法使用 C# (bouncycastle) 应用程序进行验证

C# - 是不是可以使用 RSA SHA512 对哈希进行签名?

针对 RSA 公钥对字符串进行签名

C#中RSA加密解密和签名与验证的实现