“坏数据”CryptographicException

时间:2012-03-11 23:17:54

标签: c# encryption cryptography rsa

首先,我只是为了学术目的而编写了以下代码。我说这个的原因是因为我没有将它放在生产环境中,因此我“绕过”了我需要做的一些开销,我只需要能够使用加密/解密字符串下面的代码。我能够做到这一点,但由于某种原因,我开始收到“CryptographicException Bad Data”,并且不确定是什么原因造成了这个问题。

   private string RSAEncrypt(string value)
    {
        byte[] encryptedData = Encoding.Unicode.GetBytes(value);

        CspParameters cspParams = new CspParameters();
        cspParams.KeyContainerName = _rsaContainerName;
        using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048,cspParams))
        {
            encryptedData = RSA.Encrypt(encryptedData, false);
            return Convert.ToBase64String(encryptedData);

        }

    }



    private string RSADecrypt(string value)
    {

        byte[] encryptedData = Encoding.Unicode.GetBytes(value);

        CspParameters cspParams = new CspParameters();
        cspParams.KeyContainerName = _rsaContainerName;
        using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048,cspParams))
        { 
            encryptedData = RSA.Decrypt(encryptedData,false);
            return Convert.ToBase64String(encryptedData);

        }
    }

只在RSADecrypt调用上抛出此异常。

有什么想法吗?我在某处读到了可能与传入RSA.Decrypt的加密数据的预期大小有关。

由于         }

4 个答案:

答案 0 :(得分:16)

  • 使用字符串编码(即Encoding.Unicode)来回转换明文。

  • 使用Base-64(即Convert.[To/From]Base64String)来回转换加密数据;

像这样:

private string RSAEncrypt(string value)
{
    byte[] plaintext = Encoding.Unicode.GetBytes(value);

    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = _rsaContainerName;
    using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048,cspParams))
    {
        byte[] encryptedData = RSA.Encrypt(plaintext, false);
        return Convert.ToBase64String(encryptedData);
    }
}

private string RSADecrypt(string value)
{
    byte[] encryptedData = Convert.FromBase64String(value);

    CspParameters cspParams = new CspParameters();
    cspParams.KeyContainerName = _rsaContainerName;
    using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048,cspParams))
    { 
        byte[] decryptedData = RSA.Decrypt(encryptedData,false);
        return Encoding.Unicode.GetString(decryptedData);
    }
}

答案 1 :(得分:6)

http://blogs.msdn.com/b/shawnfa/archive/2005/11/10/491431.aspx

  

不要通过字符串编码往返传输密文

     

人们在使用托管加密时犯的一个常见错误   类是他们试图存储加密的结果   通过使用其中一个Encoding类在字符串中操作。那   似乎有道理吗?毕竟,Encoding.ToString()需要一个   byte []并将其转换为一个完全相同的字符串   寻找。

     

...

     

相反,如果您想将密文转换为字符串,请使用   Base64编码。

     

...

     

每次都有效的代码结果,因为base 64编码是   保证能够准确表示任何输入字节序列。

这里有一个很好的正确例子: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx

答案 2 :(得分:1)

RSA 并不意味着加密大型对象。如果你超过填充限制,你会得到例外。实际限制基于填充本身(使用false表示您使用 PKCS#1 v1.5填充)和公钥长度(2048位)。

对大对象使用RSA的正确方法是使用对称密钥(例如256位AES密钥)加密大对象,并加密使用RSA公钥密钥。

您可以在blog上找到执行此类操作的代码。

答案 3 :(得分:0)

我遇到同样的问题,因为我把它放在我的Global.asax文件中,将Url转换为小写。

 protected void Application_BeginRequest(object sender, EventArgs e)
    {
      //   Don't rewrite requests for content (.png, .css) or scripts (.js)
        if (Request.Url.AbsolutePath.Contains("/Content/") ||
            Request.Url.AbsolutePath.Contains("/Scripts/"))
            return;

        If uppercase chars exist, redirect to a lowercase version
        var url = Request.Url.ToString();
       if (Regex.IsMatch(url, @"[A-Z]"))
        {
            Response.Clear();
           Response.Status = "301 Moved Permanently";
           Response.StatusCode = (int)HttpStatusCode.MovedPermanently;
            Response.AddHeader("Location", url.ToLower());
            Response.End();
       }
    }

所以

示例

如果使用base64字符串编码加密

  

http://localhost:11430/orderpreview?orderID=t4RZrnefb2a%253d&price=27.9

然后点击动作“Application_BeginRequest”将其转换为

  

http://localhost:11430/orderpreview?orderID=t4rzrnefb2a%253d&price=27.9

你可以看到RZ被限制转换为小rz,这将使解密失败。

<强>解决方案

在RouteConfig类里面注册RegisterRoutes方法,如果你想要小写的网址

        routes.Canonicalize().Www();
        routes.Canonicalize().Lowercase();
        routes.Canonicalize().NoTrailingSlash();