views:

171

answers:

4

Is there any way to perform private key encryption in C#?

I know about the standard RSACryptoServiceProvider in System.Security.Cryptography, but these classes provide only public key encryption and private key decryption. Also, they provide digital signature functionality, which uses internally private key encryption, but there are not any publicly accessible functions to perform private key encryption and public key decryption.

I've found this article on codeproject, which is a very good start point for performing this kind of encryption, however, I was looking for some ready-to-use code, as the code in the article can hardly encrypt arbitrary-long byte arrays containing random values (that means any values, including zeroes).

Do you know some good components (preferably free) to perform private key encryption?
I use .NET 3.5.

Note: I know this is generally considered as bad way of using asymmetric encryption (encrypting using private key and decrypting using public key), but I just need to use it that way.

Additional Explanation

Consider you have

var bytes = new byte[30] { /* ... */ };

and you want to use 2048bit RSA to ensure no one have changed anything in this array.

Normally, you would use digital signature (ie. RIPEMD160), which you then attach to the original bytes and send over to the receiver.

So, you have 30 bytes of original data, and additional 256 bytes of digital signature (because it is a 2048bit RSA), which is overall of 286 bytes. Hovewer, only 160 bits of that 256 bytes are actually hash, so there is exactly 1888 bits (236 bytes) unused.

So, my idea was this:

Take the 30 bytes of original data, attach to it the hash (20 bytes), and now encrypt these 50 bytes. You get 256 bytes long message, which is much shorter than 286 bytes, because "you were able to push the actual data inside the digital signature".

ECDSA Resources

MSDN
Eggheadcafe.com
c-plusplus.de
MSDN Blog
Wiki

DSA Resources

CodeProject
MSDN 1
MSDN 2
MSDN 3

Final Solution

If anyone is interested how I've solved this problem, I'm going to use 1024bit DSA and SHA1, which is widely supported on many different versions of Windows (Windows 2000 and newer), security is good enough (I'm not signing orders, I just need to ensure that some child can't crack the signature on his iPhone (:-D)), and the signature size is only 40 bytes long.

+2  A: 

Your Public key is a sub-set of your private key. You can use your private key as a public key as it will only use the components of the full key it requires.

In .NET both your private & public keys are stored in the RSAParameters struct. The struct contains fields for:

  • D
  • DP
  • DQ
  • Exponent
  • InverseQ
  • Modulus
  • P
  • Q
Aren
In an erased answer, I mentioned that you can probably pass the private key in to the method in place of the public key, and vice versa. I still don't recommend it, though.
Steven Sudit
@Aren B: If you pass in your public key, will it require your public key to decrypt or your private key?
Steven Sudit
Yeah, but how can I encrypt using private key? I don't want to use public part of the private key, but the private key itself. That is - (data ^ D) % Modulus, instead of (data ^ Exponent) % Modulus.
Paja
+1  A: 

I get it now, after reading the comments.

The answer is: don't do it.

Cryptographic signature algorithms are not algorithms from which you can pick and choose - or modify - steps. In particular, supposing a signature sig looks something like encrypt(hash), orig + sig is not the same as encrypt(orig + hash). Further, even outdated signature algorithms like PKCS v1.5 are not as simple as encrypt(hash) in the first place.

A technique like the one you describe sacrifices security for the sake of cleverness. If you don't have the bandwidth for a 256 byte signature, then you need one of:

  1. a different algorithm,
  2. more bandwidth, or
  3. a smaller key.

And if you go with (1), please be sure it's not an algorithm you made up! The simple fact is that crypto is hard.

ladenedge
AFAIK digital signature is just encrypted hash. If you use 256bit SHA, then 1792bits are wasted. Or what is stored in these bits?
Paja
I suggest choosing option 1 so as to allow option 3.
Steven Sudit
And what algorithm do you suggest? I need very strong security, and I think 512 bit RSA is just too small. Does `.NET` have some additional asymmetric encryption implementations, different than RSA, which are secure enough even if small key is used?
Paja
@Paja: You need to make up your mind here. If you want the security to be very strong then you have to be willing to pay for it in size and speed. .NET offers support for RSA, DSA, and Elliptic Curve Diffie-Hellman. Note that DSA is for signing and "supports key lengths from 512 bits to 1024 bits in increments of 64 bits". Here: http://msdn.microsoft.com/en-us/library/92f9ye3s.aspx
Steven Sudit
@Steven Sudit: Reading the article about [DSA](http://en.wikipedia.org/wiki/Digital_Signature_Algorithm), they recommend using at least 2048bit log key. I'm willing to use so long code, if I could manage to put part of the actual message into the signature. I still don't get it what additional security will I loose if I put my data inside the wasted space in signature.
Paja
@Paja: Compared to symmetric encryption, public key is much slower and requires more bits to guard against brute force. That's the price for flexibility, which is why we use hybrids with session keys. I'm not willing to even *suggest* that I know what harm would come of messing with the signature that way, so I wouldn't recommend it.
Steven Sudit
+1  A: 

If you're at the point where the data is so small that the digital signature is huge in comparison, then you have excess signature. The solution isn't to roll your own algorithm, but to cut down what's there. You definitely don't want to try to combine a key with the hash in an amateurish way: this has been broken already, which is why we have HMAC's.

So here's the basic idea:

  1. Create a session key using a cryptographically strong RNG.

  2. Transmit it via PKE.

  3. Use the session key to generate an HMAC-SHA1 (or HMAC-RIPEMD160, or whatever).

  4. If the size of the hash is absurdly large for the given data, cut it in half by XORing the top with the bottom. Repeat as needed.

  5. Send the data and the (possibly cut-down) hash.

  6. The receiver uses the data and the session key to regenerate the hash and then compares it with the one transmitted (possibly after first cutting it down.)

  7. Change session keys often.

This is a compromise between the insanity of rolling your own system and using an ill-fitting one.

I'm wide open to constructive criticism...

Steven Sudit
Well, I don't really understand how [HMAC](http://en.wikipedia.org/wiki/HMAC) works, but I need to make the whole client-server conversation as small as possible. But you are saying to use PKE to transmit the session key. If I use 2048bit RSA to transmit that key, I will be wasting a lot of space again. (As I said, I don't really know how HMAC works, so please excuse me if I didn't get it.)
Paja
Look, the session key can be reused, so you have to divide its size by the number of uses to calculate its overhead. You transmit the session key at the start and use it for some fixed number of data packets before transmitting another. As for HMAC, it's just a way to encrypt the hash securely. HMAC provides the signing mechanism and PKE transmits the (reusable) session key securely. You can adjust the size of each part to get the appropriate balance of speed and size.
Steven Sudit
I will be transmitting only few bytes, nothing else. Just connect to the server, send the few bytes with signature, and disconnect. That's all. I actually don't need the reusability-feature. And I'm a bit worried that the session key encrypted using PKE will be almost as big as the message itself, maybe bigger.
Paja
If the data itself is very short, then you have to *expect* the signature to be larger. If it weren't, then it would be susceptible to brute-force attacks, given how few possibilities there are for the plaintext. The only way I can see around this is to not sign each packet, but instead send an affirmation of the entire day's traffic.
Steven Sudit
I think HMAC is not suitable for my needs, as I need the asymmetric properties of the digital signature. If I understand HMAC correctly, then the other party will be able to "sign" the messages the same way as I do, using the same key, so he will be able to create messages which will looks as they were created by me. BTW, 160 bits or 256 bits are OK for me, but 2048 bits is just too much. :-(
Paja
Correct, HMAC is symmetric, which is why it's paired with a session key transmitted asymmetrically. The reason it exists is that signing each packet by asymmetrically encrypting the hash is too expensive.
Steven Sudit
I've found [ECDSA](http://msdn.microsoft.com/en-us/library/system.security.cryptography.ecdsacng.aspx), which looks very cool, the signatures are relatively small compared to RSA signature, but it is available only in Win XP SP3, Win Vista SP1 and Win 7. How big market share has Win XP SP1 and XP SP2? I'm not certain I can afford to loose support for these systems.
Paja
XP is officially dead, and anyone still running it who hasn't upgraded to at least the latest service pack should expect to be left out in the cold. As for ECDSA, it's not magic:
Steven Sudit
"As with elliptic curve cryptography in general, the bit size of the public key believed to be needed for ECDSA is about twice the size of the security level, in bits. By comparison, at a security level of 80 bits, meaning an attacker requires about the equivalent of about 280 signature generations to find the private key, the size of a DSA public key is at least 1024 bits, whereas the size of an ECDSA public key would be 160 bits.
Steven Sudit
On the other hand, the signature size is the same for both DSA and ECDSA: 4t bits, where t is the security level measured in bits, that is, about 320 bits for a security level of 80 bits." (http://en.wikipedia.org/wiki/Elliptic_Curve_DSA)
Steven Sudit
If the market share of those systems is big enough, then I can't just ignore them, even if they are ignored by Microsoft. So what are my options now? Use RSA or ECDSA to sign the message with big-enough signature, or nothing? I thought that if I encrypt the message with concatenated hash using private key, then it would be as secure as stand-alone signature, because one would have to crack the whole private key to actually cause any harm, as is in the case of digital signature. Thus, I would save several bytes that are wasted in the signature.
Paja
+3  A: 

What you are trying to design is known as a "Signature scheme with message recovery".

Designing a new signature scheme is hard. Designing a new signature scheme with message recovery is harder. I don't know all the details about your design, but there is a good chance that it is susceptible to a chosen message attack.

One proposal for signature schemes with message recovery is RSA PSS-R. But unfortunately, this proposal is covered with a patent.

The IEEE P1363 standarization group, once discussed the addition of signature schemes with message recovery. However, I'm not sure about the current state of this effort, but it might be worth checking out.

Accipitridae
+1, the only person who got this correct. There is an existing standard, ISO 9796-3, that does just this very thing. IIRC, it is not very straightforward.
GregS
Are there any C# implementation of the ISO 9796-3? If not, then I can't use this. :-( And implementing it myself is impossible for me, as I don't have any experience with implementing cryptographic standards.
Paja
Not that I know of, and I believe there were attacks on earlier versions. Bouncycastle seems to have an implementation of 9796-2, but you already have a decent solution.
GregS
Wow, this is "the only person who got this correct", yet Paja will be going with DSA, an option I brought up. How quickly they forget.
Steven Sudit
It looks to me like Paja is doing the right thing. The first step was to explore all the options. Packing part of the message into a signature is one option. And exploring the feasibility of this option was the question. Once all the options are on the table one can make a decision. For Paja it appears that support is the most important factor. For other readers facing a similar problem, the faster verification of RSA signatures might be more important.
Accipitridae