.NET 中的 RSA 加密/解密问题 [英] RSA Encrypt / Decrypt Problem in .NET

查看:21
本文介绍了.NET 中的 RSA 加密/解密问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm having a problem with C# encrypting and decrypting using RSA. I have developed a web service that will be sent sensitive financial information and transactions. What I would like to be able to do is on the client side, Encrypt the certain fields using the clients RSA Private key, once it has reached my service it will decrypt with the clients public key.

目前我不断收到要解密的数据超过此模数 128 字节的最大值".例外.我对 C# RSA 密码学的处理不多,因此不胜感激.

At the moment I keep getting a "The data to be decrypted exceeds the maximum for this modulus of 128 bytes." exception. I have not dealt much with C# RSA cryptography so any help would be greatly appreciated.

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

This is the method i am using to generate the keys

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
" +
        " to exhange keys otherwise transactions will fail", "Key Exchange", MessageBoxButtons.OK, MessageBoxIcon.Information);

}

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

Once i have generated the keys, i send the public key to the web service which stores it as an XML file.

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

Now i decided to test this so here is my method to encrypt a string

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 方法中,我然后获取这些加密数据,尝试使用客户端公钥解密数据并将其以明文形式发回.但这是抛出异常的地方.这是我对此负责的方法.

I do get what seems to be an encrypted value. In the test crypto web method that i created, i then take this encrypted data, try and decrypt the data using the clients public key and send this back in the clear. But this is where the exception is thrown. Here is my method responsible for this.

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 加密/解密没有做太多工作.

If anyone could help me that would be awesome, as i have said i have not done much with C# RSA encryption/decryption.

推荐答案

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

Allow me a bit of terminology. There is asymmetric encryption and there is digital signature.

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

  • Asymmetric encryption is about keeping confidentiality. Some sensitive data is transformed into something unreadable, save for the entity who knows the decryption key. The decryption key is necessarily the private key: if the decryption key is the public key, then everybody can decrypt the data (the public key is, well, public) and there is no confidentiality anymore. In asymmetric encryption, one encrypts with the public key and decrypts with the corresponding private key.

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

Digital signatures are meant to prove integrity. Someone computes a kind of keyed checksum over the data, in such a way that the link between the checksum and the data can be verified later. This is a "signature" only because the power to compute that checksum requires knowledge of something which is not public -- in plain words, signing uses the private key. Verification, however, should be doable by anybody, and thus use the public key.

