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.