Recently, I needed to develop something where I would use an RSA public key to encrypt a string in a Python application, then use the corresponding RSA private key in C# to decrypt that string.
What I was trying to accomplish seemed pretty simple to me. I wanted to store a public key in one place (on the python end) for encryption purposes. Then, I wanted to store a corresponding private key in another place (on the C# end) for decryption.
If you don't want to hear me prattle on about things, Skip to the example code section.
There are so many pitfalls that I fell into along the way, including (but definitely not limited to):
- Key Formats - Python really wanted the key in PEM format, C# only seems to accept XML Modulus/Exponent format. SuperDry Key Converter is a great tool for converting between the two.
- Conversion problems - between bytes and character data
- Encoding problems - Base64 Strings, UTF, Unicode, what a mess
- Which Python encryption module to use - PyCrypto, M2Crypto - ended up settling on PyCrypto
- Padding - C# defaults to some randomly generated padding thing that I couldn't seem to reproduce in python
- Signing - I didn't end up using a certificate for signing but I went down that rabbit hole for a while too
The real kicker is that the code ends up being around 20 lines total, between python and C#. Took me about 2 days to figure out those 20 lines though.
At any rate, I ended up using PyCrypto for the encryption and the built-in RSACryptoServiceProvider on the C# side.
A note about padding and signing
After the hurdles of package selection, etc. I ran into problems regarding the type of padding that is used as part of the encryption algorithm. I don't really understand padding (or signing, which is another can of worms) so I basically skipped it by using the PKCS1 v1.5 standard.
From what I gather, that standard is some sort of fixed padding thing, as opposed to a randomized padding (like OAEP). It sounds like randomized padding probably adds an additional layer of security but I couldn't get it to work. So I went with the non-randomized one.
A big disclaimer
I'm not an encryption expert. At all. Not even close.
I'm about 99% sure that this works fine based on my environment, my constraints. However, I don't necessarily claim that this will work securely in other environments. For example. I'm pretty sure that if you are generating RSA keys on the fly and passing them around networks, you need to do some sort of signing process that involves a certificate in addition to the public/private keys.
I don't understand how all that works and didn't implement here. I also didn't need to pass the keys around, so I don't think it was really necessary for what I was doing.
The example code
At any rate, here's a link to the example code. The README has the instructions you need to get up and running.
If you see something that can be improved, something I missed, or if you're having a hard time getting my example code to work, reach out in the comments or file a github issue. I'll be happy to help/for the help.