Using the StrongNameIdentityPermissionAttribute
One of the much touted features of .NET is security, and one of the gems
tucked away within the framework is the StrongNameIdentityPermissionAttribute
(which is a bit of a mouthful to be sure). This permits you to write code that
can guarantee that a caller (either the immediate caller or one somewhere up the call
chain) has been signed with a particular strong name.
One of the uses of this attribute is when you have a particular assembly
which contains an algorithm or other set of functionality that you don't want
someone to rip off by simply referencing your assembly and calling the code
within it. Use of the attribute is checked during JIT compilation, and
you can use it to guarantee, for example, that the immediate caller of your code
has been signed with a particular strong name. This won't stop someone from
decompiling the assembly, but will inhibit callers to only those you allow.
It's fairly simple to use, once you know how, and the how isn't self evident
based on the documentation and tools available to you. The attribute is valid on
any Assembly, Class, Struct, Constructor or Method, so you have the opportunity
to place it just about on any code that you would like to secure.
To use the attribute, you need (at least) two assemblies. In this example
I'll have a main executable, signed with the public key 'mainapp', and another
assembly where we use the public key portion of the mainapp key to ensure that
the direct caller into our assembly is mainapp.
The steps to create this are as follows...
(1) Create a console application.
(2) Generate a key pair using the sn utility.
(3) Update the assemblyinfo file to reference the key file created in step 2.
[assembly: AssemblyKeyFile(@'..\..\mainapp.snk')]
|
(4) Now for the nasty bit. The StrongNameIdentityPermission attribute
requires the public key portion of the strong name, so you would think that you
could extrack this using sn...
sn -p mainapp.snk mainapp.public
- This generates a file which contains the
public key, but it's in binary so that's useless.
sn -tp mainapp.snk
- This displays a fairly long string, which would appear
to be the public key that you need, however if you enter this value into code,
you'll find that you get a security exception (and it's from mscorlib, which
isn't at all helpful!).
What you need to do it use sn -Tp <assembly> (note the uppercase T)...
|
sn -Tp mainapp.exe
Microsoft (R) .NET Framework Strong Name Utility Version 1.0.3705.0
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
Public key is
0024000004800000940000000602000000240000525341310004000001000100c17577e2aa99d8
73e07f896b4dc8233d687fbfac6e0b0b403b997f75a2b252ffae47abf328bf4481d2184460e3d3
64b0ed7bba85d6ddd96f994e3397ea817ef3871ff0cfbd5590ffbba44963ae5e8784de51b58df9
059d4eda4dd638a4ae147ad2f3a5b674780b330cedd93d27a377281c6056092c2ac48a8b27c536
31f7d5b6
Public key token is 1fb524c4de32f533
|
This will generate the correct public key (though why there are different ones
I'll never know!). Armed with this information, you can now create your second
assembly, and attribute it as appropriate.
You can also extract this version of the public key from the assembly in
ILDASM, but you'll have more cutting to do to get the appropriate text, so I'd
suggest the sn -Tp route.
(5) On the code that you want to secure, add the following...
using System.Security.Permissions; ... [StrongNameIdentityPermission ( SecurityAction.Demand , PublicKey="00240000048000009400000006020000" + "00240000525341310004000001000100" + "c17577e2aa99d873e07f896b4dc8233d" + "687fbfac6e0b0b403b997f75a2b252ff" + "ae47abf328bf4481d2184460e3d364b0" + "ed7bba85d6ddd96f994e3397ea817ef3" + "871ff0cfbd5590ffbba44963ae5e8784" + "de51b58df9059d4eda4dd638a4ae147a" + "d2f3a5b674780b330cedd93d27a37728" + "1c6056092c2ac48a8b27c53631f7d5b6")]
|
Once you have done that, you can compile your second assembly, reference it
from the first, and call your code as normal.
When someone else (who has not got your key) attempts to call your assembly,
they are rewarded with a security exception, and there's no way to get around
this. The exception raised implies that you are asking for the strong name of
mscorlib, which seems a little strange, but presumably that's because
mscorlib has access to everything, and so a walk up the chain asking for a
strongname permission looks for a particular strong name first, then looks for
the mscorlib strong name.

So, your code is safe (from callers), if not from prying eyes with ILDASM/Reflector/Anakrino.
For the next level of security you could employ a code obfuscator, but that's a
whole other story.