Encryption keys

  • Thread starter Ray Cassick \(Home\)
  • Start date
R

Ray Cassick \(Home\)

Ok, time to ask the question here.. I have been battling over this one for
sometime now and just have to ask it.

I have created a few classes that I use to act a security keys. These
classes get serialized using a binary formatter and then symmetrically
encrypted. The app will deserialize them and use the contents to judge
licensing capabilities, etc.

Currently the license key and vectors are stored in the code. I don't like
the idea simply because it allows someone with a decompile to get at them.
Yes, I can obfuscate the code but being paranoid like I am I have a feeling
that is just not enough.

My real biggest fear besides the fact that someone can use the key to
decrypt the data is that someone can also use the same key to create a
program that will generate fake license keys for my app.

In another case I have to send a class across a wire on a remoting channel
and the class is going to have a users name and password in it. Again, being
the paranoid programmer that I am I am really afraid of someone with a
sniffer out there looking at the raw bits. I would like to encrypt the
password before I send the class across the wire. Again, I know that I can
just hard code the keys into the app but we all know what I feel about that.

I know that I could use asymmetrical encryption and that gives me the
ability to release a public key that can only be used to decrypt and that
takes care of part of it but from what I have seen asymmetrical encryption
is a royal pain in the butt because it only encrypts data of a maximum size
so I would have to take that into account when I am serializing data and
possibly split the data up into checks, each one encrypted.. Not a clean
option really.

I know already, I have read tones of thing on remoting and how to build
encryption sinks to be used for cases like this, but I really don't need to
encrypt the entire message, just one part of it.

There HAS to be a way to reliably use symmetrical encryption without hard
coding the keys into the code but also protecting them from being used by
other people.

Any simple ideas to this tough question?
 
W

William Stacey [MVP]

Protecting a shared session key is always a problem. If it was not for
this, things would be a lot easier and a lot less books would be written on
it. However, you may not need symmetric key depending on exactly what your
sending and what goes which way (i.e. what to server and what to client.)
If using asymmetric keys, you need at least the server's public key to get
started. This could also be the server cert, but not required. Your assem
can have the public key already in it if you sign the assembly. So the
server will know the private key and the client's will know the server's
public key. Now encrypt your fields with the servers public key. Only the
server (the owner of the private key) can decrypt the fields. Your server
gens a reply (say an xml document with fields.) The server will sign the
reply with private key. Your client can verify server msg is good as it can
validate the signature using the server's public key it has. Now you have a
valid license. However, unless you add more logic, it is valid for *any
machine. You then need to come up with some method to identify a user's
particular machine (i.e. machine hash including user name, mac, domain name,
etc) and the server's reply will include this hash as you also send it in
the request. So your client will verify lic and fail if signature does not
validate. It will then verify the machine hash matches what you dynamically
calculate and compare the two to proceed or fail. No shared secret using
this method - only the server's public key retrieved from the assembly. If
you need to encrypt stuff sent to the client, then more work is needed.
There are a few options, but the best is to not require anything in the
reply that requires encryption. You can verify the lic was produced by the
server via just the signature and the lic will not work for everyone because
of the machine hash. HTH.
 
N

Nick Malik [Microsoft]

SSL uses asymmetric encryption, but only for the handshake. It's a good
pattern to follow.

Embed the public key of your server in your code. Make it available all you
want.

When a client wants to contact you, he asks first for the cert. give it to
him. Validate the cert. It should be signed by a trusted authority.

Next, the client creates a random number. This is the symmetrical key. The
client encrypts the random number using the public key of the server, and
passes it upstream to the server. It also hashes the UNENCRYPTED form of
the key and keeps it around in memory. The server gets the cyphertext,
unencrypts it, and passes back an acknowledgement, in cleartext, containing
the Hash of the unencrypted key. The client receives the hash and compares
it to the hash that he is holding. If it matches, both sides now have a
symmetrical key that they can use.

Now, encrypt using the symmetrical key. It is much faster and easier to
use.

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
--
 
R

Ray Cassick

Thanks... This defiantly sounds like something I can put into the system...
 
W

William Stacey [MVP]

Thanks Nick. Just thinking... If the key is hashed by the server using a
simple hash like SHA1(key) or something, then it is pretty easy to brute
force the same key by hashing all keys and hashing them. Naturally,
starting from 0 may take some time, but a 16 byte key in a simple hash with
no other encryption could be found pretty easy - no? I might rather hash
the key along with the other data elements and sign it with the private key.
Thoughts?

BTW - any relation to Eddy Malik of MS?
 
S

Sean Hederman

Ray Cassick (Home) said:
Ok, time to ask the question here.. I have been battling over this one for
sometime now and just have to ask it.

I have created a few classes that I use to act a security keys. These
classes get serialized using a binary formatter and then symmetrically
encrypted. The app will deserialize them and use the contents to judge
licensing capabilities, etc.

Currently the license key and vectors are stored in the code. I don't like
the idea simply because it allows someone with a decompile to get at them.
Yes, I can obfuscate the code but being paranoid like I am I have a
feeling
that is just not enough.

This should be more than enough for your average user. Admittedly it won't
stop anyone familiar with .NET, but in that case they just round-trip your
assemblies and remove all licensing code completely, no matter what system
you use.
My real biggest fear besides the fact that someone can use the key to
decrypt the data is that someone can also use the same key to create a
program that will generate fake license keys for my app.

Hmm, I've been writing a simple licensing system:
http://home.imaginet.co.za/codingsanity/Licensing.htm, but I don't
particularly care if the users can read my license file. I use digitally
signed XML files (look at http://www.codeproject.com/dotnet/xmldsiglic.asp),
with the public key embedded in an assembly attribute. Since it's an
asymmetric key, all anyone can do with it it read the files (which they can
do anyway since the files are cleartext). They can't generate a valid new
license file from that information. Round-tripping could easily get around
this system, but frankly it can easily get around any system.

I think it was Jon Skeet who pointed out that if people like your
application enough to be cracking it, you're probably making a bit of cash
from it, so why are you worrying about a tiny percentage cheating?
 
W

William Stacey [MVP]

Hey Sean. Just curious. How are you protecting the license so that it is
unique the user and can not be emailed to another user? Using a machine
hash or something and signing that with the rest of the license? What do
you include in your machine hash?
do anyway since the files are cleartext). They can't generate a valid new
license file from that information. Round-tripping could easily get around
this system, but frankly it can easily get around any system.

Currently, you can't round-trip a XenoCode'd assembly. This may change in
the future with a new version of ildasm, but can't today. TIA
 
N

Nick Malik [Microsoft]

Hi William,

no relation to Eddie Malik.

True, salting the key on both ends will help, but the value that you salt it
with has to be easily calculated by both ends independently of one another.
This helps, but not a whole heckuva lot.

Signing with the private key doesn't provide security, it provides
non-repudiation. In other words, since the public key is public, anyone can
decrypt something encrypted with a public key. However, only the owner of
the private key could have signed it (hence the name).

The way that SSL does it is to add one more step: the private key is used to
encrypt a known phrase (I believe it is the server name from the public key
cert plus the time stamp on the server), signed. The client decrypts with
the private key and then verifies the signature. That way, the client knows
that the server knows the key and knows that only the server could have
signed the response.

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
 
N

Nick Malik [Microsoft]

Correction: I meant to say that the symmetric key is used to encrypt the
known phrase, not the private key. My apologies.

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
 
W

William Stacey [MVP]

True, salting the key on both ends will help, but the value that you salt
it
with has to be easily calculated by both ends independently of one
another.

True. You could, however, just add 10 bytes (or more) of random salt and
just remove 10 bytes at the other end. This servers more as a canary and to
make it harder as it is 80 bits larger.
Signing with the private key doesn't provide security, it provides
non-repudiation. In other words, since the public key is public, anyone can
decrypt something encrypted with a public key. However, only the owner of
the private key could have signed it (hence the name).
Agree.

The way that SSL does it is to add one more step: the private key is used to
encrypt a known phrase (I believe it is the server name from the public key
cert plus the time stamp on the server), signed. The client decrypts with
the private key and then verifies the signature. That way, the client knows
that the server knows the key and knows that only the server could have
signed the response.

