views:

375

answers:

7

Signing an assembly in .NET involves a public/private key pair. As far as I can tell from what I've read .NET uses the RSA algorithm and the private key to sign the assembly, checking it with the embedded public key.

I know how to retrieve the public key (Assembly.PublicKey). I was wondering, if that key could be used to decrypt a short string that contains some data encrypted with the private key.

The docs I've read so far (e.g.) seem to imply that only the other way round is possible: That I would have to use the public key to encrypt and the private key to decrypt - but I don't really want to include that in the assembly, do I.

I guess it would be ok, if I just signed the string. But how?

I'm a bit at a loss how to start this. Does anybody have a code snippet?

Also, encrypting / signing of the small string would ideally happen in PHP, since I want to offload that to a web server and all we have so far is your generic PHP/MySQL hosted website.

Use Case: I'm trying to come up with a lightweight licensing scheme for a software we are about to release to beta testers. Since the software will probably be freeware, all we really want to achieve is

  1. know who has the software installed (email address)
  2. let the software expire after a given period, after which the user will have to get a new license
    • this is as easy as filling out a form and waiting for an automated email with the key to arrive
    • we are trying to reduce the likelyhood of old versions coming back to bite our reputation / haunt us

Being able to encrypt a tuple (expiry date, fingerprint) and decrypt that at startup would make an easy licensing module: The first time the application is started, the user is asked for email address, name, organisation. This information is posted to the webserver along with an md5 fingerprint of some system info (nic, computer name, assembly major and minor version). The webserver answers by email (checks validity of email address) with an encrypted version of the tuple (expiry date, fingerprint) that is then saved to disk. On startup, this can be decrypted and compared with current date and regenerated fingerprint.

