【问题标题】:Securing a license key with RSA key使用 RSA 密钥保护许可证密钥
【发布时间】:2011-02-02 15:43:00
【问题描述】:

时间不早了,我累了,可能还挺密集的……

我编写了一个需要保护的应用程序,因此它只能在我为其生成密钥的机器上运行。 我现在正在做的是获取 BIOS 序列号并从中生成哈希,然后我使用 XML RSA 私钥对其进行加密。然后我签署 XML 以确保它没有被篡改。 我正在尝试打包公钥以解密和验证签名,但是每次我尝试以与生成签名的用户不同的用户身份执行代码时,我都会在签名上失败。

我的大部分代码都是根据我找到的示例代码修改的,因为我对 RSA 加密并不像我想的那样熟悉。下面是我正在使用的代码以及我认为我需要使用它才能正常工作的代码......

任何反馈都将不胜感激,因为我现在很迷茫 我使用的原始代码是这样的,只要启动程序的用户与最初签署文档的用户相同,此代码就可以正常工作...

 CspParameters cspParams = new CspParameters();
            cspParams.KeyContainerName = "XML_DSIG_RSA_KEY";
            cspParams.Flags = CspProviderFlags.UseMachineKeyStore;

            // Create a new RSA signing key and save it in the container. 
            RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams)
            {
                PersistKeyInCsp = true,
            };

这段代码是我认为我应该做的,但无论我做什么,它都无法验证签名,无论它是同一个用户还是不同的用户......

RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider();
            //Load the private key from xml file
            XmlDocument xmlPrivateKey = new XmlDocument();
            xmlPrivateKey.Load("KeyPriv.xml");
            rsaKey.FromXmlString(xmlPrivateKey.InnerXml);

我相信这与关键容器名称有关(这里是一个真正的笨蛋,请原谅我)我很确定这是导致它在第一种情况下工作并阻止它的行在第二种情况下工作....

cspParams.KeyContainerName = "XML_DSIG_RSA_KEY";

有没有办法让我在生成应用程序许可证时使用私钥对 XML 进行签名/加密,然后将公钥放到 app 目录中并使用它来验证/解密代码?如果我能让签名部分正常工作,我可以放弃加密部分。我用它作为备份来混淆我键入的许可证代码的来源。

这些有意义吗? 我是个彻头彻尾的笨蛋吗?

感谢任何人在这方面可以给我的任何帮助..

【问题讨论】:

    标签: c# rsa digital-signature


    【解决方案1】:

    我使用此方法使用存储在 xml 文件中的私钥对 xml 文档进行签名,然后将其作为资源嵌入到应用程序 .dll 中。我认为您可能正在为访问密钥库的权限而苦苦挣扎,这也会造成将代码传输到其他服务器等的麻烦。

    以下是获取作为嵌入式资源的私钥并对文档进行签名的代码: (sign是这个方法所在的类名,Licensing.Private.Private.xml是默认命名空间+文件夹+资源文件名的组合)

    public static void SignDocument(XmlDocument xmldoc)
    {
        //Get the XML content from the embedded XML privatekey.
        Stream s = null;
        string xmlkey = string.Empty;
        try
        {
            s = typeof(Sign).Assembly.GetManifestResourceStream("Licensing.Private.Private.xml");
    
            // Read-in the XML content.
            StreamReader reader = new StreamReader(s);
            xmlkey = reader.ReadToEnd();
            reader.Close();
        }
        catch (Exception e)
        {
            throw new Exception("Error: could not import key:",e);
        }
    
        // Create an RSA crypto service provider from the embedded
        // XML document resource (the private key).
        RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
        csp.FromXmlString(xmlkey);
        //Creating the XML signing object.
        SignedXml sxml = new SignedXml(xmldoc);
        sxml.SigningKey = csp;
    
        //Set the canonicalization method for the document.
        sxml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigCanonicalizationUrl; // No comments.
    
        //Create an empty reference (not enveloped) for the XPath transformation.
        Reference r = new Reference("");
    
        //Create the XPath transform and add it to the reference list.
        r.AddTransform(new XmlDsigEnvelopedSignatureTransform(false));
    
        //Add the reference to the SignedXml object.
        sxml.AddReference(r);
    
        //Compute the signature.
        sxml.ComputeSignature();
    
        // Get the signature XML and add it to the document element.
        XmlElement sig = sxml.GetXml();
        xmldoc.DocumentElement.AppendChild(sig);
    }
    

    使用以下代码生成 private.xml 和 public.xml 密钥。显然,请确保 private.xml 文件的安全。

    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    File.WriteAllText(@"C:\privateKey.xml", rsa.ToXmlString(true));  // Private Key
    File.WriteAllText(@"C:\publicKey.xml", rsa.ToXmlString(false));  // Public Key
    

    【讨论】:

    • 太棒了!谢谢您的帮助!这不仅解决了我的许可问题,还帮助我管理了应用中的其他资源。
    • 刚刚注意到我没有在 try catch 块中的 finally 中处理 StreamReader ...
    【解决方案2】:

    猜猜,问题是不同的用户无权访问为第一个用户存储的密钥(请注意:我不是密码学专家)。

    【讨论】: