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.

sn -k mainapp.snk

(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.

Don't worry, this is an image of an exception, not an exception thown by this web page!

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.