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

Bre*_*all 17 c# encryption rsa

我在使用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);

}
Run Code Online (Sandbox Code Playgroud)

生成密钥后,我将公钥发送到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;
}
Run Code Online (Sandbox Code Playgroud)

我确实得到了似乎是加密的值.在我创建的测试加密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;
}
Run Code Online (Sandbox Code Playgroud)

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

Tho*_*nin 34

请允许我使用一些术语.有非对称加密,有数字签名.

  • 非对称加密是关于保密.除了知道解密密钥的实体之外,一些敏感数据被转换为不可读的东西.解密密钥必须是私钥:如果解密密钥是公钥,那么每个人都可以解密数据(公钥是公共的),并且不再存在机密性.在非对称加密中,用公钥加密并用相应的私钥解密.

  • 数字签名旨在证明完整性.有人计算一种对数据的键控校验和,这样可以在以后验证校验和与数据之间的链接.这是一个"签名",因为计算校验和的能力需要知道非公开的东西 - 用简单的话说,签名使用私钥.但是,验证应该是任何人都可以使用的,因此使用公钥.

"RSA"算法实际上是一种可以拒绝进入非对称加密系统和数字签名系统的数学运算,这一事实暗示了一些混乱.RSA标准(又称PKCS#1)进一步增强了混淆,其隐含地依赖于如何首先描述RSA数字签名,即作为"反向加密"("签名者用他的私钥加密数据").这导致RSA签名称为"sha1WithRSAEncryption".这非常不幸.

因此,您必须首先确定是否需要机密性或签名.为了保密,用于发送数据客户服务器,服务器将自己的私钥,客户端使用服务器的公钥对数据进行加密.对于签名,每个客户端应拥有自己的私钥并使用它来签署数据,服务器验证签名.由于我上面提到的混乱,从你的描述中我无法分辨出你的真实情况.

此外,有一种称为身份验证的东西可能看起来像数字签名,但更弱.签名点比任何人都可以验证签名.特别是,签名可以向法官显示,从而作为签名者的法律武器(签名具有法律约束力 - 至少如果你做对了,并且在电子签名的现行法规中,这不是简单).在大多数情况下,你只需要一些更简单,更简单的东西,服务器确信它与正确的客户端对话,但之后不能说服其他人这个客户端真的在那里.任何具有用户密码的网站都使用此类身份验证.

有了这个说......

  • RSA非对称加密仅包含短消息.对于1024位RSA密钥(即最重要部分的密钥,"RSA模数")是一个大数字,其值在2 ^ 1023和2 ^ 1024之间,加密消息的长度为128字节),加密消息的最大大小为117个字节(这是您的错误消息的实际来源).当我们想要发送更长的消息时,我们使用混合系统,其中我们只加密一小串随机比特(比如128比特)并使用该串作为对称加密系统(例如AES)的密钥,它可以处理很多更长的消息(也更快).

  • 类似地,RSA签名只能在短消息上计算,因此PKCS#1标准要求签名实际上是通过散列值计算的.哈希值是特定哈希函数的输出,该哈希函数是在要签名的消息上计算的.散列函数具有固定大小的输出(例如,对于SHA-256为256位)但接受(几乎)任意长度的输入消息.散列函数是公共的(它们中没有键),为了保证适当的安全性,必须具有一些特殊属性.SHA-256现在不是一个糟糕的选择.SHA-1(SHA-256的前身)已被证明存在一些缺点,应予以避免.MD5(一种SHA-1的叔叔)有更大的弱点,不得使用.

  • 正确使用非对称加密,特别是在混合方案和数字签名中,比上面的文字所暗示的更为棘手.在某些时候,无形地弄错了很容易,即代码似乎可以工作,但会泄漏数据对攻击者有用.使用非对称加密或数字签名的正确方法是依靠现有的,经过深思熟虑的协议.协议是将加密元素组合成一个连贯的系统,其中泄漏得到了解决.最好的例子是TLS,也称为SSL.它是一种确保机密数据传输的协议,具有完整性和身份验证(可能是相互身份验证).HTTPS协议是HTTP和SSL的混合体.好的一面是HTTPS有现成的实现,特别是在C#中.最容易实现和调试的代码是已经实现和调试的代码.因此,使用HTTPS,您将活得更长,更快乐.


Joh*_*ers 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 <2048,RSA-2048可以一次加密的最大值.我们称这个随机数为"会话密钥".
  3. 使用RSA 2048位公钥加密会话密钥.它将为您提供2048位加密会话密钥.请注意,此操作非常慢.
  4. 使用会话密钥使用AES-256加密所有秘密数据.请注意,这比第3步快得多.
  5. 将证书,RSA加密会话密钥和AES加密数据中的公钥ID捆绑在一起.我还会用格式标识符和版本号标记它,因此您可以知道它的格式以及如何解密它.
  6. 将捆绑包发送到目的地.

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

  8. 检索其标识位于公钥ID字段中的私钥.
  9. 在RSA中使用此私钥来解密会话密钥.
  10. 使用AES中的会话密钥来解密数据.

如果您打算这样做,您应该知道它正是CMS(PKCS#7)格式的用途.我鼓励你学习标准并采用它,而不是试图发明你自己的格式.微软的CSP支持它,所以应该很容易.

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