I just found out that `RSACryptoServiceProvider`, the RSA implementation in .NET, does not allow you to use a private key to encrypt data. I'm no cryptographic expert, but I do know how asymmetric key algorithms like RSA work, and that you can use a private key for encryption. That's how signing works. But why cripple the implementation and limit it to just signing?
The rationale is in the common application of public-key cryptography, where:
- Encrypting with the public key ensures _confidentiality_, i.e. the process known as encryption in common tongue. Encrypting with a public key ensures that only the entity in possession of the private key can read the data.
- Encrypting with the private key ensures _authenticity_, i.e. the process known as signing in common tongue. There is no need to encrypt the entire data stream to ensure authenticity, so the common approach is to calculate a hash of the data and sign the hash instead.
To facilitate these patterns, the .NET public-key cryptography API is designed so that:
- `Encrypt()` encrypts with a public key, `Decrypt()` requires a private key.
- `SignData()` encrypts with a private key, but since that implies a signature, one must provide a hashing algorithm and a private key. `VerifyData()` uses a public key.
But I want to encrypt with my private key! Yes, this is what `SignData()` does, but it does so to just the hash calculated by the provided hashing algorithm, since that is the de-facto approach for signing, and implementing my own `HashAlgorithm` that passes in all the data is just wrong.
OK, these are the common uses, but why limit the API to that? There is no limitation in the RSA algorithm to my knowledge that prevents other uses than the two offered by `RSACryptoServiceProvider`. In fact, if I wanted to perform the traditional signing approach, I could just hash the data myself and encrypt it with my private key myself. Or even better, `SignData()` could be available to help me _for convenience_.
So, how do you apply RSA in .NET in an uncommon manner? Don't use .NET's cryptography API, but embrace an open source alternatives like [BouncyCastle](http://bouncycastle.org), which saves your day.
I think because RSA private key encryption for a longer string is very slow.
ReplyDeleteHi Håvard,
ReplyDeleteI very much agree, I'm a bit frustrated by this aspect of the .net implementation myself. I'm working on a project that deals with ensuring the authenticity of information on ATM smart cards, which have sensitive data on them encrypted with a CA private key to ensure authenticity, so i need to be able to decrypt with the public key. Sign/verify just isn't what I need, since I'm not the one putting the data on the cards.
I've had a look at bouncycastle, but i found the library to be a bit hard to work with, due to the abundance of classes and the lack of documenation.
Could you pls provide a few lines of example code for decryption with a public key using bublycastle? TIA!
Hi Antonio. I wrote a quick post on using BouncyCastle for RSA. Take a look at RSA using BouncyCastle. Hope it helps!
ReplyDeleteHi Håvard,
ReplyDeleteI ended up implementing RSA myself the same day I posted my question to you, but thanx anyway:) The implementation was trivial, RSA is explained well on wikipedia and the algorithm amounts to a single few-letter formula. All that's needed besides the formula is an implementation of BigInteger(to represent the encrypted text and the key), which I found on codeproject(a very good one i might add, by a chap called Chew Keong TAN - he's Danish apparently:))
Anyway, just wanted to say thanks for posting the "RSA using BouncyCastle" (now that I see the code it seems simple:)) even tho i didn't end up using it.
thank you for your post - I had exactly the same problem
ReplyDeleteI'm facing the same problem.
ReplyDeleteDid not want to implement and maintain RSA in my code, and could not find an opensource alternative.
Lets see how Bouncy Castle works out!