That was kinda what I was going for. The server hashes the shared key
(which is not included in the msg reply) plus all other elements included in
the reply. It then signs the digest with its' private key as normal. Now
the client can prove the server knows the same key the client sent and the
server does not have to send back the plain hash of the key. Basically this
adds a lot more data to the hash so it is not just the key itself that is
being hashed as that would expose the key to a brute force hash attack.
That said, if all the other information is contained in the response, you
could still brute force the signature because the only thing unknown is
still the key itself (as the rest is on the wire). So he gens a hash with
all the other elements plus the "key guess" and tries to verify the
signature, and keeps going with new key guesses until he finds a match.
Sending an extra long key (say 64 bytes) to begin with will mitigate against
that (because it is twice as long). Both sides will know the long key, but
use only 16 (or 32) bytes for the AES encryption. (uggg...)
Thanks for the reply Nick. Have a good weekend.
 
S

Sean Hederman

William said:
Hey Sean. Just curious. How are you protecting the license so that it is
unique the user and can not be emailed to another user? Using a machine
hash or something and signing that with the rest of the license? What do
you include in your machine hash?

In my currently posted code, I've just used the machine name. The
release I'm working on also allows for domain name, user name, primary
Cpu ID, primary MAC address, and a whole bunch of other variables (both
manually entered and automatically generated). Which ones you want are
set by a policy. The license file contains these values in the clear
currently. Since the license file comes back signed with those values
in them, I don't feel that hashing is required, since any tampering
with the values will invalidate the license file.

I'm also trying to make the whole scheme extensible. The default Policy
works off a signed policy file, but you can implement your own Policy
classes if you want. Basically I'm aiming for a sort of Licensing
Application Block. Any ideas will be welcomed, you can view my email
address at http://home.imaginet.co.za/codingsanity/Images/email.jpg.
Don't use this one I posted with, it's just spambait ;D.

I'd also like to implement a license server, license tracking system,
and various other goodies (but that might take a while). As usual, I
started working on this as just a simple licensing system for a little
commercial app I wrote for a friend and it just sort of ballooned out
of control ;D

I'll blog about improvements and releases as I make them.
Currently, you can't round-trip a XenoCode'd assembly. This may change in
the future with a new version of ildasm, but can't today. TIA

Interesting about XenoCode, does anyone have any idea how they crash
ILDASM?

In any case my licensing system is not meant to be a replacement for
top-quality systems like that and XHEO, but rather a decent-quality
system with enough features to be useful, and extensible enough to be
flexible. Good enough to stop someone with a bit of knowledge with
registry and XML, but not enough to stop someone with the ability to
roundtrip. Of course, if someone can let me know how to crash ILDASM,
then I'll happilly add that functionality in. Assuming it doesn't
violate any patents of course.

Sean Hederman
http://codingsanity.blogspot.com
 
W

William Stacey [MVP]

In my currently posted code, I've just used the machine name. The
release I'm working on also allows for domain name, user name, primary
Cpu ID, primary MAC address, and a whole bunch of other variables (both
manually entered and automatically generated).

Thanks Sean. I too wrote something similar after same article (have a few
replies to the author in the comments.) What I ran into when thinking about
the machine hash was: You can't really use user name, as I run as Admin and
normal user a lot and what all my programs working as both users. You can't
really use domain name for the same reason. Most NICs today have the soft
MAC where you can change them, so not sure you can always trust that.
However that is probably ok for this. Can't really use OS version as an
upgrade would require a new license. The is difficult for the user and a
management issue. The mac, cpuid, ram size, bios date, bios ver, and OS dir
are probably ok to use as hash.
I don't feel that hashing is required, since any tampering
with the values will invalidate the license file.

The hash is just to get a simple digest so you don't have to send all those
fields in the message and the server just signs the machine hash along with
the other elements of your license. Moreover, users may not want you
collecting that information so the hash makes it one way. Some users get
nervous about programs collecting data from their machines - MS has felt
this before. Anyhow, let me know about your thoughts. Cheers.
 
S

Sean Hederman

William Stacey said:
Thanks Sean. I too wrote something similar after same article (have a few
replies to the author in the comments.) What I ran into when thinking
about
the machine hash was: You can't really use user name, as I run as Admin
and
normal user a lot and what all my programs working as both users. You
can't
really use domain name for the same reason. Most NICs today have the soft
MAC where you can change them, so not sure you can always trust that.
However that is probably ok for this. Can't really use OS version as an
upgrade would require a new license. The is difficult for the user and a
management issue. The mac, cpuid, ram size, bios date, bios ver, and OS
dir
are probably ok to use as hash.

Which fields are sent will as configurable as I can make it, via a
LicensePolicy class. I've created an XmlLicensePolicy class that reads the
required fields from an XML file. So basically all this will be up to the
developer who uses the Licensing Application Block in their app. Thanks for
the comments though, I'll put your concerns about the various fields into my
documentation, assuming I get around to writing any ;D
The hash is just to get a simple digest so you don't have to send all
those
fields in the message and the server just signs the machine hash along
with
the other elements of your license. Moreover, users may not want you
collecting that information so the hash makes it one way. Some users get
nervous about programs collecting data from their machines - MS has felt
this before. Anyhow, let me know about your thoughts. Cheers.

Hmm, very good point. I think that (once again), I'll leave this up to the
developer using the Block. What I'll do is create a boolean attribute for
each field called "hash", and default it to true if it's not present. So if
the developer wants it in the clear, they actually have to change from the
defaults.

What might be a good idea is to have "soft" fields and "hard" fields. If the
soft fields change, then the license requires re-activation, whereas if the
hard fields change, the license doesn't work. Of course, that would be the
decision of the LicensePolicy class, but I'm talking about the default
implementation. So that'd mean I'd have to keep the hashes of the soft and
hard fields apart, and validate them separately. Do you think it'd be better
to keep a hash of each field, or to append all the fields together and hash
the result? The downside I can see about the One Big Hash (or 2BigHash if I
go with soft/hard) it that I wouldn't be able to determine the reason for
hash failure (i.e. "The license is not valid for this computer" as opposed
to "The license is not valid").
 
W

William Stacey [MVP]

What might be a good idea is to have "soft" fields and "hard" fields. If
the
soft fields change, then the license requires re-activation, whereas if the
hard fields change, the license doesn't work.

emm. Not sure. As the developer it does not matter much as I get a phone
call from the user either way. The other thing I am thinking is KISS. With
all these options, you can get lost in the goal of the whole thing which is
simply "hey? Is this component licensed or not?" XHEO went down the complex
route and got a bit caught up with itself IMHO. You can make a small
carieer out of that thing with all the options, guis, etc. That said, it is
a nice product from my few days of review of it. In most cases, however, I
would prefer something much simplier. Complex means support and email/phone
calls in most cases - so keep it short and sweet for both the developer and
their end-users.
Do you think it'd be better
to keep a hash of each field, or to append all the fields together and hash
the result?

I would just use one hash (i.e. MachineHash). IMO, you don't really need to
know what caused the hash not to match, as you need to send another license
anyway and will be talking with the user probably via email or phone. You
could, however, keep a saved copy of what strings made up the original
MachineHash so you could derive what changed if you really had to drill down
on a support issue. (maybe even just a log file or something.) The server
side will still have the original hash used in the lic request. I would not
complicate the lic file more with a bunch of fields, but that is a
preference.

Cheers!
 
S

Sean Hederman

William Stacey said:
emm. Not sure. As the developer it does not matter much as I get a phone
call from the user either way. The other thing I am thinking is KISS.
With
all these options, you can get lost in the goal of the whole thing which
is
simply "hey? Is this component licensed or not?" XHEO went down the
complex
route and got a bit caught up with itself IMHO. You can make a small
carieer out of that thing with all the options, guis, etc. That said, it
is
a nice product from my few days of review of it. In most cases, however,
I
would prefer something much simplier. Complex means support and
email/phone
calls in most cases - so keep it short and sweet for both the developer
and
their end-users.

Mmm, I see your point. I actually had a look at XHEO's web page and geeked
out a bit :) I'll try to restrain myself. Problem is that I want the kind
of extensibility and configurability you get with most of the App Blocks,
but you're right that it could be easy to go too far. Simplicity first,
flexibility later.
I would just use one hash (i.e. MachineHash). IMO, you don't really need
to
know what caused the hash not to match, as you need to send another
license
anyway and will be talking with the user probably via email or phone. You
could, however, keep a saved copy of what strings made up the original
MachineHash so you could derive what changed if you really had to drill
down
on a support issue. (maybe even just a log file or something.) The server
side will still have the original hash used in the lic request. I would
not
complicate the lic file more with a bunch of fields, but that is a
preference.

Good idea!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top