Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
386 views
in Technique[技术] by (71.8m points)

c# - RSA Encrypt / Decrypt Problem in .NET

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.

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);

}

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;
}

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;
}

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

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.

With that being said...

  • 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 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.

  • 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...