.NET中的RSA加密/解密问题

时间:2010-03-19 08:28:12

标签: c# rsa encryption

我在使用RSA进行C#加密和解密时遇到问题。我开发了一个Web服务,将发送敏感的财务信息和交易。我希望能够做的是在客户端,使用客户端RSA私钥加密某些字段,一旦它到达我的服务,它将使用客户端公钥解密。

目前我不断得到一个“要解密的数据超过了这个128字节模数的最大值。”例外。我没有太多关注C#RSA加密技术,所以任何帮助都会受到高度赞赏。

这是我用来生成密钥的方法

private void buttonGenerate_Click(object sender, EventArgs e)
{
    string secretKey = RandomString(12, true);

    CspParameters param = new CspParameters();
    param.Flags = CspProviderFlags.UseMachineKeyStore;

    SecureString secureString = new SecureString();
    byte[] stringBytes = Encoding.ASCII.GetBytes(secretKey);
    for (int i = 0; i < stringBytes.Length; i++)
    {
        secureString.AppendChar((char)stringBytes[i]);
    }
    secureString.MakeReadOnly();
    param.KeyPassword = secureString;

    RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(param);
    rsaProvider = (RSACryptoServiceProvider)RSACryptoServiceProvider.Create();
    rsaProvider.KeySize = 1024;


    string publicKey = rsaProvider.ToXmlString(false);
    string privateKey = rsaProvider.ToXmlString(true);

    Repository.RSA_XML_PRIVATE_KEY = privateKey;
    Repository.RSA_XML_PUBLIC_KEY = publicKey;

    textBoxRsaPrivate.Text = Repository.RSA_XML_PRIVATE_KEY;
    textBoxRsaPublic.Text = Repository.RSA_XML_PUBLIC_KEY;

    MessageBox.Show("Please note, when generating keys you must sign on to the gateway\n" +
        " to exhange keys otherwise transactions will fail", "Key Exchange", MessageBoxButtons.OK, MessageBoxIcon.Information);

}

生成密钥后,我将公钥发送到Web服务,并将其存储为XML文件。

现在我决定测试一下,所以这是加密字符串的方法

public static string RsaEncrypt(string dataToEncrypt)
{
    string rsaPrivate = RSA_XML_PRIVATE_KEY;
    CspParameters csp = new CspParameters();
    csp.Flags = CspProviderFlags.UseMachineKeyStore;

    RSACryptoServiceProvider provider = new RSACryptoServiceProvider(csp);

    provider.FromXmlString(rsaPrivate);

    ASCIIEncoding enc = new ASCIIEncoding();
    int numOfChars = enc.GetByteCount(dataToEncrypt);
    byte[] tempArray = enc.GetBytes(dataToEncrypt);
    byte[] result = provider.Encrypt(tempArray, true);
    string resultString = Convert.ToBase64String(result);
    Console.WriteLine("Encrypted : " + resultString);
    return resultString;
}

我确实得到了似乎是加密值的东西。在我创建的测试加密web方法中,然后我获取此加密数据,使用客户端公钥尝试解密数据并以明文形式发回。但这是抛出异常的地方。这是我的方法。

public string DecryptRSA(string data, string merchantId)
{
    string clearData = null;
    try
    {
        CspParameters param = new CspParameters();
        param.Flags = CspProviderFlags.UseMachineKeyStore;
        RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(param);

        string merchantRsaPublic = GetXmlRsaKey(merchantId);
        rsaProvider.FromXmlString(merchantRsaPublic);
        byte[] asciiString = Encoding.ASCII.GetBytes(data);

        byte[] decryptedData = rsaProvider.Decrypt(asciiString, false);

        clearData = Convert.ToString(decryptedData);
    }
    catch (CryptographicException ex)
    {
        Log.Error("A cryptographic error occured trying to decrypt a value for " + merchantId, ex);

    }
    return clearData;
}

如果有人能帮助我,这将是非常棒的,正如我所说,我没有做太多的C#RSA加密/解密。

5 个答案:

答案 0 :(得分:33)

答案 1 :(得分:14)

