【问题标题】:EncryptedXml DecryptDocument method throws "Bad Data" exceptionEncryptedXml DecryptDocument 方法抛出“坏数据”异常
【发布时间】:2013-03-11 13:17:44
【问题描述】:

我为加密/解密流编写了一个代码块。 该代码在我的本地机器上运行。 但是当我在网络上发布我的代码时 解密函数抛出“坏数据”异常 这是我的加密和解密函数

private static MemoryStream EncryptStream(XmlDocument xmlDoc, XmlElement elementToEncrypt, string password)
{
    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = password;
    RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
    RijndaelManaged sessionKey = null;
    try
    {

        if (xmlDoc == null)
            throw new ArgumentNullException("xmlDoc");
        if (rsaKey == null)
            throw new ArgumentNullException("rsaKey");
        if (elementToEncrypt == null)
            throw new ArgumentNullException("elementToEncrypt");

        sessionKey = new RijndaelManaged();
        sessionKey.KeySize = 256;

        EncryptedXml eXml = new EncryptedXml();
        byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);

        EncryptedData edElement = new EncryptedData();
        edElement.Type = EncryptedXml.XmlEncElementUrl;
        edElement.Id = EncryptionElementID;
        edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);

        EncryptedKey ek = new EncryptedKey();
        byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, rsaKey, false);
        ek.CipherData = new CipherData(encryptedKey);
        ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);

        edElement.KeyInfo = new KeyInfo();

        KeyInfoName kin = new KeyInfoName();
        kin.Value = KeyName;

        ek.KeyInfo.AddClause(kin);
        edElement.CipherData.CipherValue = encryptedElement;
        edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));

        EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);

        if (sessionKey != null)
        {
            sessionKey.Clear();
        }
        rsaKey.Clear();
        MemoryStream stream = new MemoryStream();
        xmlDoc.Save(stream);
        stream.Position = 0;
        Encoding encodeing = System.Text.UnicodeEncoding.Default;
        return stream;
    }
    catch (Exception e)
    {
        if (sessionKey != null)
        {
            sessionKey.Clear();
        }
        rsaKey.Clear();
        throw (e);
    }
}

private static MemoryStream DecryptStream(XmlDocument xmlDoc, string password)
{
    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = password;
    RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
    EncryptedXml exml = null;
    try
    {
        if (xmlDoc == null)
            throw new ArgumentNullException("xmlDoc");
        if (rsaKey == null)
            throw new ArgumentNullException("rsaKey");

        exml = new EncryptedXml(xmlDoc);
        exml.AddKeyNameMapping(KeyName, rsaKey);

        exml.DecryptDocument();
        rsaKey.Clear();

        MemoryStream outStream = new MemoryStream();
        xmlDoc.Save(outStream);
        outStream.Position = 0;
        return outStream;
    }
    catch (Exception e)
    {
        rsaKey.Clear();
        throw (e);
    }
}

在“exml.DecryptDocument();”上抛出异常行。

您对问题和解决方案有任何想法吗?

编辑:

MSDN页面中,有如下备注

要将 XML 加密与 X.509 证书一起使用,您必须拥有 安装了 Microsoft Enhanced Cryptographic Provider 和 X.509 证书必须使用增强提供程序。如果您没有 已安装 Microsoft 增强加密提供程序或 X.509 证书不使用增强提供程序,a 当您使用“未知错误”时,将引发 CryptographicException 解密 XML 文档。

您对“Microsoft Enhanced Cryptographic Provider”和“X.509 证书”有任何想法吗? 我的问题与这些有关吗?

【问题讨论】:

  • 你的 KeyName 在 web 中的值是多少?
  • 我在我的机器上尝试了同样的方法,但我无法模拟。请分享 KeyName 值
  • 我也试过用这个键,但希望我不能模拟。我对 xml 内容非常怀疑。也许发布xml内容会帮助我模拟和帮助你
  • 如何尝试模拟代码?你加密文件然后尝试用我的代码解密?
  • 提示:不要使用“throw e;”。使用“投掷”

标签: c# wcf encryption rsacryptoserviceprovider


【解决方案1】:

尝试在另一台 PC 上解密时,解密函数抛出“Bad Data”异常的原因是 CspParameters 链接到运行加密的 PC 上的会话。

需要在 XML 中嵌入和加密 cspParams 对象才能在另一台 PC 上启用解密。幸运的是,我们可以使用 EncryptionProperty。