the" RSA 算法实际上是一种数学运算,可以拒绝进入非对称加密系统和数字签名系统,这一事实暗示了相当多的混乱.RSA 标准(又名 PKCS#1)进一步加剧了混淆,它隐含地依赖于 RSA 数字签名最初是如何描述的,即作为反向加密"(签名者用他的私钥加密数据").这导致了诸如名为sha1WithRSAEncryption"的 RSA 签名之类的东西.这很不幸.

A fair bit of confusion is implied by the fact that "the" RSA algorithm is actually a mathematical operation which can be declined into both an asymmetric encryption system, and a digital signature system. The confusion is further enhanced by the RSA standard, aka PKCS#1, which implicitly relies on how RSA digital signatures were first described, i.e. as a "reversed encryption" ("the signer encrypts the data with his private key"). Which leads to things like RSA signatures called "sha1WithRSAEncryption". This is quite unfortunate.

因此,您必须首先决定是要保密还是要签名.为了保密,对于客户端发送到服务器的数据,服务器应该拥有一个私钥,客户端使用服务器公钥来加密数据.对于签名,每个客户端都有自己的私钥并用它来对数据进行签名,服务器验证签名.由于我上面提到的混淆,我无法从你的描述中看出你真正想要的是什么.

Therefore, you must first decide whether you want confidentiality or signatures. For confidentiality, for data sent from clients to the server, the server shall own a private key, and the clients use the server public key to encrypt the data. For signatures, each client shall have his own private key and use it to sign the data, and the server verifies the signatures. From your description I cannot tell what you are really after, thanks to the confusion I allude to above.

此外,还有一种叫做身份验证的东西,它看起来像数字签名,但功能更弱.签名的关键在于任何人都可以验证签名.特别是,签名可以展示给法官,从而作为对抗签名者的法律武器(签名具有法律约束力——至少如果你做得对,并且在当前的法规状态下通过电子签名,这并不容易).在大多数情况下,您只需要一些更弱和更简单的东西,其中服务器确信它与正确的客户端对话,但之后无法说服其他任何人该客户端确实存在.任何带有用户密码的网站都在使用这种身份验证.

Also, there is something called authentication which may look like digital signatures, but is weaker. The point of signatures is than anybody can verify the signature. In particular, the signature can be shown to a judge and thus serve as legal weapon against the signer (the signature is legally binding -- at least if you do it right, and in the current state of regulations over electronic signatures, this is not easy). In most situations you only need something weaker and simpler, in which the server is convinced that it talks to the right client, but cannot afterwards convince anybody else that this client was really there. Any web site with user passwords is using such authentication.

话虽如此……

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

  • RSA asymmetric encryption covers only short messages. For a 1024-bit RSA key (i.e. a key where the most important part, the "RSA modulus", is a big number with a value between 2^1023 and 2^1024, and encrypted messages will be of length 128 bytes), the maximum size of an encrypted message is 117 bytes (that's the actual source of your error message). When we want to send longer messages, we use an hybrid system, in which we only encrypt a small bunch of random bits (say 128 bits) and use that bunch as a key for a symmetric encryption system (e.g. AES) which can process much longer messages (and much faster, too).

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

RSA signatures, similarly, can be computed only on short messages, hence the PKCS#1 standard mandates that a signature is actually computed over a hash value. The hash value is the output of a specific hash function, which is computed over the message to sign. The hash function has a fixed-sized output (e.g. 256 bits for SHA-256) but accepts input messages of (almost) arbitrary length. Hash functions are public (there is no key in them) and, for proper security, must have some special properties. SHA-256 is, right now, not a bad choice. SHA-1 (a predecessor of SHA-256) has been proven to have some weaknesses and should be avoided. MD5 has (a kind-of uncle of SHA-1) has bigger weaknesses and shall not be used.

正确使用非对称加密,尤其是在混合方案和数字签名中,比上面的文字可能暗示的更棘手.在某些时候很容易出错,不可见,即代码看起来可以工作,但会泄漏对攻击者有用的数据.使用非对称加密或数字签名的正确方法是依赖现有的、经过深思熟虑的协议.协议是将加密元素组装到一个连贯的系统中,在其中处理泄漏.主要示例是 TLS,也称为 SSL.它是一种确保机密数据传输的协议,具有完整性和身份验证(可能是相互身份验证).HTTPS 协议是 HTTP 和 SSL 的混合.好的一面是 HTTPS 有现有的实现,特别是在 C# 中.最容易实现和调试的代码是已经实现和调试的代码.所以使用 HTTPS,你会活得更久更快乐.

Proper use of asymmetric encryption, especially in an hybrid scheme, and digital signatures, is trickier than what the text above may suggest. It is awfully easy to get it wrong at some point, invisibly, i.e. the code will appear to work but will leak data useful for an attacker. The right way to use asymmetric encryption or digital signatures is to rely on existing, well-thought protocols. A protocol is an assembly of cryptographic elements into a coherent system, where leaks are taken care of. The prime example is TLS, also known as SSL. It is a protocol which ensures confidential data transmission, with integrity and authentication (possibly mutual authentication). The HTTPS protocol is a mixture of HTTP and SSL. The bright side is that HTTPS has existing implementations, notably in C#. The code which is easiest to implement and debug is the code which has already been implemented and debugged. So use HTTPS and you will live longer and happier.

这篇关于.NET 中的 RSA 加密/解密问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