我理解你为什么问这个问题。问题是RSA不像典型的块密码(如AES或3DES)一样,一天加密8个字节,整天都在使用。 RSA是一个数学运算,返回除法的余数(模数)。回到小学,当你学会了长时间的分裂时,记住余数永远不会大于除数:如果你将20除以7,你的余数是6.无论你除以7的整数,其余的都不能更大比六岁。

RSA数学是一样的。例如,如果您使用的是1024位RSA公钥,则余数永远不会大于2 ^ 1024,即只有128个字节。因此,您只能使用此密钥一次加密128个字节。 (这是我们用比特数来衡量RSA密钥大小的一个原因。)

从技术上讲,您可以在循环中使用此RSA密钥一次加密数据的128个字节块。实际上,我们几乎从不这样做,因为RSA数学是BIG和SLOW。相反,我们使用所谓的“两阶段”加密。我们使用RSA仅加密一个简短的“会话密钥”,然后在快速对称密钥块密码(如AES)中使用该会话密钥来加密实际数据。

整个协议是:

  1. 获取目的地的RSA公钥。这通常是嵌入在证书中的;如果是,请务必验证证书以确保密钥是真实的。假设RSA密钥长度为2048位。
  2. 生成一个加密强的伪随机数,用作块密码的密钥(例如,您需要256位作为AES-256的密钥。)请注意,256&lt; 2048,RSA-2048可以立即加密的最大值。我们称这个随机数为“会话密钥”。
  3. 使用RSA 2048位公钥加密会话密钥。它将为您提供2048位加密会话密钥。请注意,此操作非常慢。
  4. 使用会话密钥使用AES-256加密所有秘密数据。请注意,这比第3步快得多。
  5. 将证书,RSA加密会话密钥和AES加密数据中的公钥ID捆绑在一起。我还会用格式标识符和版本号标记它,以便您知道它的格式以及如何解密它。
  6. 将捆绑包发送到目的地。

  7. 在目的地,您使用格式标识符和版本来拆分捆绑包。

  8. 检索其标识位于公钥ID字段中的私钥。
  9. 在RSA中使用此私钥来解密会话密钥。
  10. 使用AES中的会话密钥解密数据。
  11. 如果您要这样做,您应该知道它正是CMS(PKCS#7)格式的用途。我鼓励你学习标准并采用它,而不是试图发明你自己的格式。微软的CSP支持它,所以应该很容易。

    如果您不遵循标准,则必须自行决定“在RSA加密过程中AES密钥位应采用何种格式?”更有可能的是,你几乎肯定会犯安全错误,削弱你的系统。此外,如果你不遵守标准,你会发现像CSP这样的工具很难处理。

答案 2 :(得分:3)

在DecryptRSA中,“数据”基础64编码?如果是,则必须先撤消。

老实说,我认为你不应该自己实施这个例程来保护“敏感的财务信息”,除非你有很多加密技术的经验。制作错误的方法太多了。更好地使用一些现成的解决方案 - 可能是SSL和证书,还是仅仅是PGP或GnuPG?

答案 3 :(得分:3)

RSA主要用于验证数据的安全哈希值 - 而不是加密数据本身。因此,给定大量数据,您可以使用SHA512创建该数据的哈希值,然后使用RSA 签署该哈希值。

您需要对大型数据块使用对称加密算法 - 例如AES或3DES。

管理安全交易并不容易,而且真的应该留给那些日夜都在思考它的人。如果您通过网络公开服务,只需使用已加密并保护数据的SSL。

答案 4 :(得分:2)

首先确定您要防范的内容。如果使用私钥“加密”某些内容,任何人都可以使用公钥“解密”它,因为公钥是 - 嗯 - public

如果你真的想签名,你应该(正如保罗亚历山大解释的那样)用私钥签名哈希,然后可以在服务器上验证。

要使用RSA 加密数据,您应首先生成随机对称密钥(fx AES),使用 public 密钥加密密钥并使用对称密钥加密数据。然后,您可以将加密密钥与加密数据一起发送给私有密钥的持有者,然后该密钥可以首先使用私钥解密加密密钥,然后使用对称密钥解密数据。 / p>

您也可以考虑使用SSL,但请记住仔细考虑身份验证。您可能需要客户端身份验证,并且必须决定要信任哪些证书(您不应盲目接受Verisign颁发的任何证书)。