private static MemoryStream EncryptStream(XmlDocument xmlDoc, XmlElement elementToEncrypt, string password)
{
    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = password;
    RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
    RijndaelManaged sessionKey = null;
    try
    {
        if (xmlDoc == null)
            throw new ArgumentNullException("xmlDoc");
        if (rsaKey == null)
            throw new ArgumentNullException("rsaKey");
        if (elementToEncrypt == null)
            throw new ArgumentNullException("elementToEncrypt");

        sessionKey = new RijndaelManaged();
        sessionKey.KeySize = 256;

        EncryptedXml eXml = new EncryptedXml();
        byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);

        EncryptedData edElement = new EncryptedData();
        edElement.Type = EncryptedXml.XmlEncElementUrl;
        edElement.Id = EncryptionElementID;
        edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);

        EncryptedKey ek = new EncryptedKey();
        byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, rsaKey, false);
        ek.CipherData = new CipherData(encryptedKey);
        ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);

        // Save some more information about the key using the EncryptionProperty element.

        // Create a new "EncryptionProperty" XmlElement object. 
        var property = new XmlDocument().CreateElement("EncryptionProperty", EncryptedXml.XmlEncNamespaceUrl);

        // Set the value of the EncryptionProperty" XmlElement object.
        property.InnerText = RijndaelManagedEncryption.EncryptRijndael(Convert.ToBase64String(rsaKey.ExportCspBlob(true)),
                        "Your Salt string here");

        // Create the EncryptionProperty object using the XmlElement object. 
        var encProperty = new EncryptionProperty(property);

        // Add the EncryptionProperty object to the EncryptedKey object.
        ek.AddProperty(encProperty);

        edElement.KeyInfo = new KeyInfo();

        KeyInfoName kin = new KeyInfoName();
        kin.Value = KeyName;

        ek.KeyInfo.AddClause(kin);
        edElement.CipherData.CipherValue = encryptedElement;
        edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));

        EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);

        if (sessionKey != null)
        {
            sessionKey.Clear();
        }
        rsaKey.Clear();
        MemoryStream stream = new MemoryStream();
        xmlDoc.Save(stream);
        stream.Position = 0;
        Encoding encodeing = System.Text.UnicodeEncoding.Default;
        return stream;
    }
    catch (Exception)
    {
        if (sessionKey != null)
        {
            sessionKey.Clear();
        }
        rsaKey.Clear();
        throw;
    }
}

private static MemoryStream DecryptStream(XmlDocument xmlDoc, string password)
{
    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = password;
    RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);

    var keyInfo = xmlDoc.GetElementsByTagName("EncryptionProperty")[0].InnerText;
        rsaKey.ImportCspBlob(
            Convert.FromBase64String(RijndaelManagedEncryption.DecryptRijndael(keyInfo,
                "Your Salt string here")));
    EncryptedXml exml = null;
    try
    {
        if (xmlDoc == null)
            throw new ArgumentNullException("xmlDoc");
        if (rsaKey == null)
            throw new ArgumentNullException("rsaKey");

        exml = new EncryptedXml(xmlDoc);
        exml.AddKeyNameMapping(KeyName, rsaKey);

        exml.DecryptDocument();
        rsaKey.Clear();

        MemoryStream outStream = new MemoryStream();
        xmlDoc.Save(outStream);
        outStream.Position = 0;
        return outStream;
    }
    catch (Exception)
    {
        rsaKey.Clear();
        throw;
    }
}

查看here 的 RijndaelManagedEncryption 类。

【讨论】:

  • 感谢您的回答。这对我帮助很大。
  • 总是很高兴并且很高兴它有帮助。
【解决方案2】:

不要重新发明密码协议。 你会弄错的。例如,错误处理存储在CSPs 中的 RSA 密钥并期望它们神奇地出现在任何机器上。

要加密传输中的数据,请使用 SSL/TLS。 .Net 通过SslStream 提供开箱即用的功能。对于 WCF,请参阅 How to: Configure an IIS-hosted WCF service with SSL

【讨论】:

  • 感谢您的回复,我会实施您的建议,但除了 ssl 之外,我仍然需要实施额外的加密。所以我必须解决这个问题。你对我的问题有什么建议吗?
猜你喜欢
  • 2017-10-30
  • 1970-01-01
  • 1970-01-01
  • 2014-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多