.NET中的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); } 

生成密钥后,我将公钥发送到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方法中,然后我获取此加密数据,使用客户端公钥尝试解密数据并以明文forms发回。 但这是抛出exception的地方。 这是我的方法负责这一点。

 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加密/解密。

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

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

  • 数字签名旨在certificate完整性。 有人计算一种对数据的键控校验和,这样可以在以后validation校验和与数据之间的链接。 这是一个“签名”只是因为计算校验和的能力需要知道一些不公开的东西 – 用简单的话说,签名使用私钥 。 但是,validation应该是任何人都可以做到的,因此使用公钥。

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

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

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

有了这个说……

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

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

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

我理解你为什么问这个问题。 问题是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公钥。 这通常是嵌入证书中的; 如果是,请务必validation证书以确保密钥是真的。 假设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这样的工具将很难使用。

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

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

RSA主要用于validation数据的安全哈希值 – 而不是加密数据本身。 因此,给定大量数据,您可以使用SHA512创建该数据的哈希值,然后使用RSA对该哈希值进行签名

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

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

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

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

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

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