EDIT: OK, so I don't have all the answers to my question yet. But it looks like .NET won't make it easy to use the private key for encryption (if that is at all possible, the answers don't really agree on that).

The route I will take is this (based on my use case):

  • I will use the private key to sign the license.
  • I will use the public key to verify the license was signed by the private key
  • I will post another question aimed at PHP devs on how to use the .NET keys (produced by sn.exe) to sign some text
  • I am not really worried about the user seeing the license, as it is a hash anyway and computed from stuff he allready knows. All I want is to make it too hard to be worth any bother for your typical building architect to copy my software without me knowing (remember, the software will be freeware - all I want is a paper trail of who has it installed...)

Thank you very much for your answers.

A: 

In RSA Public keys are used for encryption, private keys are used for decryption. You can't use a public key to decrypt anything...

Jason Punyon
i think this not the complete true, public key can be used to decrypt chiffre that is encrypted with the private key. Digital signature works in this way.
martin
@martin: Verifying a signature of a message is not the same thing as decrypting the message.
Jason Punyon
Yes it is. Digital signatures encrypt a hash of the message for convenience, not because that is a fundamental feature of the algorithm. You could also encrypt the entire message with the private key if you wanted to. But what would the point of that be? That just makes more work for the decryptor. The only reason I could think of that you'd choose to encrypt an entire message with the private key is if you did not have a hash algorithm you believed was sufficiently strong.
Eric Lippert
@Eric Lippert: You school me again sir. +1
Jason Punyon
+2  A: 

You cannot decrypt using the public key. That way, the whole point of "public" would be lost.

(You might, however, be able to sign something using the private key, then verify the signature using the public key. That's what the framework uses the keys for - the assembly is signed, and the public key is used to verify the signature.)

Tor Haugen
The authentication of a signature is exactly why the public key is included in an assembly. The content of the assembly (including th public key itself) is hashed. The resulting hash is added to the assembly along with a signature generated by the private key. The public key can be used in combination with the signature to confirm that the included hash is genuine. One the hash is confirmed as genuine the content of the assembly can be confirmed as untampered by ensuring it hashs to the same value.
AnthonyWJones
Tor, what do you believe "verification" is, if not decryption? Verification is nothing more nor less than decrypting a message with the public key, so of course it is possible to decrypt with a public key.
Eric Lippert
Verifying a digital signature is not decryption. Look it up.
Tor Haugen
Tor, I don't need to look it up. Verification of a digital signature consists of (1) hashing the message, (2) decrypting the encrypted hash with the known public key of the presumed signer, and (3) comparing the hash of the message to the decrypted hash. If the decrypted hash matches the computed hash, then the decrypted hash was encrypted with the private key corresponding to the known public key. (As an alternative, the entire message could be encrypted with the private key and decrypted with the public key, if you felt that the hash was inadequate. This technique is seldom used.)
Eric Lippert
Regardless, your statement that nothing can be decrypted with the public key is simply *false*. Any message encrypted with the private key can be decrypted with the public key.
Eric Lippert
Yup, you're absolutely right. Guess I didn't really think it through. Thanks for setting me straight :-)
Tor Haugen
@Eric, what you describe above is not adequate. The PKCS #1 standard doesn't just "encrypt" a hash, it uses a more detailed padding scheme. It doesn't just compare the hashes during the verification, because that would be insecure. And finally it has been known for ages that signing a message without hashing it first is susceptible to existential attacks.
Accipitridae
A: 

Warning! This answer is wrong but I'm going to leave it here none-the-less because the series of comments attached are, I think of sufficient interest to others to keep the answer around. Ok it makes me look like an idiot but thats nothing new to me ;) Vote as you wish.

A public key can be used to:-

  • Encrypt something that can only be decrypted with the private key
  • Authenticate something signed with the private key

It can not be used to decrypt something to encrypted by a private key. Its for this reason that the Public/Private key system is refered to as an Asymetric system.

AnthonyWJones
Your two sentences contradict each other. Authentication IS "decrypting something encrypted by a private key". What else would authentication be?
Eric Lippert
Also, you've misunderstood what "asymmetric cryptosystem" means. An asymmetric cryptosystem is one in which the encrypting key and the decrypting key are different keys. That's ALL it means.
Eric Lippert
Finally, based on your comment above, you've gotten backwards what the public and private keys are. The product of the two primes is public. The public key consists of the product and a number "e" coprime to the totient of the product. The private key consists of a number "d" which, when multiplied by "e" is congruent to one, modulo the totient. So your statement that the product is part of the private key, not the public key, is false; it's the opposite. The product is a part of the public key.
Eric Lippert
@Eric: Well thats put me properly in my place :( Thanks for the correction on which side of the key the product of the primes is found and on the correct meaning of asymetric. Although I don't see how I've managed to imply the asymetric was more than the two keys being different, I'm probably not reading it as others would.
AnthonyWJones
@Eric: "What else would authentication be?". Well.. for thousands of years mankind has found ways to do "authentication" in manner where the production is hard but the authentication is easy. A wax seal and a modern bank note are two examples. The process of authentication is nothing like the process of signing. I'm clearly in error imaginng the this is true in this case.
AnthonyWJones
@Eric: I didn't think it was actually necessary (or even possible) to decrypt the signature to reveal the data inside. I imagined that the original data, the signature and the public key were combined in a way that simply confirmed the signature without any actual decrypting happening.
AnthonyWJones
It is the fact that the signature is decryptable by the public key to the correct hash that verifies that the signature was encrypted by the private key. Since only the signing entity possesses the private key, this authenticates that the hash was signed by that entity.
Eric Lippert
@Eric: Out of curiosity, do you have a background in cryptography? Just wondering because you know a lot about it.
Joan Venge
I do not. I know hardly anything at all about cryptography. The most important thing that I know about cryptography is that I am not anywhere *close* to being qualified to use cryptography to solve a real user-impacting security problem.
Eric Lippert
@Eric: I love your comments, both funny and very informative. I wish you had a training dvd of some sorts about C# and .NET for people of all levels.
Joan Venge
@Eric: That's about the most useful piece of knowledge about cryptography a programmer can have. I hope it spreads.
Bill the Lizard
A: 

Not in .NET.

In many traditional public-key encryption algorithm, like RSA, you can encrypt and decrypt both ways, typically one way is called "encryption" and the other "signing", even though you actually end up with an encrypted version of something both ways.

However, in .NET the RSA implementation has been crippled, and when signing will only produce digests of the input, not the full processed information.

It seems there's some disagreement about what can and cannot be done with RSA, so let me edit my answer to be more specific.

I'm talking about RSA math, not any particular RSA implementation.

RSA math allows you to encode information either of the two keys (private or public), and the encoded data can only be decoded with the other of the two keys.

Typically, you encode with a public key, encrypting the information, and decode it with the private key, decrypting the information. Or, you take a hash of the information, encode it with the private key, signing the hash, and decode the hash with the public key, in order to compare and verify the signature.

Typical implementations does not allow one to do full encoding of data from private to public, only by hashing the data, but the math behind RSA fully allows this.

Lasse V. Karlsen
could I reproduce the crippled signing "feature" in php? Do you know of a library for that?
Daren Thomas
Unfortunately I don't know much of PHP at all, your best bet is to augment your question and see if any PHP people can answer it.
Lasse V. Karlsen
This is nonsense. Encrypting with the private key and decrypting with the public key is not secure. You'll have to use a signature scheme instead. .NET has not been crippled. Rather it quite correctly does not allow users to misuse keys.
Accipitridae
What you're describing as "not secure" *is* a signature scheme. If you encrypt it with the private key, so that it can only be decrypted with the private key, that *is* a signature. Typically though, a signature is just a hash that has been encrypted, but the process is 100% identical. .NET has been "crippled" in that you cannot use the private key for encryption, even though the algorithm and math as such is perfectly valid. The point of doing that is creating data that is unforgeable, it can only be decrypted with the single key, which means it has been encrypted with the other key.
Lasse V. Karlsen
@Lasse, there are differences between the paddings used for encryption and signatures. These differences may look unimportant to you, but they are very important. For example ,if you use the PKCS #1 encryption padding for generating a signature then you get an scheme where at least some signatures can be forged. Once you understand the reasons behind the details in the PKCS #1 and other padding schemes, it should be obvious that the implementation of .NET is completely reasonable.
Accipitridae
That is an implementation detail. The math behind RSA is perfectly valid both ways.
Lasse V. Karlsen
Note that I don't disagree with you, I'm just saying that if someone implemented RSA in a more theoretical manner, "encryption" in both directions would work, for different purposes, but still be "the same".
Lasse V. Karlsen
To be specific; the math behind RSA allows anything encoded with the private key only to be decoded with the public key, and anything encoded with the public key to only be decoded with the private key.
Lasse V. Karlsen
What you say is correct for "textbook RSA". However, "textbook RSA" is susceptible to a large number of attacks. See for example the paper "Twenty years of attacks on the RSA cryptoystem" by D. Boneh. Standards for RSA avoid these problems, and implementations following the standards no longer have the same properties that "textbook RSA" has. At least this time, you can't blame Microsoft for following a standard.
Accipitridae
A: 

In RSA the only actual difference between a public key and a private key is which one you keep secret.

So you can use a public key as the encryption key and decrypt with the private key, or use the private key as the encryption key and decrypt with the public key.

Encrypting with the private key is used for digital signatures (anybody can decode with the public key).

But as @Lasse V. Karlsen pointed out, .Net might make it more difficult than it should be...

MZB
this is what I thought... will have to try some stuff out...
Daren Thomas
@Mike: Have you got reference to backup that first statement, that is not how I understand the maths. As I understood it, the Private Key is fundementally composed of 2 large primes the public is not. Or have things moved on since?
AnthonyWJones
Applied Cryptography 2nd Edition, Bruce Schneier, p467:"The message could just have easily have been encrypted with d and decrypted with e, the choice is arbitrary. I will spare you the number theory that proves why this works, most current texts on cryptography cover it in detail." Number Theory: A Programmer's Guide by Mark Herkommer gives the details on p205. (Too much to type). Excellent book, but in my edition the misprints make it a real challenge!
MZB
@Mike: Thanks for that, shame I had to get slammed by Eric in the process ;)
AnthonyWJones
The difference between public key and secret key is that the public key is usually a small number like 65537. If you switch them and publish your privat key then both keys are toast. NIST for example specifies that a public key can not be large, to prevent exactly this kind of mistake.
Accipitridae
A: 

I think both direction are possible encrypt with public and decrypt with private and encrypt with private key. The second is the way how digital signature works.

martin
+1  A: 

This can be done using SignedXml http://msdn.microsoft.com/en-us/library/ms229745.aspx. At a lower level you can prob use RSAPKCS1SignatureDeformatter and RSAPKCS1SignatureFormatter. These work by encrypting a hash of the data then comparing the data with the (decrypted) hash the other end. I believe the hashing is used because private key encryption can only handle small data. Not sure about reusing the assembly public key, if it is causing problems just use a separate key pair.

Word of warning, check out this as these classes can result in 20 second hang ups! http://www.pcreview.co.uk/forums/thread-3428177.php

This approach is vulnerable to the signature verification code being tampered with using Reflexil but that is another matter.

I wrote the following but rereading I think you already got this: You aren't really trying to encrypt or hide data from the user, you want to stop them from creating or tampering the license. You are right that a public private key encryption algorithm can be used for this. This is known as Signing using a private key (server side license generation). And verification of the signature using a public key (license checking in the app). I mention this terminology as it'll help with research.

DW